From 0a923be2f6427fdf2a5769b4b8a08e26c758dfab Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Thu, 28 Apr 2022 12:35:16 +0200 Subject: [PATCH 001/935] hw/openrisc: page-align FDT address The QEMU-provided FDT was only being recognized by the kernel when it was used in conjunction with -initrd. Without it, the magic bytes wouldn't be there and the kernel couldn't load it. This patch fixes the issue by page aligning the provided FDT. Cc: Stafford Horne Cc: Peter Maydell Signed-off-by: Jason A. Donenfeld Signed-off-by: Stafford Horne --- hw/openrisc/openrisc_sim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 8184caa60b..99b14940f4 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -356,7 +356,7 @@ static uint32_t openrisc_load_fdt(Or1ksimState *state, hwaddr load_start, } /* We put fdt right after the kernel and/or initrd. */ - fdt_addr = ROUND_UP(load_start, 4); + fdt_addr = TARGET_PAGE_ALIGN(load_start); ret = fdt_pack(fdt); /* Should only fail if we've built a corrupted tree */ From 8e28b65f52637917d3d02ade4e0ae85442de9f86 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 7 Apr 2022 11:39:32 +0300 Subject: [PATCH 002/935] qemu-img: properly list formats which have consistency check implemented Simple grep for the .bdrv_co_check callback presence gives the following list of block drivers * QED * VDI * VHDX * VMDK * Parallels which have this callback. The presense of the callback means that consistency check is supported. The patch updates documentation accordingly. Signed-off-by: Denis V. Lunev CC: Kevin Wolf CC: Hanna Reitz Message-Id: <20220407083932.531965-1-den@openvz.org> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- docs/tools/qemu-img.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index 8885ea11cf..85a6e05b35 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -332,8 +332,8 @@ Command description: ``-r all`` fixes all kinds of errors, with a higher risk of choosing the wrong fix or hiding corruption that has already occurred. - Only the formats ``qcow2``, ``qed`` and ``vdi`` support - consistency checks. + Only the formats ``qcow2``, ``qed``, ``parallels``, ``vhdx``, ``vmdk`` and + ``vdi`` support consistency checks. In case the image does not have any inconsistencies, check exits with ``0``. Other exit codes indicate the kind of inconsistency found or if another error From 31009d13cc505b9569971fbbe50266c1727ba5db Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 7 Apr 2022 15:36:55 +0200 Subject: [PATCH 003/935] docs/vhost-user: Clarifications for VHOST_USER_ADD/REM_MEM_REG The specification for VHOST_USER_ADD/REM_MEM_REG messages is unclear in several points, which has led to clients having incompatible implementations. This changes the specification to be more explicit about them: * VHOST_USER_ADD_MEM_REG is not specified as receiving a file descriptor, though it obviously does need to do so. All implementations agree on this one, fix the specification. * VHOST_USER_REM_MEM_REG is not specified as receiving a file descriptor either, and it also has no reason to do so. rust-vmm does not send file descriptors for removing a memory region (in agreement with the specification), libvhost-user and QEMU do (which is a bug), though libvhost-user doesn't actually make any use of it. Change the specification so that for compatibility QEMU's behaviour becomes legal, even if discouraged, but rust-vmm's behaviour becomes the explicitly recommended mode of operation. * VHOST_USER_ADD_MEM_REG doesn't have a documented return value, which is the desired behaviour in the non-postcopy case. It also implemented like this in QEMU and rust-vmm, though libvhost-user is buggy and sometimes sends an unexpected reply. This will be fixed in a separate patch. However, in postcopy mode it does reply like VHOST_USER_SET_MEM_TABLE. This behaviour is shared between libvhost-user and QEMU; rust-vmm doesn't implement postcopy mode yet. Mention it explicitly in the spec. * The specification doesn't mention how VHOST_USER_REM_MEM_REG identifies the memory region to be removed. Change it to describe the existing behaviour of libvhost-user (guest address, user address and size must match). Signed-off-by: Kevin Wolf Message-Id: <20220407133657.155281-2-kwolf@redhat.com> Reviewed-by: Raphael Norwitz Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- docs/interop/vhost-user.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst index 4dbc84fd00..f9e721ba5f 100644 --- a/docs/interop/vhost-user.rst +++ b/docs/interop/vhost-user.rst @@ -308,6 +308,7 @@ replies. Here is a list of the ones that do: There are several messages that the master sends with file descriptors passed in the ancillary data: +* ``VHOST_USER_ADD_MEM_REG`` * ``VHOST_USER_SET_MEM_TABLE`` * ``VHOST_USER_SET_LOG_BASE`` (if ``VHOST_USER_PROTOCOL_F_LOG_SHMFD``) * ``VHOST_USER_SET_LOG_FD`` @@ -1334,6 +1335,14 @@ Master message types ``VHOST_USER_REM_MEM_REG`` message, this message is used to set and update the memory tables of the slave device. + Exactly one file descriptor from which the memory is mapped is + passed in the ancillary data. + + In postcopy mode (see ``VHOST_USER_POSTCOPY_LISTEN``), the slave + replies with the bases of the memory mapped region to the master. + For further details on postcopy, see ``VHOST_USER_SET_MEM_TABLE``. + They apply to ``VHOST_USER_ADD_MEM_REG`` accordingly. + ``VHOST_USER_REM_MEM_REG`` :id: 38 :equivalent ioctl: N/A @@ -1349,6 +1358,14 @@ Master message types ``VHOST_USER_ADD_MEM_REG`` message, this message is used to set and update the memory tables of the slave device. + The memory region to be removed is identified by its guest address, + user address and size. The mmap offset is ignored. + + No file descriptors SHOULD be passed in the ancillary data. For + compatibility with existing incorrect implementations, the slave MAY + accept messages with one file descriptor. If a file descriptor is + passed, the slave MUST close it without using it otherwise. + ``VHOST_USER_SET_STATUS`` :id: 39 :equivalent ioctl: VHOST_VDPA_SET_STATUS From 5ebfdeb21223e0406a711decbb2baceb5ec8c416 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 7 Apr 2022 15:36:56 +0200 Subject: [PATCH 004/935] libvhost-user: Fix extra vu_add/rem_mem_reg reply Outside of postcopy mode, neither VHOST_USER_ADD_MEM_REG nor VHOST_USER_REM_MEM_REG are supposed to send a reply unless explicitly requested with the need_reply flag. Their current implementation always sends a reply, even if it isn't requested. This confuses the master because it will interpret the reply as a reply for the next message for which it actually expects a reply. need_reply is already handled correctly by vu_dispatch(), so just don't send a reply in the non-postcopy part of the message handler for these two commands. Signed-off-by: Kevin Wolf Message-Id: <20220407133657.155281-3-kwolf@redhat.com> Reviewed-by: Raphael Norwitz Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- subprojects/libvhost-user/libvhost-user.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c index 47d2efc60f..eccaff5168 100644 --- a/subprojects/libvhost-user/libvhost-user.c +++ b/subprojects/libvhost-user/libvhost-user.c @@ -800,8 +800,7 @@ vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { DPRINT("Successfully added new region\n"); dev->nregions++; - vmsg_set_reply_u64(vmsg, 0); - return true; + return false; } } @@ -874,15 +873,13 @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { } } - if (found) { - vmsg_set_reply_u64(vmsg, 0); - } else { + if (!found) { vu_panic(dev, "Specified region not found\n"); } close(vmsg->fds[0]); - return true; + return false; } static bool From a81d8d4a7203e4be392f9ad37af104759b7cbda5 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 7 Apr 2022 15:36:57 +0200 Subject: [PATCH 005/935] vhost-user: Don't pass file descriptor for VHOST_USER_REM_MEM_REG The spec clarifies now that QEMU should not send a file descriptor in a request to remove a memory region. Change it accordingly. For libvhost-user, this is a bug fix that makes it compatible with rust-vmm's implementation that doesn't send a file descriptor. Keep accepting, but ignoring a file descriptor for compatibility with older QEMU versions. Signed-off-by: Kevin Wolf Message-Id: <20220407133657.155281-4-kwolf@redhat.com> Reviewed-by: Raphael Norwitz Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- hw/virtio/vhost-user.c | 2 +- subprojects/libvhost-user/libvhost-user.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index a80315ecfc..2d434ff0bc 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -751,7 +751,7 @@ static int send_remove_regions(struct vhost_dev *dev, vhost_user_fill_msg_region(®ion_buffer, shadow_reg, 0); msg->payload.mem_reg.region = region_buffer; - ret = vhost_user_write(dev, msg, &fd, 1); + ret = vhost_user_write(dev, msg, NULL, 0); if (ret < 0) { return ret; } diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c index eccaff5168..d0041c864b 100644 --- a/subprojects/libvhost-user/libvhost-user.c +++ b/subprojects/libvhost-user/libvhost-user.c @@ -822,15 +822,15 @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { int i; bool found = false; - if (vmsg->fd_num != 1) { + if (vmsg->fd_num > 1) { vmsg_close_fds(vmsg); - vu_panic(dev, "VHOST_USER_REM_MEM_REG received %d fds - only 1 fd " + vu_panic(dev, "VHOST_USER_REM_MEM_REG received %d fds - at most 1 fd " "should be sent for this message type", vmsg->fd_num); return false; } if (vmsg->size < VHOST_USER_MEM_REG_SIZE) { - close(vmsg->fds[0]); + vmsg_close_fds(vmsg); vu_panic(dev, "VHOST_USER_REM_MEM_REG requires a message size of at " "least %d bytes and only %d bytes were received", VHOST_USER_MEM_REG_SIZE, vmsg->size); @@ -877,7 +877,7 @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { vu_panic(dev, "Specified region not found\n"); } - close(vmsg->fds[0]); + vmsg_close_fds(vmsg); return false; } From 15aee7ac9587562b1d021959dedc2bbb7e9a9fb3 Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Wed, 27 Apr 2022 13:40:54 +0200 Subject: [PATCH 006/935] block: Classify bdrv_get_flags() as I/O function This function is safe to call in an I/O context, and qcow2_do_open() does so (invoked in an I/O context by qcow2_co_invalidate_cache()). Signed-off-by: Hanna Reitz Message-Id: <20220427114057.36651-2-hreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block.c | 2 +- include/block/block-global-state.h | 1 - include/block/block-io.h | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/block.c b/block.c index 8cd16e757e..2c00dddd80 100644 --- a/block.c +++ b/block.c @@ -6298,7 +6298,7 @@ const char *bdrv_get_device_or_node_name(const BlockDriverState *bs) int bdrv_get_flags(BlockDriverState *bs) { - GLOBAL_STATE_CODE(); + IO_CODE(); return bs->open_flags; } diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h index 25bb69bbef..21265e3966 100644 --- a/include/block/block-global-state.h +++ b/include/block/block-global-state.h @@ -172,7 +172,6 @@ void bdrv_next_cleanup(BdrvNextIterator *it); BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs); void bdrv_iterate_format(void (*it)(void *opaque, const char *name), void *opaque, bool read_only); -int bdrv_get_flags(BlockDriverState *bs); char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp); char *bdrv_dirname(BlockDriverState *bs, Error **errp); diff --git a/include/block/block-io.h b/include/block/block-io.h index 5e3f346806..62c84f0519 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -103,6 +103,7 @@ int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg, bool bdrv_is_read_only(BlockDriverState *bs); bool bdrv_is_writable(BlockDriverState *bs); bool bdrv_is_sg(BlockDriverState *bs); +int bdrv_get_flags(BlockDriverState *bs); bool bdrv_is_inserted(BlockDriverState *bs); void bdrv_lock_medium(BlockDriverState *bs, bool locked); void bdrv_eject(BlockDriverState *bs, bool eject_flag); From 06e9cd19a4e9acf8d24327361a999943d846f607 Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Wed, 27 Apr 2022 13:40:55 +0200 Subject: [PATCH 007/935] qcow2: Do not reopen data_file in invalidate_cache qcow2_co_invalidate_cache() closes and opens the qcow2 file, by calling qcow2_close() and qcow2_do_open(). These two functions must thus be usable from both a global-state and an I/O context. As they are, they are not safe to call in an I/O context, because they use bdrv_unref_child() and bdrv_open_child() to close/open the data_file child, respectively, both of which are global-state functions. When used from qcow2_co_invalidate_cache(), we do not need to close/open the data_file child, though (we do not do this for bs->file or bs->backing either), and so we should skip it in the qcow2_co_invalidate_cache() path. To do so, add a parameter to qcow2_do_open() and qcow2_close() to make them skip handling s->data_file, and have qcow2_co_invalidate_cache() exempt it from the memset() on the BDRVQcow2State. (Note that the QED driver similarly closes/opens the QED image by invoking bdrv_qed_close()+bdrv_qed_do_open(), but both functions seem safe to use in an I/O context.) Fixes: https://gitlab.com/qemu-project/qemu/-/issues/945 Signed-off-by: Hanna Reitz Message-Id: <20220427114057.36651-3-hreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/qcow2.c | 104 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 42 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index b5c47931ef..4f5e6440fb 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1296,7 +1296,8 @@ static int validate_compression_type(BDRVQcow2State *s, Error **errp) /* Called with s->lock held. */ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, - int flags, Error **errp) + int flags, bool open_data_file, + Error **errp) { ERRP_GUARD(); BDRVQcow2State *s = bs->opaque; @@ -1614,50 +1615,52 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, goto fail; } - /* Open external data file */ - s->data_file = bdrv_open_child(NULL, options, "data-file", bs, - &child_of_bds, BDRV_CHILD_DATA, - true, errp); - if (*errp) { - ret = -EINVAL; - goto fail; - } + if (open_data_file) { + /* Open external data file */ + s->data_file = bdrv_open_child(NULL, options, "data-file", bs, + &child_of_bds, BDRV_CHILD_DATA, + true, errp); + if (*errp) { + ret = -EINVAL; + goto fail; + } - if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) { - if (!s->data_file && s->image_data_file) { - s->data_file = bdrv_open_child(s->image_data_file, options, - "data-file", bs, &child_of_bds, - BDRV_CHILD_DATA, false, errp); + if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) { + if (!s->data_file && s->image_data_file) { + s->data_file = bdrv_open_child(s->image_data_file, options, + "data-file", bs, &child_of_bds, + BDRV_CHILD_DATA, false, errp); + if (!s->data_file) { + ret = -EINVAL; + goto fail; + } + } if (!s->data_file) { + error_setg(errp, "'data-file' is required for this image"); ret = -EINVAL; goto fail; } - } - if (!s->data_file) { - error_setg(errp, "'data-file' is required for this image"); - ret = -EINVAL; - goto fail; - } - /* No data here */ - bs->file->role &= ~BDRV_CHILD_DATA; + /* No data here */ + bs->file->role &= ~BDRV_CHILD_DATA; - /* Must succeed because we have given up permissions if anything */ - bdrv_child_refresh_perms(bs, bs->file, &error_abort); - } else { - if (s->data_file) { - error_setg(errp, "'data-file' can only be set for images with an " - "external data file"); - ret = -EINVAL; - goto fail; - } + /* Must succeed because we have given up permissions if anything */ + bdrv_child_refresh_perms(bs, bs->file, &error_abort); + } else { + if (s->data_file) { + error_setg(errp, "'data-file' can only be set for images with " + "an external data file"); + ret = -EINVAL; + goto fail; + } - s->data_file = bs->file; + s->data_file = bs->file; - if (data_file_is_raw(bs)) { - error_setg(errp, "data-file-raw requires a data file"); - ret = -EINVAL; - goto fail; + if (data_file_is_raw(bs)) { + error_setg(errp, "data-file-raw requires a data file"); + ret = -EINVAL; + goto fail; + } } } @@ -1839,7 +1842,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, fail: g_free(s->image_data_file); - if (has_data_file(bs)) { + if (open_data_file && has_data_file(bs)) { bdrv_unref_child(bs, s->data_file); s->data_file = NULL; } @@ -1876,7 +1879,8 @@ static void coroutine_fn qcow2_open_entry(void *opaque) BDRVQcow2State *s = qoc->bs->opaque; qemu_co_mutex_lock(&s->lock); - qoc->ret = qcow2_do_open(qoc->bs, qoc->options, qoc->flags, qoc->errp); + qoc->ret = qcow2_do_open(qoc->bs, qoc->options, qoc->flags, true, + qoc->errp); qemu_co_mutex_unlock(&s->lock); } @@ -2714,7 +2718,7 @@ static int qcow2_inactivate(BlockDriverState *bs) return result; } -static void qcow2_close(BlockDriverState *bs) +static void qcow2_do_close(BlockDriverState *bs, bool close_data_file) { BDRVQcow2State *s = bs->opaque; qemu_vfree(s->l1_table); @@ -2740,7 +2744,7 @@ static void qcow2_close(BlockDriverState *bs) g_free(s->image_backing_file); g_free(s->image_backing_format); - if (has_data_file(bs)) { + if (close_data_file && has_data_file(bs)) { bdrv_unref_child(bs, s->data_file); s->data_file = NULL; } @@ -2749,11 +2753,17 @@ static void qcow2_close(BlockDriverState *bs) qcow2_free_snapshots(bs); } +static void qcow2_close(BlockDriverState *bs) +{ + qcow2_do_close(bs, true); +} + static void coroutine_fn qcow2_co_invalidate_cache(BlockDriverState *bs, Error **errp) { ERRP_GUARD(); BDRVQcow2State *s = bs->opaque; + BdrvChild *data_file; int flags = s->flags; QCryptoBlock *crypto = NULL; QDict *options; @@ -2767,14 +2777,24 @@ static void coroutine_fn qcow2_co_invalidate_cache(BlockDriverState *bs, crypto = s->crypto; s->crypto = NULL; - qcow2_close(bs); + /* + * Do not reopen s->data_file (i.e., have qcow2_do_close() not close it, + * and then prevent qcow2_do_open() from opening it), because this function + * runs in the I/O path and as such we must not invoke global-state + * functions like bdrv_unref_child() and bdrv_open_child(). + */ + qcow2_do_close(bs, false); + + data_file = s->data_file; memset(s, 0, sizeof(BDRVQcow2State)); + s->data_file = data_file; + options = qdict_clone_shallow(bs->options); flags &= ~BDRV_O_INACTIVE; qemu_co_mutex_lock(&s->lock); - ret = qcow2_do_open(bs, options, flags, errp); + ret = qcow2_do_open(bs, options, flags, false, errp); qemu_co_mutex_unlock(&s->lock); qobject_unref(options); if (ret < 0) { From ccfaf783c8eecae99b671e4e892954c9226ef5dc Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Wed, 27 Apr 2022 13:40:56 +0200 Subject: [PATCH 008/935] Revert "main-loop: Disable GLOBAL_STATE_CODE() assertions" This reverts commit b1c073490553f80594b903ceedfc7c1aef6b1b19. (We wanted to do so once the 7.1 tree opens, which has happened. The issue reported in https://gitlab.com/qemu-project/qemu/-/issues/945 should be fixed by the preceding patches.) Signed-off-by: Hanna Reitz Message-Id: <20220427114057.36651-4-hreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- include/qemu/main-loop.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h index d3750c8e76..89bd9edefb 100644 --- a/include/qemu/main-loop.h +++ b/include/qemu/main-loop.h @@ -284,8 +284,7 @@ bool qemu_in_main_thread(void); #else #define GLOBAL_STATE_CODE() \ do { \ - /* FIXME: Re-enable after 7.0 release */ \ - /* assert(qemu_in_main_thread()); */ \ + assert(qemu_in_main_thread()); \ } while (0) #endif /* CONFIG_COCOA */ From 96edda8f142928c627f93b3ad74c64edf86cc22f Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Wed, 27 Apr 2022 13:40:57 +0200 Subject: [PATCH 009/935] iotests: Add regression test for issue 945 Create a VM with a BDS in an iothread, add -incoming defer to the command line, and then export this BDS via NBD. Doing so should not fail an assertion. Signed-off-by: Hanna Reitz Message-Id: <20220427114057.36651-5-hreitz@redhat.com> Reviewed-by: Eric Blake Tested-by: Eric Blake Signed-off-by: Kevin Wolf --- .../tests/export-incoming-iothread | 81 +++++++++++++++++++ .../tests/export-incoming-iothread.out | 5 ++ 2 files changed, 86 insertions(+) create mode 100755 tests/qemu-iotests/tests/export-incoming-iothread create mode 100644 tests/qemu-iotests/tests/export-incoming-iothread.out diff --git a/tests/qemu-iotests/tests/export-incoming-iothread b/tests/qemu-iotests/tests/export-incoming-iothread new file mode 100755 index 0000000000..7679e49103 --- /dev/null +++ b/tests/qemu-iotests/tests/export-incoming-iothread @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 +# group: rw quick migration +# +# Regression test for issue 945: +# https://gitlab.com/qemu-project/qemu/-/issues/945 +# Test adding an export on top of an iothread-ed block device while in +# -incoming defer. +# +# Copyright (C) 2022 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import os +import iotests +from iotests import qemu_img_create + + +image_size = 1 * 1024 * 1024 +test_img = os.path.join(iotests.test_dir, 'test.img') +node_name = 'node0' +iothread_id = 'iothr0' + +nbd_sock = os.path.join(iotests.sock_dir, 'nbd.sock') + + +class TestExportIncomingIothread(iotests.QMPTestCase): + def setUp(self) -> None: + qemu_img_create('-f', iotests.imgfmt, test_img, str(image_size)) + + self.vm = iotests.VM() + self.vm.add_object(f'iothread,id={iothread_id}') + self.vm.add_blockdev(( + f'driver={iotests.imgfmt}', + f'node-name={node_name}', + 'file.driver=file', + f'file.filename={test_img}' + )) + self.vm.add_incoming('defer') + self.vm.launch() + + def tearDown(self): + self.vm.shutdown() + os.remove(test_img) + + def test_export_add(self): + result = self.vm.qmp('nbd-server-start', { + 'addr': { + 'type': 'unix', + 'data': { + 'path': nbd_sock + } + } + }) + self.assert_qmp(result, 'return', {}) + + # Regression test for issue 945: This should not fail an assertion + result = self.vm.qmp('block-export-add', { + 'type': 'nbd', + 'id': 'exp0', + 'node-name': node_name, + 'iothread': iothread_id + }) + self.assert_qmp(result, 'return', {}) + + +if __name__ == '__main__': + iotests.main(supported_fmts=['generic'], + unsupported_fmts=['luks'], # Would need a secret + supported_protocols=['file']) diff --git a/tests/qemu-iotests/tests/export-incoming-iothread.out b/tests/qemu-iotests/tests/export-incoming-iothread.out new file mode 100644 index 0000000000..ae1213e6f8 --- /dev/null +++ b/tests/qemu-iotests/tests/export-incoming-iothread.out @@ -0,0 +1,5 @@ +. +---------------------------------------------------------------------- +Ran 1 tests + +OK From 6d17e2879854d7d0e623c06a9286085e97bf3545 Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Mon, 14 Mar 2022 17:27:18 +0100 Subject: [PATCH 010/935] block/vmdk: Fix reopening bs->file VMDK disk data is stored in extents, which may or may not be separate from bs->file. VmdkExtent.file points to where they are stored. Each that is stored in bs->file will simply reuse the exact pointer value of bs->file. (That is why vmdk_free_extents() will unref VmdkExtent.file (e->file) only if e->file != bs->file.) Reopen operations can change bs->file (they will replace the whole BdrvChild object, not just the BDS stored in that BdrvChild), and then we will need to change all .file pointers of all such VmdkExtents to point to the new BdrvChild. In vmdk_reopen_prepare(), we have to check which VmdkExtents are affected, and in vmdk_reopen_commit(), we can modify them. We have to split this because: - The new BdrvChild is created only after prepare, so we can change VmdkExtent.file only in commit - In commit, there no longer is any (valid) reference to the old BdrvChild object, so there would be nothing to compare VmdkExtent.file against to see whether it was equal to bs->file before reopening (There is BDRVReopenState.old_file_bs, but the old bs->file BdrvChild's .bs pointer will be NULL-ed when the new BdrvChild is created, and so we cannot compare VmdkExtent.file->bs against BDRVReopenState.old_file_bs) Signed-off-by: Hanna Reitz Message-Id: <20220314162719.65384-2-hreitz@redhat.com> Signed-off-by: Kevin Wolf --- block/vmdk.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/block/vmdk.c b/block/vmdk.c index 37c0946066..38e5ab3806 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -178,6 +178,10 @@ typedef struct BDRVVmdkState { char *create_type; } BDRVVmdkState; +typedef struct BDRVVmdkReopenState { + bool *extents_using_bs_file; +} BDRVVmdkReopenState; + typedef struct VmdkMetaData { unsigned int l1_index; unsigned int l2_index; @@ -400,15 +404,63 @@ static int vmdk_is_cid_valid(BlockDriverState *bs) return 1; } -/* We have nothing to do for VMDK reopen, stubs just return success */ static int vmdk_reopen_prepare(BDRVReopenState *state, BlockReopenQueue *queue, Error **errp) { + BDRVVmdkState *s; + BDRVVmdkReopenState *rs; + int i; + assert(state != NULL); assert(state->bs != NULL); + assert(state->opaque == NULL); + + s = state->bs->opaque; + + rs = g_new0(BDRVVmdkReopenState, 1); + state->opaque = rs; + + /* + * Check whether there are any extents stored in bs->file; if bs->file + * changes, we will need to update their .file pointers to follow suit + */ + rs->extents_using_bs_file = g_new(bool, s->num_extents); + for (i = 0; i < s->num_extents; i++) { + rs->extents_using_bs_file[i] = s->extents[i].file == state->bs->file; + } + return 0; } +static void vmdk_reopen_clean(BDRVReopenState *state) +{ + BDRVVmdkReopenState *rs = state->opaque; + + g_free(rs->extents_using_bs_file); + g_free(rs); + state->opaque = NULL; +} + +static void vmdk_reopen_commit(BDRVReopenState *state) +{ + BDRVVmdkState *s = state->bs->opaque; + BDRVVmdkReopenState *rs = state->opaque; + int i; + + for (i = 0; i < s->num_extents; i++) { + if (rs->extents_using_bs_file[i]) { + s->extents[i].file = state->bs->file; + } + } + + vmdk_reopen_clean(state); +} + +static void vmdk_reopen_abort(BDRVReopenState *state) +{ + vmdk_reopen_clean(state); +} + static int vmdk_parent_open(BlockDriverState *bs) { char *p_name; @@ -3072,6 +3124,8 @@ static BlockDriver bdrv_vmdk = { .bdrv_open = vmdk_open, .bdrv_co_check = vmdk_co_check, .bdrv_reopen_prepare = vmdk_reopen_prepare, + .bdrv_reopen_commit = vmdk_reopen_commit, + .bdrv_reopen_abort = vmdk_reopen_abort, .bdrv_child_perm = bdrv_default_perms, .bdrv_co_preadv = vmdk_co_preadv, .bdrv_co_pwritev = vmdk_co_pwritev, From ecf3200703df77f9f5ac95e3cc8e1379e40cb36a Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Mon, 14 Mar 2022 17:27:19 +0100 Subject: [PATCH 011/935] iotests/reopen-file: Test reopening file child This should work for all format drivers that support reopening, so test it. (This serves as a regression test for HEAD^: This test used to fail for VMDK before HEAD^.) Signed-off-by: Hanna Reitz Message-Id: <20220314162719.65384-3-hreitz@redhat.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/tests/reopen-file | 89 ++++++++++++++++++++++++ tests/qemu-iotests/tests/reopen-file.out | 5 ++ 2 files changed, 94 insertions(+) create mode 100755 tests/qemu-iotests/tests/reopen-file create mode 100644 tests/qemu-iotests/tests/reopen-file.out diff --git a/tests/qemu-iotests/tests/reopen-file b/tests/qemu-iotests/tests/reopen-file new file mode 100755 index 0000000000..8590a94d53 --- /dev/null +++ b/tests/qemu-iotests/tests/reopen-file @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +# group: rw quick +# +# Test reopening a format driver's file child +# +# Copyright (C) 2022 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import os +import iotests +from iotests import imgfmt, qemu_img_create, QMPTestCase + + +image_size = 1 * 1024 * 1024 +test_img = os.path.join(iotests.test_dir, 'test.img') + + +class TestReopenFile(QMPTestCase): + def setUp(self) -> None: + res = qemu_img_create('-f', imgfmt, test_img, str(image_size)) + assert res.returncode == 0 + + # Add format driver node ('format') on top of the file ('file'), then + # add another raw node ('raw') on top of 'file' so for the reopen we + # can just switch from 'file' to 'raw' + self.vm = iotests.VM() + self.vm.add_blockdev(self.vm.qmp_to_opts({ + 'driver': imgfmt, + 'node-name': 'format', + 'file': { + 'driver': 'file', + 'node-name': 'file', + 'filename': test_img + } + })) + self.vm.add_blockdev(self.vm.qmp_to_opts({ + 'driver': 'raw', + 'node-name': 'raw', + 'file': 'file' + })) + self.vm.launch() + + def tearDown(self) -> None: + self.vm.shutdown() + os.remove(test_img) + + # Check if there was any qemu-io run that failed + if 'Pattern verification failed' in self.vm.get_log(): + print('ERROR: Pattern verification failed:') + print(self.vm.get_log()) + self.fail('qemu-io pattern verification failed') + + def test_reopen_file(self) -> None: + result = self.vm.qmp('blockdev-reopen', options=[{ + 'driver': imgfmt, + 'node-name': 'format', + 'file': 'raw' + }]) + self.assert_qmp(result, 'return', {}) + + # Do some I/O to the image to see whether it still works + # (Pattern verification will be checked by tearDown()) + result = self.vm.qmp('human-monitor-command', + command_line='qemu-io format "write -P 42 0 64k"') + self.assert_qmp(result, 'return', '') + + result = self.vm.qmp('human-monitor-command', + command_line='qemu-io format "read -P 42 0 64k"') + self.assert_qmp(result, 'return', '') + + +if __name__ == '__main__': + # Must support creating images and reopen + iotests.main(supported_fmts=['qcow', 'qcow2', 'qed', 'raw', 'vdi', 'vhdx', + 'vmdk', 'vpc'], + supported_protocols=['file']) diff --git a/tests/qemu-iotests/tests/reopen-file.out b/tests/qemu-iotests/tests/reopen-file.out new file mode 100644 index 0000000000..ae1213e6f8 --- /dev/null +++ b/tests/qemu-iotests/tests/reopen-file.out @@ -0,0 +1,5 @@ +. +---------------------------------------------------------------------- +Ran 1 tests + +OK From 34145a307d849d0b6734d0222a7aa0bb9eef7407 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 7 Mar 2022 15:38:51 +0000 Subject: [PATCH 012/935] coroutine-ucontext: use QEMU_DEFINE_STATIC_CO_TLS() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thread-Local Storage variables cannot be used directly from coroutine code because the compiler may optimize TLS variable accesses across qemu_coroutine_yield() calls. When the coroutine is re-entered from another thread the TLS variables from the old thread must no longer be used. Use QEMU_DEFINE_STATIC_CO_TLS() for the current and leader variables. Signed-off-by: Stefan Hajnoczi Message-Id: <20220307153853.602859-2-stefanha@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Kevin Wolf --- util/coroutine-ucontext.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c index ed368e1a3e..ddc98fb4f8 100644 --- a/util/coroutine-ucontext.c +++ b/util/coroutine-ucontext.c @@ -25,6 +25,7 @@ #include "qemu/osdep.h" #include #include "qemu/coroutine_int.h" +#include "qemu/coroutine-tls.h" #ifdef CONFIG_VALGRIND_H #include @@ -66,8 +67,8 @@ typedef struct { /** * Per-thread coroutine bookkeeping */ -static __thread CoroutineUContext leader; -static __thread Coroutine *current; +QEMU_DEFINE_STATIC_CO_TLS(Coroutine *, current); +QEMU_DEFINE_STATIC_CO_TLS(CoroutineUContext, leader); /* * va_args to makecontext() must be type 'int', so passing @@ -97,14 +98,15 @@ static inline __attribute__((always_inline)) void finish_switch_fiber(void *fake_stack_save) { #ifdef CONFIG_ASAN + CoroutineUContext *leaderp = get_ptr_leader(); const void *bottom_old; size_t size_old; __sanitizer_finish_switch_fiber(fake_stack_save, &bottom_old, &size_old); - if (!leader.stack) { - leader.stack = (void *)bottom_old; - leader.stack_size = size_old; + if (!leaderp->stack) { + leaderp->stack = (void *)bottom_old; + leaderp->stack_size = size_old; } #endif #ifdef CONFIG_TSAN @@ -161,8 +163,10 @@ static void coroutine_trampoline(int i0, int i1) /* Initialize longjmp environment and switch back the caller */ if (!sigsetjmp(self->env, 0)) { - start_switch_fiber_asan(COROUTINE_YIELD, &fake_stack_save, leader.stack, - leader.stack_size); + CoroutineUContext *leaderp = get_ptr_leader(); + + start_switch_fiber_asan(COROUTINE_YIELD, &fake_stack_save, + leaderp->stack, leaderp->stack_size); start_switch_fiber_tsan(&fake_stack_save, self, true); /* true=caller */ siglongjmp(*(sigjmp_buf *)co->entry_arg, 1); } @@ -297,7 +301,7 @@ qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, int ret; void *fake_stack_save = NULL; - current = to_; + set_current(to_); ret = sigsetjmp(from->env, 0); if (ret == 0) { @@ -315,18 +319,24 @@ qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, Coroutine *qemu_coroutine_self(void) { - if (!current) { - current = &leader.base; + Coroutine *self = get_current(); + CoroutineUContext *leaderp = get_ptr_leader(); + + if (!self) { + self = &leaderp->base; + set_current(self); } #ifdef CONFIG_TSAN - if (!leader.tsan_co_fiber) { - leader.tsan_co_fiber = __tsan_get_current_fiber(); + if (!leaderp->tsan_co_fiber) { + leaderp->tsan_co_fiber = __tsan_get_current_fiber(); } #endif - return current; + return self; } bool qemu_in_coroutine(void) { - return current && current->caller; + Coroutine *self = get_current(); + + return self && self->caller; } From ac387a08a9c9f6b36757da912f0339c25f421f90 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 7 Mar 2022 15:38:52 +0000 Subject: [PATCH 013/935] coroutine: use QEMU_DEFINE_STATIC_CO_TLS() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thread-Local Storage variables cannot be used directly from coroutine code because the compiler may optimize TLS variable accesses across qemu_coroutine_yield() calls. When the coroutine is re-entered from another thread the TLS variables from the old thread must no longer be used. Use QEMU_DEFINE_STATIC_CO_TLS() for the current and leader variables. The alloc_pool QSLIST needs a typedef so the return value of get_ptr_alloc_pool() can be stored in a local variable. One example of why this code is necessary: a coroutine that yields before calling qemu_coroutine_create() to create another coroutine is affected by the TLS issue. Signed-off-by: Stefan Hajnoczi Message-Id: <20220307153853.602859-3-stefanha@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Kevin Wolf --- util/qemu-coroutine.c | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c index c03b2422ff..f3e8300c8d 100644 --- a/util/qemu-coroutine.c +++ b/util/qemu-coroutine.c @@ -18,6 +18,7 @@ #include "qemu/atomic.h" #include "qemu/coroutine.h" #include "qemu/coroutine_int.h" +#include "qemu/coroutine-tls.h" #include "block/aio.h" /** Initial batch size is 64, and is increased on demand */ @@ -29,17 +30,20 @@ enum { static QSLIST_HEAD(, Coroutine) release_pool = QSLIST_HEAD_INITIALIZER(pool); static unsigned int pool_batch_size = POOL_INITIAL_BATCH_SIZE; static unsigned int release_pool_size; -static __thread QSLIST_HEAD(, Coroutine) alloc_pool = QSLIST_HEAD_INITIALIZER(pool); -static __thread unsigned int alloc_pool_size; -static __thread Notifier coroutine_pool_cleanup_notifier; + +typedef QSLIST_HEAD(, Coroutine) CoroutineQSList; +QEMU_DEFINE_STATIC_CO_TLS(CoroutineQSList, alloc_pool); +QEMU_DEFINE_STATIC_CO_TLS(unsigned int, alloc_pool_size); +QEMU_DEFINE_STATIC_CO_TLS(Notifier, coroutine_pool_cleanup_notifier); static void coroutine_pool_cleanup(Notifier *n, void *value) { Coroutine *co; Coroutine *tmp; + CoroutineQSList *alloc_pool = get_ptr_alloc_pool(); - QSLIST_FOREACH_SAFE(co, &alloc_pool, pool_next, tmp) { - QSLIST_REMOVE_HEAD(&alloc_pool, pool_next); + QSLIST_FOREACH_SAFE(co, alloc_pool, pool_next, tmp) { + QSLIST_REMOVE_HEAD(alloc_pool, pool_next); qemu_coroutine_delete(co); } } @@ -49,27 +53,30 @@ Coroutine *qemu_coroutine_create(CoroutineEntry *entry, void *opaque) Coroutine *co = NULL; if (CONFIG_COROUTINE_POOL) { - co = QSLIST_FIRST(&alloc_pool); + CoroutineQSList *alloc_pool = get_ptr_alloc_pool(); + + co = QSLIST_FIRST(alloc_pool); if (!co) { if (release_pool_size > qatomic_read(&pool_batch_size)) { /* Slow path; a good place to register the destructor, too. */ - if (!coroutine_pool_cleanup_notifier.notify) { - coroutine_pool_cleanup_notifier.notify = coroutine_pool_cleanup; - qemu_thread_atexit_add(&coroutine_pool_cleanup_notifier); + Notifier *notifier = get_ptr_coroutine_pool_cleanup_notifier(); + if (!notifier->notify) { + notifier->notify = coroutine_pool_cleanup; + qemu_thread_atexit_add(notifier); } /* This is not exact; there could be a little skew between * release_pool_size and the actual size of release_pool. But * it is just a heuristic, it does not need to be perfect. */ - alloc_pool_size = qatomic_xchg(&release_pool_size, 0); - QSLIST_MOVE_ATOMIC(&alloc_pool, &release_pool); - co = QSLIST_FIRST(&alloc_pool); + set_alloc_pool_size(qatomic_xchg(&release_pool_size, 0)); + QSLIST_MOVE_ATOMIC(alloc_pool, &release_pool); + co = QSLIST_FIRST(alloc_pool); } } if (co) { - QSLIST_REMOVE_HEAD(&alloc_pool, pool_next); - alloc_pool_size--; + QSLIST_REMOVE_HEAD(alloc_pool, pool_next); + set_alloc_pool_size(get_alloc_pool_size() - 1); } } @@ -93,9 +100,9 @@ static void coroutine_delete(Coroutine *co) qatomic_inc(&release_pool_size); return; } - if (alloc_pool_size < qatomic_read(&pool_batch_size)) { - QSLIST_INSERT_HEAD(&alloc_pool, co, pool_next); - alloc_pool_size++; + if (get_alloc_pool_size() < qatomic_read(&pool_batch_size)) { + QSLIST_INSERT_HEAD(get_ptr_alloc_pool(), co, pool_next); + set_alloc_pool_size(get_alloc_pool_size() + 1); return; } } From c1fe694357a328c807ae3cc6961c19e923448fcc Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 7 Mar 2022 15:38:53 +0000 Subject: [PATCH 014/935] coroutine-win32: use QEMU_DEFINE_STATIC_CO_TLS() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thread-Local Storage variables cannot be used directly from coroutine code because the compiler may optimize TLS variable accesses across qemu_coroutine_yield() calls. When the coroutine is re-entered from another thread the TLS variables from the old thread must no longer be used. Use QEMU_DEFINE_STATIC_CO_TLS() for the current and leader variables. I think coroutine-win32.c could get away with __thread because the variables are only used in situations where either the stale value is correct (current) or outside coroutine context (loading leader when current is NULL). Due to the difficulty of being sure that this is really safe in all scenarios it seems worth converting it anyway. Signed-off-by: Stefan Hajnoczi Message-Id: <20220307153853.602859-4-stefanha@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Kevin Wolf --- util/coroutine-win32.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/util/coroutine-win32.c b/util/coroutine-win32.c index c196f956d2..7db2e8f8c8 100644 --- a/util/coroutine-win32.c +++ b/util/coroutine-win32.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "qemu/coroutine_int.h" +#include "qemu/coroutine-tls.h" typedef struct { @@ -33,8 +34,8 @@ typedef struct CoroutineAction action; } CoroutineWin32; -static __thread CoroutineWin32 leader; -static __thread Coroutine *current; +QEMU_DEFINE_STATIC_CO_TLS(CoroutineWin32, leader); +QEMU_DEFINE_STATIC_CO_TLS(Coroutine *, current); /* This function is marked noinline to prevent GCC from inlining it * into coroutine_trampoline(). If we allow it to do that then it @@ -51,7 +52,7 @@ qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, CoroutineWin32 *from = DO_UPCAST(CoroutineWin32, base, from_); CoroutineWin32 *to = DO_UPCAST(CoroutineWin32, base, to_); - current = to_; + set_current(to_); to->action = action; SwitchToFiber(to->fiber); @@ -88,14 +89,21 @@ void qemu_coroutine_delete(Coroutine *co_) Coroutine *qemu_coroutine_self(void) { + Coroutine *current = get_current(); + if (!current) { - current = &leader.base; - leader.fiber = ConvertThreadToFiber(NULL); + CoroutineWin32 *leader = get_ptr_leader(); + + current = &leader->base; + set_current(current); + leader->fiber = ConvertThreadToFiber(NULL); } return current; } bool qemu_in_coroutine(void) { + Coroutine *current = get_current(); + return current && current->caller; } From cda86e2b46de857e8b6e16ecd13bb85d81e07899 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 26 Apr 2022 21:23:12 -0700 Subject: [PATCH 015/935] target/arm: Enable SCTLR_EL1.BT0 for aarch64-linux-user This controls whether the PACI{A,B}SP instructions trap with BTYPE=3 (indirect branch from register other than x16/x17). The linux kernel sets this in bti_enable(). Resolves: https://gitlab.com/qemu-project/qemu/-/issues/998 Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20220427042312.294300-1-richard.henderson@linaro.org [PMM: remove stray change to makefile comment] Signed-off-by: Peter Maydell --- target/arm/cpu.c | 2 ++ tests/tcg/aarch64/Makefile.target | 6 ++--- tests/tcg/aarch64/bti-3.c | 42 +++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 tests/tcg/aarch64/bti-3.c diff --git a/target/arm/cpu.c b/target/arm/cpu.c index e46a766d77..2b81b18351 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -197,6 +197,8 @@ static void arm_cpu_reset(DeviceState *dev) /* Enable all PAC keys. */ env->cp15.sctlr_el[1] |= (SCTLR_EnIA | SCTLR_EnIB | SCTLR_EnDA | SCTLR_EnDB); + /* Trap on btype=3 for PACIxSP. */ + env->cp15.sctlr_el[1] |= SCTLR_BT0; /* and to the FP/Neon instructions */ env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 20, 2, 3); /* and to the SVE instructions */ diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target index 6ad0ad49f9..d6a74d24dc 100644 --- a/tests/tcg/aarch64/Makefile.target +++ b/tests/tcg/aarch64/Makefile.target @@ -28,9 +28,9 @@ endif # BTI Tests # bti-1 tests the elf notes, so we require special compiler support. ifneq ($(CROSS_CC_HAS_ARMV8_BTI),) -AARCH64_TESTS += bti-1 -bti-1: CFLAGS += -mbranch-protection=standard -bti-1: LDFLAGS += -nostdlib +AARCH64_TESTS += bti-1 bti-3 +bti-1 bti-3: CFLAGS += -mbranch-protection=standard +bti-1 bti-3: LDFLAGS += -nostdlib endif # bti-2 tests PROT_BTI, so no special compiler support required. AARCH64_TESTS += bti-2 diff --git a/tests/tcg/aarch64/bti-3.c b/tests/tcg/aarch64/bti-3.c new file mode 100644 index 0000000000..a852856d9a --- /dev/null +++ b/tests/tcg/aarch64/bti-3.c @@ -0,0 +1,42 @@ +/* + * BTI vs PACIASP + */ + +#include "bti-crt.inc.c" + +static void skip2_sigill(int sig, siginfo_t *info, ucontext_t *uc) +{ + uc->uc_mcontext.pc += 8; + uc->uc_mcontext.pstate = 1; +} + +#define BTYPE_1() \ + asm("mov %0,#1; adr x16, 1f; br x16; 1: hint #25; mov %0,#0" \ + : "=r"(skipped) : : "x16", "x30") + +#define BTYPE_2() \ + asm("mov %0,#1; adr x16, 1f; blr x16; 1: hint #25; mov %0,#0" \ + : "=r"(skipped) : : "x16", "x30") + +#define BTYPE_3() \ + asm("mov %0,#1; adr x15, 1f; br x15; 1: hint #25; mov %0,#0" \ + : "=r"(skipped) : : "x15", "x30") + +#define TEST(WHICH, EXPECT) \ + do { WHICH(); fail += skipped ^ EXPECT; } while (0) + +int main() +{ + int fail = 0; + int skipped; + + /* Signal-like with SA_SIGINFO. */ + signal_info(SIGILL, skip2_sigill); + + /* With SCTLR_EL1.BT0 set, PACIASP is not compatible with type=3. */ + TEST(BTYPE_1, 0); + TEST(BTYPE_2, 0); + TEST(BTYPE_3, 1); + + return fail; +} From cf7c6d1004eaaae85fd6156556e2f38ff493ef48 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:49:43 -0700 Subject: [PATCH 016/935] target/arm: Split out cpregs.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move ARMCPRegInfo and all related declarations to a new internal header, out of the public cpu.h. Reviewed-by: Alex Bennée Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220501055028.646596-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- hw/arm/pxa2xx.c | 1 + hw/arm/pxa2xx_pic.c | 1 + hw/intc/arm_gicv3_cpuif.c | 1 + hw/intc/arm_gicv3_kvm.c | 2 + target/arm/cpregs.h | 413 +++++++++++++++++++++++++++++++++++++ target/arm/cpu.c | 1 + target/arm/cpu.h | 368 --------------------------------- target/arm/cpu64.c | 1 + target/arm/cpu_tcg.c | 1 + target/arm/gdbstub.c | 3 +- target/arm/helper.c | 1 + target/arm/op_helper.c | 1 + target/arm/translate-a64.c | 4 +- target/arm/translate.c | 3 +- 14 files changed, 427 insertions(+), 374 deletions(-) create mode 100644 target/arm/cpregs.h diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index a6f938f115..0683714733 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -30,6 +30,7 @@ #include "qemu/cutils.h" #include "qemu/log.h" #include "qom/object.h" +#include "target/arm/cpregs.h" static struct { hwaddr io_base; diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c index ed032fed54..b80d75d839 100644 --- a/hw/arm/pxa2xx_pic.c +++ b/hw/arm/pxa2xx_pic.c @@ -17,6 +17,7 @@ #include "hw/sysbus.h" #include "migration/vmstate.h" #include "qom/object.h" +#include "target/arm/cpregs.h" #define ICIP 0x00 /* Interrupt Controller IRQ Pending register */ #define ICMR 0x04 /* Interrupt Controller Mask register */ diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index 8404f46ee0..2d5959db94 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -20,6 +20,7 @@ #include "gicv3_internal.h" #include "hw/irq.h" #include "cpu.h" +#include "target/arm/cpregs.h" /* * Special case return value from hppvi_index(); must be larger than diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 06f5aceee5..611085e98d 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -31,6 +31,8 @@ #include "vgic_common.h" #include "migration/blocker.h" #include "qom/object.h" +#include "target/arm/cpregs.h" + #ifdef DEBUG_GICV3_KVM #define DPRINTF(fmt, ...) \ diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h new file mode 100644 index 0000000000..8064c0763e --- /dev/null +++ b/target/arm/cpregs.h @@ -0,0 +1,413 @@ +/* + * QEMU ARM CP Register access and descriptions + * + * Copyright (c) 2022 Linaro Ltd + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see + * + */ + +#ifndef TARGET_ARM_CPREGS_H +#define TARGET_ARM_CPREGS_H + +/* + * ARMCPRegInfo type field bits. If the SPECIAL bit is set this is a + * special-behaviour cp reg and bits [11..8] indicate what behaviour + * it has. Otherwise it is a simple cp reg, where CONST indicates that + * TCG can assume the value to be constant (ie load at translate time) + * and 64BIT indicates a 64 bit wide coprocessor register. SUPPRESS_TB_END + * indicates that the TB should not be ended after a write to this register + * (the default is that the TB ends after cp writes). OVERRIDE permits + * a register definition to override a previous definition for the + * same (cp, is64, crn, crm, opc1, opc2) tuple: either the new or the + * old must have the OVERRIDE bit set. + * ALIAS indicates that this register is an alias view of some underlying + * state which is also visible via another register, and that the other + * register is handling migration and reset; registers marked ALIAS will not be + * migrated but may have their state set by syncing of register state from KVM. + * NO_RAW indicates that this register has no underlying state and does not + * support raw access for state saving/loading; it will not be used for either + * migration or KVM state synchronization. (Typically this is for "registers" + * which are actually used as instructions for cache maintenance and so on.) + * IO indicates that this register does I/O and therefore its accesses + * need to be marked with gen_io_start() and also end the TB. In particular, + * registers which implement clocks or timers require this. + * RAISES_EXC is for when the read or write hook might raise an exception; + * the generated code will synchronize the CPU state before calling the hook + * so that it is safe for the hook to call raise_exception(). + * NEWEL is for writes to registers that might change the exception + * level - typically on older ARM chips. For those cases we need to + * re-read the new el when recomputing the translation flags. + */ +#define ARM_CP_SPECIAL 0x0001 +#define ARM_CP_CONST 0x0002 +#define ARM_CP_64BIT 0x0004 +#define ARM_CP_SUPPRESS_TB_END 0x0008 +#define ARM_CP_OVERRIDE 0x0010 +#define ARM_CP_ALIAS 0x0020 +#define ARM_CP_IO 0x0040 +#define ARM_CP_NO_RAW 0x0080 +#define ARM_CP_NOP (ARM_CP_SPECIAL | 0x0100) +#define ARM_CP_WFI (ARM_CP_SPECIAL | 0x0200) +#define ARM_CP_NZCV (ARM_CP_SPECIAL | 0x0300) +#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | 0x0400) +#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | 0x0500) +#define ARM_CP_DC_GVA (ARM_CP_SPECIAL | 0x0600) +#define ARM_CP_DC_GZVA (ARM_CP_SPECIAL | 0x0700) +#define ARM_LAST_SPECIAL ARM_CP_DC_GZVA +#define ARM_CP_FPU 0x1000 +#define ARM_CP_SVE 0x2000 +#define ARM_CP_NO_GDB 0x4000 +#define ARM_CP_RAISES_EXC 0x8000 +#define ARM_CP_NEWEL 0x10000 +/* Used only as a terminator for ARMCPRegInfo lists */ +#define ARM_CP_SENTINEL 0xfffff +/* Mask of only the flag bits in a type field */ +#define ARM_CP_FLAG_MASK 0x1f0ff + +/* + * Valid values for ARMCPRegInfo state field, indicating which of + * the AArch32 and AArch64 execution states this register is visible in. + * If the reginfo doesn't explicitly specify then it is AArch32 only. + * If the reginfo is declared to be visible in both states then a second + * reginfo is synthesised for the AArch32 view of the AArch64 register, + * such that the AArch32 view is the lower 32 bits of the AArch64 one. + * Note that we rely on the values of these enums as we iterate through + * the various states in some places. + */ +enum { + ARM_CP_STATE_AA32 = 0, + ARM_CP_STATE_AA64 = 1, + ARM_CP_STATE_BOTH = 2, +}; + +/* + * ARM CP register secure state flags. These flags identify security state + * attributes for a given CP register entry. + * The existence of both or neither secure and non-secure flags indicates that + * the register has both a secure and non-secure hash entry. A single one of + * these flags causes the register to only be hashed for the specified + * security state. + * Although definitions may have any combination of the S/NS bits, each + * registered entry will only have one to identify whether the entry is secure + * or non-secure. + */ +enum { + ARM_CP_SECSTATE_S = (1 << 0), /* bit[0]: Secure state register */ + ARM_CP_SECSTATE_NS = (1 << 1), /* bit[1]: Non-secure state register */ +}; + +/* + * Return true if cptype is a valid type field. This is used to try to + * catch errors where the sentinel has been accidentally left off the end + * of a list of registers. + */ +static inline bool cptype_valid(int cptype) +{ + return ((cptype & ~ARM_CP_FLAG_MASK) == 0) + || ((cptype & ARM_CP_SPECIAL) && + ((cptype & ~ARM_CP_FLAG_MASK) <= ARM_LAST_SPECIAL)); +} + +/* + * Access rights: + * We define bits for Read and Write access for what rev C of the v7-AR ARM ARM + * defines as PL0 (user), PL1 (fiq/irq/svc/abt/und/sys, ie privileged), and + * PL2 (hyp). The other level which has Read and Write bits is Secure PL1 + * (ie any of the privileged modes in Secure state, or Monitor mode). + * If a register is accessible in one privilege level it's always accessible + * in higher privilege levels too. Since "Secure PL1" also follows this rule + * (ie anything visible in PL2 is visible in S-PL1, some things are only + * visible in S-PL1) but "Secure PL1" is a bit of a mouthful, we bend the + * terminology a little and call this PL3. + * In AArch64 things are somewhat simpler as the PLx bits line up exactly + * with the ELx exception levels. + * + * If access permissions for a register are more complex than can be + * described with these bits, then use a laxer set of restrictions, and + * do the more restrictive/complex check inside a helper function. + */ +#define PL3_R 0x80 +#define PL3_W 0x40 +#define PL2_R (0x20 | PL3_R) +#define PL2_W (0x10 | PL3_W) +#define PL1_R (0x08 | PL2_R) +#define PL1_W (0x04 | PL2_W) +#define PL0_R (0x02 | PL1_R) +#define PL0_W (0x01 | PL1_W) + +/* + * For user-mode some registers are accessible to EL0 via a kernel + * trap-and-emulate ABI. In this case we define the read permissions + * as actually being PL0_R. However some bits of any given register + * may still be masked. + */ +#ifdef CONFIG_USER_ONLY +#define PL0U_R PL0_R +#else +#define PL0U_R PL1_R +#endif + +#define PL3_RW (PL3_R | PL3_W) +#define PL2_RW (PL2_R | PL2_W) +#define PL1_RW (PL1_R | PL1_W) +#define PL0_RW (PL0_R | PL0_W) + +typedef enum CPAccessResult { + /* Access is permitted */ + CP_ACCESS_OK = 0, + /* + * Access fails due to a configurable trap or enable which would + * result in a categorized exception syndrome giving information about + * the failing instruction (ie syndrome category 0x3, 0x4, 0x5, 0x6, + * 0xc or 0x18). The exception is taken to the usual target EL (EL1 or + * PL1 if in EL0, otherwise to the current EL). + */ + CP_ACCESS_TRAP = 1, + /* + * Access fails and results in an exception syndrome 0x0 ("uncategorized"). + * Note that this is not a catch-all case -- the set of cases which may + * result in this failure is specifically defined by the architecture. + */ + CP_ACCESS_TRAP_UNCATEGORIZED = 2, + /* As CP_ACCESS_TRAP, but for traps directly to EL2 or EL3 */ + CP_ACCESS_TRAP_EL2 = 3, + CP_ACCESS_TRAP_EL3 = 4, + /* As CP_ACCESS_UNCATEGORIZED, but for traps directly to EL2 or EL3 */ + CP_ACCESS_TRAP_UNCATEGORIZED_EL2 = 5, + CP_ACCESS_TRAP_UNCATEGORIZED_EL3 = 6, +} CPAccessResult; + +typedef struct ARMCPRegInfo ARMCPRegInfo; + +/* + * Access functions for coprocessor registers. These cannot fail and + * may not raise exceptions. + */ +typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque); +typedef void CPWriteFn(CPUARMState *env, const ARMCPRegInfo *opaque, + uint64_t value); +/* Access permission check functions for coprocessor registers. */ +typedef CPAccessResult CPAccessFn(CPUARMState *env, + const ARMCPRegInfo *opaque, + bool isread); +/* Hook function for register reset */ +typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *opaque); + +#define CP_ANY 0xff + +/* Definition of an ARM coprocessor register */ +struct ARMCPRegInfo { + /* Name of register (useful mainly for debugging, need not be unique) */ + const char *name; + /* + * Location of register: coprocessor number and (crn,crm,opc1,opc2) + * tuple. Any of crm, opc1 and opc2 may be CP_ANY to indicate a + * 'wildcard' field -- any value of that field in the MRC/MCR insn + * will be decoded to this register. The register read and write + * callbacks will be passed an ARMCPRegInfo with the crn/crm/opc1/opc2 + * used by the program, so it is possible to register a wildcard and + * then behave differently on read/write if necessary. + * For 64 bit registers, only crm and opc1 are relevant; crn and opc2 + * must both be zero. + * For AArch64-visible registers, opc0 is also used. + * Since there are no "coprocessors" in AArch64, cp is purely used as a + * way to distinguish (for KVM's benefit) guest-visible system registers + * from demuxed ones provided to preserve the "no side effects on + * KVM register read/write from QEMU" semantics. cp==0x13 is guest + * visible (to match KVM's encoding); cp==0 will be converted to + * cp==0x13 when the ARMCPRegInfo is registered, for convenience. + */ + uint8_t cp; + uint8_t crn; + uint8_t crm; + uint8_t opc0; + uint8_t opc1; + uint8_t opc2; + /* Execution state in which this register is visible: ARM_CP_STATE_* */ + int state; + /* Register type: ARM_CP_* bits/values */ + int type; + /* Access rights: PL*_[RW] */ + int access; + /* Security state: ARM_CP_SECSTATE_* bits/values */ + int secure; + /* + * The opaque pointer passed to define_arm_cp_regs_with_opaque() when + * this register was defined: can be used to hand data through to the + * register read/write functions, since they are passed the ARMCPRegInfo*. + */ + void *opaque; + /* + * Value of this register, if it is ARM_CP_CONST. Otherwise, if + * fieldoffset is non-zero, the reset value of the register. + */ + uint64_t resetvalue; + /* + * Offset of the field in CPUARMState for this register. + * This is not needed if either: + * 1. type is ARM_CP_CONST or one of the ARM_CP_SPECIALs + * 2. both readfn and writefn are specified + */ + ptrdiff_t fieldoffset; /* offsetof(CPUARMState, field) */ + + /* + * Offsets of the secure and non-secure fields in CPUARMState for the + * register if it is banked. These fields are only used during the static + * registration of a register. During hashing the bank associated + * with a given security state is copied to fieldoffset which is used from + * there on out. + * + * It is expected that register definitions use either fieldoffset or + * bank_fieldoffsets in the definition but not both. It is also expected + * that both bank offsets are set when defining a banked register. This + * use indicates that a register is banked. + */ + ptrdiff_t bank_fieldoffsets[2]; + + /* + * Function for making any access checks for this register in addition to + * those specified by the 'access' permissions bits. If NULL, no extra + * checks required. The access check is performed at runtime, not at + * translate time. + */ + CPAccessFn *accessfn; + /* + * Function for handling reads of this register. If NULL, then reads + * will be done by loading from the offset into CPUARMState specified + * by fieldoffset. + */ + CPReadFn *readfn; + /* + * Function for handling writes of this register. If NULL, then writes + * will be done by writing to the offset into CPUARMState specified + * by fieldoffset. + */ + CPWriteFn *writefn; + /* + * Function for doing a "raw" read; used when we need to copy + * coprocessor state to the kernel for KVM or out for + * migration. This only needs to be provided if there is also a + * readfn and it has side effects (for instance clear-on-read bits). + */ + CPReadFn *raw_readfn; + /* + * Function for doing a "raw" write; used when we need to copy KVM + * kernel coprocessor state into userspace, or for inbound + * migration. This only needs to be provided if there is also a + * writefn and it masks out "unwritable" bits or has write-one-to-clear + * or similar behaviour. + */ + CPWriteFn *raw_writefn; + /* + * Function for resetting the register. If NULL, then reset will be done + * by writing resetvalue to the field specified in fieldoffset. If + * fieldoffset is 0 then no reset will be done. + */ + CPResetFn *resetfn; + + /* + * "Original" writefn and readfn. + * For ARMv8.1-VHE register aliases, we overwrite the read/write + * accessor functions of various EL1/EL0 to perform the runtime + * check for which sysreg should actually be modified, and then + * forwards the operation. Before overwriting the accessors, + * the original function is copied here, so that accesses that + * really do go to the EL1/EL0 version proceed normally. + * (The corresponding EL2 register is linked via opaque.) + */ + CPReadFn *orig_readfn; + CPWriteFn *orig_writefn; +}; + +/* + * Macros which are lvalues for the field in CPUARMState for the + * ARMCPRegInfo *ri. + */ +#define CPREG_FIELD32(env, ri) \ + (*(uint32_t *)((char *)(env) + (ri)->fieldoffset)) +#define CPREG_FIELD64(env, ri) \ + (*(uint64_t *)((char *)(env) + (ri)->fieldoffset)) + +#define REGINFO_SENTINEL { .type = ARM_CP_SENTINEL } + +void define_arm_cp_regs_with_opaque(ARMCPU *cpu, + const ARMCPRegInfo *regs, void *opaque); +void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, + const ARMCPRegInfo *regs, void *opaque); +static inline void define_arm_cp_regs(ARMCPU *cpu, const ARMCPRegInfo *regs) +{ + define_arm_cp_regs_with_opaque(cpu, regs, 0); +} +static inline void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs) +{ + define_one_arm_cp_reg_with_opaque(cpu, regs, 0); +} +const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t encoded_cp); + +/* + * Definition of an ARM co-processor register as viewed from + * userspace. This is used for presenting sanitised versions of + * registers to userspace when emulating the Linux AArch64 CPU + * ID/feature ABI (advertised as HWCAP_CPUID). + */ +typedef struct ARMCPRegUserSpaceInfo { + /* Name of register */ + const char *name; + + /* Is the name actually a glob pattern */ + bool is_glob; + + /* Only some bits are exported to user space */ + uint64_t exported_bits; + + /* Fixed bits are applied after the mask */ + uint64_t fixed_bits; +} ARMCPRegUserSpaceInfo; + +#define REGUSERINFO_SENTINEL { .name = NULL } + +void modify_arm_cp_regs(ARMCPRegInfo *regs, const ARMCPRegUserSpaceInfo *mods); + +/* CPWriteFn that can be used to implement writes-ignored behaviour */ +void arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value); +/* CPReadFn that can be used for read-as-zero behaviour */ +uint64_t arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri); + +/* + * CPResetFn that does nothing, for use if no reset is required even + * if fieldoffset is non zero. + */ +void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque); + +/* + * Return true if this reginfo struct's field in the cpu state struct + * is 64 bits wide. + */ +static inline bool cpreg_field_is_64bit(const ARMCPRegInfo *ri) +{ + return (ri->state == ARM_CP_STATE_AA64) || (ri->type & ARM_CP_64BIT); +} + +static inline bool cp_access_ok(int current_el, + const ARMCPRegInfo *ri, int isread) +{ + return (ri->access >> ((current_el * 2) + isread)) & 1; +} + +/* Raw read of a coprocessor register (as needed for migration, etc) */ +uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri); + +#endif /* TARGET_ARM_CPREGS_H */ diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 2b81b18351..18212eb6ee 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -43,6 +43,7 @@ #include "kvm_arm.h" #include "disas/capstone.h" #include "fpu/softfloat.h" +#include "cpregs.h" static void arm_cpu_set_pc(CPUState *cs, vaddr value) { diff --git a/target/arm/cpu.h b/target/arm/cpu.h index db8ff04449..d1b558385c 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2595,144 +2595,6 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid) return kvmid; } -/* ARMCPRegInfo type field bits. If the SPECIAL bit is set this is a - * special-behaviour cp reg and bits [11..8] indicate what behaviour - * it has. Otherwise it is a simple cp reg, where CONST indicates that - * TCG can assume the value to be constant (ie load at translate time) - * and 64BIT indicates a 64 bit wide coprocessor register. SUPPRESS_TB_END - * indicates that the TB should not be ended after a write to this register - * (the default is that the TB ends after cp writes). OVERRIDE permits - * a register definition to override a previous definition for the - * same (cp, is64, crn, crm, opc1, opc2) tuple: either the new or the - * old must have the OVERRIDE bit set. - * ALIAS indicates that this register is an alias view of some underlying - * state which is also visible via another register, and that the other - * register is handling migration and reset; registers marked ALIAS will not be - * migrated but may have their state set by syncing of register state from KVM. - * NO_RAW indicates that this register has no underlying state and does not - * support raw access for state saving/loading; it will not be used for either - * migration or KVM state synchronization. (Typically this is for "registers" - * which are actually used as instructions for cache maintenance and so on.) - * IO indicates that this register does I/O and therefore its accesses - * need to be marked with gen_io_start() and also end the TB. In particular, - * registers which implement clocks or timers require this. - * RAISES_EXC is for when the read or write hook might raise an exception; - * the generated code will synchronize the CPU state before calling the hook - * so that it is safe for the hook to call raise_exception(). - * NEWEL is for writes to registers that might change the exception - * level - typically on older ARM chips. For those cases we need to - * re-read the new el when recomputing the translation flags. - */ -#define ARM_CP_SPECIAL 0x0001 -#define ARM_CP_CONST 0x0002 -#define ARM_CP_64BIT 0x0004 -#define ARM_CP_SUPPRESS_TB_END 0x0008 -#define ARM_CP_OVERRIDE 0x0010 -#define ARM_CP_ALIAS 0x0020 -#define ARM_CP_IO 0x0040 -#define ARM_CP_NO_RAW 0x0080 -#define ARM_CP_NOP (ARM_CP_SPECIAL | 0x0100) -#define ARM_CP_WFI (ARM_CP_SPECIAL | 0x0200) -#define ARM_CP_NZCV (ARM_CP_SPECIAL | 0x0300) -#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | 0x0400) -#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | 0x0500) -#define ARM_CP_DC_GVA (ARM_CP_SPECIAL | 0x0600) -#define ARM_CP_DC_GZVA (ARM_CP_SPECIAL | 0x0700) -#define ARM_LAST_SPECIAL ARM_CP_DC_GZVA -#define ARM_CP_FPU 0x1000 -#define ARM_CP_SVE 0x2000 -#define ARM_CP_NO_GDB 0x4000 -#define ARM_CP_RAISES_EXC 0x8000 -#define ARM_CP_NEWEL 0x10000 -/* Used only as a terminator for ARMCPRegInfo lists */ -#define ARM_CP_SENTINEL 0xfffff -/* Mask of only the flag bits in a type field */ -#define ARM_CP_FLAG_MASK 0x1f0ff - -/* Valid values for ARMCPRegInfo state field, indicating which of - * the AArch32 and AArch64 execution states this register is visible in. - * If the reginfo doesn't explicitly specify then it is AArch32 only. - * If the reginfo is declared to be visible in both states then a second - * reginfo is synthesised for the AArch32 view of the AArch64 register, - * such that the AArch32 view is the lower 32 bits of the AArch64 one. - * Note that we rely on the values of these enums as we iterate through - * the various states in some places. - */ -enum { - ARM_CP_STATE_AA32 = 0, - ARM_CP_STATE_AA64 = 1, - ARM_CP_STATE_BOTH = 2, -}; - -/* ARM CP register secure state flags. These flags identify security state - * attributes for a given CP register entry. - * The existence of both or neither secure and non-secure flags indicates that - * the register has both a secure and non-secure hash entry. A single one of - * these flags causes the register to only be hashed for the specified - * security state. - * Although definitions may have any combination of the S/NS bits, each - * registered entry will only have one to identify whether the entry is secure - * or non-secure. - */ -enum { - ARM_CP_SECSTATE_S = (1 << 0), /* bit[0]: Secure state register */ - ARM_CP_SECSTATE_NS = (1 << 1), /* bit[1]: Non-secure state register */ -}; - -/* Return true if cptype is a valid type field. This is used to try to - * catch errors where the sentinel has been accidentally left off the end - * of a list of registers. - */ -static inline bool cptype_valid(int cptype) -{ - return ((cptype & ~ARM_CP_FLAG_MASK) == 0) - || ((cptype & ARM_CP_SPECIAL) && - ((cptype & ~ARM_CP_FLAG_MASK) <= ARM_LAST_SPECIAL)); -} - -/* Access rights: - * We define bits for Read and Write access for what rev C of the v7-AR ARM ARM - * defines as PL0 (user), PL1 (fiq/irq/svc/abt/und/sys, ie privileged), and - * PL2 (hyp). The other level which has Read and Write bits is Secure PL1 - * (ie any of the privileged modes in Secure state, or Monitor mode). - * If a register is accessible in one privilege level it's always accessible - * in higher privilege levels too. Since "Secure PL1" also follows this rule - * (ie anything visible in PL2 is visible in S-PL1, some things are only - * visible in S-PL1) but "Secure PL1" is a bit of a mouthful, we bend the - * terminology a little and call this PL3. - * In AArch64 things are somewhat simpler as the PLx bits line up exactly - * with the ELx exception levels. - * - * If access permissions for a register are more complex than can be - * described with these bits, then use a laxer set of restrictions, and - * do the more restrictive/complex check inside a helper function. - */ -#define PL3_R 0x80 -#define PL3_W 0x40 -#define PL2_R (0x20 | PL3_R) -#define PL2_W (0x10 | PL3_W) -#define PL1_R (0x08 | PL2_R) -#define PL1_W (0x04 | PL2_W) -#define PL0_R (0x02 | PL1_R) -#define PL0_W (0x01 | PL1_W) - -/* - * For user-mode some registers are accessible to EL0 via a kernel - * trap-and-emulate ABI. In this case we define the read permissions - * as actually being PL0_R. However some bits of any given register - * may still be masked. - */ -#ifdef CONFIG_USER_ONLY -#define PL0U_R PL0_R -#else -#define PL0U_R PL1_R -#endif - -#define PL3_RW (PL3_R | PL3_W) -#define PL2_RW (PL2_R | PL2_W) -#define PL1_RW (PL1_R | PL1_W) -#define PL0_RW (PL0_R | PL0_W) - /* Return the highest implemented Exception Level */ static inline int arm_highest_el(CPUARMState *env) { @@ -2784,236 +2646,6 @@ static inline int arm_current_el(CPUARMState *env) } } -typedef struct ARMCPRegInfo ARMCPRegInfo; - -typedef enum CPAccessResult { - /* Access is permitted */ - CP_ACCESS_OK = 0, - /* Access fails due to a configurable trap or enable which would - * result in a categorized exception syndrome giving information about - * the failing instruction (ie syndrome category 0x3, 0x4, 0x5, 0x6, - * 0xc or 0x18). The exception is taken to the usual target EL (EL1 or - * PL1 if in EL0, otherwise to the current EL). - */ - CP_ACCESS_TRAP = 1, - /* Access fails and results in an exception syndrome 0x0 ("uncategorized"). - * Note that this is not a catch-all case -- the set of cases which may - * result in this failure is specifically defined by the architecture. - */ - CP_ACCESS_TRAP_UNCATEGORIZED = 2, - /* As CP_ACCESS_TRAP, but for traps directly to EL2 or EL3 */ - CP_ACCESS_TRAP_EL2 = 3, - CP_ACCESS_TRAP_EL3 = 4, - /* As CP_ACCESS_UNCATEGORIZED, but for traps directly to EL2 or EL3 */ - CP_ACCESS_TRAP_UNCATEGORIZED_EL2 = 5, - CP_ACCESS_TRAP_UNCATEGORIZED_EL3 = 6, -} CPAccessResult; - -/* Access functions for coprocessor registers. These cannot fail and - * may not raise exceptions. - */ -typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque); -typedef void CPWriteFn(CPUARMState *env, const ARMCPRegInfo *opaque, - uint64_t value); -/* Access permission check functions for coprocessor registers. */ -typedef CPAccessResult CPAccessFn(CPUARMState *env, - const ARMCPRegInfo *opaque, - bool isread); -/* Hook function for register reset */ -typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *opaque); - -#define CP_ANY 0xff - -/* Definition of an ARM coprocessor register */ -struct ARMCPRegInfo { - /* Name of register (useful mainly for debugging, need not be unique) */ - const char *name; - /* Location of register: coprocessor number and (crn,crm,opc1,opc2) - * tuple. Any of crm, opc1 and opc2 may be CP_ANY to indicate a - * 'wildcard' field -- any value of that field in the MRC/MCR insn - * will be decoded to this register. The register read and write - * callbacks will be passed an ARMCPRegInfo with the crn/crm/opc1/opc2 - * used by the program, so it is possible to register a wildcard and - * then behave differently on read/write if necessary. - * For 64 bit registers, only crm and opc1 are relevant; crn and opc2 - * must both be zero. - * For AArch64-visible registers, opc0 is also used. - * Since there are no "coprocessors" in AArch64, cp is purely used as a - * way to distinguish (for KVM's benefit) guest-visible system registers - * from demuxed ones provided to preserve the "no side effects on - * KVM register read/write from QEMU" semantics. cp==0x13 is guest - * visible (to match KVM's encoding); cp==0 will be converted to - * cp==0x13 when the ARMCPRegInfo is registered, for convenience. - */ - uint8_t cp; - uint8_t crn; - uint8_t crm; - uint8_t opc0; - uint8_t opc1; - uint8_t opc2; - /* Execution state in which this register is visible: ARM_CP_STATE_* */ - int state; - /* Register type: ARM_CP_* bits/values */ - int type; - /* Access rights: PL*_[RW] */ - int access; - /* Security state: ARM_CP_SECSTATE_* bits/values */ - int secure; - /* The opaque pointer passed to define_arm_cp_regs_with_opaque() when - * this register was defined: can be used to hand data through to the - * register read/write functions, since they are passed the ARMCPRegInfo*. - */ - void *opaque; - /* Value of this register, if it is ARM_CP_CONST. Otherwise, if - * fieldoffset is non-zero, the reset value of the register. - */ - uint64_t resetvalue; - /* Offset of the field in CPUARMState for this register. - * - * This is not needed if either: - * 1. type is ARM_CP_CONST or one of the ARM_CP_SPECIALs - * 2. both readfn and writefn are specified - */ - ptrdiff_t fieldoffset; /* offsetof(CPUARMState, field) */ - - /* Offsets of the secure and non-secure fields in CPUARMState for the - * register if it is banked. These fields are only used during the static - * registration of a register. During hashing the bank associated - * with a given security state is copied to fieldoffset which is used from - * there on out. - * - * It is expected that register definitions use either fieldoffset or - * bank_fieldoffsets in the definition but not both. It is also expected - * that both bank offsets are set when defining a banked register. This - * use indicates that a register is banked. - */ - ptrdiff_t bank_fieldoffsets[2]; - - /* Function for making any access checks for this register in addition to - * those specified by the 'access' permissions bits. If NULL, no extra - * checks required. The access check is performed at runtime, not at - * translate time. - */ - CPAccessFn *accessfn; - /* Function for handling reads of this register. If NULL, then reads - * will be done by loading from the offset into CPUARMState specified - * by fieldoffset. - */ - CPReadFn *readfn; - /* Function for handling writes of this register. If NULL, then writes - * will be done by writing to the offset into CPUARMState specified - * by fieldoffset. - */ - CPWriteFn *writefn; - /* Function for doing a "raw" read; used when we need to copy - * coprocessor state to the kernel for KVM or out for - * migration. This only needs to be provided if there is also a - * readfn and it has side effects (for instance clear-on-read bits). - */ - CPReadFn *raw_readfn; - /* Function for doing a "raw" write; used when we need to copy KVM - * kernel coprocessor state into userspace, or for inbound - * migration. This only needs to be provided if there is also a - * writefn and it masks out "unwritable" bits or has write-one-to-clear - * or similar behaviour. - */ - CPWriteFn *raw_writefn; - /* Function for resetting the register. If NULL, then reset will be done - * by writing resetvalue to the field specified in fieldoffset. If - * fieldoffset is 0 then no reset will be done. - */ - CPResetFn *resetfn; - - /* - * "Original" writefn and readfn. - * For ARMv8.1-VHE register aliases, we overwrite the read/write - * accessor functions of various EL1/EL0 to perform the runtime - * check for which sysreg should actually be modified, and then - * forwards the operation. Before overwriting the accessors, - * the original function is copied here, so that accesses that - * really do go to the EL1/EL0 version proceed normally. - * (The corresponding EL2 register is linked via opaque.) - */ - CPReadFn *orig_readfn; - CPWriteFn *orig_writefn; -}; - -/* Macros which are lvalues for the field in CPUARMState for the - * ARMCPRegInfo *ri. - */ -#define CPREG_FIELD32(env, ri) \ - (*(uint32_t *)((char *)(env) + (ri)->fieldoffset)) -#define CPREG_FIELD64(env, ri) \ - (*(uint64_t *)((char *)(env) + (ri)->fieldoffset)) - -#define REGINFO_SENTINEL { .type = ARM_CP_SENTINEL } - -void define_arm_cp_regs_with_opaque(ARMCPU *cpu, - const ARMCPRegInfo *regs, void *opaque); -void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, - const ARMCPRegInfo *regs, void *opaque); -static inline void define_arm_cp_regs(ARMCPU *cpu, const ARMCPRegInfo *regs) -{ - define_arm_cp_regs_with_opaque(cpu, regs, 0); -} -static inline void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs) -{ - define_one_arm_cp_reg_with_opaque(cpu, regs, 0); -} -const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t encoded_cp); - -/* - * Definition of an ARM co-processor register as viewed from - * userspace. This is used for presenting sanitised versions of - * registers to userspace when emulating the Linux AArch64 CPU - * ID/feature ABI (advertised as HWCAP_CPUID). - */ -typedef struct ARMCPRegUserSpaceInfo { - /* Name of register */ - const char *name; - - /* Is the name actually a glob pattern */ - bool is_glob; - - /* Only some bits are exported to user space */ - uint64_t exported_bits; - - /* Fixed bits are applied after the mask */ - uint64_t fixed_bits; -} ARMCPRegUserSpaceInfo; - -#define REGUSERINFO_SENTINEL { .name = NULL } - -void modify_arm_cp_regs(ARMCPRegInfo *regs, const ARMCPRegUserSpaceInfo *mods); - -/* CPWriteFn that can be used to implement writes-ignored behaviour */ -void arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value); -/* CPReadFn that can be used for read-as-zero behaviour */ -uint64_t arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri); - -/* CPResetFn that does nothing, for use if no reset is required even - * if fieldoffset is non zero. - */ -void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque); - -/* Return true if this reginfo struct's field in the cpu state struct - * is 64 bits wide. - */ -static inline bool cpreg_field_is_64bit(const ARMCPRegInfo *ri) -{ - return (ri->state == ARM_CP_STATE_AA64) || (ri->type & ARM_CP_64BIT); -} - -static inline bool cp_access_ok(int current_el, - const ARMCPRegInfo *ri, int isread) -{ - return (ri->access >> ((current_el * 2) + isread)) & 1; -} - -/* Raw read of a coprocessor register (as needed for migration, etc) */ -uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri); - /** * write_list_to_cpustate * @cpu: ARMCPU diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 2974cbc0d3..af5ba1d0b3 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -34,6 +34,7 @@ #include "hvf_arm.h" #include "qapi/visitor.h" #include "hw/qdev-properties.h" +#include "cpregs.h" #ifndef CONFIG_USER_ONLY diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index 13d0e9b195..0e693b182e 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -18,6 +18,7 @@ #if !defined(CONFIG_USER_ONLY) #include "hw/boards.h" #endif +#include "cpregs.h" /* CPU models. These are not needed for the AArch64 linux-user build. */ #if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c index ca1de47511..f01a126108 100644 --- a/target/arm/gdbstub.c +++ b/target/arm/gdbstub.c @@ -19,8 +19,9 @@ */ #include "qemu/osdep.h" #include "cpu.h" -#include "internals.h" #include "exec/gdbstub.h" +#include "internals.h" +#include "cpregs.h" typedef struct RegisterSysregXmlParam { CPUState *cs; diff --git a/target/arm/helper.c b/target/arm/helper.c index 5a244c3ed9..3f2e555d6f 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -36,6 +36,7 @@ #include "exec/cpu_ldst.h" #include "semihosting/common-semi.h" #endif +#include "cpregs.h" #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */ #define PMCR_NUM_COUNTERS 4 /* QEMU IMPDEF choice */ diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index 2b87e8808b..67be91c732 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -23,6 +23,7 @@ #include "internals.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" +#include "cpregs.h" #define SIGNBIT (uint32_t)0x80000000 #define SIGNBIT64 ((uint64_t)1 << 63) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index a869d57309..348a638c5c 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -27,14 +27,12 @@ #include "translate.h" #include "internals.h" #include "qemu/host-utils.h" - #include "semihosting/semihost.h" #include "exec/gen-icount.h" - #include "exec/helper-proto.h" #include "exec/helper-gen.h" #include "exec/log.h" - +#include "cpregs.h" #include "translate-a64.h" #include "qemu/atomic128.h" diff --git a/target/arm/translate.c b/target/arm/translate.c index 37fb17cdaa..fc7917cdf4 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -30,11 +30,10 @@ #include "qemu/bitops.h" #include "arm_ldst.h" #include "semihosting/semihost.h" - #include "exec/helper-proto.h" #include "exec/helper-gen.h" - #include "exec/log.h" +#include "cpregs.h" #define ENABLE_ARCH_4T arm_dc_feature(s, ARM_FEATURE_V4T) From 330477eae9416828c098513f36bd2f33f5f270fe Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:49:44 -0700 Subject: [PATCH 017/935] target/arm: Reorg CPAccessResult and access_check_cp_reg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rearrange the values of the enumerators of CPAccessResult so that we may directly extract the target el. For the two special cases in access_check_cp_reg, use CPAccessResult. Reviewed-by: Alex Bennée Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220501055028.646596-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpregs.h | 26 ++++++++++++-------- target/arm/op_helper.c | 56 +++++++++++++++++++++--------------------- 2 files changed, 44 insertions(+), 38 deletions(-) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 8064c0763e..7f2c30eab1 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -167,26 +167,32 @@ static inline bool cptype_valid(int cptype) typedef enum CPAccessResult { /* Access is permitted */ CP_ACCESS_OK = 0, + + /* + * Combined with one of the following, the low 2 bits indicate the + * target exception level. If 0, the exception is taken to the usual + * target EL (EL1 or PL1 if in EL0, otherwise to the current EL). + */ + CP_ACCESS_EL_MASK = 3, + /* * Access fails due to a configurable trap or enable which would * result in a categorized exception syndrome giving information about * the failing instruction (ie syndrome category 0x3, 0x4, 0x5, 0x6, - * 0xc or 0x18). The exception is taken to the usual target EL (EL1 or - * PL1 if in EL0, otherwise to the current EL). + * 0xc or 0x18). */ - CP_ACCESS_TRAP = 1, + CP_ACCESS_TRAP = (1 << 2), + CP_ACCESS_TRAP_EL2 = CP_ACCESS_TRAP | 2, + CP_ACCESS_TRAP_EL3 = CP_ACCESS_TRAP | 3, + /* * Access fails and results in an exception syndrome 0x0 ("uncategorized"). * Note that this is not a catch-all case -- the set of cases which may * result in this failure is specifically defined by the architecture. */ - CP_ACCESS_TRAP_UNCATEGORIZED = 2, - /* As CP_ACCESS_TRAP, but for traps directly to EL2 or EL3 */ - CP_ACCESS_TRAP_EL2 = 3, - CP_ACCESS_TRAP_EL3 = 4, - /* As CP_ACCESS_UNCATEGORIZED, but for traps directly to EL2 or EL3 */ - CP_ACCESS_TRAP_UNCATEGORIZED_EL2 = 5, - CP_ACCESS_TRAP_UNCATEGORIZED_EL3 = 6, + CP_ACCESS_TRAP_UNCATEGORIZED = (2 << 2), + CP_ACCESS_TRAP_UNCATEGORIZED_EL2 = CP_ACCESS_TRAP_UNCATEGORIZED | 2, + CP_ACCESS_TRAP_UNCATEGORIZED_EL3 = CP_ACCESS_TRAP_UNCATEGORIZED | 3, } CPAccessResult; typedef struct ARMCPRegInfo ARMCPRegInfo; diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index 67be91c732..76499ffa14 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -632,11 +632,13 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome, uint32_t isread) { const ARMCPRegInfo *ri = rip; + CPAccessResult res = CP_ACCESS_OK; int target_el; if (arm_feature(env, ARM_FEATURE_XSCALE) && ri->cp < 14 && extract32(env->cp15.c15_cpar, ri->cp, 1) == 0) { - raise_exception(env, EXCP_UDEF, syndrome, exception_target_el(env)); + res = CP_ACCESS_TRAP; + goto fail; } /* @@ -655,48 +657,46 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome, mask &= ~((1 << 4) | (1 << 14)); if (env->cp15.hstr_el2 & mask) { - target_el = 2; - goto exept; + res = CP_ACCESS_TRAP_EL2; + goto fail; } } - if (!ri->accessfn) { + if (ri->accessfn) { + res = ri->accessfn(env, ri, isread); + } + if (likely(res == CP_ACCESS_OK)) { return; } - switch (ri->accessfn(env, ri, isread)) { - case CP_ACCESS_OK: - return; + fail: + switch (res & ~CP_ACCESS_EL_MASK) { case CP_ACCESS_TRAP: - target_el = exception_target_el(env); - break; - case CP_ACCESS_TRAP_EL2: - /* Requesting a trap to EL2 when we're in EL3 is - * a bug in the access function. - */ - assert(arm_current_el(env) != 3); - target_el = 2; - break; - case CP_ACCESS_TRAP_EL3: - target_el = 3; break; case CP_ACCESS_TRAP_UNCATEGORIZED: - target_el = exception_target_el(env); - syndrome = syn_uncategorized(); - break; - case CP_ACCESS_TRAP_UNCATEGORIZED_EL2: - target_el = 2; - syndrome = syn_uncategorized(); - break; - case CP_ACCESS_TRAP_UNCATEGORIZED_EL3: - target_el = 3; syndrome = syn_uncategorized(); break; default: g_assert_not_reached(); } -exept: + target_el = res & CP_ACCESS_EL_MASK; + switch (target_el) { + case 0: + target_el = exception_target_el(env); + break; + case 2: + assert(arm_current_el(env) != 3); + assert(arm_is_el2_enabled(env)); + break; + case 3: + assert(arm_feature(env, ARM_FEATURE_EL3)); + break; + default: + /* No "direct" traps to EL1 */ + g_assert_not_reached(); + } + raise_exception(env, EXCP_UDEF, syndrome, target_el); } From 5809ac5709645b341eaca979715a32ced2e4d432 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:49:45 -0700 Subject: [PATCH 018/935] target/arm: Replace sentinels with ARRAY_SIZE in cpregs.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove a possible source of error by removing REGINFO_SENTINEL and using ARRAY_SIZE (convinently hidden inside a macro) to find the end of the set of regs being registered or modified. The space saved by not having the extra array element reduces the executable's .data.rel.ro section by about 9k. Reviewed-by: Alex Bennée Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220501055028.646596-4-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- hw/arm/pxa2xx.c | 1 - hw/arm/pxa2xx_pic.c | 1 - hw/intc/arm_gicv3_cpuif.c | 5 -- hw/intc/arm_gicv3_kvm.c | 1 - target/arm/cpregs.h | 53 +++++++++--------- target/arm/cpu64.c | 1 - target/arm/cpu_tcg.c | 4 -- target/arm/helper.c | 111 ++++++++------------------------------ 8 files changed, 48 insertions(+), 129 deletions(-) diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index 0683714733..f4f687df68 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -384,7 +384,6 @@ static const ARMCPRegInfo pxa_cp_reginfo[] = { { .name = "PWRMODE", .cp = 14, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_IO, .readfn = arm_cp_read_zero, .writefn = pxa2xx_pwrmode_write }, - REGINFO_SENTINEL }; static void pxa2xx_setup_cp14(PXA2xxState *s) diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c index b80d75d839..47132ab982 100644 --- a/hw/arm/pxa2xx_pic.c +++ b/hw/arm/pxa2xx_pic.c @@ -257,7 +257,6 @@ static const ARMCPRegInfo pxa_pic_cp_reginfo[] = { REGINFO_FOR_PIC_CP("ICLR2", 8), REGINFO_FOR_PIC_CP("ICFP2", 9), REGINFO_FOR_PIC_CP("ICPR2", 0xa), - REGINFO_SENTINEL }; static const MemoryRegionOps pxa2xx_pic_ops = { diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index 2d5959db94..9efba798f8 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -2428,7 +2428,6 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { .readfn = icc_igrpen1_el3_read, .writefn = icc_igrpen1_el3_write, }, - REGINFO_SENTINEL }; static uint64_t ich_ap_read(CPUARMState *env, const ARMCPRegInfo *ri) @@ -2682,7 +2681,6 @@ static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = { .readfn = ich_vmcr_read, .writefn = ich_vmcr_write, }, - REGINFO_SENTINEL }; static const ARMCPRegInfo gicv3_cpuif_ich_apxr1_reginfo[] = { @@ -2700,7 +2698,6 @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr1_reginfo[] = { .readfn = ich_ap_read, .writefn = ich_ap_write, }, - REGINFO_SENTINEL }; static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = { @@ -2732,7 +2729,6 @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = { .readfn = ich_ap_read, .writefn = ich_ap_write, }, - REGINFO_SENTINEL }; static void gicv3_cpuif_el_change_hook(ARMCPU *cpu, void *opaque) @@ -2807,7 +2803,6 @@ void gicv3_init_cpuif(GICv3State *s) .readfn = ich_lr_read, .writefn = ich_lr_write, }, - REGINFO_SENTINEL }; define_arm_cp_regs(cpu, lr_regset); } diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 611085e98d..2922c516e5 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -735,7 +735,6 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { */ .resetfn = arm_gicv3_icc_reset, }, - REGINFO_SENTINEL }; /** diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 7f2c30eab1..a5231504d5 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -71,8 +71,6 @@ #define ARM_CP_NO_GDB 0x4000 #define ARM_CP_RAISES_EXC 0x8000 #define ARM_CP_NEWEL 0x10000 -/* Used only as a terminator for ARMCPRegInfo lists */ -#define ARM_CP_SENTINEL 0xfffff /* Mask of only the flag bits in a type field */ #define ARM_CP_FLAG_MASK 0x1f0ff @@ -108,18 +106,6 @@ enum { ARM_CP_SECSTATE_NS = (1 << 1), /* bit[1]: Non-secure state register */ }; -/* - * Return true if cptype is a valid type field. This is used to try to - * catch errors where the sentinel has been accidentally left off the end - * of a list of registers. - */ -static inline bool cptype_valid(int cptype) -{ - return ((cptype & ~ARM_CP_FLAG_MASK) == 0) - || ((cptype & ARM_CP_SPECIAL) && - ((cptype & ~ARM_CP_FLAG_MASK) <= ARM_LAST_SPECIAL)); -} - /* * Access rights: * We define bits for Read and Write access for what rev C of the v7-AR ARM ARM @@ -346,20 +332,27 @@ struct ARMCPRegInfo { #define CPREG_FIELD64(env, ri) \ (*(uint64_t *)((char *)(env) + (ri)->fieldoffset)) -#define REGINFO_SENTINEL { .type = ARM_CP_SENTINEL } +void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, const ARMCPRegInfo *reg, + void *opaque); -void define_arm_cp_regs_with_opaque(ARMCPU *cpu, - const ARMCPRegInfo *regs, void *opaque); -void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, - const ARMCPRegInfo *regs, void *opaque); -static inline void define_arm_cp_regs(ARMCPU *cpu, const ARMCPRegInfo *regs) -{ - define_arm_cp_regs_with_opaque(cpu, regs, 0); -} static inline void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs) { - define_one_arm_cp_reg_with_opaque(cpu, regs, 0); + define_one_arm_cp_reg_with_opaque(cpu, regs, NULL); } + +void define_arm_cp_regs_with_opaque_len(ARMCPU *cpu, const ARMCPRegInfo *regs, + void *opaque, size_t len); + +#define define_arm_cp_regs_with_opaque(CPU, REGS, OPAQUE) \ + do { \ + QEMU_BUILD_BUG_ON(ARRAY_SIZE(REGS) == 0); \ + define_arm_cp_regs_with_opaque_len(CPU, REGS, OPAQUE, \ + ARRAY_SIZE(REGS)); \ + } while (0) + +#define define_arm_cp_regs(CPU, REGS) \ + define_arm_cp_regs_with_opaque(CPU, REGS, NULL) + const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t encoded_cp); /* @@ -382,9 +375,17 @@ typedef struct ARMCPRegUserSpaceInfo { uint64_t fixed_bits; } ARMCPRegUserSpaceInfo; -#define REGUSERINFO_SENTINEL { .name = NULL } +void modify_arm_cp_regs_with_len(ARMCPRegInfo *regs, size_t regs_len, + const ARMCPRegUserSpaceInfo *mods, + size_t mods_len); -void modify_arm_cp_regs(ARMCPRegInfo *regs, const ARMCPRegUserSpaceInfo *mods); +#define modify_arm_cp_regs(REGS, MODS) \ + do { \ + QEMU_BUILD_BUG_ON(ARRAY_SIZE(REGS) == 0); \ + QEMU_BUILD_BUG_ON(ARRAY_SIZE(MODS) == 0); \ + modify_arm_cp_regs_with_len(REGS, ARRAY_SIZE(REGS), \ + MODS, ARRAY_SIZE(MODS)); \ + } while (0) /* CPWriteFn that can be used to implement writes-ignored behaviour */ void arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri, diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index af5ba1d0b3..c841d55d0e 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -91,7 +91,6 @@ static const ARMCPRegInfo cortex_a72_a57_a53_cp_reginfo[] = { { .name = "L2MERRSR", .cp = 15, .opc1 = 3, .crm = 15, .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, - REGINFO_SENTINEL }; static void aarch64_a57_initfn(Object *obj) diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index 0e693b182e..9338088b22 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -264,7 +264,6 @@ static const ARMCPRegInfo cortexa8_cp_reginfo[] = { .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "L2AUXCR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 2, .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL }; static void cortex_a8_initfn(Object *obj) @@ -332,7 +331,6 @@ static const ARMCPRegInfo cortexa9_cp_reginfo[] = { .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, { .name = "TLB_ATTR", .cp = 15, .crn = 15, .crm = 7, .opc1 = 5, .opc2 = 2, .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST }, - REGINFO_SENTINEL }; static void cortex_a9_initfn(Object *obj) @@ -398,7 +396,6 @@ static const ARMCPRegInfo cortexa15_cp_reginfo[] = { #endif { .name = "L2ECTLR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 3, .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL }; static void cortex_a7_initfn(Object *obj) @@ -686,7 +683,6 @@ static const ARMCPRegInfo cortexr5_cp_reginfo[] = { .access = PL1_RW, .type = ARM_CP_CONST }, { .name = "DCACHE_INVAL", .cp = 15, .opc1 = 0, .crn = 15, .crm = 5, .opc2 = 0, .access = PL1_W, .type = ARM_CP_NOP }, - REGINFO_SENTINEL }; static void cortex_r5_initfn(Object *obj) diff --git a/target/arm/helper.c b/target/arm/helper.c index 3f2e555d6f..a68f14fe8e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -673,7 +673,6 @@ static const ARMCPRegInfo cp_reginfo[] = { .secure = ARM_CP_SECSTATE_S, .fieldoffset = offsetof(CPUARMState, cp15.contextidr_s), .resetvalue = 0, .writefn = contextidr_write, .raw_writefn = raw_write, }, - REGINFO_SENTINEL }; static const ARMCPRegInfo not_v8_cp_reginfo[] = { @@ -702,7 +701,6 @@ static const ARMCPRegInfo not_v8_cp_reginfo[] = { { .name = "CACHEMAINT", .cp = 15, .crn = 7, .crm = CP_ANY, .opc1 = 0, .opc2 = CP_ANY, .access = PL1_W, .type = ARM_CP_NOP | ARM_CP_OVERRIDE }, - REGINFO_SENTINEL }; static const ARMCPRegInfo not_v6_cp_reginfo[] = { @@ -711,7 +709,6 @@ static const ARMCPRegInfo not_v6_cp_reginfo[] = { */ { .name = "WFI_v5", .cp = 15, .crn = 7, .crm = 8, .opc1 = 0, .opc2 = 2, .access = PL1_W, .type = ARM_CP_WFI }, - REGINFO_SENTINEL }; static const ARMCPRegInfo not_v7_cp_reginfo[] = { @@ -760,7 +757,6 @@ static const ARMCPRegInfo not_v7_cp_reginfo[] = { .opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_NOP }, { .name = "NMRR", .cp = 15, .crn = 10, .crm = 2, .opc1 = 0, .opc2 = 1, .access = PL1_RW, .type = ARM_CP_NOP }, - REGINFO_SENTINEL }; static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -889,7 +885,6 @@ static const ARMCPRegInfo v6_cp_reginfo[] = { .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 2, .accessfn = cpacr_access, .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.cpacr_el1), .resetfn = cpacr_reset, .writefn = cpacr_write, .readfn = cpacr_read }, - REGINFO_SENTINEL }; typedef struct pm_event { @@ -2135,7 +2130,6 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { { .name = "TLBIMVAA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 3, .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, .writefn = tlbimvaa_write }, - REGINFO_SENTINEL }; static const ARMCPRegInfo v7mp_cp_reginfo[] = { @@ -2152,7 +2146,6 @@ static const ARMCPRegInfo v7mp_cp_reginfo[] = { { .name = "TLBIMVAAIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 3, .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, .writefn = tlbimvaa_is_write }, - REGINFO_SENTINEL }; static const ARMCPRegInfo pmovsset_cp_reginfo[] = { @@ -2170,7 +2163,6 @@ static const ARMCPRegInfo pmovsset_cp_reginfo[] = { .fieldoffset = offsetof(CPUARMState, cp15.c9_pmovsr), .writefn = pmovsset_write, .raw_writefn = raw_write }, - REGINFO_SENTINEL }; static void teecr_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -2211,7 +2203,6 @@ static const ARMCPRegInfo t2ee_cp_reginfo[] = { { .name = "TEEHBR", .cp = 14, .crn = 1, .crm = 0, .opc1 = 6, .opc2 = 0, .access = PL0_RW, .fieldoffset = offsetof(CPUARMState, teehbr), .accessfn = teehbr_access, .resetvalue = 0 }, - REGINFO_SENTINEL }; static const ARMCPRegInfo v6k_cp_reginfo[] = { @@ -2243,7 +2234,6 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = { .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tpidrprw_s), offsetoflow32(CPUARMState, cp15.tpidrprw_ns) }, .resetvalue = 0 }, - REGINFO_SENTINEL }; #ifndef CONFIG_USER_ONLY @@ -3091,7 +3081,6 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_SEC].cval), .writefn = gt_sec_cval_write, .raw_writefn = raw_write, }, - REGINFO_SENTINEL }; static CPAccessResult e2h_access(CPUARMState *env, const ARMCPRegInfo *ri, @@ -3132,7 +3121,6 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { .access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO, .readfn = gt_virt_cnt_read, }, - REGINFO_SENTINEL }; #endif @@ -3496,7 +3484,6 @@ static const ARMCPRegInfo vapa_cp_reginfo[] = { .access = PL1_W, .accessfn = ats_access, .writefn = ats_write, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC }, #endif - REGINFO_SENTINEL }; /* Return basic MPU access permission bits. */ @@ -3619,7 +3606,6 @@ static const ARMCPRegInfo pmsav7_cp_reginfo[] = { .fieldoffset = offsetof(CPUARMState, pmsav7.rnr[M_REG_NS]), .writefn = pmsav7_rgnr_write, .resetfn = arm_cp_reset_ignore }, - REGINFO_SENTINEL }; static const ARMCPRegInfo pmsav5_cp_reginfo[] = { @@ -3670,7 +3656,6 @@ static const ARMCPRegInfo pmsav5_cp_reginfo[] = { { .name = "946_PRBS7", .cp = 15, .crn = 6, .crm = 7, .opc1 = 0, .opc2 = CP_ANY, .access = PL1_RW, .resetvalue = 0, .fieldoffset = offsetof(CPUARMState, cp15.c6_region[7]) }, - REGINFO_SENTINEL }; static void vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -3824,7 +3809,6 @@ static const ARMCPRegInfo vmsa_pmsa_cp_reginfo[] = { .access = PL1_RW, .accessfn = access_tvm_trvm, .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]), .resetvalue = 0, }, - REGINFO_SENTINEL }; static const ARMCPRegInfo vmsa_cp_reginfo[] = { @@ -3857,7 +3841,6 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { /* No offsetoflow32 -- pass the entire TCR to writefn/raw_writefn. */ .bank_fieldoffsets = { offsetof(CPUARMState, cp15.tcr_el[3]), offsetof(CPUARMState, cp15.tcr_el[1])} }, - REGINFO_SENTINEL }; /* Note that unlike TTBCR, writing to TTBCR2 does not require flushing @@ -3942,7 +3925,6 @@ static const ARMCPRegInfo omap_cp_reginfo[] = { { .name = "C9", .cp = 15, .crn = 9, .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_OVERRIDE, .resetvalue = 0 }, - REGINFO_SENTINEL }; static void xscale_cpar_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -3975,7 +3957,6 @@ static const ARMCPRegInfo xscale_cp_reginfo[] = { { .name = "XSCALE_UNLOCK_DCACHE", .cp = 15, .opc1 = 0, .crn = 9, .crm = 2, .opc2 = 1, .access = PL1_W, .type = ARM_CP_NOP }, - REGINFO_SENTINEL }; static const ARMCPRegInfo dummy_c15_cp_reginfo[] = { @@ -3989,7 +3970,6 @@ static const ARMCPRegInfo dummy_c15_cp_reginfo[] = { .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_NO_RAW | ARM_CP_OVERRIDE, .resetvalue = 0 }, - REGINFO_SENTINEL }; static const ARMCPRegInfo cache_dirty_status_cp_reginfo[] = { @@ -3997,7 +3977,6 @@ static const ARMCPRegInfo cache_dirty_status_cp_reginfo[] = { { .name = "CDSR", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST | ARM_CP_NO_RAW, .resetvalue = 0 }, - REGINFO_SENTINEL }; static const ARMCPRegInfo cache_block_ops_cp_reginfo[] = { @@ -4018,7 +3997,6 @@ static const ARMCPRegInfo cache_block_ops_cp_reginfo[] = { .access = PL0_W, .type = ARM_CP_NOP|ARM_CP_64BIT }, { .name = "CIDCR", .cp = 15, .crm = 14, .opc1 = 0, .access = PL1_W, .type = ARM_CP_NOP|ARM_CP_64BIT }, - REGINFO_SENTINEL }; static const ARMCPRegInfo cache_test_clean_cp_reginfo[] = { @@ -4031,7 +4009,6 @@ static const ARMCPRegInfo cache_test_clean_cp_reginfo[] = { { .name = "TCI_DCACHE", .cp = 15, .crn = 7, .crm = 14, .opc1 = 0, .opc2 = 3, .access = PL0_R, .type = ARM_CP_CONST | ARM_CP_NO_RAW, .resetvalue = (1 << 30) }, - REGINFO_SENTINEL }; static const ARMCPRegInfo strongarm_cp_reginfo[] = { @@ -4040,7 +4017,6 @@ static const ARMCPRegInfo strongarm_cp_reginfo[] = { .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST | ARM_CP_OVERRIDE | ARM_CP_NO_RAW }, - REGINFO_SENTINEL }; static uint64_t midr_read(CPUARMState *env, const ARMCPRegInfo *ri) @@ -4107,7 +4083,6 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = { .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s), offsetof(CPUARMState, cp15.ttbr1_ns) }, .writefn = vmsa_ttbr_write, }, - REGINFO_SENTINEL }; static uint64_t aa64_fpcr_read(CPUARMState *env, const ARMCPRegInfo *ri) @@ -5126,7 +5101,6 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .access = PL1_RW, .accessfn = access_trap_aa32s_el1, .writefn = sdcr_write, .fieldoffset = offsetoflow32(CPUARMState, cp15.mdcr_el3) }, - REGINFO_SENTINEL }; /* Used to describe the behaviour of EL2 regs when EL2 does not exist. */ @@ -5237,7 +5211,6 @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = { .type = ARM_CP_CONST, .cp = 15, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 2, .access = PL2_RW, .resetvalue = 0 }, - REGINFO_SENTINEL }; /* Ditto, but for registers which exist in ARMv8 but not v7 */ @@ -5246,7 +5219,6 @@ static const ARMCPRegInfo el3_no_el2_v8_cp_reginfo[] = { .cp = 15, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 4, .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL }; static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) @@ -5679,7 +5651,6 @@ static const ARMCPRegInfo el2_cp_reginfo[] = { .cp = 15, .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 3, .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.hstr_el2) }, - REGINFO_SENTINEL }; static const ARMCPRegInfo el2_v8_cp_reginfo[] = { @@ -5689,7 +5660,6 @@ static const ARMCPRegInfo el2_v8_cp_reginfo[] = { .access = PL2_RW, .fieldoffset = offsetofhigh32(CPUARMState, cp15.hcr_el2), .writefn = hcr_writehigh }, - REGINFO_SENTINEL }; static CPAccessResult sel2_access(CPUARMState *env, const ARMCPRegInfo *ri, @@ -5710,7 +5680,6 @@ static const ARMCPRegInfo el2_sec_cp_reginfo[] = { .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 6, .opc2 = 2, .access = PL2_RW, .accessfn = sel2_access, .fieldoffset = offsetof(CPUARMState, cp15.vstcr_el2) }, - REGINFO_SENTINEL }; static CPAccessResult nsacr_access(CPUARMState *env, const ARMCPRegInfo *ri, @@ -5836,7 +5805,6 @@ static const ARMCPRegInfo el3_cp_reginfo[] = { .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 7, .opc2 = 5, .access = PL3_W, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae3_write }, - REGINFO_SENTINEL }; #ifndef CONFIG_USER_ONLY @@ -6122,7 +6090,6 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0, .access = PL1_RW, .accessfn = access_tda, .type = ARM_CP_NOP }, - REGINFO_SENTINEL }; static const ARMCPRegInfo debug_lpae_cp_reginfo[] = { @@ -6131,7 +6098,6 @@ static const ARMCPRegInfo debug_lpae_cp_reginfo[] = { .access = PL0_R, .type = ARM_CP_CONST|ARM_CP_64BIT, .resetvalue = 0 }, { .name = "DBGDSAR", .cp = 14, .crm = 2, .opc1 = 0, .access = PL0_R, .type = ARM_CP_CONST|ARM_CP_64BIT, .resetvalue = 0 }, - REGINFO_SENTINEL }; /* Return the exception level to which exceptions should be taken @@ -6617,7 +6583,6 @@ static void define_debug_regs(ARMCPU *cpu) .fieldoffset = offsetof(CPUARMState, cp15.dbgbcr[i]), .writefn = dbgbcr_write, .raw_writefn = raw_write }, - REGINFO_SENTINEL }; define_arm_cp_regs(cpu, dbgregs); } @@ -6636,7 +6601,6 @@ static void define_debug_regs(ARMCPU *cpu) .fieldoffset = offsetof(CPUARMState, cp15.dbgwcr[i]), .writefn = dbgwcr_write, .raw_writefn = raw_write }, - REGINFO_SENTINEL }; define_arm_cp_regs(cpu, dbgregs); } @@ -6699,7 +6663,6 @@ static void define_pmu_regs(ARMCPU *cpu) .type = ARM_CP_IO, .readfn = pmevtyper_readfn, .writefn = pmevtyper_writefn, .raw_writefn = pmevtyper_rawwrite }, - REGINFO_SENTINEL }; define_arm_cp_regs(cpu, pmev_regs); g_free(pmevcntr_name); @@ -6717,7 +6680,6 @@ static void define_pmu_regs(ARMCPU *cpu) .cp = 15, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 5, .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST, .resetvalue = extract64(cpu->pmceid1, 32, 32) }, - REGINFO_SENTINEL }; define_arm_cp_regs(cpu, v81_pmu_regs); } @@ -6814,7 +6776,6 @@ static const ARMCPRegInfo lor_reginfo[] = { .opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 7, .access = PL1_R, .accessfn = access_lor_ns, .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL }; #ifdef TARGET_AARCH64 @@ -6877,7 +6838,6 @@ static const ARMCPRegInfo pauth_reginfo[] = { .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 1, .opc2 = 3, .access = PL1_RW, .accessfn = access_pauth, .fieldoffset = offsetof(CPUARMState, keys.apib.hi) }, - REGINFO_SENTINEL }; static const ARMCPRegInfo tlbirange_reginfo[] = { @@ -6989,7 +6949,6 @@ static const ARMCPRegInfo tlbirange_reginfo[] = { .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 6, .opc2 = 5, .access = PL3_W, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae3_write }, - REGINFO_SENTINEL }; static const ARMCPRegInfo tlbios_reginfo[] = { @@ -7061,7 +7020,6 @@ static const ARMCPRegInfo tlbios_reginfo[] = { .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 1, .opc2 = 5, .access = PL3_W, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae3is_write }, - REGINFO_SENTINEL }; static uint64_t rndr_readfn(CPUARMState *env, const ARMCPRegInfo *ri) @@ -7100,7 +7058,6 @@ static const ARMCPRegInfo rndr_reginfo[] = { .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END | ARM_CP_IO, .opc0 = 3, .opc1 = 3, .crn = 2, .crm = 4, .opc2 = 1, .access = PL0_R, .readfn = rndr_readfn }, - REGINFO_SENTINEL }; #ifndef CONFIG_USER_ONLY @@ -7136,7 +7093,6 @@ static const ARMCPRegInfo dcpop_reg[] = { .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 12, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END, .accessfn = aa64_cacheop_poc_access, .writefn = dccvap_writefn }, - REGINFO_SENTINEL }; static const ARMCPRegInfo dcpodp_reg[] = { @@ -7144,7 +7100,6 @@ static const ARMCPRegInfo dcpodp_reg[] = { .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 13, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END, .accessfn = aa64_cacheop_poc_access, .writefn = dccvap_writefn }, - REGINFO_SENTINEL }; #endif /*CONFIG_USER_ONLY*/ @@ -7246,14 +7201,12 @@ static const ARMCPRegInfo mte_reginfo[] = { { .name = "DC_CIGDSW", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 6, .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, - REGINFO_SENTINEL }; static const ARMCPRegInfo mte_tco_ro_reginfo[] = { { .name = "TCO", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 4, .crm = 2, .opc2 = 7, .type = ARM_CP_CONST, .access = PL0_RW, }, - REGINFO_SENTINEL }; static const ARMCPRegInfo mte_el0_cacheop_reginfo[] = { @@ -7305,7 +7258,6 @@ static const ARMCPRegInfo mte_el0_cacheop_reginfo[] = { .accessfn = aa64_zva_access, #endif }, - REGINFO_SENTINEL }; #endif @@ -7351,7 +7303,6 @@ static const ARMCPRegInfo predinv_reginfo[] = { { .name = "CPPRCTX", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 0, .crn = 7, .crm = 3, .opc2 = 7, .type = ARM_CP_NOP, .access = PL0_W, .accessfn = access_predinv }, - REGINFO_SENTINEL }; static uint64_t ccsidr2_read(CPUARMState *env, const ARMCPRegInfo *ri) @@ -7366,7 +7317,6 @@ static const ARMCPRegInfo ccsidr2_reginfo[] = { .access = PL1_R, .accessfn = access_aa64_tid2, .readfn = ccsidr2_read, .type = ARM_CP_NO_RAW }, - REGINFO_SENTINEL }; static CPAccessResult access_aa64_tid3(CPUARMState *env, const ARMCPRegInfo *ri, @@ -7427,7 +7377,6 @@ static const ARMCPRegInfo jazelle_regs[] = { .cp = 14, .crn = 2, .crm = 0, .opc1 = 7, .opc2 = 0, .accessfn = access_joscr_jmcr, .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL }; static const ARMCPRegInfo vhe_reginfo[] = { @@ -7492,7 +7441,6 @@ static const ARMCPRegInfo vhe_reginfo[] = { .access = PL2_RW, .accessfn = e2h_access, .writefn = gt_virt_cval_write, .raw_writefn = raw_write }, #endif - REGINFO_SENTINEL }; #ifndef CONFIG_USER_ONLY @@ -7505,7 +7453,6 @@ static const ARMCPRegInfo ats1e1_reginfo[] = { .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 1, .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, .writefn = ats_write64 }, - REGINFO_SENTINEL }; static const ARMCPRegInfo ats1cp_reginfo[] = { @@ -7517,7 +7464,6 @@ static const ARMCPRegInfo ats1cp_reginfo[] = { .cp = 15, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 1, .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, .writefn = ats_write }, - REGINFO_SENTINEL }; #endif @@ -7539,7 +7485,6 @@ static const ARMCPRegInfo actlr2_hactlr2_reginfo[] = { .cp = 15, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 3, .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL }; void register_cp_regs_for_features(ARMCPU *cpu) @@ -7646,7 +7591,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_aa32_tid3, .resetvalue = cpu->isar.id_isar6 }, - REGINFO_SENTINEL }; define_arm_cp_regs(cpu, v6_idregs); define_arm_cp_regs(cpu, v6_cp_reginfo); @@ -7914,7 +7858,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 7, .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST, .resetvalue = cpu->pmceid1 }, - REGINFO_SENTINEL }; #ifdef CONFIG_USER_ONLY ARMCPRegUserSpaceInfo v8_user_idregs[] = { @@ -7944,7 +7887,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) .exported_bits = 0x000000f0ffffffff }, { .name = "ID_AA64ISAR*_EL1_RESERVED", .is_glob = true }, - REGUSERINFO_SENTINEL }; modify_arm_cp_regs(v8_idregs, v8_user_idregs); #endif @@ -7984,7 +7926,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL2_RW, .resetvalue = vmpidr_def, .fieldoffset = offsetof(CPUARMState, cp15.vmpidr_el2) }, - REGINFO_SENTINEL }; define_arm_cp_regs(cpu, vpidr_regs); define_arm_cp_regs(cpu, el2_cp_reginfo); @@ -8023,7 +7964,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL2_RW, .accessfn = access_el3_aa32ns, .type = ARM_CP_NO_RAW, .writefn = arm_cp_write_ignore, .readfn = mpidr_read }, - REGINFO_SENTINEL }; define_arm_cp_regs(cpu, vpidr_regs); define_arm_cp_regs(cpu, el3_no_el2_cp_reginfo); @@ -8046,7 +7986,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) .raw_writefn = raw_write, .writefn = sctlr_write, .fieldoffset = offsetof(CPUARMState, cp15.sctlr_el[3]), .resetvalue = cpu->reset_sctlr }, - REGINFO_SENTINEL }; define_arm_cp_regs(cpu, el3_regs); @@ -8181,7 +8120,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) { .name = "DUMMY", .cp = 15, .crn = 0, .crm = 7, .opc1 = 0, .opc2 = CP_ANY, .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL }; ARMCPRegInfo id_v8_midr_cp_reginfo[] = { { .name = "MIDR_EL1", .state = ARM_CP_STATE_BOTH, @@ -8201,7 +8139,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL1_R, .accessfn = access_aa64_tid1, .type = ARM_CP_CONST, .resetvalue = cpu->revidr }, - REGINFO_SENTINEL }; ARMCPRegInfo id_cp_reginfo[] = { /* These are common to v8 and pre-v8 */ @@ -8219,7 +8156,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL1_R, .accessfn = access_aa32_tid1, .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL }; /* TLBTR is specific to VMSA */ ARMCPRegInfo id_tlbtr_reginfo = { @@ -8246,25 +8182,23 @@ void register_cp_regs_for_features(ARMCPU *cpu) { .name = "MIDR_EL1", .exported_bits = 0x00000000ffffffff }, { .name = "REVIDR_EL1" }, - REGUSERINFO_SENTINEL }; modify_arm_cp_regs(id_v8_midr_cp_reginfo, id_v8_user_midr_cp_reginfo); #endif if (arm_feature(env, ARM_FEATURE_OMAPCP) || arm_feature(env, ARM_FEATURE_STRONGARM)) { - ARMCPRegInfo *r; + size_t i; /* Register the blanket "writes ignored" value first to cover the * whole space. Then update the specific ID registers to allow write * access, so that they ignore writes rather than causing them to * UNDEF. */ define_one_arm_cp_reg(cpu, &crn0_wi_reginfo); - for (r = id_pre_v8_midr_cp_reginfo; - r->type != ARM_CP_SENTINEL; r++) { - r->access = PL1_RW; + for (i = 0; i < ARRAY_SIZE(id_pre_v8_midr_cp_reginfo); ++i) { + id_pre_v8_midr_cp_reginfo[i].access = PL1_RW; } - for (r = id_cp_reginfo; r->type != ARM_CP_SENTINEL; r++) { - r->access = PL1_RW; + for (i = 0; i < ARRAY_SIZE(id_cp_reginfo); ++i) { + id_cp_reginfo[i].access = PL1_RW; } id_mpuir_reginfo.access = PL1_RW; id_tlbtr_reginfo.access = PL1_RW; @@ -8287,13 +8221,11 @@ void register_cp_regs_for_features(ARMCPU *cpu) { .name = "MPIDR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 5, .access = PL1_R, .readfn = mpidr_read, .type = ARM_CP_NO_RAW }, - REGINFO_SENTINEL }; #ifdef CONFIG_USER_ONLY ARMCPRegUserSpaceInfo mpidr_user_cp_reginfo[] = { { .name = "MPIDR_EL1", .fixed_bits = 0x0000000080000000 }, - REGUSERINFO_SENTINEL }; modify_arm_cp_regs(mpidr_cp_reginfo, mpidr_user_cp_reginfo); #endif @@ -8314,7 +8246,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 0, .opc2 = 1, .access = PL3_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - REGINFO_SENTINEL }; define_arm_cp_regs(cpu, auxcr_reginfo); if (cpu_isar_feature(aa32_ac2, cpu)) { @@ -8349,7 +8280,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) .type = ARM_CP_CONST, .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 3, .opc2 = 0, .access = PL1_R, .resetvalue = cpu->reset_cbar }, - REGINFO_SENTINEL }; /* We don't implement a r/w 64 bit CBAR currently */ assert(arm_feature(env, ARM_FEATURE_CBAR_RO)); @@ -8379,7 +8309,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) .bank_fieldoffsets = { offsetof(CPUARMState, cp15.vbar_s), offsetof(CPUARMState, cp15.vbar_ns) }, .resetvalue = 0 }, - REGINFO_SENTINEL }; define_arm_cp_regs(cpu, vbar_cp_reginfo); } @@ -8833,8 +8762,7 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, r->writefn); } } - /* Bad type field probably means missing sentinel at end of reg list */ - assert(cptype_valid(r->type)); + for (crm = crmmin; crm <= crmmax; crm++) { for (opc1 = opc1min; opc1 <= opc1max; opc1++) { for (opc2 = opc2min; opc2 <= opc2max; opc2++) { @@ -8880,13 +8808,13 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, } } -void define_arm_cp_regs_with_opaque(ARMCPU *cpu, - const ARMCPRegInfo *regs, void *opaque) +/* Define a whole list of registers */ +void define_arm_cp_regs_with_opaque_len(ARMCPU *cpu, const ARMCPRegInfo *regs, + void *opaque, size_t len) { - /* Define a whole list of registers */ - const ARMCPRegInfo *r; - for (r = regs; r->type != ARM_CP_SENTINEL; r++) { - define_one_arm_cp_reg_with_opaque(cpu, r, opaque); + size_t i; + for (i = 0; i < len; ++i) { + define_one_arm_cp_reg_with_opaque(cpu, regs + i, opaque); } } @@ -8898,17 +8826,20 @@ void define_arm_cp_regs_with_opaque(ARMCPU *cpu, * user-space cannot alter any values and dynamic values pertaining to * execution state are hidden from user space view anyway. */ -void modify_arm_cp_regs(ARMCPRegInfo *regs, const ARMCPRegUserSpaceInfo *mods) +void modify_arm_cp_regs_with_len(ARMCPRegInfo *regs, size_t regs_len, + const ARMCPRegUserSpaceInfo *mods, + size_t mods_len) { - const ARMCPRegUserSpaceInfo *m; - ARMCPRegInfo *r; - - for (m = mods; m->name; m++) { + for (size_t mi = 0; mi < mods_len; ++mi) { + const ARMCPRegUserSpaceInfo *m = mods + mi; GPatternSpec *pat = NULL; + if (m->is_glob) { pat = g_pattern_spec_new(m->name); } - for (r = regs; r->type != ARM_CP_SENTINEL; r++) { + for (size_t ri = 0; ri < regs_len; ++ri) { + ARMCPRegInfo *r = regs + ri; + if (pat && g_pattern_match_string(pat, r->name)) { r->type = ARM_CP_CONST; r->access = PL0U_R; From 10b0220e45a93410206c270b0642870e20e69d09 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:49:46 -0700 Subject: [PATCH 019/935] target/arm: Make some more cpreg data static const MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These particular data structures are not modified at runtime. Reviewed-by: Alex Bennée Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220501055028.646596-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index a68f14fe8e..ca6ba9bd82 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -7860,7 +7860,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) .resetvalue = cpu->pmceid1 }, }; #ifdef CONFIG_USER_ONLY - ARMCPRegUserSpaceInfo v8_user_idregs[] = { + static const ARMCPRegUserSpaceInfo v8_user_idregs[] = { { .name = "ID_AA64PFR0_EL1", .exported_bits = 0x000f000f00ff0000, .fixed_bits = 0x0000000000000011 }, @@ -8000,7 +8000,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) */ if (arm_feature(env, ARM_FEATURE_EL3)) { if (arm_feature(env, ARM_FEATURE_AARCH64)) { - ARMCPRegInfo nsacr = { + static const ARMCPRegInfo nsacr = { .name = "NSACR", .type = ARM_CP_CONST, .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2, .access = PL1_RW, .accessfn = nsacr_access, @@ -8008,7 +8008,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) }; define_one_arm_cp_reg(cpu, &nsacr); } else { - ARMCPRegInfo nsacr = { + static const ARMCPRegInfo nsacr = { .name = "NSACR", .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2, .access = PL3_RW | PL1_R, @@ -8019,7 +8019,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) } } else { if (arm_feature(env, ARM_FEATURE_V8)) { - ARMCPRegInfo nsacr = { + static const ARMCPRegInfo nsacr = { .name = "NSACR", .type = ARM_CP_CONST, .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2, .access = PL1_R, @@ -8172,13 +8172,13 @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->pmsav7_dregion << 8 }; - ARMCPRegInfo crn0_wi_reginfo = { + static const ARMCPRegInfo crn0_wi_reginfo = { .name = "CRN0_WI", .cp = 15, .crn = 0, .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_W, .type = ARM_CP_NOP | ARM_CP_OVERRIDE }; #ifdef CONFIG_USER_ONLY - ARMCPRegUserSpaceInfo id_v8_user_midr_cp_reginfo[] = { + static const ARMCPRegUserSpaceInfo id_v8_user_midr_cp_reginfo[] = { { .name = "MIDR_EL1", .exported_bits = 0x00000000ffffffff }, { .name = "REVIDR_EL1" }, @@ -8223,7 +8223,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL1_R, .readfn = mpidr_read, .type = ARM_CP_NO_RAW }, }; #ifdef CONFIG_USER_ONLY - ARMCPRegUserSpaceInfo mpidr_user_cp_reginfo[] = { + static const ARMCPRegUserSpaceInfo mpidr_user_cp_reginfo[] = { { .name = "MPIDR_EL1", .fixed_bits = 0x0000000080000000 }, }; @@ -8302,7 +8302,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) } if (arm_feature(env, ARM_FEATURE_VBAR)) { - ARMCPRegInfo vbar_cp_reginfo[] = { + static const ARMCPRegInfo vbar_cp_reginfo[] = { { .name = "VBAR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .writefn = vbar_write, From 87c3f0f2f791094adce2b8643d9103dac1b59702 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:49:47 -0700 Subject: [PATCH 020/935] target/arm: Reorg ARMCPRegInfo type field bits Instead of defining ARM_CP_FLAG_MASK to remove flags, define ARM_CP_SPECIAL_MASK to isolate special cases. Sort the specials to the low bits. Use an enum. Split the large comment block so as to document each value separately. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20220501055028.646596-6-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpregs.h | 130 +++++++++++++++++++++++-------------- target/arm/cpu.c | 4 +- target/arm/helper.c | 4 +- target/arm/translate-a64.c | 6 +- target/arm/translate.c | 6 +- 5 files changed, 92 insertions(+), 58 deletions(-) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index a5231504d5..ff3817decb 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -22,57 +22,87 @@ #define TARGET_ARM_CPREGS_H /* - * ARMCPRegInfo type field bits. If the SPECIAL bit is set this is a - * special-behaviour cp reg and bits [11..8] indicate what behaviour - * it has. Otherwise it is a simple cp reg, where CONST indicates that - * TCG can assume the value to be constant (ie load at translate time) - * and 64BIT indicates a 64 bit wide coprocessor register. SUPPRESS_TB_END - * indicates that the TB should not be ended after a write to this register - * (the default is that the TB ends after cp writes). OVERRIDE permits - * a register definition to override a previous definition for the - * same (cp, is64, crn, crm, opc1, opc2) tuple: either the new or the - * old must have the OVERRIDE bit set. - * ALIAS indicates that this register is an alias view of some underlying - * state which is also visible via another register, and that the other - * register is handling migration and reset; registers marked ALIAS will not be - * migrated but may have their state set by syncing of register state from KVM. - * NO_RAW indicates that this register has no underlying state and does not - * support raw access for state saving/loading; it will not be used for either - * migration or KVM state synchronization. (Typically this is for "registers" - * which are actually used as instructions for cache maintenance and so on.) - * IO indicates that this register does I/O and therefore its accesses - * need to be marked with gen_io_start() and also end the TB. In particular, - * registers which implement clocks or timers require this. - * RAISES_EXC is for when the read or write hook might raise an exception; - * the generated code will synchronize the CPU state before calling the hook - * so that it is safe for the hook to call raise_exception(). - * NEWEL is for writes to registers that might change the exception - * level - typically on older ARM chips. For those cases we need to - * re-read the new el when recomputing the translation flags. + * ARMCPRegInfo type field bits: */ -#define ARM_CP_SPECIAL 0x0001 -#define ARM_CP_CONST 0x0002 -#define ARM_CP_64BIT 0x0004 -#define ARM_CP_SUPPRESS_TB_END 0x0008 -#define ARM_CP_OVERRIDE 0x0010 -#define ARM_CP_ALIAS 0x0020 -#define ARM_CP_IO 0x0040 -#define ARM_CP_NO_RAW 0x0080 -#define ARM_CP_NOP (ARM_CP_SPECIAL | 0x0100) -#define ARM_CP_WFI (ARM_CP_SPECIAL | 0x0200) -#define ARM_CP_NZCV (ARM_CP_SPECIAL | 0x0300) -#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | 0x0400) -#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | 0x0500) -#define ARM_CP_DC_GVA (ARM_CP_SPECIAL | 0x0600) -#define ARM_CP_DC_GZVA (ARM_CP_SPECIAL | 0x0700) -#define ARM_LAST_SPECIAL ARM_CP_DC_GZVA -#define ARM_CP_FPU 0x1000 -#define ARM_CP_SVE 0x2000 -#define ARM_CP_NO_GDB 0x4000 -#define ARM_CP_RAISES_EXC 0x8000 -#define ARM_CP_NEWEL 0x10000 -/* Mask of only the flag bits in a type field */ -#define ARM_CP_FLAG_MASK 0x1f0ff +enum { + /* + * Register must be handled specially during translation. + * The method is one of the values below: + */ + ARM_CP_SPECIAL_MASK = 0x000f, + /* Special: no change to PE state: writes ignored, reads ignored. */ + ARM_CP_NOP = 0x0001, + /* Special: sysreg is WFI, for v5 and v6. */ + ARM_CP_WFI = 0x0002, + /* Special: sysreg is NZCV. */ + ARM_CP_NZCV = 0x0003, + /* Special: sysreg is CURRENTEL. */ + ARM_CP_CURRENTEL = 0x0004, + /* Special: sysreg is DC ZVA or similar. */ + ARM_CP_DC_ZVA = 0x0005, + ARM_CP_DC_GVA = 0x0006, + ARM_CP_DC_GZVA = 0x0007, + + /* Flag: reads produce resetvalue; writes ignored. */ + ARM_CP_CONST = 1 << 4, + /* Flag: For ARM_CP_STATE_AA32, sysreg is 64-bit. */ + ARM_CP_64BIT = 1 << 5, + /* + * Flag: TB should not be ended after a write to this register + * (the default is that the TB ends after cp writes). + */ + ARM_CP_SUPPRESS_TB_END = 1 << 6, + /* + * Flag: Permit a register definition to override a previous definition + * for the same (cp, is64, crn, crm, opc1, opc2) tuple: either the new + * or the old must have the ARM_CP_OVERRIDE bit set. + */ + ARM_CP_OVERRIDE = 1 << 7, + /* + * Flag: Register is an alias view of some underlying state which is also + * visible via another register, and that the other register is handling + * migration and reset; registers marked ARM_CP_ALIAS will not be migrated + * but may have their state set by syncing of register state from KVM. + */ + ARM_CP_ALIAS = 1 << 8, + /* + * Flag: Register does I/O and therefore its accesses need to be marked + * with gen_io_start() and also end the TB. In particular, registers which + * implement clocks or timers require this. + */ + ARM_CP_IO = 1 << 9, + /* + * Flag: Register has no underlying state and does not support raw access + * for state saving/loading; it will not be used for either migration or + * KVM state synchronization. Typically this is for "registers" which are + * actually used as instructions for cache maintenance and so on. + */ + ARM_CP_NO_RAW = 1 << 10, + /* + * Flag: The read or write hook might raise an exception; the generated + * code will synchronize the CPU state before calling the hook so that it + * is safe for the hook to call raise_exception(). + */ + ARM_CP_RAISES_EXC = 1 << 11, + /* + * Flag: Writes to the sysreg might change the exception level - typically + * on older ARM chips. For those cases we need to re-read the new el when + * recomputing the translation flags. + */ + ARM_CP_NEWEL = 1 << 12, + /* + * Flag: Access check for this sysreg is identical to accessing FPU state + * from an instruction: use translation fp_access_check(). + */ + ARM_CP_FPU = 1 << 13, + /* + * Flag: Access check for this sysreg is identical to accessing SVE state + * from an instruction: use translation sve_access_check(). + */ + ARM_CP_SVE = 1 << 14, + /* Flag: Do not expose in gdb sysreg xml. */ + ARM_CP_NO_GDB = 1 << 15, +}; /* * Valid values for ARMCPRegInfo state field, indicating which of diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 18212eb6ee..a7cd692010 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -117,7 +117,7 @@ static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque) ARMCPRegInfo *ri = value; ARMCPU *cpu = opaque; - if (ri->type & (ARM_CP_SPECIAL | ARM_CP_ALIAS)) { + if (ri->type & (ARM_CP_SPECIAL_MASK | ARM_CP_ALIAS)) { return; } @@ -153,7 +153,7 @@ static void cp_reg_check_reset(gpointer key, gpointer value, gpointer opaque) ARMCPU *cpu = opaque; uint64_t oldvalue, newvalue; - if (ri->type & (ARM_CP_SPECIAL | ARM_CP_ALIAS | ARM_CP_NO_RAW)) { + if (ri->type & (ARM_CP_SPECIAL_MASK | ARM_CP_ALIAS | ARM_CP_NO_RAW)) { return; } diff --git a/target/arm/helper.c b/target/arm/helper.c index ca6ba9bd82..f84377babe 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8600,7 +8600,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, * multiple times. Special registers (ie NOP/WFI) are * never migratable and not even raw-accessible. */ - if ((r->type & ARM_CP_SPECIAL)) { + if (r->type & ARM_CP_SPECIAL_MASK) { r2->type |= ARM_CP_NO_RAW; } if (((r->crm == CP_ANY) && crm != 0) || @@ -8750,7 +8750,7 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, /* Check that the register definition has enough info to handle * reads and writes if they are permitted. */ - if (!(r->type & (ARM_CP_SPECIAL|ARM_CP_CONST))) { + if (!(r->type & (ARM_CP_SPECIAL_MASK | ARM_CP_CONST))) { if (r->access & PL3_R) { assert((r->fieldoffset || (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1])) || diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 348a638c5c..a82f5d5984 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1833,7 +1833,9 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, } /* Handle special cases first */ - switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) { + switch (ri->type & ARM_CP_SPECIAL_MASK) { + case 0: + break; case ARM_CP_NOP: return; case ARM_CP_NZCV: @@ -1908,7 +1910,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, } return; default: - break; + g_assert_not_reached(); } if ((ri->type & ARM_CP_FPU) && !fp_access_check(s)) { return; diff --git a/target/arm/translate.c b/target/arm/translate.c index fc7917cdf4..050c237b07 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4744,7 +4744,9 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, } /* Handle special cases first */ - switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) { + switch (ri->type & ARM_CP_SPECIAL_MASK) { + case 0: + break; case ARM_CP_NOP: return; case ARM_CP_WFI: @@ -4756,7 +4758,7 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, s->base.is_jmp = DISAS_WFI; return; default: - break; + g_assert_not_reached(); } if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) { From d385a60571487d9409f247d07aac94d1ee40f9fe Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:49:48 -0700 Subject: [PATCH 021/935] target/arm: Avoid bare abort() or assert(0) Standardize on g_assert_not_reached() for "should not happen". Retain abort() when preceeded by fprintf or error_report. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20220501055028.646596-7-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 7 +++---- target/arm/hvf/hvf.c | 2 +- target/arm/kvm-stub.c | 4 ++-- target/arm/kvm.c | 4 ++-- target/arm/machine.c | 4 ++-- target/arm/translate-a64.c | 4 ++-- target/arm/translate-neon.c | 2 +- target/arm/translate.c | 4 ++-- 8 files changed, 15 insertions(+), 16 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index f84377babe..06f8864c77 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8740,8 +8740,7 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, break; default: /* broken reginfo with out-of-range opc1 */ - assert(false); - break; + g_assert_not_reached(); } /* assert our permissions are not too lax (stricter is fine) */ assert((r->access & ~mask) == 0); @@ -10823,7 +10822,7 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, break; default: /* Never happens, but compiler isn't smart enough to tell. */ - abort(); + g_assert_not_reached(); } } *prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot); @@ -10944,7 +10943,7 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, break; default: /* Never happens, but compiler isn't smart enough to tell. */ - abort(); + g_assert_not_reached(); } } if (domain_prot == 3) { diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index b11a8b9a18..86710509d2 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -1200,7 +1200,7 @@ int hvf_vcpu_exec(CPUState *cpu) /* we got kicked, no exit to process */ return 0; default: - assert(0); + g_assert_not_reached(); } hvf_sync_vtimer(cpu); diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c index 56a7099e6b..965a486b32 100644 --- a/target/arm/kvm-stub.c +++ b/target/arm/kvm-stub.c @@ -15,10 +15,10 @@ bool write_kvmstate_to_list(ARMCPU *cpu) { - abort(); + g_assert_not_reached(); } bool write_list_to_kvmstate(ARMCPU *cpu, int level) { - abort(); + g_assert_not_reached(); } diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 5fc37ac10a..4339e1cd6e 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -540,7 +540,7 @@ bool write_kvmstate_to_list(ARMCPU *cpu) ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r); break; default: - abort(); + g_assert_not_reached(); } if (ret) { ok = false; @@ -575,7 +575,7 @@ bool write_list_to_kvmstate(ARMCPU *cpu, int level) r.addr = (uintptr_t)(cpu->cpreg_values + i); break; default: - abort(); + g_assert_not_reached(); } ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r); if (ret) { diff --git a/target/arm/machine.c b/target/arm/machine.c index 135d2420b5..285e387d2c 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -661,7 +661,7 @@ static int cpu_pre_save(void *opaque) if (kvm_enabled()) { if (!write_kvmstate_to_list(cpu)) { /* This should never fail */ - abort(); + g_assert_not_reached(); } /* @@ -672,7 +672,7 @@ static int cpu_pre_save(void *opaque) } else { if (!write_cpustate_to_list(cpu, false)) { /* This should never fail. */ - abort(); + g_assert_not_reached(); } } diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index a82f5d5984..b80313670f 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -6151,7 +6151,7 @@ static void handle_fp_1src_half(DisasContext *s, int opcode, int rd, int rn) gen_helper_advsimd_rinth(tcg_res, tcg_op, fpst); break; default: - abort(); + g_assert_not_reached(); } write_fp_sreg(s, rd, tcg_res); @@ -6392,7 +6392,7 @@ static void handle_fp_fcvt(DisasContext *s, int opcode, break; } default: - abort(); + g_assert_not_reached(); } } diff --git a/target/arm/translate-neon.c b/target/arm/translate-neon.c index 2e4d1ec87d..321c17e2c7 100644 --- a/target/arm/translate-neon.c +++ b/target/arm/translate-neon.c @@ -679,7 +679,7 @@ static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) } break; default: - abort(); + g_assert_not_reached(); } if ((vd + a->stride * (nregs - 1)) > 31) { /* diff --git a/target/arm/translate.c b/target/arm/translate.c index 050c237b07..4e19191ed5 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5156,7 +5156,7 @@ static void gen_srs(DisasContext *s, offset = 4; break; default: - abort(); + g_assert_not_reached(); } tcg_gen_addi_i32(addr, addr, offset); tmp = load_reg(s, 14); @@ -5181,7 +5181,7 @@ static void gen_srs(DisasContext *s, offset = 0; break; default: - abort(); + g_assert_not_reached(); } tcg_gen_addi_i32(addr, addr, offset); gen_helper_set_r13_banked(cpu_env, tcg_constant_i32(mode), addr); From 39107337181e0cfcbd92e67d10dce3acd5a13f0a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:49:49 -0700 Subject: [PATCH 022/935] target/arm: Change cpreg access permissions to enum Create a typedef as well, and use it in ARMCPRegInfo. This won't be perfect for debugging, but it'll nicely display the most common cases. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220501055028.646596-8-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpregs.h | 44 +++++++++++++++++++++++--------------------- target/arm/helper.c | 2 +- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index ff3817decb..858c5da57d 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -154,31 +154,33 @@ enum { * described with these bits, then use a laxer set of restrictions, and * do the more restrictive/complex check inside a helper function. */ -#define PL3_R 0x80 -#define PL3_W 0x40 -#define PL2_R (0x20 | PL3_R) -#define PL2_W (0x10 | PL3_W) -#define PL1_R (0x08 | PL2_R) -#define PL1_W (0x04 | PL2_W) -#define PL0_R (0x02 | PL1_R) -#define PL0_W (0x01 | PL1_W) +typedef enum { + PL3_R = 0x80, + PL3_W = 0x40, + PL2_R = 0x20 | PL3_R, + PL2_W = 0x10 | PL3_W, + PL1_R = 0x08 | PL2_R, + PL1_W = 0x04 | PL2_W, + PL0_R = 0x02 | PL1_R, + PL0_W = 0x01 | PL1_W, -/* - * For user-mode some registers are accessible to EL0 via a kernel - * trap-and-emulate ABI. In this case we define the read permissions - * as actually being PL0_R. However some bits of any given register - * may still be masked. - */ + /* + * For user-mode some registers are accessible to EL0 via a kernel + * trap-and-emulate ABI. In this case we define the read permissions + * as actually being PL0_R. However some bits of any given register + * may still be masked. + */ #ifdef CONFIG_USER_ONLY -#define PL0U_R PL0_R + PL0U_R = PL0_R, #else -#define PL0U_R PL1_R + PL0U_R = PL1_R, #endif -#define PL3_RW (PL3_R | PL3_W) -#define PL2_RW (PL2_R | PL2_W) -#define PL1_RW (PL1_R | PL1_W) -#define PL0_RW (PL0_R | PL0_W) + PL3_RW = PL3_R | PL3_W, + PL2_RW = PL2_R | PL2_W, + PL1_RW = PL1_R | PL1_W, + PL0_RW = PL0_R | PL0_W, +} CPAccessRights; typedef enum CPAccessResult { /* Access is permitted */ @@ -262,7 +264,7 @@ struct ARMCPRegInfo { /* Register type: ARM_CP_* bits/values */ int type; /* Access rights: PL*_[RW] */ - int access; + CPAccessRights access; /* Security state: ARM_CP_SECSTATE_* bits/values */ int secure; /* diff --git a/target/arm/helper.c b/target/arm/helper.c index 06f8864c77..a19e04bb0b 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8711,7 +8711,7 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, * to encompass the generic architectural permission check. */ if (r->state != ARM_CP_STATE_AA32) { - int mask = 0; + CPAccessRights mask; switch (r->opc1) { case 0: /* min_EL EL1, but some accessible to EL0 via kernel ABI */ From d95101d6026641e9116225b5a22bbe6c4621828d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:49:50 -0700 Subject: [PATCH 023/935] target/arm: Name CPState type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Give this enum a name and use in ARMCPRegInfo, add_cpreg_to_hashtable and define_one_arm_cp_reg_with_opaque. Reviewed-by: Alex Bennée Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220501055028.646596-9-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpregs.h | 6 +++--- target/arm/helper.c | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 858c5da57d..4179a8cdd5 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -114,11 +114,11 @@ enum { * Note that we rely on the values of these enums as we iterate through * the various states in some places. */ -enum { +typedef enum { ARM_CP_STATE_AA32 = 0, ARM_CP_STATE_AA64 = 1, ARM_CP_STATE_BOTH = 2, -}; +} CPState; /* * ARM CP register secure state flags. These flags identify security state @@ -260,7 +260,7 @@ struct ARMCPRegInfo { uint8_t opc1; uint8_t opc2; /* Execution state in which this register is visible: ARM_CP_STATE_* */ - int state; + CPState state; /* Register type: ARM_CP_* bits/values */ int type; /* Access rights: PL*_[RW] */ diff --git a/target/arm/helper.c b/target/arm/helper.c index a19e04bb0b..d560a6a6a9 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8502,7 +8502,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) } static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, - void *opaque, int state, int secstate, + void *opaque, CPState state, int secstate, int crm, int opc1, int opc2, const char *name) { @@ -8662,13 +8662,15 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, * bits; the ARM_CP_64BIT* flag applies only to the AArch32 view of * the register, if any. */ - int crm, opc1, opc2, state; + int crm, opc1, opc2; int crmmin = (r->crm == CP_ANY) ? 0 : r->crm; int crmmax = (r->crm == CP_ANY) ? 15 : r->crm; int opc1min = (r->opc1 == CP_ANY) ? 0 : r->opc1; int opc1max = (r->opc1 == CP_ANY) ? 7 : r->opc1; int opc2min = (r->opc2 == CP_ANY) ? 0 : r->opc2; int opc2max = (r->opc2 == CP_ANY) ? 7 : r->opc2; + CPState state; + /* 64 bit registers have only CRm and Opc1 fields */ assert(!((r->type & ARM_CP_64BIT) && (r->opc2 || r->crn))); /* op0 only exists in the AArch64 encodings */ From cbe645856fb17ca0f2395fa4a75d80bdd0421614 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:49:51 -0700 Subject: [PATCH 024/935] target/arm: Name CPSecureState type Give this enum a name and use in ARMCPRegInfo and add_cpreg_to_hashtable. Add the enumerator ARM_CP_SECSTATE_BOTH to clarify how 0 is handled in define_one_arm_cp_reg_with_opaque. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220501055028.646596-10-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpregs.h | 7 ++++--- target/arm/helper.c | 7 +++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 4179a8cdd5..73984549d2 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -131,10 +131,11 @@ typedef enum { * registered entry will only have one to identify whether the entry is secure * or non-secure. */ -enum { +typedef enum { + ARM_CP_SECSTATE_BOTH = 0, /* define one cpreg for each secstate */ ARM_CP_SECSTATE_S = (1 << 0), /* bit[0]: Secure state register */ ARM_CP_SECSTATE_NS = (1 << 1), /* bit[1]: Non-secure state register */ -}; +} CPSecureState; /* * Access rights: @@ -266,7 +267,7 @@ struct ARMCPRegInfo { /* Access rights: PL*_[RW] */ CPAccessRights access; /* Security state: ARM_CP_SECSTATE_* bits/values */ - int secure; + CPSecureState secure; /* * The opaque pointer passed to define_arm_cp_regs_with_opaque() when * this register was defined: can be used to hand data through to the diff --git a/target/arm/helper.c b/target/arm/helper.c index d560a6a6a9..50ad2e3e37 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8502,7 +8502,8 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) } static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, - void *opaque, CPState state, int secstate, + void *opaque, CPState state, + CPSecureState secstate, int crm, int opc1, int opc2, const char *name) { @@ -8785,7 +8786,7 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, r->secure, crm, opc1, opc2, r->name); break; - default: + case ARM_CP_SECSTATE_BOTH: name = g_strdup_printf("%s_S", r->name); add_cpreg_to_hashtable(cpu, r, opaque, state, ARM_CP_SECSTATE_S, @@ -8795,6 +8796,8 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, ARM_CP_SECSTATE_NS, crm, opc1, opc2, r->name); break; + default: + g_assert_not_reached(); } } else { /* AArch64 registers get mapped to non-secure instance From 9da35a40fda3b577e7251d39f1b4aad42348cc08 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:49:52 -0700 Subject: [PATCH 025/935] target/arm: Drop always-true test in define_arm_vh_e2h_redirects_aliases The new_key field is always non-zero -- drop the if. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20220501055028.646596-11-richard.henderson@linaro.org [PMM: reinstated dropped PL3_RW mask] Signed-off-by: Peter Maydell --- target/arm/helper.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 50ad2e3e37..70dc1482dd 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5914,7 +5914,9 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) for (i = 0; i < ARRAY_SIZE(aliases); i++) { const struct E2HAlias *a = &aliases[i]; - ARMCPRegInfo *src_reg, *dst_reg; + ARMCPRegInfo *src_reg, *dst_reg, *new_reg; + uint32_t *new_key; + bool ok; if (a->feature && !a->feature(&cpu->isar)) { continue; @@ -5933,19 +5935,16 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) g_assert(src_reg->opaque == NULL); /* Create alias before redirection so we dup the right data. */ - if (a->new_key) { - ARMCPRegInfo *new_reg = g_memdup(src_reg, sizeof(ARMCPRegInfo)); - uint32_t *new_key = g_memdup(&a->new_key, sizeof(uint32_t)); - bool ok; + new_reg = g_memdup(src_reg, sizeof(ARMCPRegInfo)); + new_key = g_memdup(&a->new_key, sizeof(uint32_t)); - new_reg->name = a->new_name; - new_reg->type |= ARM_CP_ALIAS; - /* Remove PL1/PL0 access, leaving PL2/PL3 R/W in place. */ - new_reg->access &= PL2_RW | PL3_RW; + new_reg->name = a->new_name; + new_reg->type |= ARM_CP_ALIAS; + /* Remove PL1/PL0 access, leaving PL2/PL3 R/W in place. */ + new_reg->access &= PL2_RW | PL3_RW; - ok = g_hash_table_insert(cpu->cp_regs, new_key, new_reg); - g_assert(ok); - } + ok = g_hash_table_insert(cpu->cp_regs, new_key, new_reg); + g_assert(ok); src_reg->opaque = dst_reg; src_reg->orig_readfn = src_reg->readfn ?: raw_read; From 5860362d25f3afa99364d60295c09147a07055f1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:49:53 -0700 Subject: [PATCH 026/935] target/arm: Store cpregs key in the hash table directly Cast the uint32_t key into a gpointer directly, which allows us to avoid allocating storage for each key. Use g_hash_table_lookup when we already have a gpointer (e.g. for callbacks like count_cpreg), or when using get_arm_cp_reginfo would require casting away const. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20220501055028.646596-12-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 4 ++-- target/arm/gdbstub.c | 2 +- target/arm/helper.c | 41 ++++++++++++++++++----------------------- 3 files changed, 21 insertions(+), 26 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index a7cd692010..602c060fff 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1090,8 +1090,8 @@ static void arm_cpu_initfn(Object *obj) ARMCPU *cpu = ARM_CPU(obj); cpu_set_cpustate_pointers(cpu); - cpu->cp_regs = g_hash_table_new_full(g_int_hash, g_int_equal, - g_free, cpreg_hashtable_data_destroy); + cpu->cp_regs = g_hash_table_new_full(g_direct_hash, g_direct_equal, + NULL, cpreg_hashtable_data_destroy); QLIST_INIT(&cpu->pre_el_change_hooks); QLIST_INIT(&cpu->el_change_hooks); diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c index f01a126108..f5b35cd55f 100644 --- a/target/arm/gdbstub.c +++ b/target/arm/gdbstub.c @@ -273,7 +273,7 @@ static void arm_gen_one_xml_sysreg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml, static void arm_register_sysreg_for_xml(gpointer key, gpointer value, gpointer p) { - uint32_t ri_key = *(uint32_t *)key; + uint32_t ri_key = (uintptr_t)key; ARMCPRegInfo *ri = value; RegisterSysregXmlParam *param = (RegisterSysregXmlParam *)p; GString *s = param->s; diff --git a/target/arm/helper.c b/target/arm/helper.c index 70dc1482dd..2bc81dbc5e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -214,11 +214,8 @@ bool write_list_to_cpustate(ARMCPU *cpu) static void add_cpreg_to_list(gpointer key, gpointer opaque) { ARMCPU *cpu = opaque; - uint64_t regidx; - const ARMCPRegInfo *ri; - - regidx = *(uint32_t *)key; - ri = get_arm_cp_reginfo(cpu->cp_regs, regidx); + uint32_t regidx = (uintptr_t)key; + const ARMCPRegInfo *ri = get_arm_cp_reginfo(cpu->cp_regs, regidx); if (!(ri->type & (ARM_CP_NO_RAW|ARM_CP_ALIAS))) { cpu->cpreg_indexes[cpu->cpreg_array_len] = cpreg_to_kvm_id(regidx); @@ -230,11 +227,9 @@ static void add_cpreg_to_list(gpointer key, gpointer opaque) static void count_cpreg(gpointer key, gpointer opaque) { ARMCPU *cpu = opaque; - uint64_t regidx; const ARMCPRegInfo *ri; - regidx = *(uint32_t *)key; - ri = get_arm_cp_reginfo(cpu->cp_regs, regidx); + ri = g_hash_table_lookup(cpu->cp_regs, key); if (!(ri->type & (ARM_CP_NO_RAW|ARM_CP_ALIAS))) { cpu->cpreg_array_len++; @@ -243,8 +238,8 @@ static void count_cpreg(gpointer key, gpointer opaque) static gint cpreg_key_compare(gconstpointer a, gconstpointer b) { - uint64_t aidx = cpreg_to_kvm_id(*(uint32_t *)a); - uint64_t bidx = cpreg_to_kvm_id(*(uint32_t *)b); + uint64_t aidx = cpreg_to_kvm_id((uintptr_t)a); + uint64_t bidx = cpreg_to_kvm_id((uintptr_t)b); if (aidx > bidx) { return 1; @@ -5915,15 +5910,16 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) for (i = 0; i < ARRAY_SIZE(aliases); i++) { const struct E2HAlias *a = &aliases[i]; ARMCPRegInfo *src_reg, *dst_reg, *new_reg; - uint32_t *new_key; bool ok; if (a->feature && !a->feature(&cpu->isar)) { continue; } - src_reg = g_hash_table_lookup(cpu->cp_regs, &a->src_key); - dst_reg = g_hash_table_lookup(cpu->cp_regs, &a->dst_key); + src_reg = g_hash_table_lookup(cpu->cp_regs, + (gpointer)(uintptr_t)a->src_key); + dst_reg = g_hash_table_lookup(cpu->cp_regs, + (gpointer)(uintptr_t)a->dst_key); g_assert(src_reg != NULL); g_assert(dst_reg != NULL); @@ -5936,14 +5932,14 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) /* Create alias before redirection so we dup the right data. */ new_reg = g_memdup(src_reg, sizeof(ARMCPRegInfo)); - new_key = g_memdup(&a->new_key, sizeof(uint32_t)); new_reg->name = a->new_name; new_reg->type |= ARM_CP_ALIAS; /* Remove PL1/PL0 access, leaving PL2/PL3 R/W in place. */ new_reg->access &= PL2_RW | PL3_RW; - ok = g_hash_table_insert(cpu->cp_regs, new_key, new_reg); + ok = g_hash_table_insert(cpu->cp_regs, + (gpointer)(uintptr_t)a->new_key, new_reg); g_assert(ok); src_reg->opaque = dst_reg; @@ -8509,7 +8505,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, /* Private utility function for define_one_arm_cp_reg_with_opaque(): * add a single reginfo struct to the hash table. */ - uint32_t *key = g_new(uint32_t, 1); + uint32_t key; ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo)); int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0; int ns = (secstate & ARM_CP_SECSTATE_NS) ? 1 : 0; @@ -8576,10 +8572,10 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, if (r->cp == 0 || r->state == ARM_CP_STATE_BOTH) { r2->cp = CP_REG_ARM64_SYSREG_CP; } - *key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm, - r2->opc0, opc1, opc2); + key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm, + r2->opc0, opc1, opc2); } else { - *key = ENCODE_CP_REG(r2->cp, is64, ns, r2->crn, crm, opc1, opc2); + key = ENCODE_CP_REG(r2->cp, is64, ns, r2->crn, crm, opc1, opc2); } if (opaque) { r2->opaque = opaque; @@ -8621,8 +8617,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, * requested. */ if (!(r->type & ARM_CP_OVERRIDE)) { - ARMCPRegInfo *oldreg; - oldreg = g_hash_table_lookup(cpu->cp_regs, key); + const ARMCPRegInfo *oldreg = get_arm_cp_reginfo(cpu->cp_regs, key); if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) { fprintf(stderr, "Register redefined: cp=%d %d bit " "crn=%d crm=%d opc1=%d opc2=%d, " @@ -8632,7 +8627,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, g_assert_not_reached(); } } - g_hash_table_insert(cpu->cp_regs, key, r2); + g_hash_table_insert(cpu->cp_regs, (gpointer)(uintptr_t)key, r2); } @@ -8864,7 +8859,7 @@ void modify_arm_cp_regs_with_len(ARMCPRegInfo *regs, size_t regs_len, const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t encoded_cp) { - return g_hash_table_lookup(cpregs, &encoded_cp); + return g_hash_table_lookup(cpregs, (gpointer)(uintptr_t)encoded_cp); } void arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri, From c27f5d3a83ed2959a6a1947708b588a6774a2aec Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:49:54 -0700 Subject: [PATCH 027/935] target/arm: Merge allocation of the cpreg and its name Simplify freeing cp_regs hash table entries by using a single allocation for the entire value. This fixes a theoretical bug if we were to ever free the entire hash table, because we've been installing string literal constants into the cpreg structure in define_arm_vh_e2h_redirects_aliases. However, at present we only free entries created for AArch32 wildcard cpregs which get overwritten by more specific cpregs, so this bug is never exposed. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20220501055028.646596-13-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 16 +--------------- target/arm/helper.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 602c060fff..01176b2569 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1071,27 +1071,13 @@ uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz) return (Aff1 << ARM_AFF1_SHIFT) | Aff0; } -static void cpreg_hashtable_data_destroy(gpointer data) -{ - /* - * Destroy function for cpu->cp_regs hashtable data entries. - * We must free the name string because it was g_strdup()ed in - * add_cpreg_to_hashtable(). It's OK to cast away the 'const' - * from r->name because we know we definitely allocated it. - */ - ARMCPRegInfo *r = data; - - g_free((void *)r->name); - g_free(r); -} - static void arm_cpu_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); cpu_set_cpustate_pointers(cpu); cpu->cp_regs = g_hash_table_new_full(g_direct_hash, g_direct_equal, - NULL, cpreg_hashtable_data_destroy); + NULL, g_free); QLIST_INIT(&cpu->pre_el_change_hooks); QLIST_INIT(&cpu->el_change_hooks); diff --git a/target/arm/helper.c b/target/arm/helper.c index 2bc81dbc5e..d92fd23445 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8506,11 +8506,17 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, * add a single reginfo struct to the hash table. */ uint32_t key; - ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo)); + ARMCPRegInfo *r2; int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0; int ns = (secstate & ARM_CP_SECSTATE_NS) ? 1 : 0; + size_t name_len; + + /* Combine cpreg and name into one allocation. */ + name_len = strlen(name) + 1; + r2 = g_malloc(sizeof(*r2) + name_len); + *r2 = *r; + r2->name = memcpy(r2 + 1, name, name_len); - r2->name = g_strdup(name); /* Reset the secure state to the specific incoming state. This is * necessary as the register may have been defined with both states. */ From cac65299a403b34e57a2230c2b695bdb6d84f396 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:49:55 -0700 Subject: [PATCH 028/935] target/arm: Hoist computation of key in add_cpreg_to_hashtable Move the computation of key to the top of the function. Hoist the resolution of cp as well, as an input to the computation of key. This will be required by a subsequent patch. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20220501055028.646596-14-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 49 +++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index d92fd23445..cbc873e3e6 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8509,8 +8509,34 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, ARMCPRegInfo *r2; int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0; int ns = (secstate & ARM_CP_SECSTATE_NS) ? 1 : 0; + int cp = r->cp; size_t name_len; + switch (state) { + case ARM_CP_STATE_AA32: + /* We assume it is a cp15 register if the .cp field is left unset. */ + if (cp == 0 && r->state == ARM_CP_STATE_BOTH) { + cp = 15; + } + key = ENCODE_CP_REG(cp, is64, ns, r->crn, crm, opc1, opc2); + break; + case ARM_CP_STATE_AA64: + /* + * To allow abbreviation of ARMCPRegInfo definitions, we treat + * cp == 0 as equivalent to the value for "standard guest-visible + * sysreg". STATE_BOTH definitions are also always "standard sysreg" + * in their AArch64 view (the .cp value may be non-zero for the + * benefit of the AArch32 view). + */ + if (cp == 0 || r->state == ARM_CP_STATE_BOTH) { + cp = CP_REG_ARM64_SYSREG_CP; + } + key = ENCODE_AA64_CP_REG(cp, r->crn, crm, r->opc0, opc1, opc2); + break; + default: + g_assert_not_reached(); + } + /* Combine cpreg and name into one allocation. */ name_len = strlen(name) + 1; r2 = g_malloc(sizeof(*r2) + name_len); @@ -8554,12 +8580,6 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, } if (r->state == ARM_CP_STATE_BOTH) { - /* We assume it is a cp15 register if the .cp field is left unset. - */ - if (r2->cp == 0) { - r2->cp = 15; - } - #if HOST_BIG_ENDIAN if (r2->fieldoffset) { r2->fieldoffset += sizeof(uint32_t); @@ -8567,22 +8587,6 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, #endif } } - if (state == ARM_CP_STATE_AA64) { - /* To allow abbreviation of ARMCPRegInfo - * definitions, we treat cp == 0 as equivalent to - * the value for "standard guest-visible sysreg". - * STATE_BOTH definitions are also always "standard - * sysreg" in their AArch64 view (the .cp value may - * be non-zero for the benefit of the AArch32 view). - */ - if (r->cp == 0 || r->state == ARM_CP_STATE_BOTH) { - r2->cp = CP_REG_ARM64_SYSREG_CP; - } - key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm, - r2->opc0, opc1, opc2); - } else { - key = ENCODE_CP_REG(r2->cp, is64, ns, r2->crn, crm, opc1, opc2); - } if (opaque) { r2->opaque = opaque; } @@ -8593,6 +8597,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, /* Make sure reginfo passed to helpers for wildcarded regs * has the correct crm/opc1/opc2 for this reg, not CP_ANY: */ + r2->cp = cp; r2->crm = crm; r2->opc1 = opc1; r2->opc2 = opc2; From cc946d96694e47d30c59dbf20f79f53522cc8265 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:49:56 -0700 Subject: [PATCH 029/935] target/arm: Consolidate cpreg updates in add_cpreg_to_hashtable Put most of the value writeback to the same place, and improve the comment that goes with them. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20220501055028.646596-15-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index cbc873e3e6..8ee96d5c04 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8543,10 +8543,19 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, *r2 = *r; r2->name = memcpy(r2 + 1, name, name_len); - /* Reset the secure state to the specific incoming state. This is - * necessary as the register may have been defined with both states. + /* + * Update fields to match the instantiation, overwiting wildcards + * such as CP_ANY, ARM_CP_STATE_BOTH, or ARM_CP_SECSTATE_BOTH. */ + r2->cp = cp; + r2->crm = crm; + r2->opc1 = opc1; + r2->opc2 = opc2; + r2->state = state; r2->secure = secstate; + if (opaque) { + r2->opaque = opaque; + } if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) { /* Register is banked (using both entries in array). @@ -8587,20 +8596,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, #endif } } - if (opaque) { - r2->opaque = opaque; - } - /* reginfo passed to helpers is correct for the actual access, - * and is never ARM_CP_STATE_BOTH: - */ - r2->state = state; - /* Make sure reginfo passed to helpers for wildcarded regs - * has the correct crm/opc1/opc2 for this reg, not CP_ANY: - */ - r2->cp = cp; - r2->crm = crm; - r2->opc1 = opc1; - r2->opc2 = opc2; + /* By convention, for wildcarded registers only the first * entry is used for migration; the others are marked as * ALIAS so we don't try to transfer the register From 4c8c4541156c957498183f1ce1d5f3d97e3576c2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:49:57 -0700 Subject: [PATCH 030/935] target/arm: Use bool for is64 and ns in add_cpreg_to_hashtable Bool is a more appropriate type for these variables. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20220501055028.646596-16-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 8ee96d5c04..bba010d7cf 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8507,8 +8507,8 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, */ uint32_t key; ARMCPRegInfo *r2; - int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0; - int ns = (secstate & ARM_CP_SECSTATE_NS) ? 1 : 0; + bool is64 = r->type & ARM_CP_64BIT; + bool ns = secstate & ARM_CP_SECSTATE_NS; int cp = r->cp; size_t name_len; From 10748a965279aaaccf98ddeb253653421735e916 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:49:58 -0700 Subject: [PATCH 031/935] target/arm: Hoist isbanked computation in add_cpreg_to_hashtable Computing isbanked only once makes the code a bit easier to read. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20220501055028.646596-17-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index bba010d7cf..941b777dea 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8510,6 +8510,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, bool is64 = r->type & ARM_CP_64BIT; bool ns = secstate & ARM_CP_SECSTATE_NS; int cp = r->cp; + bool isbanked; size_t name_len; switch (state) { @@ -8557,7 +8558,8 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, r2->opaque = opaque; } - if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) { + isbanked = r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]; + if (isbanked) { /* Register is banked (using both entries in array). * Overwriting fieldoffset as the array is only used to define * banked registers but later only fieldoffset is used. @@ -8566,7 +8568,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, } if (state == ARM_CP_STATE_AA32) { - if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) { + if (isbanked) { /* If the register is banked then we don't need to migrate or * reset the 32-bit instance in certain cases: * From dc44545b0df696fd89e7a9634094cbf33ae9006c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:49:59 -0700 Subject: [PATCH 032/935] target/arm: Perform override check early in add_cpreg_to_hashtable Perform the override check early, so that it is still done even when we decide to discard an unreachable cpreg. Use assert not printf+abort. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20220501055028.646596-18-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 941b777dea..fa1e7bd462 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8538,6 +8538,14 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, g_assert_not_reached(); } + /* Overriding of an existing definition must be explicitly requested. */ + if (!(r->type & ARM_CP_OVERRIDE)) { + const ARMCPRegInfo *oldreg = get_arm_cp_reginfo(cpu->cp_regs, key); + if (oldreg) { + assert(oldreg->type & ARM_CP_OVERRIDE); + } + } + /* Combine cpreg and name into one allocation. */ name_len = strlen(name) + 1; r2 = g_malloc(sizeof(*r2) + name_len); @@ -8622,20 +8630,6 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, assert(!raw_accessors_invalid(r2)); } - /* Overriding of an existing definition must be explicitly - * requested. - */ - if (!(r->type & ARM_CP_OVERRIDE)) { - const ARMCPRegInfo *oldreg = get_arm_cp_reginfo(cpu->cp_regs, key); - if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) { - fprintf(stderr, "Register redefined: cp=%d %d bit " - "crn=%d crm=%d opc1=%d opc2=%d, " - "was %s, now %s\n", r2->cp, 32 + 32 * is64, - r2->crn, r2->crm, r2->opc1, r2->opc2, - oldreg->name, r2->name); - g_assert_not_reached(); - } - } g_hash_table_insert(cpu->cp_regs, (gpointer)(uintptr_t)key, r2); } From 1859f8c35abd06de15e58f0996ae11ae366f50d8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:50:00 -0700 Subject: [PATCH 033/935] target/arm: Reformat comments in add_cpreg_to_hashtable Put the block comments into the current coding style. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20220501055028.646596-19-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index fa1e7bd462..81612952f3 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8496,15 +8496,16 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) return cpu_list; } +/* + * Private utility function for define_one_arm_cp_reg_with_opaque(): + * add a single reginfo struct to the hash table. + */ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, void *opaque, CPState state, CPSecureState secstate, int crm, int opc1, int opc2, const char *name) { - /* Private utility function for define_one_arm_cp_reg_with_opaque(): - * add a single reginfo struct to the hash table. - */ uint32_t key; ARMCPRegInfo *r2; bool is64 = r->type & ARM_CP_64BIT; @@ -8568,7 +8569,8 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, isbanked = r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]; if (isbanked) { - /* Register is banked (using both entries in array). + /* + * Register is banked (using both entries in array). * Overwriting fieldoffset as the array is only used to define * banked registers but later only fieldoffset is used. */ @@ -8577,7 +8579,8 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, if (state == ARM_CP_STATE_AA32) { if (isbanked) { - /* If the register is banked then we don't need to migrate or + /* + * If the register is banked then we don't need to migrate or * reset the 32-bit instance in certain cases: * * 1) If the register has both 32-bit and 64-bit instances then we @@ -8592,8 +8595,9 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, r2->type |= ARM_CP_ALIAS; } } else if ((secstate != r->secure) && !ns) { - /* The register is not banked so we only want to allow migration of - * the non-secure instance. + /* + * The register is not banked so we only want to allow migration + * of the non-secure instance. */ r2->type |= ARM_CP_ALIAS; } @@ -8607,7 +8611,8 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, } } - /* By convention, for wildcarded registers only the first + /* + * By convention, for wildcarded registers only the first * entry is used for migration; the others are marked as * ALIAS so we don't try to transfer the register * multiple times. Special registers (ie NOP/WFI) are @@ -8622,7 +8627,8 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, r2->type |= ARM_CP_ALIAS | ARM_CP_NO_GDB; } - /* Check that raw accesses are either forbidden or handled. Note that + /* + * Check that raw accesses are either forbidden or handled. Note that * we can't assert this earlier because the setup of fieldoffset for * banked registers has to be done first. */ From 7d00b4d8d382558f61a168180be6230cda0905d6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:50:01 -0700 Subject: [PATCH 034/935] target/arm: Remove HOST_BIG_ENDIAN ifdef in add_cpreg_to_hashtable Since e03b56863d2bc, our host endian indicator is unconditionally set, which means that we can use a normal C condition. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20220501055028.646596-20-richard.henderson@linaro.org [PMM: quote correct git hash in commit message] Signed-off-by: Peter Maydell --- target/arm/helper.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 81612952f3..14ea5caad9 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8602,12 +8602,9 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, r2->type |= ARM_CP_ALIAS; } - if (r->state == ARM_CP_STATE_BOTH) { -#if HOST_BIG_ENDIAN - if (r2->fieldoffset) { - r2->fieldoffset += sizeof(uint32_t); - } -#endif + if (HOST_BIG_ENDIAN && + r->state == ARM_CP_STATE_BOTH && r2->fieldoffset) { + r2->fieldoffset += sizeof(uint32_t); } } From ca56aac59f6ca936b60f7f6bea5ab54e3f70e379 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:50:05 -0700 Subject: [PATCH 035/935] target/arm: Add isar predicates for FEAT_Debugv8p2 Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220501055028.646596-24-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index d1b558385c..7303103016 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3704,6 +3704,11 @@ static inline bool isar_feature_aa32_ssbs(const ARMISARegisters *id) return FIELD_EX32(id->id_pfr2, ID_PFR2, SSBS) != 0; } +static inline bool isar_feature_aa32_debugv8p2(const ARMISARegisters *id) +{ + return FIELD_EX32(id->id_dfr0, ID_DFR0, COPDBG) >= 8; +} + /* * 64-bit feature tests via id registers. */ @@ -4010,6 +4015,11 @@ static inline bool isar_feature_aa64_ssbs(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SSBS) != 0; } +static inline bool isar_feature_aa64_debugv8p2(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, DEBUGVER) >= 8; +} + static inline bool isar_feature_aa64_sve2(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, SVEVER) != 0; @@ -4093,6 +4103,11 @@ static inline bool isar_feature_any_tts2uxn(const ARMISARegisters *id) return isar_feature_aa64_tts2uxn(id) || isar_feature_aa32_tts2uxn(id); } +static inline bool isar_feature_any_debugv8p2(const ARMISARegisters *id) +{ + return isar_feature_aa64_debugv8p2(id) || isar_feature_aa32_debugv8p2(id); +} + /* * Forward to the above feature tests given an ARMCPU pointer. */ From 25e168ab70627bf3368944cf5b1d97490c853007 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 22:50:15 -0700 Subject: [PATCH 036/935] target/arm: Add isar_feature_{aa64,any}_ras Add the aa64 predicate for detecting RAS support from id registers. We already have the aa32 version from the M-profile work. Add the 'any' predicate for testing both aa64 and aa32. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220501055028.646596-34-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 7303103016..ca01f909a8 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3886,6 +3886,11 @@ static inline bool isar_feature_aa64_aa32_el1(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, EL1) >= 2; } +static inline bool isar_feature_aa64_ras(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RAS) != 0; +} + static inline bool isar_feature_aa64_sve(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SVE) != 0; @@ -4108,6 +4113,11 @@ static inline bool isar_feature_any_debugv8p2(const ARMISARegisters *id) return isar_feature_aa64_debugv8p2(id) || isar_feature_aa32_debugv8p2(id); } +static inline bool isar_feature_any_ras(const ARMISARegisters *id) +{ + return isar_feature_aa64_ras(id) || isar_feature_aa32_ras(id); +} + /* * Forward to the above feature tests given an ARMCPU pointer. */ From 99a50d1a67c602126fc2b3a4812d3000eba9bf34 Mon Sep 17 00:00:00 2001 From: Alex Zuepke Date: Thu, 28 Apr 2022 15:27:17 +0200 Subject: [PATCH 037/935] target/arm: read access to performance counters from EL0 The ARMv8 manual defines that PMUSERENR_EL0.ER enables read-access to both PMXEVCNTR_EL0 and PMEVCNTR_EL0 registers, however, we only use it for PMXEVCNTR_EL0. Extend to PMEVCNTR_EL0 as well. Signed-off-by: Alex Zuepke Reviewed-by: Richard Henderson Message-id: 20220428132717.84190-1-alex.zuepke@tum.de Signed-off-by: Peter Maydell --- target/arm/helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 14ea5caad9..b4daf4f076 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6639,10 +6639,10 @@ static void define_pmu_regs(ARMCPU *cpu) .crm = 8 | (3 & (i >> 3)), .opc1 = 0, .opc2 = i & 7, .access = PL0_RW, .type = ARM_CP_IO | ARM_CP_ALIAS, .readfn = pmevcntr_readfn, .writefn = pmevcntr_writefn, - .accessfn = pmreg_access }, + .accessfn = pmreg_access_xevcntr }, { .name = pmevcntr_el0_name, .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 8 | (3 & (i >> 3)), - .opc2 = i & 7, .access = PL0_RW, .accessfn = pmreg_access, + .opc2 = i & 7, .access = PL0_RW, .accessfn = pmreg_access_xevcntr, .type = ARM_CP_IO, .readfn = pmevcntr_readfn, .writefn = pmevcntr_writefn, .raw_readfn = pmevcntr_rawread, From 942069e0d2164e8c88a55f36a117a196a3920dc5 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Wed, 30 Mar 2022 21:17:14 -0300 Subject: [PATCH 038/935] target/ppc: initialize 'val' union in kvm_get_one_spr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Valgrind isn't convinced that we are initializing the values we assign to env->spr[spr] because it doesn't understand that the 'val' union is being written by the kvm_vcpu_ioctl() that follows (via struct kvm_one_reg). This results in Valgrind complaining about uninitialized values every time we use env->spr in a conditional, like this instance: ==707578== Thread 1: ==707578== Conditional jump or move depends on uninitialised value(s) ==707578== at 0xA10A40: hreg_compute_hflags_value (helper_regs.c:106) ==707578== by 0xA10C9F: hreg_compute_hflags (helper_regs.c:173) ==707578== by 0xA110F7: hreg_store_msr (helper_regs.c:262) ==707578== by 0xA051A3: ppc_cpu_reset (cpu_init.c:7168) ==707578== by 0xD4730F: device_transitional_reset (qdev.c:799) ==707578== by 0xD4A11B: resettable_phase_hold (resettable.c:182) ==707578== by 0xD49A77: resettable_assert_reset (resettable.c:60) ==707578== by 0xD4994B: resettable_reset (resettable.c:45) ==707578== by 0xD458BB: device_cold_reset (qdev.c:296) ==707578== by 0x48FBC7: cpu_reset (cpu-common.c:114) ==707578== by 0x97B5EB: spapr_reset_vcpu (spapr_cpu_core.c:38) ==707578== by 0x97BABB: spapr_cpu_core_reset (spapr_cpu_core.c:209) ==707578== Uninitialised value was created by a stack allocation ==707578== at 0xB11F08: kvm_get_one_spr (kvm.c:543) Initializing 'val' has no impact in the logic and makes Valgrind output more bearable. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Daniel Henrique Barboza Reviewed-by: David Gibson Message-Id: <20220331001717.616938-2-danielhb413@gmail.com> Signed-off-by: Daniel Henrique Barboza --- target/ppc/kvm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index a3c31b4e48..01baea467f 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -542,10 +542,11 @@ static void kvm_get_one_spr(CPUState *cs, uint64_t id, int spr) { PowerPCCPU *cpu = POWERPC_CPU(cs); CPUPPCState *env = &cpu->env; + /* Init 'val' to avoid "uninitialised value" Valgrind warnings */ union { uint32_t u32; uint64_t u64; - } val; + } val = { }; struct kvm_one_reg reg = { .id = id, .addr = (uintptr_t) &val, From 59411579b2ce0010442154f604d7062566c10040 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Wed, 30 Mar 2022 21:17:15 -0300 Subject: [PATCH 039/935] target/ppc: init 'lpcr' in kvmppc_enable_cap_large_decr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'lpcr' is used as an input of kvm_get_one_reg(). Valgrind doesn't understand that and it returns warnings as such for this function: ==55240== Thread 1: ==55240== Conditional jump or move depends on uninitialised value(s) ==55240== at 0xB011E4: kvmppc_enable_cap_large_decr (kvm.c:2546) ==55240== by 0x92F28F: cap_large_decr_cpu_apply (spapr_caps.c:523) ==55240== by 0x930C37: spapr_caps_cpu_apply (spapr_caps.c:921) ==55240== by 0x955D3B: spapr_reset_vcpu (spapr_cpu_core.c:73) ==55240== by 0x95612B: spapr_cpu_core_reset (spapr_cpu_core.c:209) ==55240== by 0x95619B: spapr_cpu_core_reset_handler (spapr_cpu_core.c:218) ==55240== by 0xD3605F: qemu_devices_reset (reset.c:69) ==55240== by 0x92112B: spapr_machine_reset (spapr.c:1641) ==55240== by 0x4FBD63: qemu_system_reset (runstate.c:444) ==55240== by 0x62812B: qdev_machine_creation_done (machine.c:1247) ==55240== by 0x5064C3: qemu_machine_creation_done (vl.c:2725) ==55240== by 0x5065DF: qmp_x_exit_preconfig (vl.c:2748) ==55240== Uninitialised value was created by a stack allocation ==55240== at 0xB01158: kvmppc_enable_cap_large_decr (kvm.c:2540) Init 'lpcr' to avoid this warning. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Daniel Henrique Barboza Message-Id: <20220331001717.616938-3-danielhb413@gmail.com> Signed-off-by: Daniel Henrique Barboza --- target/ppc/kvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 01baea467f..69094ddb7a 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -2537,7 +2537,7 @@ int kvmppc_get_cap_large_decr(void) int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable) { CPUState *cs = CPU(cpu); - uint64_t lpcr; + uint64_t lpcr = 0; kvm_get_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr); /* Do we need to modify the LPCR? */ From b339427cfc90f7cd158f36eb0cb301c15f582d50 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Wed, 30 Mar 2022 21:17:16 -0300 Subject: [PATCH 040/935] target/ppc: init 'sregs' in kvmppc_put_books_sregs() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Init 'sregs' to avoid Valgrind complaints about uninitialized bytes from kvmppc_put_books_sregs(): ==54059== Thread 3: ==54059== Syscall param ioctl(generic) points to uninitialised byte(s) ==54059== at 0x55864E4: ioctl (in /usr/lib64/libc.so.6) ==54059== by 0xD1FA23: kvm_vcpu_ioctl (kvm-all.c:3053) ==54059== by 0xAFB18B: kvmppc_put_books_sregs (kvm.c:891) ==54059== by 0xAFB47B: kvm_arch_put_registers (kvm.c:949) ==54059== by 0xD1EDA7: do_kvm_cpu_synchronize_post_init (kvm-all.c:2766) ==54059== by 0x481AF3: process_queued_cpu_work (cpus-common.c:343) ==54059== by 0x4EF247: qemu_wait_io_event_common (cpus.c:412) ==54059== by 0x4EF343: qemu_wait_io_event (cpus.c:436) ==54059== by 0xD21E83: kvm_vcpu_thread_fn (kvm-accel-ops.c:54) ==54059== by 0xFFEBF3: qemu_thread_start (qemu-thread-posix.c:556) ==54059== by 0x54E6DC3: start_thread (in /usr/lib64/libc.so.6) ==54059== by 0x5596C9F: clone (in /usr/lib64/libc.so.6) ==54059== Address 0x799d1cc is on thread 3's stack ==54059== in frame #2, created by kvmppc_put_books_sregs (kvm.c:851) ==54059== Uninitialised value was created by a stack allocation ==54059== at 0xAFAEB0: kvmppc_put_books_sregs (kvm.c:851) This happens because Valgrind does not consider the 'sregs' initialization done by kvm_vcpu_ioctl() at the end of the function. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Daniel Henrique Barboza Message-Id: <20220331001717.616938-4-danielhb413@gmail.com> Signed-off-by: Daniel Henrique Barboza --- target/ppc/kvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 69094ddb7a..c4180b7270 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -850,7 +850,7 @@ static int kvm_put_vpa(CPUState *cs) int kvmppc_put_books_sregs(PowerPCCPU *cpu) { CPUPPCState *env = &cpu->env; - struct kvm_sregs sregs; + struct kvm_sregs sregs = { }; int i; sregs.pvr = env->spr[SPR_PVR]; From 55baf4b584709fb4d675741a4c3bd15cb0b49c91 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Wed, 30 Mar 2022 21:17:17 -0300 Subject: [PATCH 041/935] target/ppc: init 'rmmu_info' in kvm_get_radix_page_info() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Init the struct to avoid Valgrind complaints about unitialized bytes, such as this one: ==39549== Syscall param ioctl(generic) points to uninitialised byte(s) ==39549== at 0x55864E4: ioctl (in /usr/lib64/libc.so.6) ==39549== by 0xD1F7EF: kvm_vm_ioctl (kvm-all.c:3035) ==39549== by 0xAF8F5B: kvm_get_radix_page_info (kvm.c:276) ==39549== by 0xB00533: kvmppc_host_cpu_class_init (kvm.c:2369) ==39549== by 0xD3DCE7: type_initialize (object.c:366) ==39549== by 0xD3FACF: object_class_foreach_tramp (object.c:1071) ==39549== by 0x502757B: g_hash_table_foreach (in /usr/lib64/libglib-2.0.so.0.7000.5) ==39549== by 0xD3FC1B: object_class_foreach (object.c:1093) ==39549== by 0xB0141F: kvm_ppc_register_host_cpu_type (kvm.c:2613) ==39549== by 0xAF87E7: kvm_arch_init (kvm.c:157) ==39549== by 0xD1E2A7: kvm_init (kvm-all.c:2595) ==39549== by 0x8E6E93: accel_init_machine (accel-softmmu.c:39) ==39549== Address 0x1fff00e208 is on thread 1's stack ==39549== in frame #2, created by kvm_get_radix_page_info (kvm.c:267) ==39549== Uninitialised value was created by a stack allocation ==39549== at 0xAF8EE8: kvm_get_radix_page_info (kvm.c:267) Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Daniel Henrique Barboza Message-Id: <20220331001717.616938-5-danielhb413@gmail.com> Signed-off-by: Daniel Henrique Barboza --- target/ppc/kvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index c4180b7270..7a777a4d0c 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -266,7 +266,7 @@ struct ppc_radix_page_info *kvm_get_radix_page_info(void) { KVMState *s = KVM_STATE(current_accel()); struct ppc_radix_page_info *radix_page_info; - struct kvm_ppc_rmmu_info rmmu_info; + struct kvm_ppc_rmmu_info rmmu_info = { }; int i; if (!kvm_check_extension(s, KVM_CAP_PPC_MMU_RADIX)) { From 1220ab3ee2bff4a3932cd40e09553ee6bbfaa8a4 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 21 Apr 2022 09:17:29 +0800 Subject: [PATCH 042/935] target/ppc: Fix BookE debug interrupt generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per E500 core reference manual [1], chapter 8.4.4 "Branch Taken Debug Event" and chapter 8.4.5 "Instruction Complete Debug Event": "A branch taken debug event occurs if both MSR[DE] and DBCR0[BRT] are set ... Branch taken debug events are not recognized if MSR[DE] is cleared when the branch instruction executes." "An instruction complete debug event occurs when any instruction completes execution so long as MSR[DE] and DBCR0[ICMP] are both set ... Instruction complete debug events are not recognized if MSR[DE] is cleared at the time of the instruction execution." Current codes do not check MSR.DE bit before setting HFLAGS_SE and HFLAGS_BE flag, which would cause the immediate debug interrupt to be generated, e.g.: when DBCR0.ICMP bit is set by guest software and MSR.DE is not set. [1] https://www.nxp.com/docs/en/reference-manual/E500CORERM.pdf Signed-off-by: Bin Meng Reviewed-by: Cédric Le Goater Reviewed-by: Fabiano Rosas Reviewed-by: Lucas Mateus Castro Message-Id: <20220421011729.1148727-1-bmeng.cn@gmail.com> Signed-off-by: Daniel Henrique Barboza --- target/ppc/helper_regs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index 9a691d6833..77bc57415c 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -63,10 +63,10 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env) if (ppc_flags & POWERPC_FLAG_DE) { target_ulong dbcr0 = env->spr[SPR_BOOKE_DBCR0]; - if (dbcr0 & DBCR0_ICMP) { + if ((dbcr0 & DBCR0_ICMP) && msr_de) { hflags |= 1 << HFLAGS_SE; } - if (dbcr0 & DBCR0_BRT) { + if ((dbcr0 & DBCR0_BRT) && msr_de) { hflags |= 1 << HFLAGS_BE; } } else { From 97252353c1f6ecbb54385c9272378b5788749a16 Mon Sep 17 00:00:00 2001 From: Murilo Opsfelder Araujo Date: Tue, 3 May 2022 15:01:08 -0300 Subject: [PATCH 043/935] vhost-user: Use correct macro name TARGET_PPC64 The correct name of the macro is TARGET_PPC64. Fixes: 27598393a232 ("Lift max memory slots limit imposed by vhost-user") Reported-by: Fabiano Rosas Signed-off-by: Murilo Opsfelder Araujo Cc: Raphael Norwitz Cc: Peter Turschmid Reviewed-by: Daniel Henrique Barboza Reviewed-by: Michael S. Tsirkin Reviewed-by: Raphael Norwitz Message-Id: <20220503180108.34506-1-muriloo@linux.ibm.com> Signed-off-by: Daniel Henrique Barboza --- hw/virtio/vhost-user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 2d434ff0bc..afd51f79b3 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -51,7 +51,7 @@ #include "hw/acpi/acpi.h" #define VHOST_USER_MAX_RAM_SLOTS ACPI_MAX_RAM_SLOTS -#elif defined(TARGET_PPC) || defined(TARGET_PPC_64) +#elif defined(TARGET_PPC) || defined(TARGET_PPC64) #include "hw/ppc/spapr.h" #define VHOST_USER_MAX_RAM_SLOTS SPAPR_MAX_RAM_SLOTS From a66257a287f6e2832fb6ecd7587da4933b39cfc4 Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Fri, 29 Apr 2022 09:16:19 +0200 Subject: [PATCH 044/935] ppc/xive: Always recompute the PIPR when pushing an OS context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Post Interrupt Priority Register (PIPR) is not restored like the other OS-context related fields of the TIMA when pushing an OS context on the CPU. It's not needed because it can be calculated from the Interrupt Pending Buffer (IPB), which is saved and restored. The PIPR must therefore always be recomputed when pushing an OS context. This patch fixes a path on P9 and P10 where it was not done. If there was a pending interrupt when the OS context was pulled, the IPB was saved correctly. When pushing back the context, the code in xive_tctx_need_resend() was checking for a interrupt raised while the context was not on the CPU, saved in the NVT. If one was found, then it was merged with the saved IPB and the PIPR updated and everything was fine. However, if there was no interrupt found in the NVT, then xive_tctx_ipb_update() was not being called and the PIPR was not updated. This patch fixes it by always calling xive_tctx_ipb_update(). Note that on P10 (xive2.c) and because of the above, there's no longer any need to check the CPPR value so it can go away. Reviewed-by: Cédric Le Goater Signed-off-by: Frederic Barrat Message-Id: <20220429071620.177142-2-fbarrat@linux.ibm.com> Signed-off-by: Daniel Henrique Barboza --- hw/intc/xive.c | 11 ++++++++--- hw/intc/xive2.c | 16 +++++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/hw/intc/xive.c b/hw/intc/xive.c index b8e4c7294d..c729f6a478 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -413,10 +413,15 @@ static void xive_tctx_need_resend(XiveRouter *xrtr, XiveTCTX *tctx, /* Reset the NVT value */ nvt.w4 = xive_set_field32(NVT_W4_IPB, nvt.w4, 0); xive_router_write_nvt(xrtr, nvt_blk, nvt_idx, &nvt, 4); - - /* Merge in current context */ - xive_tctx_ipb_update(tctx, TM_QW1_OS, ipb); } + /* + * Always call xive_tctx_ipb_update(). Even if there were no + * escalation triggered, there could be a pending interrupt which + * was saved when the context was pulled and that we need to take + * into account by recalculating the PIPR (which is not + * saved/restored). + */ + xive_tctx_ipb_update(tctx, TM_QW1_OS, ipb); } /* diff --git a/hw/intc/xive2.c b/hw/intc/xive2.c index 3aff42a69e..400fd70aa8 100644 --- a/hw/intc/xive2.c +++ b/hw/intc/xive2.c @@ -316,7 +316,6 @@ static void xive2_tctx_need_resend(Xive2Router *xrtr, XiveTCTX *tctx, { Xive2Nvp nvp; uint8_t ipb; - uint8_t cppr = 0; /* * Grab the associated thread interrupt context registers in the @@ -337,7 +336,7 @@ static void xive2_tctx_need_resend(Xive2Router *xrtr, XiveTCTX *tctx, /* Automatically restore thread context registers */ if (xive2_router_get_config(xrtr) & XIVE2_VP_SAVE_RESTORE && do_restore) { - cppr = xive2_tctx_restore_os_ctx(xrtr, tctx, nvp_blk, nvp_idx, &nvp); + xive2_tctx_restore_os_ctx(xrtr, tctx, nvp_blk, nvp_idx, &nvp); } ipb = xive_get_field32(NVP2_W2_IPB, nvp.w2); @@ -345,11 +344,14 @@ static void xive2_tctx_need_resend(Xive2Router *xrtr, XiveTCTX *tctx, nvp.w2 = xive_set_field32(NVP2_W2_IPB, nvp.w2, 0); xive2_router_write_nvp(xrtr, nvp_blk, nvp_idx, &nvp, 2); } - - /* An IPB or CPPR change can trigger a resend */ - if (ipb || cppr) { - xive_tctx_ipb_update(tctx, TM_QW1_OS, ipb); - } + /* + * Always call xive_tctx_ipb_update(). Even if there were no + * escalation triggered, there could be a pending interrupt which + * was saved when the context was pulled and that we need to take + * into account by recalculating the PIPR (which is not + * saved/restored). + */ + xive_tctx_ipb_update(tctx, TM_QW1_OS, ipb); } /* From f65772118718bd8c04dde2618c2c272ae2fe8939 Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Fri, 29 Apr 2022 09:16:20 +0200 Subject: [PATCH 045/935] ppc/xive: Update the state of the External interrupt signal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When pulling or pushing an OS context from/to a CPU, we should re-evaluate the state of the External interrupt signal. Otherwise, we can end up catching the External interrupt exception in hypervisor mode, which is unexpected. The problem is best illustrated with the following scenario: 1. an External interrupt is raised while the guest is on the CPU. 2. before the guest can ack the External interrupt, an hypervisor interrupt is raised, for example the Hypervisor Decrementer or Hypervisor Virtualization interrupt. The hypervisor interrupt forces the guest to exit while the External interrupt is still pending. 3. the hypervisor handles the hypervisor interrupt. At this point, the External interrupt is still pending. So it's very likely to be delivered while the hypervisor is running. That's unexpected and can result in an infinite loop where the hypervisor catches the External interrupt, looks for an interrupt in its hypervisor queue, doesn't find any, exits the interrupt handler with the External interrupt still raised, repeat... The fix is simply to always lower the External interrupt signal when pulling an OS context. It means it needs to be raised again when re-pushing the OS context. Fortunately, it's already the case, as we now always call xive_tctx_ipb_update(), which will raise the signal if needed. Reviewed-by: Cédric Le Goater Signed-off-by: Frederic Barrat Message-Id: <20220429071620.177142-3-fbarrat@linux.ibm.com> Signed-off-by: Daniel Henrique Barboza --- hw/intc/xive.c | 14 ++++++++++++++ hw/intc/xive2.c | 2 ++ include/hw/ppc/xive.h | 1 + 3 files changed, 17 insertions(+) diff --git a/hw/intc/xive.c b/hw/intc/xive.c index c729f6a478..ae221fed73 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -114,6 +114,17 @@ static void xive_tctx_notify(XiveTCTX *tctx, uint8_t ring) } } +void xive_tctx_reset_os_signal(XiveTCTX *tctx) +{ + /* + * Lower the External interrupt. Used when pulling an OS + * context. It is necessary to avoid catching it in the hypervisor + * context. It should be raised again when re-pushing the OS + * context. + */ + qemu_irq_lower(xive_tctx_output(tctx, TM_QW1_OS)); +} + static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr) { uint8_t *regs = &tctx->regs[ring]; @@ -388,6 +399,8 @@ static uint64_t xive_tm_pull_os_ctx(XivePresenter *xptr, XiveTCTX *tctx, /* Invalidate CAM line */ qw1w2_new = xive_set_field32(TM_QW1W2_VO, qw1w2, 0); xive_tctx_set_os_cam(tctx, qw1w2_new); + + xive_tctx_reset_os_signal(tctx); return qw1w2; } @@ -420,6 +433,7 @@ static void xive_tctx_need_resend(XiveRouter *xrtr, XiveTCTX *tctx, * was saved when the context was pulled and that we need to take * into account by recalculating the PIPR (which is not * saved/restored). + * It will also raise the External interrupt signal if needed. */ xive_tctx_ipb_update(tctx, TM_QW1_OS, ipb); } diff --git a/hw/intc/xive2.c b/hw/intc/xive2.c index 400fd70aa8..4d9ff41956 100644 --- a/hw/intc/xive2.c +++ b/hw/intc/xive2.c @@ -269,6 +269,7 @@ uint64_t xive2_tm_pull_os_ctx(XivePresenter *xptr, XiveTCTX *tctx, xive2_tctx_save_os_ctx(xrtr, tctx, nvp_blk, nvp_idx); } + xive_tctx_reset_os_signal(tctx); return qw1w2; } @@ -350,6 +351,7 @@ static void xive2_tctx_need_resend(Xive2Router *xrtr, XiveTCTX *tctx, * was saved when the context was pulled and that we need to take * into account by recalculating the PIPR (which is not * saved/restored). + * It will also raise the External interrupt signal if needed. */ xive_tctx_ipb_update(tctx, TM_QW1_OS, ipb); } diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index 126e4e2c3a..f7eea4ca81 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -527,6 +527,7 @@ Object *xive_tctx_create(Object *cpu, XivePresenter *xptr, Error **errp); void xive_tctx_reset(XiveTCTX *tctx); void xive_tctx_destroy(XiveTCTX *tctx); void xive_tctx_ipb_update(XiveTCTX *tctx, uint8_t ring, uint8_t ipb); +void xive_tctx_reset_os_signal(XiveTCTX *tctx); /* * KVM XIVE device helpers From 208d803326416b43e51e3476826813869050a350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:20 -0300 Subject: [PATCH 046/935] target/ppc: Remove fpscr_* macros from cpu.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fpscr_* defined macros are hiding the usage of *env behind them. Substitute the usage of these macros with `env->fpscr & FP_*` to make the code cleaner. Suggested-by: Richard Henderson Reviewed-by: Richard Henderson Signed-off-by: Víctor Colombo Message-Id: <20220504210541.115256-2-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.c | 2 +- target/ppc/cpu.h | 29 ----------------------------- target/ppc/fpu_helper.c | 28 ++++++++++++++-------------- 3 files changed, 15 insertions(+), 44 deletions(-) diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c index d7b42bae52..401b6f9e63 100644 --- a/target/ppc/cpu.c +++ b/target/ppc/cpu.c @@ -88,7 +88,7 @@ static inline void fpscr_set_rounding_mode(CPUPPCState *env) int rnd_type; /* Set rounding mode */ - switch (fpscr_rn) { + switch (env->fpscr & FP_RN) { case 0: /* Best approximation (round to nearest) */ rnd_type = float_round_nearest_even; diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index c2b6c987c0..ad31e51d69 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -713,41 +713,12 @@ enum { #define FPSCR_NI 2 /* Floating-point non-IEEE mode */ #define FPSCR_RN1 1 #define FPSCR_RN0 0 /* Floating-point rounding control */ -#define fpscr_drn (((env->fpscr) & FP_DRN) >> FPSCR_DRN0) -#define fpscr_fex (((env->fpscr) >> FPSCR_FEX) & 0x1) -#define fpscr_vx (((env->fpscr) >> FPSCR_VX) & 0x1) -#define fpscr_ox (((env->fpscr) >> FPSCR_OX) & 0x1) -#define fpscr_ux (((env->fpscr) >> FPSCR_UX) & 0x1) -#define fpscr_zx (((env->fpscr) >> FPSCR_ZX) & 0x1) -#define fpscr_xx (((env->fpscr) >> FPSCR_XX) & 0x1) -#define fpscr_vxsnan (((env->fpscr) >> FPSCR_VXSNAN) & 0x1) -#define fpscr_vxisi (((env->fpscr) >> FPSCR_VXISI) & 0x1) -#define fpscr_vxidi (((env->fpscr) >> FPSCR_VXIDI) & 0x1) -#define fpscr_vxzdz (((env->fpscr) >> FPSCR_VXZDZ) & 0x1) -#define fpscr_vximz (((env->fpscr) >> FPSCR_VXIMZ) & 0x1) -#define fpscr_vxvc (((env->fpscr) >> FPSCR_VXVC) & 0x1) -#define fpscr_fpcc (((env->fpscr) >> FPSCR_FPCC) & 0xF) -#define fpscr_vxsoft (((env->fpscr) >> FPSCR_VXSOFT) & 0x1) -#define fpscr_vxsqrt (((env->fpscr) >> FPSCR_VXSQRT) & 0x1) -#define fpscr_vxcvi (((env->fpscr) >> FPSCR_VXCVI) & 0x1) -#define fpscr_ve (((env->fpscr) >> FPSCR_VE) & 0x1) -#define fpscr_oe (((env->fpscr) >> FPSCR_OE) & 0x1) -#define fpscr_ue (((env->fpscr) >> FPSCR_UE) & 0x1) -#define fpscr_ze (((env->fpscr) >> FPSCR_ZE) & 0x1) -#define fpscr_xe (((env->fpscr) >> FPSCR_XE) & 0x1) -#define fpscr_ni (((env->fpscr) >> FPSCR_NI) & 0x1) -#define fpscr_rn (((env->fpscr) >> FPSCR_RN0) & 0x3) /* Invalid operation exception summary */ #define FPSCR_IX ((1 << FPSCR_VXSNAN) | (1 << FPSCR_VXISI) | \ (1 << FPSCR_VXIDI) | (1 << FPSCR_VXZDZ) | \ (1 << FPSCR_VXIMZ) | (1 << FPSCR_VXVC) | \ (1 << FPSCR_VXSOFT) | (1 << FPSCR_VXSQRT) | \ (1 << FPSCR_VXCVI)) -/* exception summary */ -#define fpscr_ex (((env->fpscr) >> FPSCR_XX) & 0x1F) -/* enabled exception summary */ -#define fpscr_eex (((env->fpscr) >> FPSCR_XX) & ((env->fpscr) >> FPSCR_XE) & \ - 0x1F) #define FP_DRN2 (1ull << FPSCR_DRN2) #define FP_DRN1 (1ull << FPSCR_DRN1) diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 99281cc37a..f6c8318a71 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -202,7 +202,7 @@ static void finish_invalid_op_excp(CPUPPCState *env, int op, uintptr_t retaddr) env->fpscr |= FP_VX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; - if (fpscr_ve != 0) { + if (env->fpscr & FP_VE) { /* Update the floating-point enabled exception summary */ env->fpscr |= FP_FEX; if (fp_exceptions_enabled(env)) { @@ -216,7 +216,7 @@ static void finish_invalid_op_arith(CPUPPCState *env, int op, bool set_fpcc, uintptr_t retaddr) { env->fpscr &= ~(FP_FR | FP_FI); - if (fpscr_ve == 0) { + if (!(env->fpscr & FP_VE)) { if (set_fpcc) { env->fpscr &= ~FP_FPCC; env->fpscr |= (FP_C | FP_FU); @@ -286,7 +286,7 @@ static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc, /* Update the floating-point exception summary */ env->fpscr |= FP_FX; /* We must update the target FPR before raising the exception */ - if (fpscr_ve != 0) { + if (env->fpscr & FP_VE) { CPUState *cs = env_cpu(env); cs->exception_index = POWERPC_EXCP_PROGRAM; @@ -303,7 +303,7 @@ static void float_invalid_op_vxcvi(CPUPPCState *env, bool set_fpcc, { env->fpscr |= FP_VXCVI; env->fpscr &= ~(FP_FR | FP_FI); - if (fpscr_ve == 0) { + if (!(env->fpscr & FP_VE)) { if (set_fpcc) { env->fpscr &= ~FP_FPCC; env->fpscr |= (FP_C | FP_FU); @@ -318,7 +318,7 @@ static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr) env->fpscr &= ~(FP_FR | FP_FI); /* Update the floating-point exception summary */ env->fpscr |= FP_FX; - if (fpscr_ze != 0) { + if (env->fpscr & FP_ZE) { /* Update the floating-point enabled exception summary */ env->fpscr |= FP_FEX; if (fp_exceptions_enabled(env)) { @@ -336,7 +336,7 @@ static inline void float_overflow_excp(CPUPPCState *env) env->fpscr |= FP_OX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; - if (fpscr_oe != 0) { + if (env->fpscr & FP_OE) { /* XXX: should adjust the result */ /* Update the floating-point enabled exception summary */ env->fpscr |= FP_FEX; @@ -356,7 +356,7 @@ static inline void float_underflow_excp(CPUPPCState *env) env->fpscr |= FP_UX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; - if (fpscr_ue != 0) { + if (env->fpscr & FP_UE) { /* XXX: should adjust the result */ /* Update the floating-point enabled exception summary */ env->fpscr |= FP_FEX; @@ -374,7 +374,7 @@ static inline void float_inexact_excp(CPUPPCState *env) env->fpscr |= FP_XX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; - if (fpscr_xe != 0) { + if (env->fpscr & FP_XE) { /* Update the floating-point enabled exception summary */ env->fpscr |= FP_FEX; /* We must update the target FPR before raising the exception */ @@ -2274,7 +2274,7 @@ VSX_MADDQ(XSNMSUBQPO, NMSUB_FLGS, 0) vxvc = svxvc; \ if (flags & float_flag_invalid_snan) { \ float_invalid_op_vxsnan(env, GETPC()); \ - vxvc &= fpscr_ve == 0; \ + vxvc &= !(env->fpscr & FP_VE); \ } \ if (vxvc) { \ float_invalid_op_vxvc(env, 0, GETPC()); \ @@ -2375,7 +2375,7 @@ static inline void do_scalar_cmp(CPUPPCState *env, ppc_vsr_t *xa, ppc_vsr_t *xb, if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status) || float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) { vxsnan_flag = true; - if (fpscr_ve == 0 && ordered) { + if (!(env->fpscr & FP_VE) && ordered) { vxvc_flag = true; } } else if (float64_is_quiet_nan(xa->VsrD(0), &env->fp_status) || @@ -2440,7 +2440,7 @@ static inline void do_scalar_cmpq(CPUPPCState *env, ppc_vsr_t *xa, if (float128_is_signaling_nan(xa->f128, &env->fp_status) || float128_is_signaling_nan(xb->f128, &env->fp_status)) { vxsnan_flag = true; - if (fpscr_ve == 0 && ordered) { + if (!(env->fpscr & FP_VE) && ordered) { vxvc_flag = true; } } else if (float128_is_quiet_nan(xa->f128, &env->fp_status) || @@ -2590,7 +2590,7 @@ void helper_##name(CPUPPCState *env, \ t.VsrD(0) = xb->VsrD(0); \ } \ \ - vex_flag = fpscr_ve & vxsnan_flag; \ + vex_flag = (env->fpscr & FP_VE) && vxsnan_flag; \ if (vxsnan_flag) { \ float_invalid_op_vxsnan(env, GETPC()); \ } \ @@ -3320,7 +3320,7 @@ void helper_xsrqpi(CPUPPCState *env, uint32_t opcode, if (r == 0 && rmc == 0) { rmode = float_round_ties_away; } else if (r == 0 && rmc == 0x3) { - rmode = fpscr_rn; + rmode = env->fpscr & FP_RN; } else if (r == 1) { switch (rmc) { case 0: @@ -3374,7 +3374,7 @@ void helper_xsrqpxp(CPUPPCState *env, uint32_t opcode, if (r == 0 && rmc == 0) { rmode = float_round_ties_away; } else if (r == 0 && rmc == 0x3) { - rmode = fpscr_rn; + rmode = env->fpscr & FP_RN; } else if (r == 1) { switch (rmc) { case 0: From 92984c96df27d9f5bb783846c0cc2ccc8068a7a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:21 -0300 Subject: [PATCH 047/935] target/ppc: Remove unused msr_* macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some msr_* macros are not used anywhere. Remove them as part of the work to remove all hidden usage of *env. Suggested-by: Richard Henderson Reviewed-by: Richard Henderson Signed-off-by: Víctor Colombo Message-Id: <20220504210541.115256-3-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index ad31e51d69..112b456220 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -463,23 +463,14 @@ typedef enum { #define HFSCR_MSGP PPC_BIT(53) /* Privileged Message Send Facilities */ #define HFSCR_IC_MSGP 0xA -#define msr_sf ((env->msr >> MSR_SF) & 1) -#define msr_isf ((env->msr >> MSR_ISF) & 1) #if defined(TARGET_PPC64) #define msr_hv ((env->msr >> MSR_HV) & 1) #else #define msr_hv (0) #endif #define msr_cm ((env->msr >> MSR_CM) & 1) -#define msr_icm ((env->msr >> MSR_ICM) & 1) #define msr_gs ((env->msr >> MSR_GS) & 1) -#define msr_ucle ((env->msr >> MSR_UCLE) & 1) -#define msr_vr ((env->msr >> MSR_VR) & 1) -#define msr_spe ((env->msr >> MSR_SPE) & 1) -#define msr_vsx ((env->msr >> MSR_VSX) & 1) -#define msr_key ((env->msr >> MSR_KEY) & 1) #define msr_pow ((env->msr >> MSR_POW) & 1) -#define msr_tgpr ((env->msr >> MSR_TGPR) & 1) #define msr_ce ((env->msr >> MSR_CE) & 1) #define msr_ile ((env->msr >> MSR_ILE) & 1) #define msr_ee ((env->msr >> MSR_EE) & 1) @@ -487,25 +478,14 @@ typedef enum { #define msr_fp ((env->msr >> MSR_FP) & 1) #define msr_me ((env->msr >> MSR_ME) & 1) #define msr_fe0 ((env->msr >> MSR_FE0) & 1) -#define msr_se ((env->msr >> MSR_SE) & 1) -#define msr_dwe ((env->msr >> MSR_DWE) & 1) -#define msr_uble ((env->msr >> MSR_UBLE) & 1) -#define msr_be ((env->msr >> MSR_BE) & 1) #define msr_de ((env->msr >> MSR_DE) & 1) #define msr_fe1 ((env->msr >> MSR_FE1) & 1) -#define msr_al ((env->msr >> MSR_AL) & 1) #define msr_ep ((env->msr >> MSR_EP) & 1) #define msr_ir ((env->msr >> MSR_IR) & 1) #define msr_dr ((env->msr >> MSR_DR) & 1) -#define msr_is ((env->msr >> MSR_IS) & 1) #define msr_ds ((env->msr >> MSR_DS) & 1) -#define msr_pe ((env->msr >> MSR_PE) & 1) -#define msr_px ((env->msr >> MSR_PX) & 1) -#define msr_pmm ((env->msr >> MSR_PMM) & 1) -#define msr_ri ((env->msr >> MSR_RI) & 1) #define msr_le ((env->msr >> MSR_LE) & 1) #define msr_ts ((env->msr >> MSR_TS1) & 3) -#define msr_tm ((env->msr >> MSR_TM) & 1) #define DBCR0_ICMP (1 << 27) #define DBCR0_BRT (1 << 26) From d41ccf6eea918ec121cd38eda6e2526b446013f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:22 -0300 Subject: [PATCH 048/935] target/ppc: Remove msr_pr macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msr_pr macro hides the usage of env->msr, which is a bad behavior Substitute it with FIELD_EX64 calls that explicitly use env->msr as a parameter. Suggested-by: Richard Henderson Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Message-Id: <20220504210541.115256-4-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- hw/ppc/pegasos2.c | 2 +- hw/ppc/spapr.c | 2 +- target/ppc/cpu.h | 4 +++- target/ppc/cpu_init.c | 4 ++-- target/ppc/excp_helper.c | 8 +++++--- target/ppc/mem_helper.c | 5 +++-- target/ppc/mmu-radix64.c | 5 +++-- target/ppc/mmu_common.c | 23 ++++++++++++----------- 8 files changed, 30 insertions(+), 23 deletions(-) diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c index 56bf203dfd..9411ca6b16 100644 --- a/hw/ppc/pegasos2.c +++ b/hw/ppc/pegasos2.c @@ -461,7 +461,7 @@ static void pegasos2_hypercall(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu) /* The TCG path should also be holding the BQL at this point */ g_assert(qemu_mutex_iothread_locked()); - if (msr_pr) { + if (FIELD_EX64(env->msr, MSR, PR)) { qemu_log_mask(LOG_GUEST_ERROR, "Hypercall made with MSR[PR]=1\n"); env->gpr[3] = H_PRIVILEGE; } else if (env->gpr[3] == KVMPPC_H_RTAS) { diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 22569305d2..fe9937e811 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1269,7 +1269,7 @@ static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp, g_assert(!vhyp_cpu_in_nested(cpu)); - if (msr_pr) { + if (FIELD_EX64(env->msr, MSR, PR)) { hcall_dprintf("Hypercall made with MSR[PR]=1\n"); env->gpr[3] = H_PRIVILEGE; } else { diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 112b456220..8f1dc4cb15 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -25,6 +25,7 @@ #include "exec/cpu-defs.h" #include "cpu-qom.h" #include "qom/object.h" +#include "hw/registerfields.h" #define TCG_GUEST_DEFAULT_MO 0 @@ -353,6 +354,8 @@ typedef enum { #define MSR_RI 1 /* Recoverable interrupt 1 */ #define MSR_LE 0 /* Little-endian mode 1 hflags */ +FIELD(MSR, PR, MSR_PR, 1) + /* PMU bits */ #define MMCR0_FC PPC_BIT(32) /* Freeze Counters */ #define MMCR0_PMAO PPC_BIT(56) /* Perf Monitor Alert Ocurred */ @@ -474,7 +477,6 @@ typedef enum { #define msr_ce ((env->msr >> MSR_CE) & 1) #define msr_ile ((env->msr >> MSR_ILE) & 1) #define msr_ee ((env->msr >> MSR_EE) & 1) -#define msr_pr ((env->msr >> MSR_PR) & 1) #define msr_fp ((env->msr >> MSR_FP) & 1) #define msr_me ((env->msr >> MSR_ME) & 1) #define msr_fe0 ((env->msr >> MSR_FE0) & 1) diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index d42e2ba8e0..ac16a64846 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -6303,7 +6303,7 @@ static bool cpu_has_work_POWER9(CPUState *cs) if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) && (env->spr[SPR_LPCR] & LPCR_EEE)) { bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); - if (heic == 0 || !msr_hv || msr_pr) { + if (!heic || !msr_hv || FIELD_EX64(env->msr, MSR, PR)) { return true; } } @@ -6517,7 +6517,7 @@ static bool cpu_has_work_POWER10(CPUState *cs) if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) && (env->spr[SPR_LPCR] & LPCR_EEE)) { bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); - if (heic == 0 || !msr_hv || msr_pr) { + if (!heic || !msr_hv || FIELD_EX64(env->msr, MSR, PR)) { return true; } } diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index d3e2cfcd71..7e8e34ef06 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1738,7 +1738,8 @@ static void ppc_hw_interrupt(CPUPPCState *env) bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); /* HEIC blocks delivery to the hypervisor */ - if ((async_deliver && !(heic && msr_hv && !msr_pr)) || + if ((async_deliver && !(heic && msr_hv && + !FIELD_EX64(env->msr, MSR, PR))) || (env->has_hv_mode && msr_hv == 0 && !lpes0)) { if (books_vhyp_promotes_external_to_hvirt(cpu)) { powerpc_excp(cpu, POWERPC_EXCP_HVIRT); @@ -1818,7 +1819,8 @@ static void ppc_hw_interrupt(CPUPPCState *env) * EBB exception must be taken in problem state and * with BESCR_GE set. */ - if (msr_pr == 1 && env->spr[SPR_BESCR] & BESCR_GE) { + if (FIELD_EX64(env->msr, MSR, PR) && + (env->spr[SPR_BESCR] & BESCR_GE)) { env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EBB); if (env->spr[SPR_BESCR] & BESCR_PMEO) { @@ -2094,7 +2096,7 @@ static void do_ebb(CPUPPCState *env, int ebb_excp) env->spr[SPR_BESCR] |= BESCR_EEO; } - if (msr_pr == 1) { + if (FIELD_EX64(env->msr, MSR, PR)) { powerpc_excp(cpu, ebb_excp); } else { env->pending_interrupts |= 1 << PPC_INTERRUPT_EBB; diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c index c4ff8fd632..fba7f84b7a 100644 --- a/target/ppc/mem_helper.c +++ b/target/ppc/mem_helper.c @@ -613,10 +613,11 @@ void helper_tbegin(CPUPPCState *env) (1ULL << TEXASR_FAILURE_PERSISTENT) | (1ULL << TEXASR_NESTING_OVERFLOW) | (msr_hv << TEXASR_PRIVILEGE_HV) | - (msr_pr << TEXASR_PRIVILEGE_PR) | + (FIELD_EX64(env->msr, MSR, PR) << TEXASR_PRIVILEGE_PR) | (1ULL << TEXASR_FAILURE_SUMMARY) | (1ULL << TEXASR_TFIAR_EXACT); - env->spr[SPR_TFIAR] = env->nip | (msr_hv << 1) | msr_pr; + env->spr[SPR_TFIAR] = env->nip | (msr_hv << 1) | + FIELD_EX64(env->msr, MSR, PR); env->spr[SPR_TFHAR] = env->nip + 4; env->crf[0] = 0xB; /* 0b1010 = transaction failure */ } diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 5414fd63c1..e88f51fd34 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -191,12 +191,13 @@ static bool ppc_radix64_check_prot(PowerPCCPU *cpu, MMUAccessType access_type, } /* Determine permissions allowed by Encoded Access Authority */ - if (!partition_scoped && (pte & R_PTE_EAA_PRIV) && msr_pr) { + if (!partition_scoped && (pte & R_PTE_EAA_PRIV) && + FIELD_EX64(env->msr, MSR, PR)) { *prot = 0; } else if (mmuidx_pr(mmu_idx) || (pte & R_PTE_EAA_PRIV) || partition_scoped) { *prot = ppc_radix64_get_prot_eaa(pte); - } else { /* !msr_pr && !(pte & R_PTE_EAA_PRIV) && !partition_scoped */ + } else { /* !MSR_PR && !(pte & R_PTE_EAA_PRIV) && !partition_scoped */ *prot = ppc_radix64_get_prot_eaa(pte); *prot &= ppc_radix64_get_prot_amr(cpu); /* Least combined permissions */ } diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c index e9c5b14c0f..6ef8b1c00d 100644 --- a/target/ppc/mmu_common.c +++ b/target/ppc/mmu_common.c @@ -273,8 +273,8 @@ static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp, bl = (*BATu & 0x00001FFC) << 15; valid = 0; prot = 0; - if (((msr_pr == 0) && (*BATu & 0x00000002)) || - ((msr_pr != 0) && (*BATu & 0x00000001))) { + if ((!FIELD_EX64(env->msr, MSR, PR) && (*BATu & 0x00000002)) || + (FIELD_EX64(env->msr, MSR, PR) && (*BATu & 0x00000001))) { valid = 1; pp = *BATl & 0x00000003; if (pp != 0) { @@ -368,16 +368,17 @@ static int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, PowerPCCPU *cpu = env_archcpu(env); hwaddr hash; target_ulong vsid; - int ds, pr, target_page_bits; + int ds, target_page_bits; + bool pr; int ret; target_ulong sr, pgidx; - pr = msr_pr; + pr = FIELD_EX64(env->msr, MSR, PR); ctx->eaddr = eaddr; sr = env->sr[eaddr >> 28]; - ctx->key = (((sr & 0x20000000) && (pr != 0)) || - ((sr & 0x40000000) && (pr == 0))) ? 1 : 0; + ctx->key = (((sr & 0x20000000) && pr) || + ((sr & 0x40000000) && !pr)) ? 1 : 0; ds = sr & 0x80000000 ? 1 : 0; ctx->nx = sr & 0x10000000 ? 1 : 0; vsid = sr & 0x00FFFFFF; @@ -386,8 +387,8 @@ static int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, "Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx " ir=%d dr=%d pr=%d %d t=%d\n", - eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir, - (int)msr_dr, pr != 0 ? 1 : 0, + eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, + (int)msr_ir, (int)msr_dr, pr ? 1 : 0, access_type == MMU_DATA_STORE, type); pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits; hash = vsid ^ pgidx; @@ -530,7 +531,7 @@ static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, ret = -1; raddr = (hwaddr)-1ULL; - pr = msr_pr; + pr = FIELD_EX64(env->msr, MSR, PR); for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb.tlbe[i]; if (ppcemb_tlb_check(env, tlb, &raddr, address, @@ -618,7 +619,7 @@ static int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb, found_tlb: - if (msr_pr != 0) { + if (FIELD_EX64(env->msr, MSR, PR)) { prot2 = tlb->prot & 0xF; } else { prot2 = (tlb->prot >> 4) & 0xF; @@ -768,7 +769,7 @@ static bool mmubooke206_get_as(CPUPPCState *env, return true; } else { *as_out = msr_ds; - *pr_out = msr_pr; + *pr_out = FIELD_EX64(env->msr, MSR, PR); return false; } } From 1922322ce43091cfb004a4da8d5851b3630718f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:23 -0300 Subject: [PATCH 049/935] target/ppc: Remove msr_le macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msr_le macro hides the usage of env->msr, which is a bad behavior Substitute it with FIELD_EX64 calls that explicitly use env->msr as a parameter. Suggested-by: Richard Henderson Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Message-Id: <20220504210541.115256-5-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 2 +- target/ppc/cpu_init.c | 2 +- target/ppc/gdbstub.c | 2 +- target/ppc/mem_helper.c | 16 ++++++++-------- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 8f1dc4cb15..c561d664de 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -355,6 +355,7 @@ typedef enum { #define MSR_LE 0 /* Little-endian mode 1 hflags */ FIELD(MSR, PR, MSR_PR, 1) +FIELD(MSR, LE, MSR_LE, 1) /* PMU bits */ #define MMCR0_FC PPC_BIT(32) /* Freeze Counters */ @@ -486,7 +487,6 @@ FIELD(MSR, PR, MSR_PR, 1) #define msr_ir ((env->msr >> MSR_IR) & 1) #define msr_dr ((env->msr >> MSR_DR) & 1) #define msr_ds ((env->msr >> MSR_DS) & 1) -#define msr_le ((env->msr >> MSR_LE) & 1) #define msr_ts ((env->msr >> MSR_TS1) & 3) #define DBCR0_ICMP (1 << 27) diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index ac16a64846..0c6b83406e 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -7210,7 +7210,7 @@ static bool ppc_cpu_is_big_endian(CPUState *cs) cpu_synchronize_state(cs); - return !msr_le; + return !FIELD_EX64(env->msr, MSR, LE); } #ifdef CONFIG_TCG diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c index 1252429a2a..1a0b9ca82c 100644 --- a/target/ppc/gdbstub.c +++ b/target/ppc/gdbstub.c @@ -95,7 +95,7 @@ static int ppc_gdb_register_len(int n) void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len) { #ifndef CONFIG_USER_ONLY - if (!msr_le) { + if (!FIELD_EX64(env->msr, MSR, LE)) { /* do nothing */ } else if (len == 4) { bswap32s((uint32_t *)mem_buf); diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c index fba7f84b7a..9af135e88e 100644 --- a/target/ppc/mem_helper.c +++ b/target/ppc/mem_helper.c @@ -33,9 +33,9 @@ static inline bool needs_byteswap(const CPUPPCState *env) { #if TARGET_BIG_ENDIAN - return msr_le; + return FIELD_EX64(env->msr, MSR, LE); #else - return !msr_le; + return !FIELD_EX64(env->msr, MSR, LE); #endif } @@ -470,8 +470,8 @@ uint32_t helper_stqcx_be_parallel(CPUPPCState *env, target_ulong addr, #endif /* - * We use msr_le to determine index ordering in a vector. However, - * byteswapping is not simply controlled by msr_le. We also need to + * We use MSR_LE to determine index ordering in a vector. However, + * byteswapping is not simply controlled by MSR_LE. We also need to * take into account endianness of the target. This is done for the * little-endian PPC64 user-mode target. */ @@ -484,7 +484,7 @@ uint32_t helper_stqcx_be_parallel(CPUPPCState *env, target_ulong addr, int adjust = HI_IDX * (n_elems - 1); \ int sh = sizeof(r->element[0]) >> 1; \ int index = (addr & 0xf) >> sh; \ - if (msr_le) { \ + if (FIELD_EX64(env->msr, MSR, LE)) { \ index = n_elems - index - 1; \ } \ \ @@ -511,7 +511,7 @@ LVE(lvewx, cpu_ldl_data_ra, bswap32, u32) int adjust = HI_IDX * (n_elems - 1); \ int sh = sizeof(r->element[0]) >> 1; \ int index = (addr & 0xf) >> sh; \ - if (msr_le) { \ + if (FIELD_EX64(env->msr, MSR, LE)) { \ index = n_elems - index - 1; \ } \ \ @@ -545,7 +545,7 @@ void helper_##name(CPUPPCState *env, target_ulong addr, \ t.s128 = int128_zero(); \ if (nb) { \ nb = (nb >= 16) ? 16 : nb; \ - if (msr_le && !lj) { \ + if (FIELD_EX64(env->msr, MSR, LE) && !lj) { \ for (i = 16; i > 16 - nb; i--) { \ t.VsrB(i - 1) = cpu_ldub_data_ra(env, addr, GETPC()); \ addr = addr_add(env, addr, 1); \ @@ -576,7 +576,7 @@ void helper_##name(CPUPPCState *env, target_ulong addr, \ } \ \ nb = (nb >= 16) ? 16 : nb; \ - if (msr_le && !lj) { \ + if (FIELD_EX64(env->msr, MSR, LE) && !lj) { \ for (i = 16; i > 16 - nb; i--) { \ cpu_stb_data_ra(env, addr, xt->VsrB(i - 1), GETPC()); \ addr = addr_add(env, addr, 1); \ From 26363616c67633aef7f53db24050b8adfd2da3b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:24 -0300 Subject: [PATCH 050/935] target/ppc: Remove msr_ds macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msr_ds macro hides the usage of env->msr, which is a bad behavior Substitute it with FIELD_EX64 calls that explicitly use env->msr as a parameter. Suggested-by: Richard Henderson Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Message-Id: <20220504210541.115256-6-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 2 +- target/ppc/mmu_common.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index c561d664de..5abc612fe0 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -355,6 +355,7 @@ typedef enum { #define MSR_LE 0 /* Little-endian mode 1 hflags */ FIELD(MSR, PR, MSR_PR, 1) +FIELD(MSR, DS, MSR_DS, 1) FIELD(MSR, LE, MSR_LE, 1) /* PMU bits */ @@ -486,7 +487,6 @@ FIELD(MSR, LE, MSR_LE, 1) #define msr_ep ((env->msr >> MSR_EP) & 1) #define msr_ir ((env->msr >> MSR_IR) & 1) #define msr_dr ((env->msr >> MSR_DR) & 1) -#define msr_ds ((env->msr >> MSR_DS) & 1) #define msr_ts ((env->msr >> MSR_TS1) & 3) #define DBCR0_ICMP (1 << 27) diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c index 6ef8b1c00d..7e77b9b84a 100644 --- a/target/ppc/mmu_common.c +++ b/target/ppc/mmu_common.c @@ -768,7 +768,7 @@ static bool mmubooke206_get_as(CPUPPCState *env, *pr_out = !!(epidr & EPID_EPR); return true; } else { - *as_out = msr_ds; + *as_out = FIELD_EX64(env->msr, MSR, DS); *pr_out = FIELD_EX64(env->msr, MSR, PR); return false; } From 3868540f05c5e678d9cd889700dbcd66330c43cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:25 -0300 Subject: [PATCH 051/935] target/ppc: Remove msr_ile macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msr_ile macro hides the usage of env->msr, which is a bad behavior Substitute it with FIELD_EX64 calls that explicitly use env->msr as a parameter. Suggested-by: Richard Henderson Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Message-Id: <20220504210541.115256-7-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 5abc612fe0..0d5a850794 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -354,6 +354,7 @@ typedef enum { #define MSR_RI 1 /* Recoverable interrupt 1 */ #define MSR_LE 0 /* Little-endian mode 1 hflags */ +FIELD(MSR, ILE, MSR_ILE, 1) FIELD(MSR, PR, MSR_PR, 1) FIELD(MSR, DS, MSR_DS, 1) FIELD(MSR, LE, MSR_LE, 1) @@ -477,7 +478,6 @@ FIELD(MSR, LE, MSR_LE, 1) #define msr_gs ((env->msr >> MSR_GS) & 1) #define msr_pow ((env->msr >> MSR_POW) & 1) #define msr_ce ((env->msr >> MSR_CE) & 1) -#define msr_ile ((env->msr >> MSR_ILE) & 1) #define msr_ee ((env->msr >> MSR_EE) & 1) #define msr_fp ((env->msr >> MSR_FP) & 1) #define msr_me ((env->msr >> MSR_ME) & 1) @@ -2679,7 +2679,7 @@ static inline bool ppc_interrupts_little_endian(PowerPCCPU *cpu, bool hv) } else if (pcc->lpcr_mask & LPCR_ILE) { ile = !!(env->spr[SPR_LPCR] & LPCR_ILE); } else { - ile = !!(msr_ile); + ile = FIELD_EX64(env->msr, MSR, ILE); } return ile; From 0939b8f8df43ad163a602d36f989dc9fd6e378f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:26 -0300 Subject: [PATCH 052/935] target/ppc: Remove msr_ee macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msr_ee macro hides the usage of env->msr, which is a bad behavior Substitute it with FIELD_EX64 calls that explicitly use env->msr as a parameter. Suggested-by: Richard Henderson Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Message-Id: <20220504210541.115256-8-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 2 +- target/ppc/cpu_init.c | 15 ++++++++++----- target/ppc/excp_helper.c | 2 +- target/ppc/kvm.c | 3 ++- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 0d5a850794..06667c2c60 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -355,6 +355,7 @@ typedef enum { #define MSR_LE 0 /* Little-endian mode 1 hflags */ FIELD(MSR, ILE, MSR_ILE, 1) +FIELD(MSR, EE, MSR_EE, 1) FIELD(MSR, PR, MSR_PR, 1) FIELD(MSR, DS, MSR_DS, 1) FIELD(MSR, LE, MSR_LE, 1) @@ -478,7 +479,6 @@ FIELD(MSR, LE, MSR_LE, 1) #define msr_gs ((env->msr >> MSR_GS) & 1) #define msr_pow ((env->msr >> MSR_POW) & 1) #define msr_ce ((env->msr >> MSR_CE) & 1) -#define msr_ee ((env->msr >> MSR_EE) & 1) #define msr_fp ((env->msr >> MSR_FP) & 1) #define msr_me ((env->msr >> MSR_ME) & 1) #define msr_fe0 ((env->msr >> MSR_FE0) & 1) diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 0c6b83406e..10e7c41bc9 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -5949,7 +5949,8 @@ static bool cpu_has_work_POWER7(CPUState *cs) } return false; } else { - return msr_ee && (cs->interrupt_request & CPU_INTERRUPT_HARD); + return FIELD_EX64(env->msr, MSR, EE) && + (cs->interrupt_request & CPU_INTERRUPT_HARD); } } @@ -6120,7 +6121,8 @@ static bool cpu_has_work_POWER8(CPUState *cs) } return false; } else { - return msr_ee && (cs->interrupt_request & CPU_INTERRUPT_HARD); + return FIELD_EX64(env->msr, MSR, EE) && + (cs->interrupt_request & CPU_INTERRUPT_HARD); } } @@ -6337,7 +6339,8 @@ static bool cpu_has_work_POWER9(CPUState *cs) } return false; } else { - return msr_ee && (cs->interrupt_request & CPU_INTERRUPT_HARD); + return FIELD_EX64(env->msr, MSR, EE) && + (cs->interrupt_request & CPU_INTERRUPT_HARD); } } @@ -6551,7 +6554,8 @@ static bool cpu_has_work_POWER10(CPUState *cs) } return false; } else { - return msr_ee && (cs->interrupt_request & CPU_INTERRUPT_HARD); + return FIELD_EX64(env->msr, MSR, EE) && + (cs->interrupt_request & CPU_INTERRUPT_HARD); } } @@ -7119,7 +7123,8 @@ static bool ppc_cpu_has_work(CPUState *cs) PowerPCCPU *cpu = POWERPC_CPU(cs); CPUPPCState *env = &cpu->env; - return msr_ee && (cs->interrupt_request & CPU_INTERRUPT_HARD); + return FIELD_EX64(env->msr, MSR, EE) && + (cs->interrupt_request & CPU_INTERRUPT_HARD); } static void ppc_cpu_reset(DeviceState *dev) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 7e8e34ef06..4c206ba209 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1709,7 +1709,7 @@ static void ppc_hw_interrupt(CPUPPCState *env) * clear when coming out of some power management states (in order * for them to become a 0x100). */ - async_deliver = (msr_ee != 0) || env->resume_as_sreset; + async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset; /* Hypervisor decrementer exception */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 7a777a4d0c..db3a92869c 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -1352,7 +1352,8 @@ static int kvmppc_handle_halt(PowerPCCPU *cpu) CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - if (!(cs->interrupt_request & CPU_INTERRUPT_HARD) && (msr_ee)) { + if (!(cs->interrupt_request & CPU_INTERRUPT_HARD) && + FIELD_EX64(env->msr, MSR, EE)) { cs->halted = 1; cs->exception_index = EXCP_HLT; } From acc861c2e95dec0795581016a6a8b044d28b1d61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:27 -0300 Subject: [PATCH 053/935] target/ppc: Remove msr_ce macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msr_ce macro hides the usage of env->msr, which is a bad behavior Substitute it with FIELD_EX64 calls that explicitly use env->msr as a parameter. Suggested-by: Richard Henderson Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Message-Id: <20220504210541.115256-9-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 2 +- target/ppc/excp_helper.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 06667c2c60..b1883b23e2 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -354,6 +354,7 @@ typedef enum { #define MSR_RI 1 /* Recoverable interrupt 1 */ #define MSR_LE 0 /* Little-endian mode 1 hflags */ +FIELD(MSR, CE, MSR_CE, 1) FIELD(MSR, ILE, MSR_ILE, 1) FIELD(MSR, EE, MSR_EE, 1) FIELD(MSR, PR, MSR_PR, 1) @@ -478,7 +479,6 @@ FIELD(MSR, LE, MSR_LE, 1) #define msr_cm ((env->msr >> MSR_CM) & 1) #define msr_gs ((env->msr >> MSR_GS) & 1) #define msr_pow ((env->msr >> MSR_POW) & 1) -#define msr_ce ((env->msr >> MSR_CE) & 1) #define msr_fp ((env->msr >> MSR_FP) & 1) #define msr_me ((env->msr >> MSR_ME) & 1) #define msr_fe0 ((env->msr >> MSR_FE0) & 1) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 4c206ba209..ca80c1ed63 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1749,7 +1749,7 @@ static void ppc_hw_interrupt(CPUPPCState *env) return; } } - if (msr_ce != 0) { + if (FIELD_EX64(env->msr, MSR, CE)) { /* External critical interrupt */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) { powerpc_excp(cpu, POWERPC_EXCP_CRITICAL); From 8e54ad65c218a547111c9dfadec792c43b933600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:28 -0300 Subject: [PATCH 054/935] target/ppc: Remove msr_pow macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msr_pow macro hides the usage of env->msr, which is a bad behavior Substitute it with FIELD_EX64 calls that explicitly use env->msr as a parameter. Suggested-by: Richard Henderson Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Message-Id: <20220504210541.115256-10-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 2 +- target/ppc/excp_helper.c | 12 ++++++------ target/ppc/helper_regs.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index b1883b23e2..5a83c4b028 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -354,6 +354,7 @@ typedef enum { #define MSR_RI 1 /* Recoverable interrupt 1 */ #define MSR_LE 0 /* Little-endian mode 1 hflags */ +FIELD(MSR, POW, MSR_POW, 1) FIELD(MSR, CE, MSR_CE, 1) FIELD(MSR, ILE, MSR_ILE, 1) FIELD(MSR, EE, MSR_EE, 1) @@ -478,7 +479,6 @@ FIELD(MSR, LE, MSR_LE, 1) #endif #define msr_cm ((env->msr >> MSR_CM) & 1) #define msr_gs ((env->msr >> MSR_GS) & 1) -#define msr_pow ((env->msr >> MSR_POW) & 1) #define msr_fp ((env->msr >> MSR_FP) & 1) #define msr_me ((env->msr >> MSR_ME) & 1) #define msr_fe0 ((env->msr >> MSR_FE0) & 1) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index ca80c1ed63..ee63641dd0 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -661,7 +661,7 @@ static void powerpc_excp_6xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_ITLB: /* Instruction TLB error */ break; case POWERPC_EXCP_RESET: /* System reset exception */ - if (msr_pow) { + if (FIELD_EX64(env->msr, MSR, POW)) { cpu_abort(cs, "Trying to deliver power-saving system reset " "exception %d with no HV support\n", excp); } @@ -853,7 +853,7 @@ static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_DECR: /* Decrementer exception */ break; case POWERPC_EXCP_RESET: /* System reset exception */ - if (msr_pow) { + if (FIELD_EX64(env->msr, MSR, POW)) { cpu_abort(cs, "Trying to deliver power-saving system reset " "exception %d with no HV support\n", excp); } @@ -1038,7 +1038,7 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_DECR: /* Decrementer exception */ break; case POWERPC_EXCP_RESET: /* System reset exception */ - if (msr_pow) { + if (FIELD_EX64(env->msr, MSR, POW)) { cpu_abort(cs, "Trying to deliver power-saving system reset " "exception %d with no HV support\n", excp); } @@ -1248,7 +1248,7 @@ static void powerpc_excp_booke(PowerPCCPU *cpu, int excp) env->spr[SPR_BOOKE_ESR] = ESR_SPV; break; case POWERPC_EXCP_RESET: /* System reset exception */ - if (msr_pow) { + if (FIELD_EX64(env->msr, MSR, POW)) { cpu_abort(cs, "Trying to deliver power-saving system reset " "exception %d with no HV support\n", excp); } @@ -1507,7 +1507,7 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp) break; case POWERPC_EXCP_RESET: /* System reset exception */ /* A power-saving exception sets ME, otherwise it is unchanged */ - if (msr_pow) { + if (FIELD_EX64(env->msr, MSR, POW)) { /* indicate that we resumed from power save mode */ msr |= 0x10000; new_msr |= ((target_ulong)1 << MSR_ME); @@ -1519,7 +1519,7 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp) */ new_msr |= (target_ulong)MSR_HVB; } else { - if (msr_pow) { + if (FIELD_EX64(env->msr, MSR, POW)) { cpu_abort(cs, "Trying to deliver power-saving system reset " "exception %d with no HV support\n", excp); } diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index 77bc57415c..79c0143a7a 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -261,7 +261,7 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) env->msr = value; hreg_compute_hflags(env); #if !defined(CONFIG_USER_ONLY) - if (unlikely(msr_pow == 1)) { + if (unlikely(FIELD_EX64(env->msr, MSR, POW))) { if (!env->pending_interrupts && (*env->check_pow)(env)) { cs->halted = 1; excp = EXCP_HALTED; From c354d85828a44e374ccc68b418989dcd26f650db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:29 -0300 Subject: [PATCH 055/935] target/ppc: Remove msr_me macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msr_me macro hides the usage of env->msr, which is a bad behavior Substitute it with FIELD_EX64 calls that explicitly use env->msr as a parameter. Suggested-by: Richard Henderson Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Message-Id: <20220504210541.115256-11-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 2 +- target/ppc/excp_helper.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 5a83c4b028..deb861f5f3 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -359,6 +359,7 @@ FIELD(MSR, CE, MSR_CE, 1) FIELD(MSR, ILE, MSR_ILE, 1) FIELD(MSR, EE, MSR_EE, 1) FIELD(MSR, PR, MSR_PR, 1) +FIELD(MSR, ME, MSR_ME, 1) FIELD(MSR, DS, MSR_DS, 1) FIELD(MSR, LE, MSR_LE, 1) @@ -480,7 +481,6 @@ FIELD(MSR, LE, MSR_LE, 1) #define msr_cm ((env->msr >> MSR_CM) & 1) #define msr_gs ((env->msr >> MSR_GS) & 1) #define msr_fp ((env->msr >> MSR_FP) & 1) -#define msr_me ((env->msr >> MSR_ME) & 1) #define msr_fe0 ((env->msr >> MSR_FE0) & 1) #define msr_de ((env->msr >> MSR_DE) & 1) #define msr_fe1 ((env->msr >> MSR_FE1) & 1) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index ee63641dd0..e254ae806c 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -444,7 +444,7 @@ static void powerpc_excp_40x(PowerPCCPU *cpu, int excp) srr1 = SPR_40x_SRR3; break; case POWERPC_EXCP_MCHECK: /* Machine check exception */ - if (msr_me == 0) { + if (!FIELD_EX64(env->msr, MSR, ME)) { /* * Machine check exception is not enabled. Enter * checkstop state. @@ -575,7 +575,7 @@ static void powerpc_excp_6xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_CRITICAL: /* Critical input */ break; case POWERPC_EXCP_MCHECK: /* Machine check exception */ - if (msr_me == 0) { + if (!FIELD_EX64(env->msr, MSR, ME)) { /* * Machine check exception is not enabled. Enter * checkstop state. @@ -748,7 +748,7 @@ static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp) switch (excp) { case POWERPC_EXCP_MCHECK: /* Machine check exception */ - if (msr_me == 0) { + if (!FIELD_EX64(env->msr, MSR, ME)) { /* * Machine check exception is not enabled. Enter * checkstop state. @@ -933,7 +933,7 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp) switch (excp) { case POWERPC_EXCP_MCHECK: /* Machine check exception */ - if (msr_me == 0) { + if (!FIELD_EX64(env->msr, MSR, ME)) { /* * Machine check exception is not enabled. Enter * checkstop state. @@ -1128,7 +1128,7 @@ static void powerpc_excp_booke(PowerPCCPU *cpu, int excp) srr1 = SPR_BOOKE_CSRR1; break; case POWERPC_EXCP_MCHECK: /* Machine check exception */ - if (msr_me == 0) { + if (!FIELD_EX64(env->msr, MSR, ME)) { /* * Machine check exception is not enabled. Enter * checkstop state. @@ -1366,7 +1366,7 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp) switch (excp) { case POWERPC_EXCP_MCHECK: /* Machine check exception */ - if (msr_me == 0) { + if (!FIELD_EX64(env->msr, MSR, ME)) { /* * Machine check exception is not enabled. Enter * checkstop state. From 10b2b373919ff24c8fabec035f40a4fdb1c40da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:30 -0300 Subject: [PATCH 056/935] target/ppc: Remove msr_gs macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msr_gs macro hides the usage of env->msr, which is a bad behavior Substitute it with FIELD_EX64 calls that explicitly use env->msr as a parameter. Suggested-by: Richard Henderson Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Message-Id: <20220504210541.115256-12-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 2 +- target/ppc/helper_regs.c | 2 +- target/ppc/mmu_helper.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index deb861f5f3..bd5dffc9b1 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -354,6 +354,7 @@ typedef enum { #define MSR_RI 1 /* Recoverable interrupt 1 */ #define MSR_LE 0 /* Little-endian mode 1 hflags */ +FIELD(MSR, GS, MSR_GS, 1) FIELD(MSR, POW, MSR_POW, 1) FIELD(MSR, CE, MSR_CE, 1) FIELD(MSR, ILE, MSR_ILE, 1) @@ -479,7 +480,6 @@ FIELD(MSR, LE, MSR_LE, 1) #define msr_hv (0) #endif #define msr_cm ((env->msr >> MSR_CM) & 1) -#define msr_gs ((env->msr >> MSR_GS) & 1) #define msr_fp ((env->msr >> MSR_FP) & 1) #define msr_fe0 ((env->msr >> MSR_FE0) & 1) #define msr_de ((env->msr >> MSR_DE) & 1) diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index 79c0143a7a..4e649d8b0e 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -233,7 +233,7 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) } if ((env->mmu_model == POWERPC_MMU_BOOKE || env->mmu_model == POWERPC_MMU_BOOKE206) && - ((value >> MSR_GS) & 1) != msr_gs) { + ((value ^ env->msr) & R_MSR_GS_MASK)) { cpu_interrupt_exittb(cs); } if (unlikely((env->flags & POWERPC_FLAG_TGPR) && diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c index 142a717255..5bb5c71038 100644 --- a/target/ppc/mmu_helper.c +++ b/target/ppc/mmu_helper.c @@ -935,7 +935,7 @@ void helper_booke206_tlbwe(CPUPPCState *env) } if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) && - !msr_gs) { + !FIELD_EX64(env->msr, MSR, GS)) { /* XXX we don't support direct LRAT setting yet */ fprintf(stderr, "cpu: don't support LRAT setting yet\n"); return; @@ -962,7 +962,7 @@ void helper_booke206_tlbwe(CPUPPCState *env) POWERPC_EXCP_INVAL_INVAL, GETPC()); } - if (msr_gs) { + if (FIELD_EX64(env->msr, MSR, GS)) { cpu_abort(env_cpu(env), "missing HV implementation\n"); } From 39695e156ff519a466dda8ad3dd6b37b5ef85e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:31 -0300 Subject: [PATCH 057/935] target/ppc: Remove msr_fp macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msr_fp macro hides the usage of env->msr, which is a bad behavior Substitute it with FIELD_EX64 calls that explicitly use env->msr as a parameter. Suggested-by: Richard Henderson Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Message-Id: <20220504210541.115256-13-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 2 +- target/ppc/excp_helper.c | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index bd5dffc9b1..17b7f5f6d9 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -360,6 +360,7 @@ FIELD(MSR, CE, MSR_CE, 1) FIELD(MSR, ILE, MSR_ILE, 1) FIELD(MSR, EE, MSR_EE, 1) FIELD(MSR, PR, MSR_PR, 1) +FIELD(MSR, FP, MSR_FP, 1) FIELD(MSR, ME, MSR_ME, 1) FIELD(MSR, DS, MSR_DS, 1) FIELD(MSR, LE, MSR_LE, 1) @@ -480,7 +481,6 @@ FIELD(MSR, LE, MSR_LE, 1) #define msr_hv (0) #endif #define msr_cm ((env->msr >> MSR_CM) & 1) -#define msr_fp ((env->msr >> MSR_FP) & 1) #define msr_fe0 ((env->msr >> MSR_FE0) & 1) #define msr_de ((env->msr >> MSR_DE) & 1) #define msr_fe1 ((env->msr >> MSR_FE1) & 1) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index e254ae806c..30baad0489 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -478,7 +478,8 @@ static void powerpc_excp_40x(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: - if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { + if ((msr_fe0 == 0 && msr_fe1 == 0) || + !FIELD_EX64(env->msr, MSR, FP)) { trace_ppc_excp_fp_ignore(); powerpc_reset_excp_state(cpu); return; @@ -615,7 +616,8 @@ static void powerpc_excp_6xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: - if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { + if ((msr_fe0 == 0 && msr_fe1 == 0) || + !FIELD_EX64(env->msr, MSR, FP)) { trace_ppc_excp_fp_ignore(); powerpc_reset_excp_state(cpu); return; @@ -788,7 +790,8 @@ static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: - if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { + if ((msr_fe0 == 0 && msr_fe1 == 0) || + !FIELD_EX64(env->msr, MSR, FP)) { trace_ppc_excp_fp_ignore(); powerpc_reset_excp_state(cpu); return; @@ -973,7 +976,8 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: - if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { + if ((msr_fe0 == 0 && msr_fe1 == 0) || + !FIELD_EX64(env->msr, MSR, FP)) { trace_ppc_excp_fp_ignore(); powerpc_reset_excp_state(cpu); return; @@ -1171,7 +1175,8 @@ static void powerpc_excp_booke(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: - if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { + if ((msr_fe0 == 0 && msr_fe1 == 0) || + !FIELD_EX64(env->msr, MSR, FP)) { trace_ppc_excp_fp_ignore(); powerpc_reset_excp_state(cpu); return; @@ -1434,7 +1439,8 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: - if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { + if ((msr_fe0 == 0 && msr_fe1 == 0) || + !FIELD_EX64(env->msr, MSR, FP)) { trace_ppc_excp_fp_ignore(); powerpc_reset_excp_state(cpu); return; From cda2336027d2ef744d04271810bb64085ab2cd29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:32 -0300 Subject: [PATCH 058/935] target/ppc: Remove msr_cm macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msr_cm macro hides the usage of env->msr, which is a bad behavior Substitute it with FIELD_EX64 calls that explicitly use env->msr as a parameter. Suggested-by: Richard Henderson Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Message-Id: <20220504210541.115256-14-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 2 +- target/ppc/mmu_common.c | 2 +- target/ppc/mmu_helper.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 17b7f5f6d9..75a81d4304 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -354,6 +354,7 @@ typedef enum { #define MSR_RI 1 /* Recoverable interrupt 1 */ #define MSR_LE 0 /* Little-endian mode 1 hflags */ +FIELD(MSR, CM, MSR_CM, 1) FIELD(MSR, GS, MSR_GS, 1) FIELD(MSR, POW, MSR_POW, 1) FIELD(MSR, CE, MSR_CE, 1) @@ -480,7 +481,6 @@ FIELD(MSR, LE, MSR_LE, 1) #else #define msr_hv (0) #endif -#define msr_cm ((env->msr >> MSR_CM) & 1) #define msr_fe0 ((env->msr >> MSR_FE0) & 1) #define msr_de ((env->msr >> MSR_DE) & 1) #define msr_fe1 ((env->msr >> MSR_FE1) & 1) diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c index 7e77b9b84a..031bb4493b 100644 --- a/target/ppc/mmu_common.c +++ b/target/ppc/mmu_common.c @@ -692,7 +692,7 @@ int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, hwaddr mask; uint32_t tlb_pid; - if (!msr_cm) { + if (!FIELD_EX64(env->msr, MSR, CM)) { /* In 32bit mode we can only address 32bit EAs */ address = (uint32_t)address; } diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c index 5bb5c71038..15239dc95b 100644 --- a/target/ppc/mmu_helper.c +++ b/target/ppc/mmu_helper.c @@ -1003,7 +1003,7 @@ void helper_booke206_tlbwe(CPUPPCState *env) /* Add a mask for page attributes */ mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E; - if (!msr_cm) { + if (!FIELD_EX64(env->msr, MSR, CM)) { /* * Executing a tlbwe instruction in 32-bit mode will set bits * 0:31 of the TLB EPN field to zero. From 4d979c9ffbe19931bd8b44810eb3c1c396798911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:33 -0300 Subject: [PATCH 059/935] target/ppc: Remove msr_ir macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msr_ir macro hides the usage of env->msr, which is a bad behavior Substitute it with FIELD_EX64 calls that explicitly use env->msr as a parameter. Suggested-by: Richard Henderson Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Message-Id: <20220504210541.115256-15-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 2 +- target/ppc/helper_regs.c | 2 +- target/ppc/mmu_common.c | 11 ++++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 75a81d4304..6cfbec26a1 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -363,6 +363,7 @@ FIELD(MSR, EE, MSR_EE, 1) FIELD(MSR, PR, MSR_PR, 1) FIELD(MSR, FP, MSR_FP, 1) FIELD(MSR, ME, MSR_ME, 1) +FIELD(MSR, IR, MSR_IR, 1) FIELD(MSR, DS, MSR_DS, 1) FIELD(MSR, LE, MSR_LE, 1) @@ -485,7 +486,6 @@ FIELD(MSR, LE, MSR_LE, 1) #define msr_de ((env->msr >> MSR_DE) & 1) #define msr_fe1 ((env->msr >> MSR_FE1) & 1) #define msr_ep ((env->msr >> MSR_EP) & 1) -#define msr_ir ((env->msr >> MSR_IR) & 1) #define msr_dr ((env->msr >> MSR_DR) & 1) #define msr_ts ((env->msr >> MSR_TS1) & 3) diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index 4e649d8b0e..e40078c001 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -227,7 +227,7 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) value &= ~MSR_HVB; value |= env->msr & MSR_HVB; } - if (((value >> MSR_IR) & 1) != msr_ir || + if (((value ^ env->msr) & R_MSR_IR_MASK) || ((value >> MSR_DR) & 1) != msr_dr) { cpu_interrupt_exittb(cs); } diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c index 031bb4493b..30deca0425 100644 --- a/target/ppc/mmu_common.c +++ b/target/ppc/mmu_common.c @@ -388,7 +388,7 @@ static int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx " ir=%d dr=%d pr=%d %d t=%d\n", eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, - (int)msr_ir, (int)msr_dr, pr ? 1 : 0, + (int)FIELD_EX64(env->msr, MSR, IR), (int)msr_dr, pr ? 1 : 0, access_type == MMU_DATA_STORE, type); pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits; hash = vsid ^ pgidx; @@ -626,7 +626,8 @@ found_tlb: } /* Check the address space */ - if ((access_type == MMU_INST_FETCH ? msr_ir : msr_dr) != (tlb->attr & 1)) { + if ((access_type == MMU_INST_FETCH ? + FIELD_EX64(env->msr, MSR, IR) : msr_dr) != (tlb->attr & 1)) { qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__); return -1; } @@ -839,7 +840,7 @@ found_tlb: if (access_type == MMU_INST_FETCH) { /* There is no way to fetch code using epid load */ assert(!use_epid); - as = msr_ir; + as = FIELD_EX64(env->msr, MSR, IR); } if (as != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { @@ -1169,7 +1170,7 @@ int get_physical_address_wtlb(CPUPPCState *env, mmu_ctx_t *ctx, int mmu_idx) { int ret = -1; - bool real_mode = (type == ACCESS_CODE && msr_ir == 0) + bool real_mode = (type == ACCESS_CODE && !FIELD_EX64(env->msr, MSR, IR)) || (type != ACCESS_CODE && msr_dr == 0); switch (env->mmu_model) { @@ -1231,7 +1232,7 @@ static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address, bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr); if (access_type == MMU_INST_FETCH) { - as = msr_ir; + as = FIELD_EX64(env->msr, MSR, IR); } env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK; env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK; From e4eea6ef667a9bf75114ad860d0e6b239b74b537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:34 -0300 Subject: [PATCH 060/935] target/ppc: Remove msr_dr macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msr_dr macro hides the usage of env->msr, which is a bad behavior Substitute it with FIELD_EX64 calls that explicitly use env->msr as a parameter. Suggested-by: Richard Henderson Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Message-Id: <20220504210541.115256-16-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 2 +- target/ppc/helper_regs.c | 3 +-- target/ppc/mmu_common.c | 10 ++++++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 6cfbec26a1..cd672dec93 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -364,6 +364,7 @@ FIELD(MSR, PR, MSR_PR, 1) FIELD(MSR, FP, MSR_FP, 1) FIELD(MSR, ME, MSR_ME, 1) FIELD(MSR, IR, MSR_IR, 1) +FIELD(MSR, DR, MSR_DR, 1) FIELD(MSR, DS, MSR_DS, 1) FIELD(MSR, LE, MSR_LE, 1) @@ -486,7 +487,6 @@ FIELD(MSR, LE, MSR_LE, 1) #define msr_de ((env->msr >> MSR_DE) & 1) #define msr_fe1 ((env->msr >> MSR_FE1) & 1) #define msr_ep ((env->msr >> MSR_EP) & 1) -#define msr_dr ((env->msr >> MSR_DR) & 1) #define msr_ts ((env->msr >> MSR_TS1) & 3) #define DBCR0_ICMP (1 << 27) diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index e40078c001..b150b78182 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -227,8 +227,7 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) value &= ~MSR_HVB; value |= env->msr & MSR_HVB; } - if (((value ^ env->msr) & R_MSR_IR_MASK) || - ((value >> MSR_DR) & 1) != msr_dr) { + if ((value ^ env->msr) & (R_MSR_IR_MASK | R_MSR_DR_MASK)) { cpu_interrupt_exittb(cs); } if ((env->mmu_model == POWERPC_MMU_BOOKE || diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c index 30deca0425..89107a6af2 100644 --- a/target/ppc/mmu_common.c +++ b/target/ppc/mmu_common.c @@ -388,7 +388,8 @@ static int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx " ir=%d dr=%d pr=%d %d t=%d\n", eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, - (int)FIELD_EX64(env->msr, MSR, IR), (int)msr_dr, pr ? 1 : 0, + (int)FIELD_EX64(env->msr, MSR, IR), + (int)FIELD_EX64(env->msr, MSR, DR), pr ? 1 : 0, access_type == MMU_DATA_STORE, type); pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits; hash = vsid ^ pgidx; @@ -627,7 +628,8 @@ found_tlb: /* Check the address space */ if ((access_type == MMU_INST_FETCH ? - FIELD_EX64(env->msr, MSR, IR) : msr_dr) != (tlb->attr & 1)) { + FIELD_EX64(env->msr, MSR, IR) : + FIELD_EX64(env->msr, MSR, DR)) != (tlb->attr & 1)) { qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__); return -1; } @@ -1170,8 +1172,8 @@ int get_physical_address_wtlb(CPUPPCState *env, mmu_ctx_t *ctx, int mmu_idx) { int ret = -1; - bool real_mode = (type == ACCESS_CODE && !FIELD_EX64(env->msr, MSR, IR)) - || (type != ACCESS_CODE && msr_dr == 0); + bool real_mode = (type == ACCESS_CODE && !FIELD_EX64(env->msr, MSR, IR)) || + (type != ACCESS_CODE && !FIELD_EX64(env->msr, MSR, DR)); switch (env->mmu_model) { case POWERPC_MMU_SOFT_6xx: From 502423309159a4305f315e55ff6ec75aa61a91b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:35 -0300 Subject: [PATCH 061/935] target/ppc: Remove msr_ep macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msr_ep macro hides the usage of env->msr, which is a bad behavior Substitute it with FIELD_EX64 calls that explicitly use env->msr as a parameter. Suggested-by: Richard Henderson Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Message-Id: <20220504210541.115256-17-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 2 +- target/ppc/helper_regs.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index cd672dec93..5e804f0373 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -363,6 +363,7 @@ FIELD(MSR, EE, MSR_EE, 1) FIELD(MSR, PR, MSR_PR, 1) FIELD(MSR, FP, MSR_FP, 1) FIELD(MSR, ME, MSR_ME, 1) +FIELD(MSR, EP, MSR_EP, 1) FIELD(MSR, IR, MSR_IR, 1) FIELD(MSR, DR, MSR_DR, 1) FIELD(MSR, DS, MSR_DS, 1) @@ -486,7 +487,6 @@ FIELD(MSR, LE, MSR_LE, 1) #define msr_fe0 ((env->msr >> MSR_FE0) & 1) #define msr_de ((env->msr >> MSR_DE) & 1) #define msr_fe1 ((env->msr >> MSR_FE1) & 1) -#define msr_ep ((env->msr >> MSR_EP) & 1) #define msr_ts ((env->msr >> MSR_TS1) & 3) #define DBCR0_ICMP (1 << 27) diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index b150b78182..97cd263131 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -240,8 +240,8 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) /* Swap temporary saved registers with GPRs */ hreg_swap_gpr_tgpr(env); } - if (unlikely((value >> MSR_EP) & 1) != msr_ep) { - env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000; + if (unlikely((value ^ env->msr) & R_MSR_EP_MASK)) { + env->excp_prefix = FIELD_EX64(value, MSR, EP) * 0xFFF00000; } /* * If PR=1 then EE, IR and DR must be 1 From da806a6c63c8a62700fcb7bc09ba908f0f5e5648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:36 -0300 Subject: [PATCH 062/935] target/ppc: Remove msr_fe0 and msr_fe1 macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msr_fe0 and msr_fe1 macros hide the usage of env->msr, which is a bad behavior. Substitute it with FIELD_EX64 calls that explicitly use env->msr as a parameter. Suggested-by: Richard Henderson Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Message-Id: <20220504210541.115256-18-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 11 +++++++++-- target/ppc/excp_helper.c | 18 ++++++------------ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 5e804f0373..74a3c01f99 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -363,12 +363,21 @@ FIELD(MSR, EE, MSR_EE, 1) FIELD(MSR, PR, MSR_PR, 1) FIELD(MSR, FP, MSR_FP, 1) FIELD(MSR, ME, MSR_ME, 1) +FIELD(MSR, FE0, MSR_FE0, 1) +FIELD(MSR, FE1, MSR_FE1, 1) FIELD(MSR, EP, MSR_EP, 1) FIELD(MSR, IR, MSR_IR, 1) FIELD(MSR, DR, MSR_DR, 1) FIELD(MSR, DS, MSR_DS, 1) FIELD(MSR, LE, MSR_LE, 1) +/* + * FE0 and FE1 bits are not side-by-side + * so we can't combine them using FIELD() + */ +#define FIELD_EX64_FE(msr) \ + ((FIELD_EX64(msr, MSR, FE0) << 1) | FIELD_EX64(msr, MSR, FE1)) + /* PMU bits */ #define MMCR0_FC PPC_BIT(32) /* Freeze Counters */ #define MMCR0_PMAO PPC_BIT(56) /* Perf Monitor Alert Ocurred */ @@ -484,9 +493,7 @@ FIELD(MSR, LE, MSR_LE, 1) #else #define msr_hv (0) #endif -#define msr_fe0 ((env->msr >> MSR_FE0) & 1) #define msr_de ((env->msr >> MSR_DE) & 1) -#define msr_fe1 ((env->msr >> MSR_FE1) & 1) #define msr_ts ((env->msr >> MSR_TS1) & 3) #define DBCR0_ICMP (1 << 27) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 30baad0489..aa201c63c6 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -478,8 +478,7 @@ static void powerpc_excp_40x(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: - if ((msr_fe0 == 0 && msr_fe1 == 0) || - !FIELD_EX64(env->msr, MSR, FP)) { + if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) { trace_ppc_excp_fp_ignore(); powerpc_reset_excp_state(cpu); return; @@ -616,8 +615,7 @@ static void powerpc_excp_6xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: - if ((msr_fe0 == 0 && msr_fe1 == 0) || - !FIELD_EX64(env->msr, MSR, FP)) { + if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) { trace_ppc_excp_fp_ignore(); powerpc_reset_excp_state(cpu); return; @@ -790,8 +788,7 @@ static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: - if ((msr_fe0 == 0 && msr_fe1 == 0) || - !FIELD_EX64(env->msr, MSR, FP)) { + if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) { trace_ppc_excp_fp_ignore(); powerpc_reset_excp_state(cpu); return; @@ -976,8 +973,7 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: - if ((msr_fe0 == 0 && msr_fe1 == 0) || - !FIELD_EX64(env->msr, MSR, FP)) { + if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) { trace_ppc_excp_fp_ignore(); powerpc_reset_excp_state(cpu); return; @@ -1175,8 +1171,7 @@ static void powerpc_excp_booke(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: - if ((msr_fe0 == 0 && msr_fe1 == 0) || - !FIELD_EX64(env->msr, MSR, FP)) { + if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) { trace_ppc_excp_fp_ignore(); powerpc_reset_excp_state(cpu); return; @@ -1439,8 +1434,7 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: - if ((msr_fe0 == 0 && msr_fe1 == 0) || - !FIELD_EX64(env->msr, MSR, FP)) { + if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) { trace_ppc_excp_fp_ignore(); powerpc_reset_excp_state(cpu); return; From ca241959cd824e1feeabed4948e2c754d1e2b635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:37 -0300 Subject: [PATCH 063/935] target/ppc: Remove msr_ts macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msr_ts macro hides the usage of env->msr, which is a bad behavior. Substitute it with FIELD_EX64 calls that explicitly use env->msr as a parameter. Suggested-by: Richard Henderson Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Message-Id: <20220504210541.115256-19-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 2 +- target/ppc/kvm.c | 4 ++-- target/ppc/machine.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 74a3c01f99..5ac7d7d68f 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -354,6 +354,7 @@ typedef enum { #define MSR_RI 1 /* Recoverable interrupt 1 */ #define MSR_LE 0 /* Little-endian mode 1 hflags */ +FIELD(MSR, TS, MSR_TS0, 2) FIELD(MSR, CM, MSR_CM, 1) FIELD(MSR, GS, MSR_GS, 1) FIELD(MSR, POW, MSR_POW, 1) @@ -494,7 +495,6 @@ FIELD(MSR, LE, MSR_LE, 1) #define msr_hv (0) #endif #define msr_de ((env->msr >> MSR_DE) & 1) -#define msr_ts ((env->msr >> MSR_TS1) & 3) #define DBCR0_ICMP (1 << 27) #define DBCR0_BRT (1 << 26) diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index db3a92869c..6eed466f80 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -974,7 +974,7 @@ int kvm_arch_put_registers(CPUState *cs, int level) } #ifdef TARGET_PPC64 - if (msr_ts) { + if (FIELD_EX64(env->msr, MSR, TS)) { for (i = 0; i < ARRAY_SIZE(env->tm_gpr); i++) { kvm_set_one_reg(cs, KVM_REG_PPC_TM_GPR(i), &env->tm_gpr[i]); } @@ -1282,7 +1282,7 @@ int kvm_arch_get_registers(CPUState *cs) } #ifdef TARGET_PPC64 - if (msr_ts) { + if (FIELD_EX64(env->msr, MSR, TS)) { for (i = 0; i < ARRAY_SIZE(env->tm_gpr); i++) { kvm_get_one_reg(cs, KVM_REG_PPC_TM_GPR(i), &env->tm_gpr[i]); } diff --git a/target/ppc/machine.c b/target/ppc/machine.c index e673944597..7104a5c67e 100644 --- a/target/ppc/machine.c +++ b/target/ppc/machine.c @@ -417,7 +417,7 @@ static bool tm_needed(void *opaque) { PowerPCCPU *cpu = opaque; CPUPPCState *env = &cpu->env; - return msr_ts; + return FIELD_EX64(env->msr, MSR, TS); } static const VMStateDescription vmstate_tm = { From 9de754d30d54b9d5d2ba0756bcbd63625c82e63c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:38 -0300 Subject: [PATCH 064/935] target/ppc: Remove msr_hv macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msr_hv macro hides the usage of env->msr, which is a bad behavior. Substitute it with FIELD_EX64 calls that explicitly use env->msr as a parameter. Suggested-by: Richard Henderson Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Message-Id: <20220504210541.115256-20-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 11 ++++++----- target/ppc/cpu_init.c | 6 ++++-- target/ppc/excp_helper.c | 8 ++++---- target/ppc/mem_helper.c | 4 ++-- target/ppc/misc_helper.c | 2 +- target/ppc/mmu-radix64.c | 6 +++--- 6 files changed, 20 insertions(+), 17 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 5ac7d7d68f..9f19b3c0a8 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -354,6 +354,12 @@ typedef enum { #define MSR_RI 1 /* Recoverable interrupt 1 */ #define MSR_LE 0 /* Little-endian mode 1 hflags */ +#if defined(TARGET_PPC64) +FIELD(MSR, HV, MSR_HV, 1) +#define FIELD_EX64_HV(storage) FIELD_EX64(storage, MSR, HV) +#else +#define FIELD_EX64_HV(storage) 0 +#endif FIELD(MSR, TS, MSR_TS0, 2) FIELD(MSR, CM, MSR_CM, 1) FIELD(MSR, GS, MSR_GS, 1) @@ -489,11 +495,6 @@ FIELD(MSR, LE, MSR_LE, 1) #define HFSCR_MSGP PPC_BIT(53) /* Privileged Message Send Facilities */ #define HFSCR_IC_MSGP 0xA -#if defined(TARGET_PPC64) -#define msr_hv ((env->msr >> MSR_HV) & 1) -#else -#define msr_hv (0) -#endif #define msr_de ((env->msr >> MSR_DE) & 1) #define DBCR0_ICMP (1 << 27) diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 10e7c41bc9..d4c7813de5 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -6305,7 +6305,8 @@ static bool cpu_has_work_POWER9(CPUState *cs) if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) && (env->spr[SPR_LPCR] & LPCR_EEE)) { bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); - if (!heic || !msr_hv || FIELD_EX64(env->msr, MSR, PR)) { + if (!heic || !FIELD_EX64_HV(env->msr) || + FIELD_EX64(env->msr, MSR, PR)) { return true; } } @@ -6520,7 +6521,8 @@ static bool cpu_has_work_POWER10(CPUState *cs) if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) && (env->spr[SPR_LPCR] & LPCR_EEE)) { bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); - if (!heic || !msr_hv || FIELD_EX64(env->msr, MSR, PR)) { + if (!heic || !FIELD_EX64_HV(env->msr) || + FIELD_EX64(env->msr, MSR, PR)) { return true; } } diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index aa201c63c6..cb752b184a 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1715,7 +1715,7 @@ static void ppc_hw_interrupt(CPUPPCState *env) if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { /* LPCR will be clear when not supported so this will work */ bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); - if ((async_deliver || msr_hv == 0) && hdice) { + if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) { /* HDEC clears on delivery */ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); powerpc_excp(cpu, POWERPC_EXCP_HDECR); @@ -1727,7 +1727,7 @@ static void ppc_hw_interrupt(CPUPPCState *env) if (env->pending_interrupts & (1 << PPC_INTERRUPT_HVIRT)) { /* LPCR will be clear when not supported so this will work */ bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE); - if ((async_deliver || msr_hv == 0) && hvice) { + if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) { powerpc_excp(cpu, POWERPC_EXCP_HVIRT); return; } @@ -1738,9 +1738,9 @@ static void ppc_hw_interrupt(CPUPPCState *env) bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); /* HEIC blocks delivery to the hypervisor */ - if ((async_deliver && !(heic && msr_hv && + if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) && !FIELD_EX64(env->msr, MSR, PR))) || - (env->has_hv_mode && msr_hv == 0 && !lpes0)) { + (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) { if (books_vhyp_promotes_external_to_hvirt(cpu)) { powerpc_excp(cpu, POWERPC_EXCP_HVIRT); } else { diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c index 9af135e88e..d1163f316c 100644 --- a/target/ppc/mem_helper.c +++ b/target/ppc/mem_helper.c @@ -612,11 +612,11 @@ void helper_tbegin(CPUPPCState *env) env->spr[SPR_TEXASR] = (1ULL << TEXASR_FAILURE_PERSISTENT) | (1ULL << TEXASR_NESTING_OVERFLOW) | - (msr_hv << TEXASR_PRIVILEGE_HV) | + (FIELD_EX64_HV(env->msr) << TEXASR_PRIVILEGE_HV) | (FIELD_EX64(env->msr, MSR, PR) << TEXASR_PRIVILEGE_PR) | (1ULL << TEXASR_FAILURE_SUMMARY) | (1ULL << TEXASR_TFIAR_EXACT); - env->spr[SPR_TFIAR] = env->nip | (msr_hv << 1) | + env->spr[SPR_TFIAR] = env->nip | (FIELD_EX64_HV(env->msr) << 1) | FIELD_EX64(env->msr, MSR, PR); env->spr[SPR_TFHAR] = env->nip + 4; env->crf[0] = 0xB; /* 0b1010 = transaction failure */ diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c index 06aa716cab..b0a5e7ce76 100644 --- a/target/ppc/misc_helper.c +++ b/target/ppc/misc_helper.c @@ -73,7 +73,7 @@ void helper_hfscr_facility_check(CPUPPCState *env, uint32_t bit, const char *caller, uint32_t cause) { #ifdef TARGET_PPC64 - if ((env->msr_mask & MSR_HVB) && !msr_hv && + if ((env->msr_mask & MSR_HVB) && !FIELD_EX64(env->msr, MSR, HV) && !(env->spr[SPR_HFSCR] & (1UL << bit))) { raise_hv_fu_exception(env, bit, caller, cause, GETPC()); } diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index e88f51fd34..21ac958e48 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -37,7 +37,7 @@ static bool ppc_radix64_get_fully_qualified_addr(const CPUPPCState *env, return false; } - if (msr_hv) { /* MSR[HV] -> Hypervisor/bare metal */ + if (FIELD_EX64(env->msr, MSR, HV)) { /* MSR[HV] -> Hypervisor/bare metal */ switch (eaddr & R_EADDR_QUADRANT) { case R_EADDR_QUADRANT0: *lpid = 0; @@ -306,7 +306,7 @@ static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate) if (!(pate->dw0 & PATE0_HR)) { return false; } - if (lpid == 0 && !msr_hv) { + if (lpid == 0 && !FIELD_EX64(env->msr, MSR, HV)) { return false; } if ((pate->dw0 & PATE1_R_PRTS) < 5) { @@ -431,7 +431,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, *g_page_size = PRTBE_R_GET_RTS(prtbe0); base_addr = prtbe0 & PRTBE_R_RPDB; nls = prtbe0 & PRTBE_R_RPDS; - if (msr_hv || vhyp_flat_addressing(cpu)) { + if (FIELD_EX64(env->msr, MSR, HV) || vhyp_flat_addressing(cpu)) { /* * Can treat process table addresses as real addresses */ From 67935ecdd9a5d5dfed83cb0a7e7f6be925a7d761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:39 -0300 Subject: [PATCH 065/935] target/ppc: Remove msr_de macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msr_de macro hides the usage of env->msr, which is a bad behavior. Substitute it with FIELD_EX64 calls that explicitly use env->msr as a parameter. Suggested-by: Richard Henderson Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Message-Id: <20220504210541.115256-21-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 3 +-- target/ppc/helper_regs.c | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 9f19b3c0a8..af249239d5 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -371,6 +371,7 @@ FIELD(MSR, PR, MSR_PR, 1) FIELD(MSR, FP, MSR_FP, 1) FIELD(MSR, ME, MSR_ME, 1) FIELD(MSR, FE0, MSR_FE0, 1) +FIELD(MSR, DE, MSR_DE, 1) FIELD(MSR, FE1, MSR_FE1, 1) FIELD(MSR, EP, MSR_EP, 1) FIELD(MSR, IR, MSR_IR, 1) @@ -495,8 +496,6 @@ FIELD(MSR, LE, MSR_LE, 1) #define HFSCR_MSGP PPC_BIT(53) /* Privileged Message Send Facilities */ #define HFSCR_IC_MSGP 0xA -#define msr_de ((env->msr >> MSR_DE) & 1) - #define DBCR0_ICMP (1 << 27) #define DBCR0_BRT (1 << 26) #define DBSR_ICMP (1 << 27) diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index 97cd263131..6159a15b7b 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -63,10 +63,10 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env) if (ppc_flags & POWERPC_FLAG_DE) { target_ulong dbcr0 = env->spr[SPR_BOOKE_DBCR0]; - if ((dbcr0 & DBCR0_ICMP) && msr_de) { + if ((dbcr0 & DBCR0_ICMP) && FIELD_EX64(env->msr, MSR, DE)) { hflags |= 1 << HFLAGS_SE; } - if ((dbcr0 & DBCR0_BRT) && msr_de) { + if ((dbcr0 & DBCR0_BRT) && FIELD_EX64(env->msr, MSR, DE)) { hflags |= 1 << HFLAGS_BE; } } else { From 39af1384faec88e49e14dc066f7653f219d79850 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:40 -0300 Subject: [PATCH 066/935] target/ppc: Add unused msr bits FIELDs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add FIELDs macros for msr bits that had an unused msr_* before. Signed-off-by: Víctor Colombo Acked-by: Richard Henderson Message-Id: <20220504210541.115256-22-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index af249239d5..4577cfcc23 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -354,16 +354,31 @@ typedef enum { #define MSR_RI 1 /* Recoverable interrupt 1 */ #define MSR_LE 0 /* Little-endian mode 1 hflags */ +FIELD(MSR, SF, MSR_SF, 1) +FIELD(MSR, TAG, MSR_TAG, 1) +FIELD(MSR, ISF, MSR_ISF, 1) #if defined(TARGET_PPC64) FIELD(MSR, HV, MSR_HV, 1) #define FIELD_EX64_HV(storage) FIELD_EX64(storage, MSR, HV) #else #define FIELD_EX64_HV(storage) 0 #endif +FIELD(MSR, TS0, MSR_TS0, 1) +FIELD(MSR, TS1, MSR_TS1, 1) FIELD(MSR, TS, MSR_TS0, 2) +FIELD(MSR, TM, MSR_TM, 1) FIELD(MSR, CM, MSR_CM, 1) +FIELD(MSR, ICM, MSR_ICM, 1) FIELD(MSR, GS, MSR_GS, 1) +FIELD(MSR, UCLE, MSR_UCLE, 1) +FIELD(MSR, VR, MSR_VR, 1) +FIELD(MSR, SPE, MSR_SPE, 1) +FIELD(MSR, VSX, MSR_VSX, 1) +FIELD(MSR, S, MSR_S, 1) +FIELD(MSR, KEY, MSR_KEY, 1) FIELD(MSR, POW, MSR_POW, 1) +FIELD(MSR, WE, MSR_WE, 1) +FIELD(MSR, TGPR, MSR_TGPR, 1) FIELD(MSR, CE, MSR_CE, 1) FIELD(MSR, ILE, MSR_ILE, 1) FIELD(MSR, EE, MSR_EE, 1) @@ -371,12 +386,22 @@ FIELD(MSR, PR, MSR_PR, 1) FIELD(MSR, FP, MSR_FP, 1) FIELD(MSR, ME, MSR_ME, 1) FIELD(MSR, FE0, MSR_FE0, 1) +FIELD(MSR, SE, MSR_SE, 1) +FIELD(MSR, DWE, MSR_DWE, 1) +FIELD(MSR, UBLE, MSR_UBLE, 1) +FIELD(MSR, BE, MSR_BE, 1) FIELD(MSR, DE, MSR_DE, 1) FIELD(MSR, FE1, MSR_FE1, 1) +FIELD(MSR, AL, MSR_AL, 1) FIELD(MSR, EP, MSR_EP, 1) FIELD(MSR, IR, MSR_IR, 1) FIELD(MSR, DR, MSR_DR, 1) +FIELD(MSR, IS, MSR_IS, 1) FIELD(MSR, DS, MSR_DS, 1) +FIELD(MSR, PE, MSR_PE, 1) +FIELD(MSR, PX, MSR_PX, 1) +FIELD(MSR, PMM, MSR_PMM, 1) +FIELD(MSR, RI, MSR_RI, 1) FIELD(MSR, LE, MSR_LE, 1) /* From bf3dd1e6d0d7c5c4906f89776e15dddc22af784b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 4 May 2022 18:05:41 -0300 Subject: [PATCH 067/935] target/ppc: Change MSR_* to follow POWER ISA numbering convention MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Today we have the issue where MSR_* values are the 'inverted order' bit numbers from what the ISA specifies. e.g. MSR_LE is bit 63 but is defined as 0 in QEMU. Add a macro to be used to convert from QEMU order to ISA order. This solution requires less changes than to use the already defined PPC_BIT macro, which would turn MSR_* in masks instead of the numbers itself. Signed-off-by: Víctor Colombo Acked-by: Richard Henderson Message-Id: <20220504210541.115256-23-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 87 ++++++++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 4577cfcc23..48596cfb25 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -38,6 +38,7 @@ #define PPC_ELF_MACHINE EM_PPC #endif +#define PPC_BIT_NR(bit) (63 - (bit)) #define PPC_BIT(bit) (0x8000000000000000ULL >> (bit)) #define PPC_BIT32(bit) (0x80000000 >> (bit)) #define PPC_BIT8(bit) (0x80 >> (bit)) @@ -310,49 +311,49 @@ typedef enum { /*****************************************************************************/ /* Machine state register bits definition */ -#define MSR_SF 63 /* Sixty-four-bit mode hflags */ -#define MSR_TAG 62 /* Tag-active mode (POWERx ?) */ -#define MSR_ISF 61 /* Sixty-four-bit interrupt mode on 630 */ -#define MSR_HV 60 /* hypervisor state hflags */ -#define MSR_TS0 34 /* Transactional state, 2 bits (Book3s) */ -#define MSR_TS1 33 -#define MSR_TM 32 /* Transactional Memory Available (Book3s) */ -#define MSR_CM 31 /* Computation mode for BookE hflags */ -#define MSR_ICM 30 /* Interrupt computation mode for BookE */ -#define MSR_GS 28 /* guest state for BookE */ -#define MSR_UCLE 26 /* User-mode cache lock enable for BookE */ -#define MSR_VR 25 /* altivec available x hflags */ -#define MSR_SPE 25 /* SPE enable for BookE x hflags */ -#define MSR_VSX 23 /* Vector Scalar Extension (ISA 2.06 and later) x hflags */ -#define MSR_S 22 /* Secure state */ -#define MSR_KEY 19 /* key bit on 603e */ -#define MSR_POW 18 /* Power management */ -#define MSR_WE 18 /* Wait State Enable on 405 */ -#define MSR_TGPR 17 /* TGPR usage on 602/603 x */ -#define MSR_CE 17 /* Critical interrupt enable on embedded PowerPC x */ -#define MSR_ILE 16 /* Interrupt little-endian mode */ -#define MSR_EE 15 /* External interrupt enable */ -#define MSR_PR 14 /* Problem state hflags */ -#define MSR_FP 13 /* Floating point available hflags */ -#define MSR_ME 12 /* Machine check interrupt enable */ -#define MSR_FE0 11 /* Floating point exception mode 0 */ -#define MSR_SE 10 /* Single-step trace enable x hflags */ -#define MSR_DWE 10 /* Debug wait enable on 405 x */ -#define MSR_UBLE 10 /* User BTB lock enable on e500 x */ -#define MSR_BE 9 /* Branch trace enable x hflags */ -#define MSR_DE 9 /* Debug interrupts enable on embedded PowerPC x */ -#define MSR_FE1 8 /* Floating point exception mode 1 */ -#define MSR_AL 7 /* AL bit on POWER */ -#define MSR_EP 6 /* Exception prefix on 601 */ -#define MSR_IR 5 /* Instruction relocate */ -#define MSR_DR 4 /* Data relocate */ -#define MSR_IS 5 /* Instruction address space (BookE) */ -#define MSR_DS 4 /* Data address space (BookE) */ -#define MSR_PE 3 /* Protection enable on 403 */ -#define MSR_PX 2 /* Protection exclusive on 403 x */ -#define MSR_PMM 2 /* Performance monitor mark on POWER x */ -#define MSR_RI 1 /* Recoverable interrupt 1 */ -#define MSR_LE 0 /* Little-endian mode 1 hflags */ +#define MSR_SF PPC_BIT_NR(0) /* Sixty-four-bit mode hflags */ +#define MSR_TAG PPC_BIT_NR(1) /* Tag-active mode (POWERx ?) */ +#define MSR_ISF PPC_BIT_NR(2) /* Sixty-four-bit interrupt mode on 630 */ +#define MSR_HV PPC_BIT_NR(3) /* hypervisor state hflags */ +#define MSR_TS0 PPC_BIT_NR(29) /* Transactional state, 2 bits (Book3s) */ +#define MSR_TS1 PPC_BIT_NR(30) +#define MSR_TM PPC_BIT_NR(31) /* Transactional Memory Available (Book3s) */ +#define MSR_CM PPC_BIT_NR(32) /* Computation mode for BookE hflags */ +#define MSR_ICM PPC_BIT_NR(33) /* Interrupt computation mode for BookE */ +#define MSR_GS PPC_BIT_NR(35) /* guest state for BookE */ +#define MSR_UCLE PPC_BIT_NR(37) /* User-mode cache lock enable for BookE */ +#define MSR_VR PPC_BIT_NR(38) /* altivec available x hflags */ +#define MSR_SPE PPC_BIT_NR(38) /* SPE enable for BookE x hflags */ +#define MSR_VSX PPC_BIT_NR(40) /* Vector Scalar Extension (>= 2.06)x hflags */ +#define MSR_S PPC_BIT_NR(41) /* Secure state */ +#define MSR_KEY PPC_BIT_NR(44) /* key bit on 603e */ +#define MSR_POW PPC_BIT_NR(45) /* Power management */ +#define MSR_WE PPC_BIT_NR(45) /* Wait State Enable on 405 */ +#define MSR_TGPR PPC_BIT_NR(46) /* TGPR usage on 602/603 x */ +#define MSR_CE PPC_BIT_NR(46) /* Critical int. enable on embedded PPC x */ +#define MSR_ILE PPC_BIT_NR(47) /* Interrupt little-endian mode */ +#define MSR_EE PPC_BIT_NR(48) /* External interrupt enable */ +#define MSR_PR PPC_BIT_NR(49) /* Problem state hflags */ +#define MSR_FP PPC_BIT_NR(50) /* Floating point available hflags */ +#define MSR_ME PPC_BIT_NR(51) /* Machine check interrupt enable */ +#define MSR_FE0 PPC_BIT_NR(52) /* Floating point exception mode 0 */ +#define MSR_SE PPC_BIT_NR(53) /* Single-step trace enable x hflags */ +#define MSR_DWE PPC_BIT_NR(53) /* Debug wait enable on 405 x */ +#define MSR_UBLE PPC_BIT_NR(53) /* User BTB lock enable on e500 x */ +#define MSR_BE PPC_BIT_NR(54) /* Branch trace enable x hflags */ +#define MSR_DE PPC_BIT_NR(54) /* Debug int. enable on embedded PPC x */ +#define MSR_FE1 PPC_BIT_NR(55) /* Floating point exception mode 1 */ +#define MSR_AL PPC_BIT_NR(56) /* AL bit on POWER */ +#define MSR_EP PPC_BIT_NR(57) /* Exception prefix on 601 */ +#define MSR_IR PPC_BIT_NR(58) /* Instruction relocate */ +#define MSR_IS PPC_BIT_NR(58) /* Instruction address space (BookE) */ +#define MSR_DR PPC_BIT_NR(59) /* Data relocate */ +#define MSR_DS PPC_BIT_NR(59) /* Data address space (BookE) */ +#define MSR_PE PPC_BIT_NR(60) /* Protection enable on 403 */ +#define MSR_PX PPC_BIT_NR(61) /* Protection exclusive on 403 x */ +#define MSR_PMM PPC_BIT_NR(61) /* Performance monitor mark on POWER x */ +#define MSR_RI PPC_BIT_NR(62) /* Recoverable interrupt 1 */ +#define MSR_LE PPC_BIT_NR(63) /* Little-endian mode 1 hflags */ FIELD(MSR, SF, MSR_SF, 1) FIELD(MSR, TAG, MSR_TAG, 1) From a6f5770fb2b22cb219a684469c8224ebec74ca2e Mon Sep 17 00:00:00 2001 From: "Longpeng(Mike)" Date: Sat, 26 Mar 2022 14:02:22 +0800 Subject: [PATCH 068/935] vfio: simplify the conditional statements in vfio_msi_enable It's unnecessary to test against the specific return value of VFIO_DEVICE_SET_IRQS, since any positive return is an error indicating the number of vectors we should retry with. Signed-off-by: Longpeng(Mike) Link: https://lore.kernel.org/r/20220326060226.1892-2-longpeng2@huawei.com Signed-off-by: Alex Williamson --- hw/vfio/pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 9fd9faee1d..cab1a6ef57 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -653,7 +653,7 @@ retry: if (ret) { if (ret < 0) { error_report("vfio: Error: Failed to setup MSI fds: %m"); - } else if (ret != vdev->nr_vectors) { + } else { error_report("vfio: Error: Failed to enable %d " "MSI vectors, retry with %d", vdev->nr_vectors, ret); } @@ -671,7 +671,7 @@ retry: g_free(vdev->msi_vectors); vdev->msi_vectors = NULL; - if (ret > 0 && ret != vdev->nr_vectors) { + if (ret > 0) { vdev->nr_vectors = ret; goto retry; } From be4a46eccfe97069fd62f967f6660407c9aa2a03 Mon Sep 17 00:00:00 2001 From: "Longpeng(Mike)" Date: Sat, 26 Mar 2022 14:02:23 +0800 Subject: [PATCH 069/935] vfio: move re-enabling INTX out of the common helper Move re-enabling INTX out, and the callers should decide to re-enable it or not. Signed-off-by: Longpeng(Mike) Link: https://lore.kernel.org/r/20220326060226.1892-3-longpeng2@huawei.com Signed-off-by: Alex Williamson --- hw/vfio/pci.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index cab1a6ef57..b3c27c22aa 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -693,7 +693,6 @@ retry: static void vfio_msi_disable_common(VFIOPCIDevice *vdev) { - Error *err = NULL; int i; for (i = 0; i < vdev->nr_vectors; i++) { @@ -712,15 +711,11 @@ static void vfio_msi_disable_common(VFIOPCIDevice *vdev) vdev->msi_vectors = NULL; vdev->nr_vectors = 0; vdev->interrupt = VFIO_INT_NONE; - - vfio_intx_enable(vdev, &err); - if (err) { - error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); - } } static void vfio_msix_disable(VFIOPCIDevice *vdev) { + Error *err = NULL; int i; msix_unset_vector_notifiers(&vdev->pdev); @@ -741,6 +736,10 @@ static void vfio_msix_disable(VFIOPCIDevice *vdev) } vfio_msi_disable_common(vdev); + vfio_intx_enable(vdev, &err); + if (err) { + error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); + } memset(vdev->msix->pending, 0, BITS_TO_LONGS(vdev->msix->entries) * sizeof(unsigned long)); @@ -750,8 +749,14 @@ static void vfio_msix_disable(VFIOPCIDevice *vdev) static void vfio_msi_disable(VFIOPCIDevice *vdev) { + Error *err = NULL; + vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSI_IRQ_INDEX); vfio_msi_disable_common(vdev); + vfio_intx_enable(vdev, &err); + if (err) { + error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); + } trace_vfio_msi_disable(vdev->vbasedev.name); } From 8ab217d5d34275ee471a3b085ec90728b8f06d80 Mon Sep 17 00:00:00 2001 From: "Longpeng(Mike)" Date: Sat, 26 Mar 2022 14:02:24 +0800 Subject: [PATCH 070/935] vfio: simplify the failure path in vfio_msi_enable Use vfio_msi_disable_common to simplify the error handling in vfio_msi_enable. Signed-off-by: Longpeng(Mike) Link: https://lore.kernel.org/r/20220326060226.1892-4-longpeng2@huawei.com Signed-off-by: Alex Williamson --- hw/vfio/pci.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index b3c27c22aa..50562629ea 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -47,6 +47,7 @@ static void vfio_disable_interrupts(VFIOPCIDevice *vdev); static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled); +static void vfio_msi_disable_common(VFIOPCIDevice *vdev); /* * Disabling BAR mmaping can be slow, but toggling it around INTx can @@ -658,24 +659,12 @@ retry: "MSI vectors, retry with %d", vdev->nr_vectors, ret); } - for (i = 0; i < vdev->nr_vectors; i++) { - VFIOMSIVector *vector = &vdev->msi_vectors[i]; - if (vector->virq >= 0) { - vfio_remove_kvm_msi_virq(vector); - } - qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt), - NULL, NULL, NULL); - event_notifier_cleanup(&vector->interrupt); - } - - g_free(vdev->msi_vectors); - vdev->msi_vectors = NULL; + vfio_msi_disable_common(vdev); if (ret > 0) { vdev->nr_vectors = ret; goto retry; } - vdev->nr_vectors = 0; /* * Failing to setup MSI doesn't really fall within any specification. @@ -683,7 +672,6 @@ retry: * out to fall back to INTx for this device. */ error_report("vfio: Error: Failed to enable MSI"); - vdev->interrupt = VFIO_INT_NONE; return; } From 75d546fc18023d36779c687b948128c1a4666a96 Mon Sep 17 00:00:00 2001 From: "Longpeng(Mike)" Date: Sat, 26 Mar 2022 14:02:25 +0800 Subject: [PATCH 071/935] Revert "vfio: Avoid disabling and enabling vectors repeatedly in VFIO migration" Commit ecebe53fe993 ("vfio: Avoid disabling and enabling vectors repeatedly in VFIO migration") avoids inefficiently disabling and enabling vectors repeatedly and lets the unmasked vectors be enabled one by one. But we want to batch multiple routes and defer the commit, and only commit once outside the loop of setting vector notifiers, so we cannot enable the vectors one by one in the loop now. Revert that commit and we will take another way in the next patch, it can not only avoid disabling/enabling vectors repeatedly, but also satisfy our requirement of defer to commit. Signed-off-by: Longpeng(Mike) Link: https://lore.kernel.org/r/20220326060226.1892-5-longpeng2@huawei.com Signed-off-by: Alex Williamson --- hw/vfio/pci.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 50562629ea..8bc36f081a 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -572,9 +572,6 @@ static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr) static void vfio_msix_enable(VFIOPCIDevice *vdev) { - PCIDevice *pdev = &vdev->pdev; - unsigned int nr, max_vec = 0; - vfio_disable_interrupts(vdev); vdev->msi_vectors = g_new0(VFIOMSIVector, vdev->msix->entries); @@ -593,22 +590,11 @@ static void vfio_msix_enable(VFIOPCIDevice *vdev) * triggering to userspace, then immediately release the vector, leaving * the physical device with no vectors enabled, but MSI-X enabled, just * like the guest view. - * If there are already unmasked vectors (in migration resume phase and - * some guest startups) which will be enabled soon, we can allocate all - * of them here to avoid inefficiently disabling and enabling vectors - * repeatedly later. */ - if (!pdev->msix_function_masked) { - for (nr = 0; nr < msix_nr_vectors_allocated(pdev); nr++) { - if (!msix_is_masked(pdev, nr)) { - max_vec = nr; - } - } - } - vfio_msix_vector_do_use(pdev, max_vec, NULL, NULL); - vfio_msix_vector_release(pdev, max_vec); + vfio_msix_vector_do_use(&vdev->pdev, 0, NULL, NULL); + vfio_msix_vector_release(&vdev->pdev, 0); - if (msix_set_vector_notifiers(pdev, vfio_msix_vector_use, + if (msix_set_vector_notifiers(&vdev->pdev, vfio_msix_vector_use, vfio_msix_vector_release, NULL)) { error_report("vfio: msix_set_vector_notifiers failed"); } From dc580d51f7dd3e02134957be2b771636ac59e868 Mon Sep 17 00:00:00 2001 From: "Longpeng(Mike)" Date: Sat, 26 Mar 2022 14:02:26 +0800 Subject: [PATCH 072/935] vfio: defer to commit kvm irq routing when enable msi/msix In migration resume phase, all unmasked msix vectors need to be setup when loading the VF state. However, the setup operation would take longer if the VM has more VFs and each VF has more unmasked vectors. The hot spot is kvm_irqchip_commit_routes, it'll scan and update all irqfds that are already assigned each invocation, so more vectors means need more time to process them. vfio_pci_load_config vfio_msix_enable msix_set_vector_notifiers for (vector = 0; vector < dev->msix_entries_nr; vector++) { vfio_msix_vector_do_use vfio_add_kvm_msi_virq kvm_irqchip_commit_routes <-- expensive } We can reduce the cost by only committing once outside the loop. The routes are cached in kvm_state, we commit them first and then bind irqfd for each vector. The test VM has 128 vcpus and 8 VF (each one has 65 vectors), we measure the cost of the vfio_msix_enable for each VF, and we can see 90+% costs can be reduce. VF Count of irqfds[*] Original With this patch 1st 65 8 2 2nd 130 15 2 3rd 195 22 2 4th 260 24 3 5th 325 36 2 6th 390 44 3 7th 455 51 3 8th 520 58 4 Total 258ms 21ms [*] Count of irqfds How many irqfds that already assigned and need to process in this round. The optimization can be applied to msi type too. Signed-off-by: Longpeng(Mike) Link: https://lore.kernel.org/r/20220326060226.1892-6-longpeng2@huawei.com Signed-off-by: Alex Williamson --- hw/vfio/pci.c | 130 +++++++++++++++++++++++++++++++++++++------------- hw/vfio/pci.h | 2 + 2 files changed, 99 insertions(+), 33 deletions(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 8bc36f081a..ef9d7bf326 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -45,6 +45,9 @@ #define TYPE_VFIO_PCI_NOHOTPLUG "vfio-pci-nohotplug" +/* Protected by BQL */ +static KVMRouteChange vfio_route_change; + static void vfio_disable_interrupts(VFIOPCIDevice *vdev); static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled); static void vfio_msi_disable_common(VFIOPCIDevice *vdev); @@ -413,33 +416,36 @@ static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix) static void vfio_add_kvm_msi_virq(VFIOPCIDevice *vdev, VFIOMSIVector *vector, int vector_n, bool msix) { - KVMRouteChange c; - int virq; - if ((msix && vdev->no_kvm_msix) || (!msix && vdev->no_kvm_msi)) { return; } - if (event_notifier_init(&vector->kvm_interrupt, 0)) { + vector->virq = kvm_irqchip_add_msi_route(&vfio_route_change, + vector_n, &vdev->pdev); +} + +static void vfio_connect_kvm_msi_virq(VFIOMSIVector *vector) +{ + if (vector->virq < 0) { return; } - c = kvm_irqchip_begin_route_changes(kvm_state); - virq = kvm_irqchip_add_msi_route(&c, vector_n, &vdev->pdev); - if (virq < 0) { - event_notifier_cleanup(&vector->kvm_interrupt); - return; + if (event_notifier_init(&vector->kvm_interrupt, 0)) { + goto fail_notifier; } - kvm_irqchip_commit_route_changes(&c); if (kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, &vector->kvm_interrupt, - NULL, virq) < 0) { - kvm_irqchip_release_virq(kvm_state, virq); - event_notifier_cleanup(&vector->kvm_interrupt); - return; + NULL, vector->virq) < 0) { + goto fail_kvm; } - vector->virq = virq; + return; + +fail_kvm: + event_notifier_cleanup(&vector->kvm_interrupt); +fail_notifier: + kvm_irqchip_release_virq(kvm_state, vector->virq); + vector->virq = -1; } static void vfio_remove_kvm_msi_virq(VFIOMSIVector *vector) @@ -494,7 +500,14 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, } } else { if (msg) { - vfio_add_kvm_msi_virq(vdev, vector, nr, true); + if (vdev->defer_kvm_irq_routing) { + vfio_add_kvm_msi_virq(vdev, vector, nr, true); + } else { + vfio_route_change = kvm_irqchip_begin_route_changes(kvm_state); + vfio_add_kvm_msi_virq(vdev, vector, nr, true); + kvm_irqchip_commit_route_changes(&vfio_route_change); + vfio_connect_kvm_msi_virq(vector); + } } } @@ -504,11 +517,13 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, * increase them as needed. */ if (vdev->nr_vectors < nr + 1) { - vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX); vdev->nr_vectors = nr + 1; - ret = vfio_enable_vectors(vdev, true); - if (ret) { - error_report("vfio: failed to enable vectors, %d", ret); + if (!vdev->defer_kvm_irq_routing) { + vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX); + ret = vfio_enable_vectors(vdev, true); + if (ret) { + error_report("vfio: failed to enable vectors, %d", ret); + } } } else { Error *err = NULL; @@ -570,6 +585,27 @@ static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr) } } +static void vfio_prepare_kvm_msi_virq_batch(VFIOPCIDevice *vdev) +{ + assert(!vdev->defer_kvm_irq_routing); + vdev->defer_kvm_irq_routing = true; + vfio_route_change = kvm_irqchip_begin_route_changes(kvm_state); +} + +static void vfio_commit_kvm_msi_virq_batch(VFIOPCIDevice *vdev) +{ + int i; + + assert(vdev->defer_kvm_irq_routing); + vdev->defer_kvm_irq_routing = false; + + kvm_irqchip_commit_route_changes(&vfio_route_change); + + for (i = 0; i < vdev->nr_vectors; i++) { + vfio_connect_kvm_msi_virq(&vdev->msi_vectors[i]); + } +} + static void vfio_msix_enable(VFIOPCIDevice *vdev) { vfio_disable_interrupts(vdev); @@ -579,26 +615,45 @@ static void vfio_msix_enable(VFIOPCIDevice *vdev) vdev->interrupt = VFIO_INT_MSIX; /* - * Some communication channels between VF & PF or PF & fw rely on the - * physical state of the device and expect that enabling MSI-X from the - * guest enables the same on the host. When our guest is Linux, the - * guest driver call to pci_enable_msix() sets the enabling bit in the - * MSI-X capability, but leaves the vector table masked. We therefore - * can't rely on a vector_use callback (from request_irq() in the guest) - * to switch the physical device into MSI-X mode because that may come a - * long time after pci_enable_msix(). This code enables vector 0 with - * triggering to userspace, then immediately release the vector, leaving - * the physical device with no vectors enabled, but MSI-X enabled, just - * like the guest view. + * Setting vector notifiers triggers synchronous vector-use + * callbacks for each active vector. Deferring to commit the KVM + * routes once rather than per vector provides a substantial + * performance improvement. */ - vfio_msix_vector_do_use(&vdev->pdev, 0, NULL, NULL); - vfio_msix_vector_release(&vdev->pdev, 0); + vfio_prepare_kvm_msi_virq_batch(vdev); if (msix_set_vector_notifiers(&vdev->pdev, vfio_msix_vector_use, vfio_msix_vector_release, NULL)) { error_report("vfio: msix_set_vector_notifiers failed"); } + vfio_commit_kvm_msi_virq_batch(vdev); + + if (vdev->nr_vectors) { + int ret; + + ret = vfio_enable_vectors(vdev, true); + if (ret) { + error_report("vfio: failed to enable vectors, %d", ret); + } + } else { + /* + * Some communication channels between VF & PF or PF & fw rely on the + * physical state of the device and expect that enabling MSI-X from the + * guest enables the same on the host. When our guest is Linux, the + * guest driver call to pci_enable_msix() sets the enabling bit in the + * MSI-X capability, but leaves the vector table masked. We therefore + * can't rely on a vector_use callback (from request_irq() in the guest) + * to switch the physical device into MSI-X mode because that may come a + * long time after pci_enable_msix(). This code enables vector 0 with + * triggering to userspace, then immediately release the vector, leaving + * the physical device with no vectors enabled, but MSI-X enabled, just + * like the guest view. + */ + vfio_msix_vector_do_use(&vdev->pdev, 0, NULL, NULL); + vfio_msix_vector_release(&vdev->pdev, 0); + } + trace_vfio_msix_enable(vdev->vbasedev.name); } @@ -608,6 +663,13 @@ static void vfio_msi_enable(VFIOPCIDevice *vdev) vfio_disable_interrupts(vdev); + /* + * Setting vector notifiers needs to enable route for each vector. + * Deferring to commit the KVM routes once rather than per vector + * provides a substantial performance improvement. + */ + vfio_prepare_kvm_msi_virq_batch(vdev); + vdev->nr_vectors = msi_nr_vectors_allocated(&vdev->pdev); retry: vdev->msi_vectors = g_new0(VFIOMSIVector, vdev->nr_vectors); @@ -633,6 +695,8 @@ retry: vfio_add_kvm_msi_virq(vdev, vector, i, false); } + vfio_commit_kvm_msi_virq_batch(vdev); + /* Set interrupt type prior to possible interrupts */ vdev->interrupt = VFIO_INT_MSI; diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h index 64777516d1..7c236a52f4 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -19,6 +19,7 @@ #include "qemu/queue.h" #include "qemu/timer.h" #include "qom/object.h" +#include "sysemu/kvm.h" #define PCI_ANY_ID (~0) @@ -171,6 +172,7 @@ struct VFIOPCIDevice { bool no_kvm_ioeventfd; bool no_vfio_ioeventfd; bool enable_ramfb; + bool defer_kvm_irq_routing; VFIODisplay *dpy; Notifier irqchip_change_notifier; }; From 99510d271b173f21a7a1e8a238b5f35d9e88a147 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Sat, 16 Apr 2022 17:08:24 +0800 Subject: [PATCH 073/935] vfio/common: Fix a small boundary issue of a trace It uses [offset, offset + size - 1] to indicate that the length of range is size in most places in vfio trace code (such as trace_vfio_region_region_mmap()) execpt trace_vfio_region_sparse_mmap_entry(). So change it for trace_vfio_region_sparse_mmap_entry(), but if size is zero, the trace will be weird with an underflow, so move the trace and trace it only if size is not zero. Signed-off-by: Xiang Chen Link: https://lore.kernel.org/r/1650100104-130737-1-git-send-email-chenxiang66@hisilicon.com Signed-off-by: Alex Williamson --- hw/vfio/common.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 2b1f78fdfa..6065834717 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1544,11 +1544,10 @@ static int vfio_setup_region_sparse_mmaps(VFIORegion *region, region->mmaps = g_new0(VFIOMmap, sparse->nr_areas); for (i = 0, j = 0; i < sparse->nr_areas; i++) { - trace_vfio_region_sparse_mmap_entry(i, sparse->areas[i].offset, - sparse->areas[i].offset + - sparse->areas[i].size); - if (sparse->areas[i].size) { + trace_vfio_region_sparse_mmap_entry(i, sparse->areas[i].offset, + sparse->areas[i].offset + + sparse->areas[i].size - 1); region->mmaps[j].offset = sparse->areas[i].offset; region->mmaps[j].size = sparse->areas[i].size; j++; From 4168cdad398843ed53d650a27651868b4d3e21c9 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Fri, 6 May 2022 15:25:09 +0200 Subject: [PATCH 074/935] sysemu: tpm: Add a stub function for TPM_IS_CRB In a subsequent patch, VFIO will need to recognize if a memory region owner is a TPM CRB device. Hence VFIO needs to use TPM_IS_CRB() even if CONFIG_TPM is unset. So let's add a stub function. Signed-off-by: Eric Auger Suggested-by: Cornelia Huck Reviewed-by: Stefan Berger Link: https://lore.kernel.org/r/20220506132510.1847942-2-eric.auger@redhat.com Signed-off-by: Alex Williamson --- include/sysemu/tpm.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h index 68b2206463..fb40e30ff6 100644 --- a/include/sysemu/tpm.h +++ b/include/sysemu/tpm.h @@ -80,6 +80,12 @@ static inline TPMVersion tpm_get_version(TPMIf *ti) #define tpm_init() (0) #define tpm_cleanup() +/* needed for an alignment check in non-tpm code */ +static inline Object *TPM_IS_CRB(Object *obj) +{ + return NULL; +} + #endif /* CONFIG_TPM */ #endif /* QEMU_TPM_H */ From 851d6d1a0ff29a87ec588205842edf6b86d99b5c Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Fri, 6 May 2022 15:25:10 +0200 Subject: [PATCH 075/935] vfio/common: remove spurious tpm-crb-cmd misalignment warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CRB command buffer currently is a RAM MemoryRegion and given its base address alignment, it causes an error report on vfio_listener_region_add(). This region could have been a RAM device region, easing the detection of such safe situation but this option was not well received. So let's add a helper function that uses the memory region owner type to detect the situation is safe wrt the assignment. Other device types can be checked here if such kind of problem occurs again. Signed-off-by: Eric Auger Reviewed-by: Philippe Mathieu-Daudé Acked-by: Stefan Berger Reviewed-by: Cornelia Huck Link: https://lore.kernel.org/r/20220506132510.1847942-3-eric.auger@redhat.com Signed-off-by: Alex Williamson --- hw/vfio/common.c | 27 ++++++++++++++++++++++++++- hw/vfio/trace-events | 1 + 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 6065834717..cfcb71974a 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -40,6 +40,7 @@ #include "trace.h" #include "qapi/error.h" #include "migration/migration.h" +#include "sysemu/tpm.h" VFIOGroupList vfio_group_list = QLIST_HEAD_INITIALIZER(vfio_group_list); @@ -861,6 +862,22 @@ static void vfio_unregister_ram_discard_listener(VFIOContainer *container, g_free(vrdl); } +static bool vfio_known_safe_misalignment(MemoryRegionSection *section) +{ + MemoryRegion *mr = section->mr; + + if (!TPM_IS_CRB(mr->owner)) { + return false; + } + + /* this is a known safe misaligned region, just trace for debug purpose */ + trace_vfio_known_safe_misalignment(memory_region_name(mr), + section->offset_within_address_space, + section->offset_within_region, + qemu_real_host_page_size()); + return true; +} + static void vfio_listener_region_add(MemoryListener *listener, MemoryRegionSection *section) { @@ -884,7 +901,15 @@ static void vfio_listener_region_add(MemoryListener *listener, if (unlikely((section->offset_within_address_space & ~qemu_real_host_page_mask()) != (section->offset_within_region & ~qemu_real_host_page_mask()))) { - error_report("%s received unaligned region", __func__); + if (!vfio_known_safe_misalignment(section)) { + error_report("%s received unaligned region %s iova=0x%"PRIx64 + " offset_within_region=0x%"PRIx64 + " qemu_real_host_page_size=0x%"PRIxPTR, + __func__, memory_region_name(section->mr), + section->offset_within_address_space, + section->offset_within_region, + qemu_real_host_page_size()); + } return; } diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index 0ef1b5f4a6..582882db91 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -100,6 +100,7 @@ vfio_listener_region_add_skip(uint64_t start, uint64_t end) "SKIPPING region_add vfio_spapr_group_attach(int groupfd, int tablefd) "Attached groupfd %d to liobn fd %d" vfio_listener_region_add_iommu(uint64_t start, uint64_t end) "region_add [iommu] 0x%"PRIx64" - 0x%"PRIx64 vfio_listener_region_add_ram(uint64_t iova_start, uint64_t iova_end, void *vaddr) "region_add [ram] 0x%"PRIx64" - 0x%"PRIx64" [%p]" +vfio_known_safe_misalignment(const char *name, uint64_t iova, uint64_t offset_within_region, uintptr_t page_size) "Region \"%s\" iova=0x%"PRIx64" offset_within_region=0x%"PRIx64" qemu_real_host_page_size=0x%"PRIxPTR ": cannot be mapped for DMA" vfio_listener_region_add_no_dma_map(const char *name, uint64_t iova, uint64_t size, uint64_t page_size) "Region \"%s\" 0x%"PRIx64" size=0x%"PRIx64" is not aligned to 0x%"PRIx64" and cannot be mapped for DMA" vfio_listener_region_del_skip(uint64_t start, uint64_t end) "SKIPPING region_del 0x%"PRIx64" - 0x%"PRIx64 vfio_listener_region_del(uint64_t start, uint64_t end) "region_del 0x%"PRIx64" - 0x%"PRIx64 From 9d38ffc5d82839cdc9effb2e9ee84a6941a25e1a Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 2 May 2022 02:42:21 -0700 Subject: [PATCH 076/935] hw/vfio/pci: fix vfio_pci_hot_reset_result trace point "%m" format specifier is not interpreted by the trace infrastructure and thus "%m" is output instead of the actual errno string. Fix it by outputting strerror(errno). Signed-off-by: Eric Auger Signed-off-by: Yi Liu Link: https://lore.kernel.org/r/20220502094223.36384-2-yi.l.liu@intel.com [aw: replace commit log as provided by Eric] Signed-off-by: Alex Williamson --- hw/vfio/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index ef9d7bf326..cb912bd3f4 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -2380,7 +2380,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single) g_free(reset); trace_vfio_pci_hot_reset_result(vdev->vbasedev.name, - ret ? "%m" : "Success"); + ret ? strerror(errno) : "Success"); out: /* Re-enable INTx on affected devices */ From 0d570a2572395cca79b83002e589aeb24fcd1732 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 2 May 2022 02:42:22 -0700 Subject: [PATCH 077/935] vfio/pci: Use vbasedev local variable in vfio_realize() Using a VFIODevice handle local variable to improve the code readability. no functional change intended Signed-off-by: Eric Auger Signed-off-by: Yi Liu Link: https://lore.kernel.org/r/20220502094223.36384-3-yi.l.liu@intel.com Signed-off-by: Alex Williamson --- hw/vfio/pci.c | 49 +++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index cb912bd3f4..939dcc3d4a 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -2846,6 +2846,7 @@ static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev) static void vfio_realize(PCIDevice *pdev, Error **errp) { VFIOPCIDevice *vdev = VFIO_PCI(pdev); + VFIODevice *vbasedev = &vdev->vbasedev; VFIODevice *vbasedev_iter; VFIOGroup *group; char *tmp, *subsys, group_path[PATH_MAX], *group_name; @@ -2856,7 +2857,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) int i, ret; bool is_mdev; - if (!vdev->vbasedev.sysfsdev) { + if (!vbasedev->sysfsdev) { if (!(~vdev->host.domain || ~vdev->host.bus || ~vdev->host.slot || ~vdev->host.function)) { error_setg(errp, "No provided host device"); @@ -2864,24 +2865,24 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) "or -device vfio-pci,sysfsdev=PATH_TO_DEVICE\n"); return; } - vdev->vbasedev.sysfsdev = + vbasedev->sysfsdev = g_strdup_printf("/sys/bus/pci/devices/%04x:%02x:%02x.%01x", vdev->host.domain, vdev->host.bus, vdev->host.slot, vdev->host.function); } - if (stat(vdev->vbasedev.sysfsdev, &st) < 0) { + if (stat(vbasedev->sysfsdev, &st) < 0) { error_setg_errno(errp, errno, "no such host device"); - error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.sysfsdev); + error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->sysfsdev); return; } - vdev->vbasedev.name = g_path_get_basename(vdev->vbasedev.sysfsdev); - vdev->vbasedev.ops = &vfio_pci_ops; - vdev->vbasedev.type = VFIO_DEVICE_TYPE_PCI; - vdev->vbasedev.dev = DEVICE(vdev); + vbasedev->name = g_path_get_basename(vbasedev->sysfsdev); + vbasedev->ops = &vfio_pci_ops; + vbasedev->type = VFIO_DEVICE_TYPE_PCI; + vbasedev->dev = DEVICE(vdev); - tmp = g_strdup_printf("%s/iommu_group", vdev->vbasedev.sysfsdev); + tmp = g_strdup_printf("%s/iommu_group", vbasedev->sysfsdev); len = readlink(tmp, group_path, sizeof(group_path)); g_free(tmp); @@ -2899,7 +2900,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) goto error; } - trace_vfio_realize(vdev->vbasedev.name, groupid); + trace_vfio_realize(vbasedev->name, groupid); group = vfio_get_group(groupid, pci_device_iommu_address_space(pdev), errp); if (!group) { @@ -2907,7 +2908,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) } QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { - if (strcmp(vbasedev_iter->name, vdev->vbasedev.name) == 0) { + if (strcmp(vbasedev_iter->name, vbasedev->name) == 0) { error_setg(errp, "device is already attached"); vfio_put_group(group); goto error; @@ -2920,22 +2921,22 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) * stays in sync with the active working set of the guest driver. Prevent * the x-balloon-allowed option unless this is minimally an mdev device. */ - tmp = g_strdup_printf("%s/subsystem", vdev->vbasedev.sysfsdev); + tmp = g_strdup_printf("%s/subsystem", vbasedev->sysfsdev); subsys = realpath(tmp, NULL); g_free(tmp); is_mdev = subsys && (strcmp(subsys, "/sys/bus/mdev") == 0); free(subsys); - trace_vfio_mdev(vdev->vbasedev.name, is_mdev); + trace_vfio_mdev(vbasedev->name, is_mdev); - if (vdev->vbasedev.ram_block_discard_allowed && !is_mdev) { + if (vbasedev->ram_block_discard_allowed && !is_mdev) { error_setg(errp, "x-balloon-allowed only potentially compatible " "with mdev devices"); vfio_put_group(group); goto error; } - ret = vfio_get_device(group, vdev->vbasedev.name, &vdev->vbasedev, errp); + ret = vfio_get_device(group, vbasedev->name, vbasedev, errp); if (ret) { vfio_put_group(group); goto error; @@ -2948,7 +2949,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) } /* Get a copy of config space */ - ret = pread(vdev->vbasedev.fd, vdev->pdev.config, + ret = pread(vbasedev->fd, vdev->pdev.config, MIN(pci_config_size(&vdev->pdev), vdev->config_size), vdev->config_offset); if (ret < (int)MIN(pci_config_size(&vdev->pdev), vdev->config_size)) { @@ -2976,7 +2977,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) goto error; } vfio_add_emulated_word(vdev, PCI_VENDOR_ID, vdev->vendor_id, ~0); - trace_vfio_pci_emulated_vendor_id(vdev->vbasedev.name, vdev->vendor_id); + trace_vfio_pci_emulated_vendor_id(vbasedev->name, vdev->vendor_id); } else { vdev->vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID); } @@ -2987,7 +2988,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) goto error; } vfio_add_emulated_word(vdev, PCI_DEVICE_ID, vdev->device_id, ~0); - trace_vfio_pci_emulated_device_id(vdev->vbasedev.name, vdev->device_id); + trace_vfio_pci_emulated_device_id(vbasedev->name, vdev->device_id); } else { vdev->device_id = pci_get_word(pdev->config + PCI_DEVICE_ID); } @@ -2999,7 +3000,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) } vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_VENDOR_ID, vdev->sub_vendor_id, ~0); - trace_vfio_pci_emulated_sub_vendor_id(vdev->vbasedev.name, + trace_vfio_pci_emulated_sub_vendor_id(vbasedev->name, vdev->sub_vendor_id); } @@ -3009,7 +3010,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) goto error; } vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_ID, vdev->sub_device_id, ~0); - trace_vfio_pci_emulated_sub_device_id(vdev->vbasedev.name, + trace_vfio_pci_emulated_sub_device_id(vbasedev->name, vdev->sub_device_id); } @@ -3068,7 +3069,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) goto out_teardown; } - ret = vfio_get_dev_region_info(&vdev->vbasedev, + ret = vfio_get_dev_region_info(vbasedev, VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL, VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION, &opregion); if (ret) { @@ -3144,9 +3145,9 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) } if (!pdev->failover_pair_id) { - ret = vfio_migration_probe(&vdev->vbasedev, errp); + ret = vfio_migration_probe(vbasedev, errp); if (ret) { - error_report("%s: Migration disabled", vdev->vbasedev.name); + error_report("%s: Migration disabled", vbasedev->name); } } @@ -3163,7 +3164,7 @@ out_teardown: vfio_teardown_msi(vdev); vfio_bars_exit(vdev); error: - error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.name); + error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->name); } static void vfio_instance_finalize(Object *obj) From 44ee6aaae0c937abb631e57a9853c2cdef2bc9bb Mon Sep 17 00:00:00 2001 From: Yi Liu Date: Mon, 2 May 2022 02:42:23 -0700 Subject: [PATCH 078/935] vfio/common: Rename VFIOGuestIOMMU::iommu into ::iommu_mr Rename VFIOGuestIOMMU iommu field into iommu_mr. Then it becomes clearer it is an IOMMU memory region. no functional change intended Signed-off-by: Yi Liu Link: https://lore.kernel.org/r/20220502094223.36384-4-yi.l.liu@intel.com Signed-off-by: Alex Williamson --- hw/vfio/common.c | 16 ++++++++-------- include/hw/vfio/vfio-common.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index cfcb71974a..159f910421 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1017,7 +1017,7 @@ static void vfio_listener_region_add(MemoryListener *listener, * device emulation the VFIO iommu handles to use). */ giommu = g_malloc0(sizeof(*giommu)); - giommu->iommu = iommu_mr; + giommu->iommu_mr = iommu_mr; giommu->iommu_offset = section->offset_within_address_space - section->offset_within_region; giommu->container = container; @@ -1032,7 +1032,7 @@ static void vfio_listener_region_add(MemoryListener *listener, int128_get64(llend), iommu_idx); - ret = memory_region_iommu_set_page_size_mask(giommu->iommu, + ret = memory_region_iommu_set_page_size_mask(giommu->iommu_mr, container->pgsizes, &err); if (ret) { @@ -1047,7 +1047,7 @@ static void vfio_listener_region_add(MemoryListener *listener, goto fail; } QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next); - memory_region_iommu_replay(giommu->iommu, &giommu->n); + memory_region_iommu_replay(giommu->iommu_mr, &giommu->n); return; } @@ -1153,7 +1153,7 @@ static void vfio_listener_region_del(MemoryListener *listener, VFIOGuestIOMMU *giommu; QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) { - if (MEMORY_REGION(giommu->iommu) == section->mr && + if (MEMORY_REGION(giommu->iommu_mr) == section->mr && giommu->n.start == section->offset_within_region) { memory_region_unregister_iommu_notifier(section->mr, &giommu->n); @@ -1418,11 +1418,11 @@ static int vfio_sync_dirty_bitmap(VFIOContainer *container, VFIOGuestIOMMU *giommu; QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) { - if (MEMORY_REGION(giommu->iommu) == section->mr && + if (MEMORY_REGION(giommu->iommu_mr) == section->mr && giommu->n.start == section->offset_within_region) { Int128 llend; vfio_giommu_dirty_notifier gdn = { .giommu = giommu }; - int idx = memory_region_iommu_attrs_to_index(giommu->iommu, + int idx = memory_region_iommu_attrs_to_index(giommu->iommu_mr, MEMTXATTRS_UNSPECIFIED); llend = int128_add(int128_make64(section->offset_within_region), @@ -1435,7 +1435,7 @@ static int vfio_sync_dirty_bitmap(VFIOContainer *container, section->offset_within_region, int128_get64(llend), idx); - memory_region_iommu_replay(giommu->iommu, &gdn.n); + memory_region_iommu_replay(giommu->iommu_mr, &gdn.n); break; } } @@ -2270,7 +2270,7 @@ static void vfio_disconnect_container(VFIOGroup *group) QLIST_FOREACH_SAFE(giommu, &container->giommu_list, giommu_next, tmp) { memory_region_unregister_iommu_notifier( - MEMORY_REGION(giommu->iommu), &giommu->n); + MEMORY_REGION(giommu->iommu_mr), &giommu->n); QLIST_REMOVE(giommu, giommu_next); g_free(giommu); } diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 8af11b0a76..e573f5a9f1 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -98,7 +98,7 @@ typedef struct VFIOContainer { typedef struct VFIOGuestIOMMU { VFIOContainer *container; - IOMMUMemoryRegion *iommu; + IOMMUMemoryRegion *iommu_mr; hwaddr iommu_offset; IOMMUNotifier n; QLIST_ENTRY(VFIOGuestIOMMU) giommu_next; From 0269a6cf4ebff2eb6d8f893a5179be818efa90c2 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Thu, 21 Apr 2022 13:08:23 -0700 Subject: [PATCH 079/935] target/xtensa: fix missing tcg_temp_free in gen_window_check pc and w are allocated with tcg_const_i32 but not freed in gen_window_check. Use tcg_constant_i32 for them both. Fixes: 2db59a76c421 ("target-xtensa: record available window in TB flags") Reviewed-by: Richard Henderson Signed-off-by: Max Filippov --- target/xtensa/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 1485df2f22..591d87b4ef 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -571,8 +571,8 @@ static bool gen_window_check(DisasContext *dc, uint32_t mask) unsigned r = 31 - clz32(mask); if (r / 4 > dc->window) { - TCGv_i32 pc = tcg_const_i32(dc->pc); - TCGv_i32 w = tcg_const_i32(r / 4); + TCGv_i32 pc = tcg_constant_i32(dc->pc); + TCGv_i32 w = tcg_constant_i32(r / 4); gen_helper_window_check(cpu_env, pc, w); dc->base.is_jmp = DISAS_NORETURN; From 2b570a178a59338ad7512478c7dda06f07658506 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Thu, 21 Apr 2022 13:27:27 -0700 Subject: [PATCH 080/935] target/xtensa: use tcg_contatnt_* for numeric literals Replace tcg_const_* for numeric literals with tcg_constant_*. Reviewed-by: Richard Henderson Signed-off-by: Max Filippov --- target/xtensa/translate.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 591d87b4ef..58b3e32dcb 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -306,16 +306,14 @@ static void gen_right_shift_sar(DisasContext *dc, TCGv_i32 sa) static void gen_left_shift_sar(DisasContext *dc, TCGv_i32 sa) { - TCGv_i32 tmp = tcg_const_i32(32); if (!dc->sar_m32_allocated) { dc->sar_m32 = tcg_temp_local_new_i32(); dc->sar_m32_allocated = true; } tcg_gen_andi_i32(dc->sar_m32, sa, 0x1f); - tcg_gen_sub_i32(cpu_SR[SAR], tmp, dc->sar_m32); + tcg_gen_sub_i32(cpu_SR[SAR], tcg_constant_i32(32), dc->sar_m32); dc->sar_5bit = false; dc->sar_m32_5bit = true; - tcg_temp_free(tmp); } static void gen_exception(DisasContext *dc, int excp) @@ -1957,11 +1955,10 @@ static void translate_mov(DisasContext *dc, const OpcodeArg arg[], static void translate_movcond(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 zero = tcg_constant_i32(0); tcg_gen_movcond_i32(par[0], arg[0].out, arg[2].in, zero, arg[1].in, arg[0].in); - tcg_temp_free(zero); } static void translate_movi(DisasContext *dc, const OpcodeArg arg[], @@ -1973,7 +1970,7 @@ static void translate_movi(DisasContext *dc, const OpcodeArg arg[], static void translate_movp(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 zero = tcg_constant_i32(0); TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_andi_i32(tmp, arg[2].in, 1 << arg[2].imm); @@ -1981,7 +1978,6 @@ static void translate_movp(DisasContext *dc, const OpcodeArg arg[], arg[0].out, tmp, zero, arg[1].in, arg[0].in); tcg_temp_free(tmp); - tcg_temp_free(zero); } static void translate_movsp(DisasContext *dc, const OpcodeArg arg[], @@ -6444,7 +6440,7 @@ static void translate_compare_d(DisasContext *dc, const OpcodeArg arg[], [COMPARE_OLE] = gen_helper_ole_d, [COMPARE_ULE] = gen_helper_ule_d, }; - TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 zero = tcg_constant_i32(0); TCGv_i32 res = tcg_temp_new_i32(); TCGv_i32 set_br = tcg_temp_new_i32(); TCGv_i32 clr_br = tcg_temp_new_i32(); @@ -6456,7 +6452,6 @@ static void translate_compare_d(DisasContext *dc, const OpcodeArg arg[], tcg_gen_movcond_i32(TCG_COND_NE, arg[0].out, res, zero, set_br, clr_br); - tcg_temp_free(zero); tcg_temp_free(res); tcg_temp_free(set_br); tcg_temp_free(clr_br); @@ -6476,7 +6471,7 @@ static void translate_compare_s(DisasContext *dc, const OpcodeArg arg[], [COMPARE_ULE] = gen_helper_ule_s, }; OpcodeArg arg32[3]; - TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 zero = tcg_constant_i32(0); TCGv_i32 res = tcg_temp_new_i32(); TCGv_i32 set_br = tcg_temp_new_i32(); TCGv_i32 clr_br = tcg_temp_new_i32(); @@ -6490,7 +6485,6 @@ static void translate_compare_s(DisasContext *dc, const OpcodeArg arg[], arg[0].out, res, zero, set_br, clr_br); put_f32_i2(arg, arg32, 1, 2); - tcg_temp_free(zero); tcg_temp_free(res); tcg_temp_free(set_br); tcg_temp_free(clr_br); @@ -6666,14 +6660,13 @@ static void translate_mov_s(DisasContext *dc, const OpcodeArg arg[], static void translate_movcond_d(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i64 zero = tcg_const_i64(0); + TCGv_i64 zero = tcg_constant_i64(0); TCGv_i64 arg2 = tcg_temp_new_i64(); tcg_gen_ext_i32_i64(arg2, arg[2].in); tcg_gen_movcond_i64(par[0], arg[0].out, arg2, zero, arg[1].in, arg[0].in); - tcg_temp_free_i64(zero); tcg_temp_free_i64(arg2); } @@ -6681,12 +6674,11 @@ static void translate_movcond_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { if (arg[0].num_bits == 32) { - TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 zero = tcg_constant_i32(0); tcg_gen_movcond_i32(par[0], arg[0].out, arg[2].in, zero, arg[1].in, arg[0].in); - tcg_temp_free(zero); } else { translate_movcond_d(dc, arg, par); } @@ -6695,7 +6687,7 @@ static void translate_movcond_s(DisasContext *dc, const OpcodeArg arg[], static void translate_movp_d(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i64 zero = tcg_const_i64(0); + TCGv_i64 zero = tcg_constant_i64(0); TCGv_i32 tmp1 = tcg_temp_new_i32(); TCGv_i64 tmp2 = tcg_temp_new_i64(); @@ -6704,7 +6696,6 @@ static void translate_movp_d(DisasContext *dc, const OpcodeArg arg[], tcg_gen_movcond_i64(par[0], arg[0].out, tmp2, zero, arg[1].in, arg[0].in); - tcg_temp_free_i64(zero); tcg_temp_free_i32(tmp1); tcg_temp_free_i64(tmp2); } @@ -6713,7 +6704,7 @@ static void translate_movp_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { if (arg[0].num_bits == 32) { - TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 zero = tcg_constant_i32(0); TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_andi_i32(tmp, arg[2].in, 1 << arg[2].imm); @@ -6721,7 +6712,6 @@ static void translate_movp_s(DisasContext *dc, const OpcodeArg arg[], arg[0].out, tmp, zero, arg[1].in, arg[0].in); tcg_temp_free(tmp); - tcg_temp_free(zero); } else { translate_movp_d(dc, arg, par); } From f99fbd125b916b484d2d92428e3cd8746cbef14c Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Thu, 21 Apr 2022 13:38:58 -0700 Subject: [PATCH 081/935] target/xtensa: use tcg_constant_* for exceptions Use tcg_contant_* for exception number, exception cause, debug cause code and exception PC. Reviewed-by: Richard Henderson Signed-off-by: Max Filippov --- target/xtensa/translate.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 58b3e32dcb..a21cfa91ed 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -318,18 +318,13 @@ static void gen_left_shift_sar(DisasContext *dc, TCGv_i32 sa) static void gen_exception(DisasContext *dc, int excp) { - TCGv_i32 tmp = tcg_const_i32(excp); - gen_helper_exception(cpu_env, tmp); - tcg_temp_free(tmp); + gen_helper_exception(cpu_env, tcg_constant_i32(excp)); } static void gen_exception_cause(DisasContext *dc, uint32_t cause) { - TCGv_i32 tpc = tcg_const_i32(dc->pc); - TCGv_i32 tcause = tcg_const_i32(cause); - gen_helper_exception_cause(cpu_env, tpc, tcause); - tcg_temp_free(tpc); - tcg_temp_free(tcause); + TCGv_i32 pc = tcg_constant_i32(dc->pc); + gen_helper_exception_cause(cpu_env, pc, tcg_constant_i32(cause)); if (cause == ILLEGAL_INSTRUCTION_CAUSE || cause == SYSCALL_CAUSE) { dc->base.is_jmp = DISAS_NORETURN; @@ -338,11 +333,8 @@ static void gen_exception_cause(DisasContext *dc, uint32_t cause) static void gen_debug_exception(DisasContext *dc, uint32_t cause) { - TCGv_i32 tpc = tcg_const_i32(dc->pc); - TCGv_i32 tcause = tcg_const_i32(cause); - gen_helper_debug_exception(cpu_env, tpc, tcause); - tcg_temp_free(tpc); - tcg_temp_free(tcause); + TCGv_i32 pc = tcg_constant_i32(dc->pc); + gen_helper_debug_exception(cpu_env, pc, tcg_constant_i32(cause)); if (cause & (DEBUGCAUSE_IB | DEBUGCAUSE_BI | DEBUGCAUSE_BN)) { dc->base.is_jmp = DISAS_NORETURN; } From 4ee412df69907b5fc91489732b4013f23dc91083 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Thu, 21 Apr 2022 13:38:58 -0700 Subject: [PATCH 082/935] target/xtensa: use tcg_constant_* for TLB opcodes dtlb is a boolean flag, use tcg_constant_* for it. Reviewed-by: Richard Henderson Signed-off-by: Max Filippov --- target/xtensa/translate.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index a21cfa91ed..3cfcbf93a7 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -1708,10 +1708,9 @@ static void translate_itlb(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - TCGv_i32 dtlb = tcg_const_i32(par[0]); + TCGv_i32 dtlb = tcg_constant_i32(par[0]); gen_helper_itlb(cpu_env, arg[0].in, dtlb); - tcg_temp_free(dtlb); #endif } @@ -2048,11 +2047,10 @@ static void translate_ptlb(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - TCGv_i32 dtlb = tcg_const_i32(par[0]); + TCGv_i32 dtlb = tcg_constant_i32(par[0]); tcg_gen_movi_i32(cpu_pc, dc->pc); gen_helper_ptlb(arg[0].out, cpu_env, arg[1].in, dtlb); - tcg_temp_free(dtlb); #endif } @@ -2251,10 +2249,9 @@ static void translate_rtlb(DisasContext *dc, const OpcodeArg arg[], gen_helper_rtlb0, gen_helper_rtlb1, }; - TCGv_i32 dtlb = tcg_const_i32(par[0]); + TCGv_i32 dtlb = tcg_constant_i32(par[0]); helper[par[1]](arg[0].out, cpu_env, arg[1].in, dtlb); - tcg_temp_free(dtlb); #endif } @@ -2562,10 +2559,9 @@ static void translate_wtlb(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - TCGv_i32 dtlb = tcg_const_i32(par[0]); + TCGv_i32 dtlb = tcg_constant_i32(par[0]); gen_helper_wtlb(cpu_env, arg[0].in, arg[1].in, dtlb); - tcg_temp_free(dtlb); #endif } From dad266a1e35f0b24f07e6e18c67a02edf347c0b3 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Thu, 21 Apr 2022 13:38:58 -0700 Subject: [PATCH 083/935] target/xtensa: use tcg_constant_* for numbered special registers Numbered special registers are small arrays of consecutive SRs. Use tcg_constant_* for the SR index. Reviewed-by: Richard Henderson Signed-off-by: Max Filippov --- target/xtensa/translate.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 3cfcbf93a7..557e4e173f 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -2613,15 +2613,13 @@ static void translate_wsr_ccompare(DisasContext *dc, const OpcodeArg arg[], { #ifndef CONFIG_USER_ONLY uint32_t id = par[0] - CCOMPARE; - TCGv_i32 tmp = tcg_const_i32(id); assert(id < dc->config->nccompare); if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { gen_io_start(); } tcg_gen_mov_i32(cpu_SR[par[0]], arg[0].in); - gen_helper_update_ccompare(cpu_env, tmp); - tcg_temp_free(tmp); + gen_helper_update_ccompare(cpu_env, tcg_constant_i32(id)); #endif } @@ -2641,11 +2639,9 @@ static void translate_wsr_dbreaka(DisasContext *dc, const OpcodeArg arg[], { #ifndef CONFIG_USER_ONLY unsigned id = par[0] - DBREAKA; - TCGv_i32 tmp = tcg_const_i32(id); assert(id < dc->config->ndbreak); - gen_helper_wsr_dbreaka(cpu_env, tmp, arg[0].in); - tcg_temp_free(tmp); + gen_helper_wsr_dbreaka(cpu_env, tcg_constant_i32(id), arg[0].in); #endif } @@ -2654,11 +2650,9 @@ static void translate_wsr_dbreakc(DisasContext *dc, const OpcodeArg arg[], { #ifndef CONFIG_USER_ONLY unsigned id = par[0] - DBREAKC; - TCGv_i32 tmp = tcg_const_i32(id); assert(id < dc->config->ndbreak); - gen_helper_wsr_dbreakc(cpu_env, tmp, arg[0].in); - tcg_temp_free(tmp); + gen_helper_wsr_dbreakc(cpu_env, tcg_constant_i32(id), arg[0].in); #endif } @@ -2667,11 +2661,9 @@ static void translate_wsr_ibreaka(DisasContext *dc, const OpcodeArg arg[], { #ifndef CONFIG_USER_ONLY unsigned id = par[0] - IBREAKA; - TCGv_i32 tmp = tcg_const_i32(id); assert(id < dc->config->nibreak); - gen_helper_wsr_ibreaka(cpu_env, tmp, arg[0].in); - tcg_temp_free(tmp); + gen_helper_wsr_ibreaka(cpu_env, tcg_constant_i32(id), arg[0].in); #endif } From 867e354cbda0cac2d20a478ef39d01aa3bf67118 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Thu, 21 Apr 2022 13:38:58 -0700 Subject: [PATCH 084/935] target/xtensa: use tcg_constant_* for FPU conversion opcodes FPU conversion opcodes pass scale (range 0..15) and rounding mode to their helpers. Use tcg_constant_* for them. Reviewed-by: Richard Henderson Signed-off-by: Max Filippov --- target/xtensa/translate.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 557e4e173f..74272c0770 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -6513,20 +6513,19 @@ static void translate_const_s(DisasContext *dc, const OpcodeArg arg[], static void translate_float_d(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 scale = tcg_const_i32(-arg[2].imm); + TCGv_i32 scale = tcg_constant_i32(-arg[2].imm); if (par[0]) { gen_helper_uitof_d(arg[0].out, cpu_env, arg[1].in, scale); } else { gen_helper_itof_d(arg[0].out, cpu_env, arg[1].in, scale); } - tcg_temp_free(scale); } static void translate_float_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 scale = tcg_const_i32(-arg[2].imm); + TCGv_i32 scale = tcg_constant_i32(-arg[2].imm); OpcodeArg arg32[1]; get_f32_o1(arg, arg32, 0); @@ -6536,14 +6535,13 @@ static void translate_float_s(DisasContext *dc, const OpcodeArg arg[], gen_helper_itof_s(arg32[0].out, cpu_env, arg[1].in, scale); } put_f32_o1(arg, arg32, 0); - tcg_temp_free(scale); } static void translate_ftoi_d(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 rounding_mode = tcg_const_i32(par[0]); - TCGv_i32 scale = tcg_const_i32(arg[2].imm); + TCGv_i32 rounding_mode = tcg_constant_i32(par[0]); + TCGv_i32 scale = tcg_constant_i32(arg[2].imm); if (par[1]) { gen_helper_ftoui_d(arg[0].out, cpu_env, arg[1].in, @@ -6552,15 +6550,13 @@ static void translate_ftoi_d(DisasContext *dc, const OpcodeArg arg[], gen_helper_ftoi_d(arg[0].out, cpu_env, arg[1].in, rounding_mode, scale); } - tcg_temp_free(rounding_mode); - tcg_temp_free(scale); } static void translate_ftoi_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 rounding_mode = tcg_const_i32(par[0]); - TCGv_i32 scale = tcg_const_i32(arg[2].imm); + TCGv_i32 rounding_mode = tcg_constant_i32(par[0]); + TCGv_i32 scale = tcg_constant_i32(arg[2].imm); OpcodeArg arg32[2]; get_f32_i1(arg, arg32, 1); @@ -6572,8 +6568,6 @@ static void translate_ftoi_s(DisasContext *dc, const OpcodeArg arg[], rounding_mode, scale); } put_f32_i1(arg, arg32, 1); - tcg_temp_free(rounding_mode); - tcg_temp_free(scale); } static void translate_ldsti(DisasContext *dc, const OpcodeArg arg[], From 6ade0ce972042a8e6d6a62373644cd1bd0f5ba4f Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Thu, 21 Apr 2022 13:46:20 -0700 Subject: [PATCH 085/935] target/xtensa: use tcg_constant_* for remaining opcodes - gen_jumpi passes target PC to the helper; - gen_callw_slot uses callinc (1..3); - gen_brcondi passes immediate field (less than 32 different possible values) to the helper; - disas_xtensa_insn passes PC to the helpers; - translate_entry passes PC, stack register number (0..15) and stack frame size to the helper; - gen_check_exclusive passes PC and boolean flag to the helper; - test_exceptions_retw passes PC to the helper; - gen_check_atomctl passes PC to the helper; - translate_ssai passes immediate shift amount (0..31) to the helper; - gen_waiti passes next PC and an immediate (0..15) to the helper; use tcg_constant_* for the constants listed above. Fold gen_waiti body into the translate_waiti as it's the only user. Reviewed-by: Richard Henderson Signed-off-by: Max Filippov --- target/xtensa/translate.c | 77 +++++++++++++-------------------------- 1 file changed, 25 insertions(+), 52 deletions(-) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 74272c0770..b0576d90fa 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -396,19 +396,15 @@ static int adjust_jump_slot(DisasContext *dc, uint32_t dest, int slot) static void gen_jumpi(DisasContext *dc, uint32_t dest, int slot) { - TCGv_i32 tmp = tcg_const_i32(dest); - gen_jump_slot(dc, tmp, adjust_jump_slot(dc, dest, slot)); - tcg_temp_free(tmp); + gen_jump_slot(dc, tcg_constant_i32(dest), + adjust_jump_slot(dc, dest, slot)); } static void gen_callw_slot(DisasContext *dc, int callinc, TCGv_i32 dest, int slot) { - TCGv_i32 tcallinc = tcg_const_i32(callinc); - tcg_gen_deposit_i32(cpu_SR[PS], cpu_SR[PS], - tcallinc, PS_CALLINC_SHIFT, PS_CALLINC_LEN); - tcg_temp_free(tcallinc); + tcg_constant_i32(callinc), PS_CALLINC_SHIFT, PS_CALLINC_LEN); tcg_gen_movi_i32(cpu_R[callinc << 2], (callinc << 30) | (dc->base.pc_next & 0x3fffffff)); gen_jump_slot(dc, dest, slot); @@ -454,9 +450,7 @@ static void gen_brcond(DisasContext *dc, TCGCond cond, static void gen_brcondi(DisasContext *dc, TCGCond cond, TCGv_i32 t0, uint32_t t1, uint32_t addr) { - TCGv_i32 tmp = tcg_const_i32(t1); - gen_brcond(dc, cond, t0, tmp, addr); - tcg_temp_free(tmp); + gen_brcond(dc, cond, t0, tcg_constant_i32(t1), addr); } static uint32_t test_exceptions_sr(DisasContext *dc, const OpcodeArg arg[], @@ -541,21 +535,6 @@ static MemOp gen_load_store_alignment(DisasContext *dc, MemOp mop, return mop; } -#ifndef CONFIG_USER_ONLY -static void gen_waiti(DisasContext *dc, uint32_t imm4) -{ - TCGv_i32 pc = tcg_const_i32(dc->base.pc_next); - TCGv_i32 intlevel = tcg_const_i32(imm4); - - if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_waiti(cpu_env, pc, intlevel); - tcg_temp_free(pc); - tcg_temp_free(intlevel); -} -#endif - static bool gen_window_check(DisasContext *dc, uint32_t mask) { unsigned r = 31 - clz32(mask); @@ -1070,17 +1049,15 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) } if (op_flags & XTENSA_OP_UNDERFLOW) { - TCGv_i32 tmp = tcg_const_i32(dc->pc); + TCGv_i32 pc = tcg_constant_i32(dc->pc); - gen_helper_test_underflow_retw(cpu_env, tmp); - tcg_temp_free(tmp); + gen_helper_test_underflow_retw(cpu_env, pc); } if (op_flags & XTENSA_OP_ALLOCA) { - TCGv_i32 tmp = tcg_const_i32(dc->pc); + TCGv_i32 pc = tcg_constant_i32(dc->pc); - gen_helper_movsp(cpu_env, tmp); - tcg_temp_free(tmp); + gen_helper_movsp(cpu_env, pc); } if (coprocessor && !gen_check_cpenable(dc, coprocessor)) { @@ -1660,13 +1637,10 @@ static uint32_t test_overflow_entry(DisasContext *dc, const OpcodeArg arg[], static void translate_entry(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 pc = tcg_const_i32(dc->pc); - TCGv_i32 s = tcg_const_i32(arg[0].imm); - TCGv_i32 imm = tcg_const_i32(arg[1].imm); + TCGv_i32 pc = tcg_constant_i32(dc->pc); + TCGv_i32 s = tcg_constant_i32(arg[0].imm); + TCGv_i32 imm = tcg_constant_i32(arg[1].imm); gen_helper_entry(cpu_env, pc, s, imm); - tcg_temp_free(imm); - tcg_temp_free(s); - tcg_temp_free(pc); } static void translate_extui(DisasContext *dc, const OpcodeArg arg[], @@ -1746,12 +1720,10 @@ static void gen_check_exclusive(DisasContext *dc, TCGv_i32 addr, bool is_write) static void gen_check_exclusive(DisasContext *dc, TCGv_i32 addr, bool is_write) { if (!option_enabled(dc, XTENSA_OPTION_MPU)) { - TCGv_i32 tpc = tcg_const_i32(dc->pc); - TCGv_i32 write = tcg_const_i32(is_write); + TCGv_i32 pc = tcg_constant_i32(dc->pc); - gen_helper_check_exclusive(cpu_env, tpc, addr, write); - tcg_temp_free(tpc); - tcg_temp_free(write); + gen_helper_check_exclusive(cpu_env, pc, addr, + tcg_constant_i32(is_write)); } } #endif @@ -2128,10 +2100,9 @@ static uint32_t test_exceptions_retw(DisasContext *dc, const OpcodeArg arg[], "Illegal retw instruction(pc = %08x)\n", dc->pc); return XTENSA_OP_ILL; } else { - TCGv_i32 tmp = tcg_const_i32(dc->pc); + TCGv_i32 pc = tcg_constant_i32(dc->pc); - gen_helper_test_ill_retw(cpu_env, tmp); - tcg_temp_free(tmp); + gen_helper_test_ill_retw(cpu_env, pc); return 0; } } @@ -2291,10 +2262,9 @@ static void gen_check_atomctl(DisasContext *dc, TCGv_i32 addr) #else static void gen_check_atomctl(DisasContext *dc, TCGv_i32 addr) { - TCGv_i32 tpc = tcg_const_i32(dc->pc); + TCGv_i32 pc = tcg_constant_i32(dc->pc); - gen_helper_check_atomctl(cpu_env, tpc, addr); - tcg_temp_free(tpc); + gen_helper_check_atomctl(cpu_env, pc, addr); } #endif @@ -2515,9 +2485,7 @@ static void translate_ssa8l(DisasContext *dc, const OpcodeArg arg[], static void translate_ssai(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 tmp = tcg_const_i32(arg[0].imm); - gen_right_shift_sar(dc, tmp); - tcg_temp_free(tmp); + gen_right_shift_sar(dc, tcg_constant_i32(arg[0].imm)); } static void translate_ssl(DisasContext *dc, const OpcodeArg arg[], @@ -2551,7 +2519,12 @@ static void translate_waiti(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - gen_waiti(dc, arg[0].imm); + TCGv_i32 pc = tcg_constant_i32(dc->base.pc_next); + + if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } + gen_helper_waiti(cpu_env, pc, tcg_constant_i32(arg[0].imm)); #endif } From 8c48e36548a124dff8ad25b28f9cd2210dcdc407 Mon Sep 17 00:00:00 2001 From: Simon Safar Date: Fri, 22 Apr 2022 21:08:36 -0700 Subject: [PATCH 086/935] target/xtensa: import core lx106 This is the core used in e.g. ESP8266 chips. Importing them using import_core.sh, with the required files sourced from https://github.com/espressif/xtensa-overlays core-lx106.c was generated by the script; the only change is removing the reference to core-matmap.h which doesn't seem to be available. Signed-off-by: Simon Safar Reviewed-by: Max Filippov Message-Id: <20220423040835.29254-1-simon@simonsafar.com> Signed-off-by: Max Filippov --- target/xtensa/core-lx106.c | 51 + target/xtensa/core-lx106/core-isa.h | 470 + target/xtensa/core-lx106/gdb-config.c.inc | 83 + target/xtensa/core-lx106/xtensa-modules.c.inc | 7668 +++++++++++++++++ target/xtensa/cores.list | 1 + 5 files changed, 8273 insertions(+) create mode 100644 target/xtensa/core-lx106.c create mode 100644 target/xtensa/core-lx106/core-isa.h create mode 100644 target/xtensa/core-lx106/gdb-config.c.inc create mode 100644 target/xtensa/core-lx106/xtensa-modules.c.inc diff --git a/target/xtensa/core-lx106.c b/target/xtensa/core-lx106.c new file mode 100644 index 0000000000..7a771d09a6 --- /dev/null +++ b/target/xtensa/core-lx106.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022, Simon Safar, Max Filippov, Open Source and Linux Lab. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/gdbstub.h" +#include "qemu/host-utils.h" + +#include "core-lx106/core-isa.h" +#include "overlay_tool.h" + +#define xtensa_modules xtensa_modules_lx106 +#include "core-lx106/xtensa-modules.c.inc" + +static XtensaConfig lx106 __attribute__((unused)) = { + .name = "lx106", + .gdb_regmap = { + .reg = { +#include "core-lx106/gdb-config.c.inc" + } + }, + .isa_internal = &xtensa_modules, + .clock_freq_khz = 40000, + DEFAULT_SECTIONS +}; + +REGISTER_CORE(lx106) diff --git a/target/xtensa/core-lx106/core-isa.h b/target/xtensa/core-lx106/core-isa.h new file mode 100644 index 0000000000..86bcf1a5d6 --- /dev/null +++ b/target/xtensa/core-lx106/core-isa.h @@ -0,0 +1,470 @@ +/* + * xtensa/config/core-isa.h -- HAL definitions that are dependent on Xtensa + * processor CORE configuration + * + * See , which includes this file, for more details. + */ + +/* Xtensa processor core configuration information. + + Copyright (c) 1999-2010 Tensilica Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _XTENSA_CORE_CONFIGURATION_H +#define _XTENSA_CORE_CONFIGURATION_H + + +/**************************************************************************** + Parameters Useful for Any Code, USER or PRIVILEGED + ****************************************************************************/ + +/* + * Note: Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is + * configured, and a value of 0 otherwise. These macros are always defined. + */ + + +/*---------------------------------------------------------------------- + ISA + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_BE 0 /* big-endian byte ordering */ +#define XCHAL_HAVE_WINDOWED 0 /* windowed registers option */ +#define XCHAL_NUM_AREGS 16 /* num of physical addr regs */ +#define XCHAL_NUM_AREGS_LOG2 4 /* log2(XCHAL_NUM_AREGS) */ +#define XCHAL_MAX_INSTRUCTION_SIZE 3 /* max instr bytes (3..8) */ +#define XCHAL_HAVE_DEBUG 1 /* debug option */ +#define XCHAL_HAVE_DENSITY 1 /* 16-bit instructions */ +#define XCHAL_HAVE_LOOPS 0 /* zero-overhead loops */ +#define XCHAL_HAVE_NSA 1 /* NSA/NSAU instructions */ +#define XCHAL_HAVE_MINMAX 0 /* MIN/MAX instructions */ +#define XCHAL_HAVE_SEXT 0 /* SEXT instruction */ +#define XCHAL_HAVE_CLAMPS 0 /* CLAMPS instruction */ +#define XCHAL_HAVE_MUL16 1 /* MUL16S/MUL16U instructions */ +#define XCHAL_HAVE_MUL32 1 /* MULL instruction */ +#define XCHAL_HAVE_MUL32_HIGH 0 /* MULUH/MULSH instructions */ +#define XCHAL_HAVE_DIV32 0 /* QUOS/QUOU/REMS/REMU instructions */ +#define XCHAL_HAVE_L32R 1 /* L32R instruction */ +#define XCHAL_HAVE_ABSOLUTE_LITERALS 1 /* non-PC-rel (extended) L32R */ +#define XCHAL_HAVE_CONST16 0 /* CONST16 instruction */ +#define XCHAL_HAVE_ADDX 1 /* ADDX#/SUBX# instructions */ +#define XCHAL_HAVE_WIDE_BRANCHES 0 /* B*.W18 or B*.W15 instr's */ +#define XCHAL_HAVE_PREDICTED_BRANCHES 0 /* B[EQ/EQZ/NE/NEZ]T instr's */ +#define XCHAL_HAVE_CALL4AND12 0 /* (obsolete option) */ +#define XCHAL_HAVE_ABS 1 /* ABS instruction */ +/*#define XCHAL_HAVE_POPC 0*/ /* POPC instruction */ +/*#define XCHAL_HAVE_CRC 0*/ /* CRC instruction */ +#define XCHAL_HAVE_RELEASE_SYNC 0 /* L32AI/S32RI instructions */ +#define XCHAL_HAVE_S32C1I 0 /* S32C1I instruction */ +#define XCHAL_HAVE_SPECULATION 0 /* speculation */ +#define XCHAL_HAVE_FULL_RESET 1 /* all regs/state reset */ +#define XCHAL_NUM_CONTEXTS 1 /* */ +#define XCHAL_NUM_MISC_REGS 0 /* num of scratch regs (0..4) */ +#define XCHAL_HAVE_TAP_MASTER 0 /* JTAG TAP control instr's */ +#define XCHAL_HAVE_PRID 1 /* processor ID register */ +#define XCHAL_HAVE_EXTERN_REGS 1 /* WER/RER instructions */ +#define XCHAL_HAVE_MP_INTERRUPTS 0 /* interrupt distributor port */ +#define XCHAL_HAVE_MP_RUNSTALL 0 /* core RunStall control port */ +#define XCHAL_HAVE_THREADPTR 0 /* THREADPTR register */ +#define XCHAL_HAVE_BOOLEANS 0 /* boolean registers */ +#define XCHAL_HAVE_CP 0 /* CPENABLE reg (coprocessor) */ +#define XCHAL_CP_MAXCFG 0 /* max allowed cp id plus one */ +#define XCHAL_HAVE_MAC16 0 /* MAC16 package */ +#define XCHAL_HAVE_VECTORFPU2005 0 /* vector floating-point pkg */ +#define XCHAL_HAVE_FP 0 /* floating point pkg */ +#define XCHAL_HAVE_DFP 0 /* double precision FP pkg */ +#define XCHAL_HAVE_DFP_accel 0 /* double precision FP acceleration pkg */ +#define XCHAL_HAVE_VECTRA1 0 /* Vectra I pkg */ +#define XCHAL_HAVE_VECTRALX 0 /* Vectra LX pkg */ +#define XCHAL_HAVE_HIFIPRO 0 /* HiFiPro Audio Engine pkg */ +#define XCHAL_HAVE_HIFI2 0 /* HiFi2 Audio Engine pkg */ +#define XCHAL_HAVE_CONNXD2 0 /* ConnX D2 pkg */ + + +/*---------------------------------------------------------------------- + MISC + ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_WRITEBUFFER_ENTRIES 1 /* size of write buffer */ +#define XCHAL_INST_FETCH_WIDTH 4 /* instr-fetch width in bytes */ +#define XCHAL_DATA_WIDTH 4 /* data width in bytes */ +/* In T1050, applies to selected core load and store instructions (see ISA): */ +#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1 /* unaligned loads cause exc. */ +#define XCHAL_UNALIGNED_STORE_EXCEPTION 1 /* unaligned stores cause exc.*/ +#define XCHAL_UNALIGNED_LOAD_HW 0 /* unaligned loads work in hw */ +#define XCHAL_UNALIGNED_STORE_HW 0 /* unaligned stores work in hw*/ + +#define XCHAL_SW_VERSION 800001 /* sw version of this header */ + +#define XCHAL_CORE_ID "lx106" /* alphanum core name + (CoreID) set in the Xtensa + Processor Generator */ + +#define XCHAL_BUILD_UNIQUE_ID 0x0002B6F6 /* 22-bit sw build ID */ + +/* + * These definitions describe the hardware targeted by this software. + */ +#define XCHAL_HW_CONFIGID0 0xC28CDAFA /* ConfigID hi 32 bits*/ +#define XCHAL_HW_CONFIGID1 0x1082B6F6 /* ConfigID lo 32 bits*/ +#define XCHAL_HW_VERSION_NAME "LX3.0.1" /* full version name */ +#define XCHAL_HW_VERSION_MAJOR 2300 /* major ver# of targeted hw */ +#define XCHAL_HW_VERSION_MINOR 1 /* minor ver# of targeted hw */ +#define XCHAL_HW_VERSION 230001 /* major*100+minor */ +#define XCHAL_HW_REL_LX3 1 +#define XCHAL_HW_REL_LX3_0 1 +#define XCHAL_HW_REL_LX3_0_1 1 +#define XCHAL_HW_CONFIGID_RELIABLE 1 +/* If software targets a *range* of hardware versions, these are the bounds: */ +#define XCHAL_HW_MIN_VERSION_MAJOR 2300 /* major v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION_MINOR 1 /* minor v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION 230001 /* earliest targeted hw */ +#define XCHAL_HW_MAX_VERSION_MAJOR 2300 /* major v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION_MINOR 1 /* minor v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION 230001 /* latest targeted hw */ + + +/*---------------------------------------------------------------------- + CACHE + ----------------------------------------------------------------------*/ + +#define XCHAL_ICACHE_LINESIZE 4 /* I-cache line size in bytes */ +#define XCHAL_DCACHE_LINESIZE 4 /* D-cache line size in bytes */ +#define XCHAL_ICACHE_LINEWIDTH 2 /* log2(I line size in bytes) */ +#define XCHAL_DCACHE_LINEWIDTH 2 /* log2(D line size in bytes) */ + +#define XCHAL_ICACHE_SIZE 0 /* I-cache size in bytes or 0 */ +#define XCHAL_DCACHE_SIZE 0 /* D-cache size in bytes or 0 */ + +#define XCHAL_DCACHE_IS_WRITEBACK 0 /* writeback feature */ +#define XCHAL_DCACHE_IS_COHERENT 0 /* MP coherence feature */ + +#define XCHAL_HAVE_PREFETCH 0 /* PREFCTL register */ + + + + +/**************************************************************************** + Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code + ****************************************************************************/ + + +#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY + +/*---------------------------------------------------------------------- + CACHE + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_PIF 1 /* any outbound PIF present */ + +/* If present, cache size in bytes == (ways * 2^(linewidth + setwidth)). */ + +/* Number of cache sets in log2(lines per way): */ +#define XCHAL_ICACHE_SETWIDTH 0 +#define XCHAL_DCACHE_SETWIDTH 0 + +/* Cache set associativity (number of ways): */ +#define XCHAL_ICACHE_WAYS 1 +#define XCHAL_DCACHE_WAYS 1 + +/* Cache features: */ +#define XCHAL_ICACHE_LINE_LOCKABLE 0 +#define XCHAL_DCACHE_LINE_LOCKABLE 0 +#define XCHAL_ICACHE_ECC_PARITY 0 +#define XCHAL_DCACHE_ECC_PARITY 0 + +/* Cache access size in bytes (affects operation of SICW instruction): */ +#define XCHAL_ICACHE_ACCESS_SIZE 1 +#define XCHAL_DCACHE_ACCESS_SIZE 1 + +/* Number of encoded cache attr bits (see for decoded bits): */ +#define XCHAL_CA_BITS 4 + + +/*---------------------------------------------------------------------- + INTERNAL I/D RAM/ROMs and XLMI + ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_INSTROM 1 /* number of core instr. ROMs */ +#define XCHAL_NUM_INSTRAM 2 /* number of core instr. RAMs */ +#define XCHAL_NUM_DATAROM 1 /* number of core data ROMs */ +#define XCHAL_NUM_DATARAM 2 /* number of core data RAMs */ +#define XCHAL_NUM_URAM 0 /* number of core unified RAMs*/ +#define XCHAL_NUM_XLMI 1 /* number of core XLMI ports */ + +/* Instruction ROM 0: */ +#define XCHAL_INSTROM0_VADDR 0x40200000 +#define XCHAL_INSTROM0_PADDR 0x40200000 +// #define XCHAL_INSTROM0_VADDR 0x400000 +// #define XCHAL_INSTROM0_PADDR 0x400000 +#define XCHAL_INSTROM0_SIZE 1048576 +#define XCHAL_INSTROM0_ECC_PARITY 0 + +/* Instruction RAM 0: */ +#define XCHAL_INSTRAM0_VADDR 0x40000000 +#define XCHAL_INSTRAM0_PADDR 0x40000000 +#define XCHAL_INSTRAM0_SIZE 1048576 +#define XCHAL_INSTRAM0_ECC_PARITY 0 + +/* Instruction RAM 1: */ +#define XCHAL_INSTRAM1_VADDR 0x40100000 +#define XCHAL_INSTRAM1_PADDR 0x40100000 +#define XCHAL_INSTRAM1_SIZE 1048576 +#define XCHAL_INSTRAM1_ECC_PARITY 0 + +/* Data ROM 0: */ +#define XCHAL_DATAROM0_VADDR 0x3FF40000 +#define XCHAL_DATAROM0_PADDR 0x3FF40000 +#define XCHAL_DATAROM0_SIZE 262144 +#define XCHAL_DATAROM0_ECC_PARITY 0 + +/* Data RAM 0: */ +#define XCHAL_DATARAM0_VADDR 0x3FFC0000 +#define XCHAL_DATARAM0_PADDR 0x3FFC0000 +#define XCHAL_DATARAM0_SIZE 262144 +#define XCHAL_DATARAM0_ECC_PARITY 0 + +/* Data RAM 1: */ +#define XCHAL_DATARAM1_VADDR 0x3FF80000 +#define XCHAL_DATARAM1_PADDR 0x3FF80000 +#define XCHAL_DATARAM1_SIZE 262144 +#define XCHAL_DATARAM1_ECC_PARITY 0 + +/* XLMI Port 0: */ +#define XCHAL_XLMI0_VADDR 0x3FF00000 +#define XCHAL_XLMI0_PADDR 0x3FF00000 +#define XCHAL_XLMI0_SIZE 262144 +#define XCHAL_XLMI0_ECC_PARITY 0 + + +/*---------------------------------------------------------------------- + INTERRUPTS and TIMERS + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_INTERRUPTS 1 /* interrupt option */ +#define XCHAL_HAVE_HIGHPRI_INTERRUPTS 1 /* med/high-pri. interrupts */ +#define XCHAL_HAVE_NMI 1 /* non-maskable interrupt */ +#define XCHAL_HAVE_CCOUNT 1 /* CCOUNT reg. (timer option) */ +#define XCHAL_NUM_TIMERS 1 /* number of CCOMPAREn regs */ +#define XCHAL_NUM_INTERRUPTS 15 /* number of interrupts */ +#define XCHAL_NUM_INTERRUPTS_LOG2 4 /* ceil(log2(NUM_INTERRUPTS)) */ +#define XCHAL_NUM_EXTINTERRUPTS 13 /* num of external interrupts */ +#define XCHAL_NUM_INTLEVELS 2 /* number of interrupt levels + (not including level zero) */ +#define XCHAL_EXCM_LEVEL 1 /* level masked by PS.EXCM */ + /* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */ + +/* Masks of interrupts at each interrupt level: */ +#define XCHAL_INTLEVEL1_MASK 0x00003FFF +#define XCHAL_INTLEVEL2_MASK 0x00000000 +#define XCHAL_INTLEVEL3_MASK 0x00004000 +#define XCHAL_INTLEVEL4_MASK 0x00000000 +#define XCHAL_INTLEVEL5_MASK 0x00000000 +#define XCHAL_INTLEVEL6_MASK 0x00000000 +#define XCHAL_INTLEVEL7_MASK 0x00000000 + +/* Masks of interrupts at each range 1..n of interrupt levels: */ +#define XCHAL_INTLEVEL1_ANDBELOW_MASK 0x00003FFF +#define XCHAL_INTLEVEL2_ANDBELOW_MASK 0x00003FFF +#define XCHAL_INTLEVEL3_ANDBELOW_MASK 0x00007FFF +#define XCHAL_INTLEVEL4_ANDBELOW_MASK 0x00007FFF +#define XCHAL_INTLEVEL5_ANDBELOW_MASK 0x00007FFF +#define XCHAL_INTLEVEL6_ANDBELOW_MASK 0x00007FFF +#define XCHAL_INTLEVEL7_ANDBELOW_MASK 0x00007FFF + +/* Level of each interrupt: */ +#define XCHAL_INT0_LEVEL 1 +#define XCHAL_INT1_LEVEL 1 +#define XCHAL_INT2_LEVEL 1 +#define XCHAL_INT3_LEVEL 1 +#define XCHAL_INT4_LEVEL 1 +#define XCHAL_INT5_LEVEL 1 +#define XCHAL_INT6_LEVEL 1 +#define XCHAL_INT7_LEVEL 1 +#define XCHAL_INT8_LEVEL 1 +#define XCHAL_INT9_LEVEL 1 +#define XCHAL_INT10_LEVEL 1 +#define XCHAL_INT11_LEVEL 1 +#define XCHAL_INT12_LEVEL 1 +#define XCHAL_INT13_LEVEL 1 +#define XCHAL_INT14_LEVEL 3 +#define XCHAL_DEBUGLEVEL 2 /* debug interrupt level */ +#define XCHAL_HAVE_DEBUG_EXTERN_INT 1 /* OCD external db interrupt */ +#define XCHAL_NMILEVEL 3 /* NMI "level" (for use with + EXCSAVE/EPS/EPC_n, RFI n) */ + +/* Type of each interrupt: */ +#define XCHAL_INT0_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT1_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT2_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT3_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT4_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT5_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT6_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT7_TYPE XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT8_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT9_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT10_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT11_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT12_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT13_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT14_TYPE XTHAL_INTTYPE_NMI + +/* Masks of interrupts for each type of interrupt: */ +#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xFFFF8000 +#define XCHAL_INTTYPE_MASK_SOFTWARE 0x00000080 +#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x00003F00 +#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x0000003F +#define XCHAL_INTTYPE_MASK_TIMER 0x00000040 +#define XCHAL_INTTYPE_MASK_NMI 0x00004000 +#define XCHAL_INTTYPE_MASK_WRITE_ERROR 0x00000000 + +/* Interrupt numbers assigned to specific interrupt sources: */ +#define XCHAL_TIMER0_INTERRUPT 6 /* CCOMPARE0 */ +#define XCHAL_TIMER1_INTERRUPT XTHAL_TIMER_UNCONFIGURED +#define XCHAL_TIMER2_INTERRUPT XTHAL_TIMER_UNCONFIGURED +#define XCHAL_TIMER3_INTERRUPT XTHAL_TIMER_UNCONFIGURED +#define XCHAL_NMI_INTERRUPT 14 /* non-maskable interrupt */ + +/* Interrupt numbers for levels at which only one interrupt is configured: */ +#define XCHAL_INTLEVEL3_NUM 14 +/* (There are many interrupts each at level(s) 1.) */ + + +/* + * External interrupt vectors/levels. + * These macros describe how Xtensa processor interrupt numbers + * (as numbered internally, eg. in INTERRUPT and INTENABLE registers) + * map to external BInterrupt pins, for those interrupts + * configured as external (level-triggered, edge-triggered, or NMI). + * See the Xtensa processor databook for more details. + */ + +/* Core interrupt numbers mapped to each EXTERNAL interrupt number: */ +#define XCHAL_EXTINT0_NUM 0 /* (intlevel 1) */ +#define XCHAL_EXTINT1_NUM 1 /* (intlevel 1) */ +#define XCHAL_EXTINT2_NUM 2 /* (intlevel 1) */ +#define XCHAL_EXTINT3_NUM 3 /* (intlevel 1) */ +#define XCHAL_EXTINT4_NUM 4 /* (intlevel 1) */ +#define XCHAL_EXTINT5_NUM 5 /* (intlevel 1) */ +#define XCHAL_EXTINT6_NUM 8 /* (intlevel 1) */ +#define XCHAL_EXTINT7_NUM 9 /* (intlevel 1) */ +#define XCHAL_EXTINT8_NUM 10 /* (intlevel 1) */ +#define XCHAL_EXTINT9_NUM 11 /* (intlevel 1) */ +#define XCHAL_EXTINT10_NUM 12 /* (intlevel 1) */ +#define XCHAL_EXTINT11_NUM 13 /* (intlevel 1) */ +#define XCHAL_EXTINT12_NUM 14 /* (intlevel 3) */ + + +/*---------------------------------------------------------------------- + EXCEPTIONS and VECTORS + ----------------------------------------------------------------------*/ + +#define XCHAL_XEA_VERSION 2 /* Xtensa Exception Architecture + number: 1 == XEA1 (old) + 2 == XEA2 (new) + 0 == XEAX (extern) */ +#define XCHAL_HAVE_XEA1 0 /* Exception Architecture 1 */ +#define XCHAL_HAVE_XEA2 1 /* Exception Architecture 2 */ +#define XCHAL_HAVE_XEAX 0 /* External Exception Arch. */ +#define XCHAL_HAVE_EXCEPTIONS 1 /* exception option */ +#define XCHAL_HAVE_MEM_ECC_PARITY 0 /* local memory ECC/parity */ +#define XCHAL_HAVE_VECTOR_SELECT 1 /* relocatable vectors */ +#define XCHAL_HAVE_VECBASE 1 /* relocatable vectors */ +#define XCHAL_VECBASE_RESET_VADDR 0x40000000 /* VECBASE reset value */ +#define XCHAL_VECBASE_RESET_PADDR 0x40000000 +#define XCHAL_RESET_VECBASE_OVERLAP 0 + +#define XCHAL_RESET_VECTOR0_VADDR 0x50000000 +#define XCHAL_RESET_VECTOR0_PADDR 0x50000000 +#define XCHAL_RESET_VECTOR1_VADDR 0x40000080 +#define XCHAL_RESET_VECTOR1_PADDR 0x40000080 +#define XCHAL_RESET_VECTOR_VADDR 0x50000000 +#define XCHAL_RESET_VECTOR_PADDR 0x50000000 + +// #define XCHAL_RESET_VECTOR0_VADDR 0x4000f8 +// #define XCHAL_RESET_VECTOR0_PADDR 0x4000f8 +// #define XCHAL_RESET_VECTOR1_VADDR 0x40000080 +// #define XCHAL_RESET_VECTOR1_PADDR 0x40000080 +// #define XCHAL_RESET_VECTOR_VADDR 0x4000f8 +// #define XCHAL_RESET_VECTOR_PADDR 0x4000f8 + + +#define XCHAL_USER_VECOFS 0x00000050 +#define XCHAL_USER_VECTOR_VADDR 0x40000050 +#define XCHAL_USER_VECTOR_PADDR 0x40000050 +#define XCHAL_KERNEL_VECOFS 0x00000030 +#define XCHAL_KERNEL_VECTOR_VADDR 0x40000030 +#define XCHAL_KERNEL_VECTOR_PADDR 0x40000030 +#define XCHAL_DOUBLEEXC_VECOFS 0x00000070 +#define XCHAL_DOUBLEEXC_VECTOR_VADDR 0x40000070 +#define XCHAL_DOUBLEEXC_VECTOR_PADDR 0x40000070 +#define XCHAL_INTLEVEL2_VECOFS 0x00000010 +#define XCHAL_INTLEVEL2_VECTOR_VADDR 0x40000010 +#define XCHAL_INTLEVEL2_VECTOR_PADDR 0x40000010 +#define XCHAL_DEBUG_VECOFS XCHAL_INTLEVEL2_VECOFS +#define XCHAL_DEBUG_VECTOR_VADDR XCHAL_INTLEVEL2_VECTOR_VADDR +#define XCHAL_DEBUG_VECTOR_PADDR XCHAL_INTLEVEL2_VECTOR_PADDR +#define XCHAL_NMI_VECOFS 0x00000020 +#define XCHAL_NMI_VECTOR_VADDR 0x40000020 +#define XCHAL_NMI_VECTOR_PADDR 0x40000020 +#define XCHAL_INTLEVEL3_VECOFS XCHAL_NMI_VECOFS +#define XCHAL_INTLEVEL3_VECTOR_VADDR XCHAL_NMI_VECTOR_VADDR +#define XCHAL_INTLEVEL3_VECTOR_PADDR XCHAL_NMI_VECTOR_PADDR + + +/*---------------------------------------------------------------------- + DEBUG + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_OCD 1 /* OnChipDebug option */ +#define XCHAL_NUM_IBREAK 1 /* number of IBREAKn regs */ +#define XCHAL_NUM_DBREAK 1 /* number of DBREAKn regs */ +#define XCHAL_HAVE_OCD_DIR_ARRAY 0 /* faster OCD option */ + + +/*---------------------------------------------------------------------- + MMU + ----------------------------------------------------------------------*/ + +/* See core-matmap.h header file for more details. */ + +#define XCHAL_HAVE_TLBS 1 /* inverse of HAVE_CACHEATTR */ +#define XCHAL_HAVE_SPANNING_WAY 1 /* one way maps I+D 4GB vaddr */ +#define XCHAL_SPANNING_WAY 0 /* TLB spanning way number */ +#define XCHAL_HAVE_IDENTITY_MAP 1 /* vaddr == paddr always */ +#define XCHAL_HAVE_CACHEATTR 0 /* CACHEATTR register present */ +#define XCHAL_HAVE_MIMIC_CACHEATTR 1 /* region protection */ +#define XCHAL_HAVE_XLT_CACHEATTR 0 /* region prot. w/translation */ +#define XCHAL_HAVE_PTP_MMU 0 /* full MMU (with page table + [autorefill] and protection) + usable for an MMU-based OS */ +/* If none of the above last 4 are set, it's a custom TLB configuration. */ + +#define XCHAL_MMU_ASID_BITS 0 /* number of bits in ASIDs */ +#define XCHAL_MMU_RINGS 1 /* number of rings (1..4) */ +#define XCHAL_MMU_RING_BITS 0 /* num of bits in RING field */ + +#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */ + + +#endif /* _XTENSA_CORE_CONFIGURATION_H */ + diff --git a/target/xtensa/core-lx106/gdb-config.c.inc b/target/xtensa/core-lx106/gdb-config.c.inc new file mode 100644 index 0000000000..365d6fe609 --- /dev/null +++ b/target/xtensa/core-lx106/gdb-config.c.inc @@ -0,0 +1,83 @@ +/* Configuration for the Xtensa architecture for GDB, the GNU debugger. + + Copyright (c) 2003-2010 Tensilica Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + XTREG( 0, 0,32, 4, 4,0x0000,0x0006,-2, 8,0x0100,a0, 0,0,0,0,0,0) + XTREG( 1, 4,32, 4, 4,0x0001,0x0006,-2, 8,0x0100,a1, 0,0,0,0,0,0) + XTREG( 2, 8,32, 4, 4,0x0002,0x0006,-2, 8,0x0100,a2, 0,0,0,0,0,0) + XTREG( 3, 12,32, 4, 4,0x0003,0x0006,-2, 8,0x0100,a3, 0,0,0,0,0,0) + XTREG( 4, 16,32, 4, 4,0x0004,0x0006,-2, 8,0x0100,a4, 0,0,0,0,0,0) + XTREG( 5, 20,32, 4, 4,0x0005,0x0006,-2, 8,0x0100,a5, 0,0,0,0,0,0) + XTREG( 6, 24,32, 4, 4,0x0006,0x0006,-2, 8,0x0100,a6, 0,0,0,0,0,0) + XTREG( 7, 28,32, 4, 4,0x0007,0x0006,-2, 8,0x0100,a7, 0,0,0,0,0,0) + XTREG( 8, 32,32, 4, 4,0x0008,0x0006,-2, 8,0x0100,a8, 0,0,0,0,0,0) + XTREG( 9, 36,32, 4, 4,0x0009,0x0006,-2, 8,0x0100,a9, 0,0,0,0,0,0) + XTREG( 10, 40,32, 4, 4,0x000a,0x0006,-2, 8,0x0100,a10, 0,0,0,0,0,0) + XTREG( 11, 44,32, 4, 4,0x000b,0x0006,-2, 8,0x0100,a11, 0,0,0,0,0,0) + XTREG( 12, 48,32, 4, 4,0x000c,0x0006,-2, 8,0x0100,a12, 0,0,0,0,0,0) + XTREG( 13, 52,32, 4, 4,0x000d,0x0006,-2, 8,0x0100,a13, 0,0,0,0,0,0) + XTREG( 14, 56,32, 4, 4,0x000e,0x0006,-2, 8,0x0100,a14, 0,0,0,0,0,0) + XTREG( 15, 60,32, 4, 4,0x000f,0x0006,-2, 8,0x0100,a15, 0,0,0,0,0,0) + XTREG( 16, 64,32, 4, 4,0x0020,0x0006,-2, 9,0x0100,pc, 0,0,0,0,0,0) + XTREG( 17, 68, 6, 4, 4,0x0203,0x0006,-2, 2,0x1100,sar, 0,0,0,0,0,0) + XTREG( 18, 72,32, 4, 4,0x0205,0x0006,-2, 2,0x1100,litbase, 0,0,0,0,0,0) + XTREG( 19, 76,32, 4, 4,0x02b0,0x0002,-2, 2,0x1000,sr176, 0,0,0,0,0,0) + XTREG( 20, 80,32, 4, 4,0x02d0,0x0002,-2, 2,0x1000,sr208, 0,0,0,0,0,0) + XTREG( 21, 84, 6, 4, 4,0x02e6,0x0006,-2, 2,0x1100,ps, 0,0,0,0,0,0) + XTREG( 22, 88,32, 4, 4,0x0259,0x000d,-2, 2,0x1000,mmid, 0,0,0,0,0,0) + XTREG( 23, 92, 1, 4, 4,0x0260,0x0007,-2, 2,0x1000,ibreakenable,0,0,0,0,0,0) + XTREG( 24, 96,32, 4, 4,0x0268,0x0007,-2, 2,0x1000,ddr, 0,0,0,0,0,0) + XTREG( 25,100,32, 4, 4,0x0280,0x0007,-2, 2,0x1000,ibreaka0, 0,0,0,0,0,0) + XTREG( 26,104,32, 4, 4,0x0290,0x0007,-2, 2,0x1000,dbreaka0, 0,0,0,0,0,0) + XTREG( 27,108,32, 4, 4,0x02a0,0x0007,-2, 2,0x1000,dbreakc0, 0,0,0,0,0,0) + XTREG( 28,112,32, 4, 4,0x02b1,0x0007,-2, 2,0x1000,epc1, 0,0,0,0,0,0) + XTREG( 29,116,32, 4, 4,0x02b2,0x0007,-2, 2,0x1000,epc2, 0,0,0,0,0,0) + XTREG( 30,120,32, 4, 4,0x02b3,0x0007,-2, 2,0x1000,epc3, 0,0,0,0,0,0) + XTREG( 31,124,32, 4, 4,0x02c0,0x0007,-2, 2,0x1000,depc, 0,0,0,0,0,0) + XTREG( 32,128, 6, 4, 4,0x02c2,0x0007,-2, 2,0x1000,eps2, 0,0,0,0,0,0) + XTREG( 33,132, 6, 4, 4,0x02c3,0x0007,-2, 2,0x1000,eps3, 0,0,0,0,0,0) + XTREG( 34,136,32, 4, 4,0x02d1,0x0007,-2, 2,0x1000,excsave1, 0,0,0,0,0,0) + XTREG( 35,140,32, 4, 4,0x02d2,0x0007,-2, 2,0x1000,excsave2, 0,0,0,0,0,0) + XTREG( 36,144,32, 4, 4,0x02d3,0x0007,-2, 2,0x1000,excsave3, 0,0,0,0,0,0) + XTREG( 37,148,15, 4, 4,0x02e2,0x000b,-2, 2,0x1000,interrupt, 0,0,0,0,0,0) + XTREG( 38,152,15, 4, 4,0x02e2,0x000d,-2, 2,0x1000,intset, 0,0,0,0,0,0) + XTREG( 39,156,15, 4, 4,0x02e3,0x000d,-2, 2,0x1000,intclear, 0,0,0,0,0,0) + XTREG( 40,160,15, 4, 4,0x02e4,0x0007,-2, 2,0x1000,intenable, 0,0,0,0,0,0) + XTREG( 41,164,32, 4, 4,0x02e7,0x0007,-2, 2,0x1000,vecbase, 0,0,0,0,0,0) + XTREG( 42,168, 6, 4, 4,0x02e8,0x0007,-2, 2,0x1000,exccause, 0,0,0,0,0,0) + XTREG( 43,172,12, 4, 4,0x02e9,0x0003,-2, 2,0x1000,debugcause, 0,0,0,0,0,0) + XTREG( 44,176,32, 4, 4,0x02ea,0x000f,-2, 2,0x1000,ccount, 0,0,0,0,0,0) + XTREG( 45,180,32, 4, 4,0x02eb,0x0003,-2, 2,0x1000,prid, 0,0,0,0,0,0) + XTREG( 46,184,32, 4, 4,0x02ec,0x000f,-2, 2,0x1000,icount, 0,0,0,0,0,0) + XTREG( 47,188, 4, 4, 4,0x02ed,0x0007,-2, 2,0x1000,icountlevel, 0,0,0,0,0,0) + XTREG( 48,192,32, 4, 4,0x02ee,0x0007,-2, 2,0x1000,excvaddr, 0,0,0,0,0,0) + XTREG( 49,196,32, 4, 4,0x02f0,0x000f,-2, 2,0x1000,ccompare0, 0,0,0,0,0,0) + XTREG( 50,200, 4, 4, 4,0x2002,0x0006,-2, 6,0x1010,psintlevel, + 0,0,&xtensa_mask0,0,0,0) + XTREG( 51,204, 1, 4, 4,0x2003,0x0006,-2, 6,0x1010,psum, + 0,0,&xtensa_mask1,0,0,0) + XTREG( 52,208, 1, 4, 4,0x2004,0x0006,-2, 6,0x1010,psexcm, + 0,0,&xtensa_mask2,0,0,0) + XTREG( 53,212,20, 4, 4,0x2005,0x0006,-2, 6,0x1010,litbaddr, + 0,0,&xtensa_mask3,0,0,0) + XTREG( 54,216, 1, 4, 4,0x2006,0x0006,-2, 6,0x1010,litben, + 0,0,&xtensa_mask4,0,0,0) + XTREG_END diff --git a/target/xtensa/core-lx106/xtensa-modules.c.inc b/target/xtensa/core-lx106/xtensa-modules.c.inc new file mode 100644 index 0000000000..f2b5efc6ec --- /dev/null +++ b/target/xtensa/core-lx106/xtensa-modules.c.inc @@ -0,0 +1,7668 @@ +/* Xtensa configuration-specific ISA information. + + Copyright (c) 2003-2010 Tensilica Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "xtensa-isa.h" +#include "xtensa-isa-internal.h" + + +/* Sysregs. */ + +static xtensa_sysreg_internal sysregs[] = { + { "MMID", 89, 0 }, + { "DDR", 104, 0 }, + { "176", 176, 0 }, + { "208", 208, 0 }, + { "INTERRUPT", 226, 0 }, + { "INTCLEAR", 227, 0 }, + { "CCOUNT", 234, 0 }, + { "PRID", 235, 0 }, + { "ICOUNT", 236, 0 }, + { "CCOMPARE0", 240, 0 }, + { "VECBASE", 231, 0 }, + { "EPC1", 177, 0 }, + { "EPC2", 178, 0 }, + { "EPC3", 179, 0 }, + { "EXCSAVE1", 209, 0 }, + { "EXCSAVE2", 210, 0 }, + { "EXCSAVE3", 211, 0 }, + { "EPS2", 194, 0 }, + { "EPS3", 195, 0 }, + { "EXCCAUSE", 232, 0 }, + { "DEPC", 192, 0 }, + { "EXCVADDR", 238, 0 }, + { "SAR", 3, 0 }, + { "LITBASE", 5, 0 }, + { "PS", 230, 0 }, + { "INTENABLE", 228, 0 }, + { "DBREAKA0", 144, 0 }, + { "DBREAKC0", 160, 0 }, + { "IBREAKA0", 128, 0 }, + { "IBREAKENABLE", 96, 0 }, + { "ICOUNTLEVEL", 237, 0 }, + { "DEBUGCAUSE", 233, 0 } +}; + +#define NUM_SYSREGS 32 +#define MAX_SPECIAL_REG 240 +#define MAX_USER_REG 0 + + +/* Processor states. */ + +static xtensa_state_internal states[] = { + { "PC", 32, 0 }, + { "ICOUNT", 32, 0 }, + { "DDR", 32, 0 }, + { "INTERRUPT", 15, 0 }, + { "CCOUNT", 32, 0 }, + { "XTSYNC", 1, 0 }, + { "VECBASE", 25, 0 }, + { "EPC1", 32, 0 }, + { "EPC2", 32, 0 }, + { "EPC3", 32, 0 }, + { "EXCSAVE1", 32, 0 }, + { "EXCSAVE2", 32, 0 }, + { "EXCSAVE3", 32, 0 }, + { "EPS2", 6, 0 }, + { "EPS3", 6, 0 }, + { "EXCCAUSE", 6, 0 }, + { "PSINTLEVEL", 4, 0 }, + { "PSUM", 1, 0 }, + { "PSEXCM", 1, 0 }, + { "DEPC", 32, 0 }, + { "EXCVADDR", 32, 0 }, + { "SAR", 6, 0 }, + { "LITBADDR", 20, 0 }, + { "LITBEN", 1, 0 }, + { "InOCDMode", 1, 0 }, + { "INTENABLE", 15, 0 }, + { "DBREAKA0", 32, 0 }, + { "DBREAKC0", 8, 0 }, + { "IBREAKA0", 32, 0 }, + { "IBREAKENABLE", 1, 0 }, + { "ICOUNTLEVEL", 4, 0 }, + { "DEBUGCAUSE", 6, 0 }, + { "DBNUM", 4, 0 }, + { "CCOMPARE0", 32, 0 } +}; + +#define NUM_STATES 34 + +enum xtensa_state_id { + STATE_PC, + STATE_ICOUNT, + STATE_DDR, + STATE_INTERRUPT, + STATE_CCOUNT, + STATE_XTSYNC, + STATE_VECBASE, + STATE_EPC1, + STATE_EPC2, + STATE_EPC3, + STATE_EXCSAVE1, + STATE_EXCSAVE2, + STATE_EXCSAVE3, + STATE_EPS2, + STATE_EPS3, + STATE_EXCCAUSE, + STATE_PSINTLEVEL, + STATE_PSUM, + STATE_PSEXCM, + STATE_DEPC, + STATE_EXCVADDR, + STATE_SAR, + STATE_LITBADDR, + STATE_LITBEN, + STATE_InOCDMode, + STATE_INTENABLE, + STATE_DBREAKA0, + STATE_DBREAKC0, + STATE_IBREAKA0, + STATE_IBREAKENABLE, + STATE_ICOUNTLEVEL, + STATE_DEBUGCAUSE, + STATE_DBNUM, + STATE_CCOMPARE0 +}; + + +/* Field definitions. */ + +static unsigned +Field_t_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_t_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_s_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_s_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_r_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_r_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_op2_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 8) >> 28); + return tie_t; +} + +static void +Field_op2_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00000) | (tie_t << 20); +} + +static unsigned +Field_op1_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 12) >> 28); + return tie_t; +} + +static void +Field_op1_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0000) | (tie_t << 16); +} + +static unsigned +Field_op0_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_op0_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_m_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 24) >> 30); + return tie_t; +} + +static void +Field_m_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc0) | (tie_t << 6); +} + +static unsigned +Field_n_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_n_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_thi3_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 24) >> 29); + return tie_t; +} + +static void +Field_thi3_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe0) | (tie_t << 5); +} + +static unsigned +Field_sr_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sr_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_op0_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_op0_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_z_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 25) >> 31); + return tie_t; +} + +static void +Field_z_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x40) | (tie_t << 6); +} + +static unsigned +Field_i_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 24) >> 31); + return tie_t; +} + +static void +Field_i_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x80) | (tie_t << 7); +} + +static unsigned +Field_op0_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_op0_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_t_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_t_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_r_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_r_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_s_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_s_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_t_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_t_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_bbi4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 19) >> 31); + return tie_t; +} + +static void +Field_bbi4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x1000) | (tie_t << 12); +} + +static unsigned +Field_bbi_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 19) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_bbi_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x1000) | (tie_t << 12); +} + +static unsigned +Field_imm12_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 12) | ((insn[0] << 8) >> 20); + return tie_t; +} + +static void +Field_imm12_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 20) >> 20; + insn[0] = (insn[0] & ~0xfff000) | (tie_t << 12); +} + +static unsigned +Field_imm8_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 8) | ((insn[0] << 8) >> 24); + return tie_t; +} + +static void +Field_imm8_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 24) >> 24; + insn[0] = (insn[0] & ~0xff0000) | (tie_t << 16); +} + +static unsigned +Field_s_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_s_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_imm12b_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 8) | ((insn[0] << 8) >> 24); + return tie_t; +} + +static void +Field_imm12b_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 24) >> 24; + insn[0] = (insn[0] & ~0xff0000) | (tie_t << 16); + tie_t = (val << 20) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_imm16_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 16) | ((insn[0] << 8) >> 16); + return tie_t; +} + +static void +Field_imm16_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 16) >> 16; + insn[0] = (insn[0] & ~0xffff00) | (tie_t << 8); +} + +static unsigned +Field_offset_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 18) | ((insn[0] << 8) >> 14); + return tie_t; +} + +static void +Field_offset_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 14) >> 14; + insn[0] = (insn[0] & ~0xffffc0) | (tie_t << 6); +} + +static unsigned +Field_r_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_r_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_sa4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 11) >> 31); + return tie_t; +} + +static void +Field_sa4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x100000) | (tie_t << 20); +} + +static unsigned +Field_sae4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 15) >> 31); + return tie_t; +} + +static void +Field_sae4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x10000) | (tie_t << 16); +} + +static unsigned +Field_sae_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 15) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sae_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x10000) | (tie_t << 16); +} + +static unsigned +Field_sal_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 11) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_sal_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100000) | (tie_t << 20); +} + +static unsigned +Field_sargt_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 11) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sargt_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100000) | (tie_t << 20); +} + +static unsigned +Field_sas4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 27) >> 31); + return tie_t; +} + +static void +Field_sas4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x10) | (tie_t << 4); +} + +static unsigned +Field_sas_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 27) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sas_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x10) | (tie_t << 4); +} + +static unsigned +Field_sr_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sr_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_sr_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sr_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_st_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_st_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_st_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_st_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_st_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_st_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_imm4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm4_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm4_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm4_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm4_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_i_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 24) >> 31); + return tie_t; +} + +static void +Field_i_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x80) | (tie_t << 7); +} + +static unsigned +Field_imm6lo_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6lo_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm6lo_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6lo_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm6hi_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_imm6hi_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm6hi_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_imm6hi_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm7lo_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7lo_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm7lo_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7lo_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm7hi_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + return tie_t; +} + +static void +Field_imm7hi_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_imm7hi_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + return tie_t; +} + +static void +Field_imm7hi_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_z_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 25) >> 31); + return tie_t; +} + +static void +Field_z_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x40) | (tie_t << 6); +} + +static unsigned +Field_imm6_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 26) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm6_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 26) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm7_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 25) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_imm7_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 25) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_xt_wbr15_imm_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 15) | ((insn[0] << 8) >> 17); + return tie_t; +} + +static void +Field_xt_wbr15_imm_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 17) >> 17; + insn[0] = (insn[0] & ~0xfffe00) | (tie_t << 9); +} + +static unsigned +Field_xt_wbr18_imm_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 18) | ((insn[0] << 8) >> 14); + return tie_t; +} + +static void +Field_xt_wbr18_imm_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 14) >> 14; + insn[0] = (insn[0] & ~0xffffc0) | (tie_t << 6); +} + +static void +Implicit_Field_set (xtensa_insnbuf insn ATTRIBUTE_UNUSED, + uint32 val ATTRIBUTE_UNUSED) +{ + /* Do nothing. */ +} + +static unsigned +Implicit_Field_ar0_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 0; +} + +enum xtensa_field_id { + FIELD_t, + FIELD_bbi4, + FIELD_bbi, + FIELD_imm12, + FIELD_imm8, + FIELD_s, + FIELD_imm12b, + FIELD_imm16, + FIELD_m, + FIELD_n, + FIELD_offset, + FIELD_op0, + FIELD_op1, + FIELD_op2, + FIELD_r, + FIELD_sa4, + FIELD_sae4, + FIELD_sae, + FIELD_sal, + FIELD_sargt, + FIELD_sas4, + FIELD_sas, + FIELD_sr, + FIELD_st, + FIELD_thi3, + FIELD_imm4, + FIELD_i, + FIELD_imm6lo, + FIELD_imm6hi, + FIELD_imm7lo, + FIELD_imm7hi, + FIELD_z, + FIELD_imm6, + FIELD_imm7, + FIELD_xt_wbr15_imm, + FIELD_xt_wbr18_imm, + FIELD__ar0 +}; + + +/* Functional units. */ + +static xtensa_funcUnit_internal funcUnits[] = { + +}; + + +/* Register files. */ + +enum xtensa_regfile_id { + REGFILE_AR +}; + +static xtensa_regfile_internal regfiles[] = { + { "AR", "a", REGFILE_AR, 32, 16 } +}; + + +/* Interfaces. */ + +static xtensa_interface_internal interfaces[] = { + +}; + + +/* Constant tables. */ + +/* constant table ai4c */ +static const unsigned CONST_TBL_ai4c_0[] = { + 0xffffffff, + 0x1, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0x9, + 0xa, + 0xb, + 0xc, + 0xd, + 0xe, + 0xf, + 0 +}; + +/* constant table b4c */ +static const unsigned CONST_TBL_b4c_0[] = { + 0xffffffff, + 0x1, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0xa, + 0xc, + 0x10, + 0x20, + 0x40, + 0x80, + 0x100, + 0 +}; + +/* constant table b4cu */ +static const unsigned CONST_TBL_b4cu_0[] = { + 0x8000, + 0x10000, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0xa, + 0xc, + 0x10, + 0x20, + 0x40, + 0x80, + 0x100, + 0 +}; + + +/* Instruction operands. */ + +static int +Operand_art_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_art_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0xf) != 0; + return error; +} + +static int +Operand_ars_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ars_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0xf) != 0; + return error; +} + +static int +Operand_arr_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_arr_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0xf) != 0; + return error; +} + +static int +Operand_ar0_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ar0_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0xf) != 0; + return error; +} + +static int +Operand_soffsetx4_decode (uint32 *valp) +{ + unsigned soffsetx4_0, offset_0; + offset_0 = *valp & 0x3ffff; + soffsetx4_0 = 0x4 + ((((int) offset_0 << 14) >> 14) << 2); + *valp = soffsetx4_0; + return 0; +} + +static int +Operand_soffsetx4_encode (uint32 *valp) +{ + unsigned offset_0, soffsetx4_0; + soffsetx4_0 = *valp; + offset_0 = ((soffsetx4_0 - 0x4) >> 2) & 0x3ffff; + *valp = offset_0; + return 0; +} + +static int +Operand_soffsetx4_ator (uint32 *valp, uint32 pc) +{ + *valp -= (pc & ~0x3); + return 0; +} + +static int +Operand_soffsetx4_rtoa (uint32 *valp, uint32 pc) +{ + *valp += (pc & ~0x3); + return 0; +} + +static int +Operand_lsi4x4_decode (uint32 *valp) +{ + unsigned lsi4x4_0, r_0; + r_0 = *valp & 0xf; + lsi4x4_0 = r_0 << 2; + *valp = lsi4x4_0; + return 0; +} + +static int +Operand_lsi4x4_encode (uint32 *valp) +{ + unsigned r_0, lsi4x4_0; + lsi4x4_0 = *valp; + r_0 = ((lsi4x4_0 >> 2) & 0xf); + *valp = r_0; + return 0; +} + +static int +Operand_simm7_decode (uint32 *valp) +{ + unsigned simm7_0, imm7_0; + imm7_0 = *valp & 0x7f; + simm7_0 = ((((-((((imm7_0 >> 6) & 1)) & (((imm7_0 >> 5) & 1)))) & 0x1ffffff)) << 7) | imm7_0; + *valp = simm7_0; + return 0; +} + +static int +Operand_simm7_encode (uint32 *valp) +{ + unsigned imm7_0, simm7_0; + simm7_0 = *valp; + imm7_0 = (simm7_0 & 0x7f); + *valp = imm7_0; + return 0; +} + +static int +Operand_uimm6_decode (uint32 *valp) +{ + unsigned uimm6_0, imm6_0; + imm6_0 = *valp & 0x3f; + uimm6_0 = 0x4 + (((0) << 6) | imm6_0); + *valp = uimm6_0; + return 0; +} + +static int +Operand_uimm6_encode (uint32 *valp) +{ + unsigned imm6_0, uimm6_0; + uimm6_0 = *valp; + imm6_0 = (uimm6_0 - 0x4) & 0x3f; + *valp = imm6_0; + return 0; +} + +static int +Operand_uimm6_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_uimm6_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_ai4const_decode (uint32 *valp) +{ + unsigned ai4const_0, t_0; + t_0 = *valp & 0xf; + ai4const_0 = CONST_TBL_ai4c_0[t_0 & 0xf]; + *valp = ai4const_0; + return 0; +} + +static int +Operand_ai4const_encode (uint32 *valp) +{ + unsigned t_0, ai4const_0; + ai4const_0 = *valp; + switch (ai4const_0) + { + case 0xffffffff: t_0 = 0; break; + case 0x1: t_0 = 0x1; break; + case 0x2: t_0 = 0x2; break; + case 0x3: t_0 = 0x3; break; + case 0x4: t_0 = 0x4; break; + case 0x5: t_0 = 0x5; break; + case 0x6: t_0 = 0x6; break; + case 0x7: t_0 = 0x7; break; + case 0x8: t_0 = 0x8; break; + case 0x9: t_0 = 0x9; break; + case 0xa: t_0 = 0xa; break; + case 0xb: t_0 = 0xb; break; + case 0xc: t_0 = 0xc; break; + case 0xd: t_0 = 0xd; break; + case 0xe: t_0 = 0xe; break; + default: t_0 = 0xf; break; + } + *valp = t_0; + return 0; +} + +static int +Operand_b4const_decode (uint32 *valp) +{ + unsigned b4const_0, r_0; + r_0 = *valp & 0xf; + b4const_0 = CONST_TBL_b4c_0[r_0 & 0xf]; + *valp = b4const_0; + return 0; +} + +static int +Operand_b4const_encode (uint32 *valp) +{ + unsigned r_0, b4const_0; + b4const_0 = *valp; + switch (b4const_0) + { + case 0xffffffff: r_0 = 0; break; + case 0x1: r_0 = 0x1; break; + case 0x2: r_0 = 0x2; break; + case 0x3: r_0 = 0x3; break; + case 0x4: r_0 = 0x4; break; + case 0x5: r_0 = 0x5; break; + case 0x6: r_0 = 0x6; break; + case 0x7: r_0 = 0x7; break; + case 0x8: r_0 = 0x8; break; + case 0xa: r_0 = 0x9; break; + case 0xc: r_0 = 0xa; break; + case 0x10: r_0 = 0xb; break; + case 0x20: r_0 = 0xc; break; + case 0x40: r_0 = 0xd; break; + case 0x80: r_0 = 0xe; break; + default: r_0 = 0xf; break; + } + *valp = r_0; + return 0; +} + +static int +Operand_b4constu_decode (uint32 *valp) +{ + unsigned b4constu_0, r_0; + r_0 = *valp & 0xf; + b4constu_0 = CONST_TBL_b4cu_0[r_0 & 0xf]; + *valp = b4constu_0; + return 0; +} + +static int +Operand_b4constu_encode (uint32 *valp) +{ + unsigned r_0, b4constu_0; + b4constu_0 = *valp; + switch (b4constu_0) + { + case 0x8000: r_0 = 0; break; + case 0x10000: r_0 = 0x1; break; + case 0x2: r_0 = 0x2; break; + case 0x3: r_0 = 0x3; break; + case 0x4: r_0 = 0x4; break; + case 0x5: r_0 = 0x5; break; + case 0x6: r_0 = 0x6; break; + case 0x7: r_0 = 0x7; break; + case 0x8: r_0 = 0x8; break; + case 0xa: r_0 = 0x9; break; + case 0xc: r_0 = 0xa; break; + case 0x10: r_0 = 0xb; break; + case 0x20: r_0 = 0xc; break; + case 0x40: r_0 = 0xd; break; + case 0x80: r_0 = 0xe; break; + default: r_0 = 0xf; break; + } + *valp = r_0; + return 0; +} + +static int +Operand_uimm8_decode (uint32 *valp) +{ + unsigned uimm8_0, imm8_0; + imm8_0 = *valp & 0xff; + uimm8_0 = imm8_0; + *valp = uimm8_0; + return 0; +} + +static int +Operand_uimm8_encode (uint32 *valp) +{ + unsigned imm8_0, uimm8_0; + uimm8_0 = *valp; + imm8_0 = (uimm8_0 & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_uimm8x2_decode (uint32 *valp) +{ + unsigned uimm8x2_0, imm8_0; + imm8_0 = *valp & 0xff; + uimm8x2_0 = imm8_0 << 1; + *valp = uimm8x2_0; + return 0; +} + +static int +Operand_uimm8x2_encode (uint32 *valp) +{ + unsigned imm8_0, uimm8x2_0; + uimm8x2_0 = *valp; + imm8_0 = ((uimm8x2_0 >> 1) & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_uimm8x4_decode (uint32 *valp) +{ + unsigned uimm8x4_0, imm8_0; + imm8_0 = *valp & 0xff; + uimm8x4_0 = imm8_0 << 2; + *valp = uimm8x4_0; + return 0; +} + +static int +Operand_uimm8x4_encode (uint32 *valp) +{ + unsigned imm8_0, uimm8x4_0; + uimm8x4_0 = *valp; + imm8_0 = ((uimm8x4_0 >> 2) & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_uimm4x16_decode (uint32 *valp) +{ + unsigned uimm4x16_0, op2_0; + op2_0 = *valp & 0xf; + uimm4x16_0 = op2_0 << 4; + *valp = uimm4x16_0; + return 0; +} + +static int +Operand_uimm4x16_encode (uint32 *valp) +{ + unsigned op2_0, uimm4x16_0; + uimm4x16_0 = *valp; + op2_0 = ((uimm4x16_0 >> 4) & 0xf); + *valp = op2_0; + return 0; +} + +static int +Operand_simm8_decode (uint32 *valp) +{ + unsigned simm8_0, imm8_0; + imm8_0 = *valp & 0xff; + simm8_0 = ((int) imm8_0 << 24) >> 24; + *valp = simm8_0; + return 0; +} + +static int +Operand_simm8_encode (uint32 *valp) +{ + unsigned imm8_0, simm8_0; + simm8_0 = *valp; + imm8_0 = (simm8_0 & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_simm8x256_decode (uint32 *valp) +{ + unsigned simm8x256_0, imm8_0; + imm8_0 = *valp & 0xff; + simm8x256_0 = (((int) imm8_0 << 24) >> 24) << 8; + *valp = simm8x256_0; + return 0; +} + +static int +Operand_simm8x256_encode (uint32 *valp) +{ + unsigned imm8_0, simm8x256_0; + simm8x256_0 = *valp; + imm8_0 = ((simm8x256_0 >> 8) & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_simm12b_decode (uint32 *valp) +{ + unsigned simm12b_0, imm12b_0; + imm12b_0 = *valp & 0xfff; + simm12b_0 = ((int) imm12b_0 << 20) >> 20; + *valp = simm12b_0; + return 0; +} + +static int +Operand_simm12b_encode (uint32 *valp) +{ + unsigned imm12b_0, simm12b_0; + simm12b_0 = *valp; + imm12b_0 = (simm12b_0 & 0xfff); + *valp = imm12b_0; + return 0; +} + +static int +Operand_msalp32_decode (uint32 *valp) +{ + unsigned msalp32_0, sal_0; + sal_0 = *valp & 0x1f; + msalp32_0 = 0x20 - sal_0; + *valp = msalp32_0; + return 0; +} + +static int +Operand_msalp32_encode (uint32 *valp) +{ + unsigned sal_0, msalp32_0; + msalp32_0 = *valp; + sal_0 = (0x20 - msalp32_0) & 0x1f; + *valp = sal_0; + return 0; +} + +static int +Operand_op2p1_decode (uint32 *valp) +{ + unsigned op2p1_0, op2_0; + op2_0 = *valp & 0xf; + op2p1_0 = op2_0 + 0x1; + *valp = op2p1_0; + return 0; +} + +static int +Operand_op2p1_encode (uint32 *valp) +{ + unsigned op2_0, op2p1_0; + op2p1_0 = *valp; + op2_0 = (op2p1_0 - 0x1) & 0xf; + *valp = op2_0; + return 0; +} + +static int +Operand_label8_decode (uint32 *valp) +{ + unsigned label8_0, imm8_0; + imm8_0 = *valp & 0xff; + label8_0 = 0x4 + (((int) imm8_0 << 24) >> 24); + *valp = label8_0; + return 0; +} + +static int +Operand_label8_encode (uint32 *valp) +{ + unsigned imm8_0, label8_0; + label8_0 = *valp; + imm8_0 = (label8_0 - 0x4) & 0xff; + *valp = imm8_0; + return 0; +} + +static int +Operand_label8_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_label8_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_label12_decode (uint32 *valp) +{ + unsigned label12_0, imm12_0; + imm12_0 = *valp & 0xfff; + label12_0 = 0x4 + (((int) imm12_0 << 20) >> 20); + *valp = label12_0; + return 0; +} + +static int +Operand_label12_encode (uint32 *valp) +{ + unsigned imm12_0, label12_0; + label12_0 = *valp; + imm12_0 = (label12_0 - 0x4) & 0xfff; + *valp = imm12_0; + return 0; +} + +static int +Operand_label12_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_label12_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_soffset_decode (uint32 *valp) +{ + unsigned soffset_0, offset_0; + offset_0 = *valp & 0x3ffff; + soffset_0 = 0x4 + (((int) offset_0 << 14) >> 14); + *valp = soffset_0; + return 0; +} + +static int +Operand_soffset_encode (uint32 *valp) +{ + unsigned offset_0, soffset_0; + soffset_0 = *valp; + offset_0 = (soffset_0 - 0x4) & 0x3ffff; + *valp = offset_0; + return 0; +} + +static int +Operand_soffset_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_soffset_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_uimm16x4_decode (uint32 *valp) +{ + unsigned uimm16x4_0, imm16_0; + imm16_0 = *valp & 0xffff; + uimm16x4_0 = (((0xffff) << 16) | imm16_0) << 2; + *valp = uimm16x4_0; + return 0; +} + +static int +Operand_uimm16x4_encode (uint32 *valp) +{ + unsigned imm16_0, uimm16x4_0; + uimm16x4_0 = *valp; + imm16_0 = (uimm16x4_0 >> 2) & 0xffff; + *valp = imm16_0; + return 0; +} + +static int +Operand_uimm16x4_ator (uint32 *valp, uint32 pc) +{ + *valp -= ((pc + 3) & ~0x3); + return 0; +} + +static int +Operand_uimm16x4_rtoa (uint32 *valp, uint32 pc) +{ + *valp += ((pc + 3) & ~0x3); + return 0; +} + +static int +Operand_immt_decode (uint32 *valp) +{ + unsigned immt_0, t_0; + t_0 = *valp & 0xf; + immt_0 = t_0; + *valp = immt_0; + return 0; +} + +static int +Operand_immt_encode (uint32 *valp) +{ + unsigned t_0, immt_0; + immt_0 = *valp; + t_0 = immt_0 & 0xf; + *valp = t_0; + return 0; +} + +static int +Operand_imms_decode (uint32 *valp) +{ + unsigned imms_0, s_0; + s_0 = *valp & 0xf; + imms_0 = s_0; + *valp = imms_0; + return 0; +} + +static int +Operand_imms_encode (uint32 *valp) +{ + unsigned s_0, imms_0; + imms_0 = *valp; + s_0 = imms_0 & 0xf; + *valp = s_0; + return 0; +} + +static int +Operand_xt_wbr15_label_decode (uint32 *valp) +{ + unsigned xt_wbr15_label_0, xt_wbr15_imm_0; + xt_wbr15_imm_0 = *valp & 0x7fff; + xt_wbr15_label_0 = 0x4 + (((int) xt_wbr15_imm_0 << 17) >> 17); + *valp = xt_wbr15_label_0; + return 0; +} + +static int +Operand_xt_wbr15_label_encode (uint32 *valp) +{ + unsigned xt_wbr15_imm_0, xt_wbr15_label_0; + xt_wbr15_label_0 = *valp; + xt_wbr15_imm_0 = (xt_wbr15_label_0 - 0x4) & 0x7fff; + *valp = xt_wbr15_imm_0; + return 0; +} + +static int +Operand_xt_wbr15_label_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_xt_wbr15_label_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_xt_wbr18_label_decode (uint32 *valp) +{ + unsigned xt_wbr18_label_0, xt_wbr18_imm_0; + xt_wbr18_imm_0 = *valp & 0x3ffff; + xt_wbr18_label_0 = 0x4 + (((int) xt_wbr18_imm_0 << 14) >> 14); + *valp = xt_wbr18_label_0; + return 0; +} + +static int +Operand_xt_wbr18_label_encode (uint32 *valp) +{ + unsigned xt_wbr18_imm_0, xt_wbr18_label_0; + xt_wbr18_label_0 = *valp; + xt_wbr18_imm_0 = (xt_wbr18_label_0 - 0x4) & 0x3ffff; + *valp = xt_wbr18_imm_0; + return 0; +} + +static int +Operand_xt_wbr18_label_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_xt_wbr18_label_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static xtensa_operand_internal operands[] = { + { "art", FIELD_t, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_art_encode, Operand_art_decode, + 0, 0 }, + { "ars", FIELD_s, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_ars_encode, Operand_ars_decode, + 0, 0 }, + { "*ars_invisible", FIELD_s, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ars_encode, Operand_ars_decode, + 0, 0 }, + { "arr", FIELD_r, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_arr_encode, Operand_arr_decode, + 0, 0 }, + { "ar0", FIELD__ar0, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ar0_encode, Operand_ar0_decode, + 0, 0 }, + { "soffsetx4", FIELD_offset, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_soffsetx4_encode, Operand_soffsetx4_decode, + Operand_soffsetx4_ator, Operand_soffsetx4_rtoa }, + { "lsi4x4", FIELD_r, -1, 0, + 0, + Operand_lsi4x4_encode, Operand_lsi4x4_decode, + 0, 0 }, + { "simm7", FIELD_imm7, -1, 0, + 0, + Operand_simm7_encode, Operand_simm7_decode, + 0, 0 }, + { "uimm6", FIELD_imm6, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_uimm6_encode, Operand_uimm6_decode, + Operand_uimm6_ator, Operand_uimm6_rtoa }, + { "ai4const", FIELD_t, -1, 0, + 0, + Operand_ai4const_encode, Operand_ai4const_decode, + 0, 0 }, + { "b4const", FIELD_r, -1, 0, + 0, + Operand_b4const_encode, Operand_b4const_decode, + 0, 0 }, + { "b4constu", FIELD_r, -1, 0, + 0, + Operand_b4constu_encode, Operand_b4constu_decode, + 0, 0 }, + { "uimm8", FIELD_imm8, -1, 0, + 0, + Operand_uimm8_encode, Operand_uimm8_decode, + 0, 0 }, + { "uimm8x2", FIELD_imm8, -1, 0, + 0, + Operand_uimm8x2_encode, Operand_uimm8x2_decode, + 0, 0 }, + { "uimm8x4", FIELD_imm8, -1, 0, + 0, + Operand_uimm8x4_encode, Operand_uimm8x4_decode, + 0, 0 }, + { "uimm4x16", FIELD_op2, -1, 0, + 0, + Operand_uimm4x16_encode, Operand_uimm4x16_decode, + 0, 0 }, + { "simm8", FIELD_imm8, -1, 0, + 0, + Operand_simm8_encode, Operand_simm8_decode, + 0, 0 }, + { "simm8x256", FIELD_imm8, -1, 0, + 0, + Operand_simm8x256_encode, Operand_simm8x256_decode, + 0, 0 }, + { "simm12b", FIELD_imm12b, -1, 0, + 0, + Operand_simm12b_encode, Operand_simm12b_decode, + 0, 0 }, + { "msalp32", FIELD_sal, -1, 0, + 0, + Operand_msalp32_encode, Operand_msalp32_decode, + 0, 0 }, + { "op2p1", FIELD_op2, -1, 0, + 0, + Operand_op2p1_encode, Operand_op2p1_decode, + 0, 0 }, + { "label8", FIELD_imm8, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_label8_encode, Operand_label8_decode, + Operand_label8_ator, Operand_label8_rtoa }, + { "label12", FIELD_imm12, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_label12_encode, Operand_label12_decode, + Operand_label12_ator, Operand_label12_rtoa }, + { "soffset", FIELD_offset, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_soffset_encode, Operand_soffset_decode, + Operand_soffset_ator, Operand_soffset_rtoa }, + { "uimm16x4", FIELD_imm16, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_uimm16x4_encode, Operand_uimm16x4_decode, + Operand_uimm16x4_ator, Operand_uimm16x4_rtoa }, + { "immt", FIELD_t, -1, 0, + 0, + Operand_immt_encode, Operand_immt_decode, + 0, 0 }, + { "imms", FIELD_s, -1, 0, + 0, + Operand_imms_encode, Operand_imms_decode, + 0, 0 }, + { "xt_wbr15_label", FIELD_xt_wbr15_imm, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_xt_wbr15_label_encode, Operand_xt_wbr15_label_decode, + Operand_xt_wbr15_label_ator, Operand_xt_wbr15_label_rtoa }, + { "xt_wbr18_label", FIELD_xt_wbr18_imm, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_xt_wbr18_label_encode, Operand_xt_wbr18_label_decode, + Operand_xt_wbr18_label_ator, Operand_xt_wbr18_label_rtoa }, + { "t", FIELD_t, -1, 0, 0, 0, 0, 0, 0 }, + { "bbi4", FIELD_bbi4, -1, 0, 0, 0, 0, 0, 0 }, + { "bbi", FIELD_bbi, -1, 0, 0, 0, 0, 0, 0 }, + { "imm12", FIELD_imm12, -1, 0, 0, 0, 0, 0, 0 }, + { "imm8", FIELD_imm8, -1, 0, 0, 0, 0, 0, 0 }, + { "s", FIELD_s, -1, 0, 0, 0, 0, 0, 0 }, + { "imm12b", FIELD_imm12b, -1, 0, 0, 0, 0, 0, 0 }, + { "imm16", FIELD_imm16, -1, 0, 0, 0, 0, 0, 0 }, + { "m", FIELD_m, -1, 0, 0, 0, 0, 0, 0 }, + { "n", FIELD_n, -1, 0, 0, 0, 0, 0, 0 }, + { "offset", FIELD_offset, -1, 0, 0, 0, 0, 0, 0 }, + { "op0", FIELD_op0, -1, 0, 0, 0, 0, 0, 0 }, + { "op1", FIELD_op1, -1, 0, 0, 0, 0, 0, 0 }, + { "op2", FIELD_op2, -1, 0, 0, 0, 0, 0, 0 }, + { "r", FIELD_r, -1, 0, 0, 0, 0, 0, 0 }, + { "sa4", FIELD_sa4, -1, 0, 0, 0, 0, 0, 0 }, + { "sae4", FIELD_sae4, -1, 0, 0, 0, 0, 0, 0 }, + { "sae", FIELD_sae, -1, 0, 0, 0, 0, 0, 0 }, + { "sal", FIELD_sal, -1, 0, 0, 0, 0, 0, 0 }, + { "sargt", FIELD_sargt, -1, 0, 0, 0, 0, 0, 0 }, + { "sas4", FIELD_sas4, -1, 0, 0, 0, 0, 0, 0 }, + { "sas", FIELD_sas, -1, 0, 0, 0, 0, 0, 0 }, + { "sr", FIELD_sr, -1, 0, 0, 0, 0, 0, 0 }, + { "st", FIELD_st, -1, 0, 0, 0, 0, 0, 0 }, + { "thi3", FIELD_thi3, -1, 0, 0, 0, 0, 0, 0 }, + { "imm4", FIELD_imm4, -1, 0, 0, 0, 0, 0, 0 }, + { "i", FIELD_i, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6lo", FIELD_imm6lo, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6hi", FIELD_imm6hi, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7lo", FIELD_imm7lo, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7hi", FIELD_imm7hi, -1, 0, 0, 0, 0, 0, 0 }, + { "z", FIELD_z, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6", FIELD_imm6, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7", FIELD_imm7, -1, 0, 0, 0, 0, 0, 0 }, + { "xt_wbr15_imm", FIELD_xt_wbr15_imm, -1, 0, 0, 0, 0, 0, 0 }, + { "xt_wbr18_imm", FIELD_xt_wbr18_imm, -1, 0, 0, 0, 0, 0, 0 } +}; + +enum xtensa_operand_id { + OPERAND_art, + OPERAND_ars, + OPERAND__ars_invisible, + OPERAND_arr, + OPERAND_ar0, + OPERAND_soffsetx4, + OPERAND_lsi4x4, + OPERAND_simm7, + OPERAND_uimm6, + OPERAND_ai4const, + OPERAND_b4const, + OPERAND_b4constu, + OPERAND_uimm8, + OPERAND_uimm8x2, + OPERAND_uimm8x4, + OPERAND_uimm4x16, + OPERAND_simm8, + OPERAND_simm8x256, + OPERAND_simm12b, + OPERAND_msalp32, + OPERAND_op2p1, + OPERAND_label8, + OPERAND_label12, + OPERAND_soffset, + OPERAND_uimm16x4, + OPERAND_immt, + OPERAND_imms, + OPERAND_xt_wbr15_label, + OPERAND_xt_wbr18_label, + OPERAND_t, + OPERAND_bbi4, + OPERAND_bbi, + OPERAND_imm12, + OPERAND_imm8, + OPERAND_s, + OPERAND_imm12b, + OPERAND_imm16, + OPERAND_m, + OPERAND_n, + OPERAND_offset, + OPERAND_op0, + OPERAND_op1, + OPERAND_op2, + OPERAND_r, + OPERAND_sa4, + OPERAND_sae4, + OPERAND_sae, + OPERAND_sal, + OPERAND_sargt, + OPERAND_sas4, + OPERAND_sas, + OPERAND_sr, + OPERAND_st, + OPERAND_thi3, + OPERAND_imm4, + OPERAND_i, + OPERAND_imm6lo, + OPERAND_imm6hi, + OPERAND_imm7lo, + OPERAND_imm7hi, + OPERAND_z, + OPERAND_imm6, + OPERAND_imm7, + OPERAND_xt_wbr15_imm, + OPERAND_xt_wbr18_imm +}; + + +/* Iclass table. */ + +static xtensa_arg_internal Iclass_xt_iclass_rfe_stateArgs[] = { + { { STATE_PSEXCM }, 'o' }, + { { STATE_EPC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfde_stateArgs[] = { + { { STATE_DEPC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_add_n_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addi_n_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_ai4const }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bz6_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm6 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loadi4_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_lsi4x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mov_n_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movi_n_args[] = { + { { OPERAND_ars }, 'o' }, + { { OPERAND_simm7 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_retn_args[] = { + { { OPERAND__ars_invisible }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_storei4_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_lsi4x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addi_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_simm8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addmi_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_simm8x256 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addsub_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bit_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsi8_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_b4const }, 'i' }, + { { OPERAND_label8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsi8b_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_bbi }, 'i' }, + { { OPERAND_label8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsi8u_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_b4constu }, 'i' }, + { { OPERAND_label8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bst8_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_label8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsz12_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_label12 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call0_args[] = { + { { OPERAND_soffsetx4 }, 'i' }, + { { OPERAND_ar0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx0_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_ar0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_exti_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_sae }, 'i' }, + { { OPERAND_op2p1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_jump_args[] = { + { { OPERAND_soffset }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_jumpx_args[] = { + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l16ui_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l16si_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32i_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32r_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_uimm16x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32r_stateArgs[] = { + { { STATE_LITBADDR }, 'i' }, + { { STATE_LITBEN }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l8i_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movi_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_simm12b }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movz_args[] = { + { { OPERAND_arr }, 'm' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_neg_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_return_args[] = { + { { OPERAND__ars_invisible }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s16i_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32i_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s8i_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sar_args[] = { + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sar_stateArgs[] = { + { { STATE_SAR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sari_args[] = { + { { OPERAND_sas }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sari_stateArgs[] = { + { { STATE_SAR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shifts_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shifts_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftst_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftst_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftt_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftt_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_slli_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_msalp32 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_srai_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_sargt }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_srli_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_s }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sync_stateArgs[] = { + { { STATE_XTSYNC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsil_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_s }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsil_stateArgs[] = { + { { STATE_PSUM }, 'i' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_sar_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_sar_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_sar_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_sar_stateArgs[] = { + { { STATE_SAR }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_sar_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_sar_stateArgs[] = { + { { STATE_SAR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_litbase_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_litbase_stateArgs[] = { + { { STATE_LITBADDR }, 'i' }, + { { STATE_LITBEN }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_litbase_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_litbase_stateArgs[] = { + { { STATE_LITBADDR }, 'o' }, + { { STATE_LITBEN }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_litbase_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_litbase_stateArgs[] = { + { { STATE_LITBADDR }, 'm' }, + { { STATE_LITBEN }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_176_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_176_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_208_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ps_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ps_stateArgs[] = { + { { STATE_PSUM }, 'i' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ps_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ps_stateArgs[] = { + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'o' }, + { { STATE_PSINTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ps_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ps_stateArgs[] = { + { { STATE_PSUM }, 'm' }, + { { STATE_PSEXCM }, 'm' }, + { { STATE_PSINTLEVEL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc1_stateArgs[] = { + { { STATE_EPC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc1_stateArgs[] = { + { { STATE_EPC1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc1_stateArgs[] = { + { { STATE_EPC1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave1_stateArgs[] = { + { { STATE_EXCSAVE1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave1_stateArgs[] = { + { { STATE_EXCSAVE1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave1_stateArgs[] = { + { { STATE_EXCSAVE1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc2_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc2_stateArgs[] = { + { { STATE_EPC2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc2_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc2_stateArgs[] = { + { { STATE_EPC2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc2_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc2_stateArgs[] = { + { { STATE_EPC2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave2_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave2_stateArgs[] = { + { { STATE_EXCSAVE2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave2_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave2_stateArgs[] = { + { { STATE_EXCSAVE2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave2_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave2_stateArgs[] = { + { { STATE_EXCSAVE2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc3_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc3_stateArgs[] = { + { { STATE_EPC3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc3_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc3_stateArgs[] = { + { { STATE_EPC3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc3_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc3_stateArgs[] = { + { { STATE_EPC3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave3_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave3_stateArgs[] = { + { { STATE_EXCSAVE3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave3_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave3_stateArgs[] = { + { { STATE_EXCSAVE3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave3_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave3_stateArgs[] = { + { { STATE_EXCSAVE3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps2_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps2_stateArgs[] = { + { { STATE_EPS2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps2_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps2_stateArgs[] = { + { { STATE_EPS2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps2_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps2_stateArgs[] = { + { { STATE_EPS2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps3_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps3_stateArgs[] = { + { { STATE_EPS3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps3_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps3_stateArgs[] = { + { { STATE_EPS3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps3_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps3_stateArgs[] = { + { { STATE_EPS3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excvaddr_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excvaddr_stateArgs[] = { + { { STATE_EXCVADDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excvaddr_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excvaddr_stateArgs[] = { + { { STATE_EXCVADDR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excvaddr_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excvaddr_stateArgs[] = { + { { STATE_EXCVADDR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_depc_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_depc_stateArgs[] = { + { { STATE_DEPC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_depc_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_depc_stateArgs[] = { + { { STATE_DEPC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_depc_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_depc_stateArgs[] = { + { { STATE_DEPC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_exccause_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_exccause_stateArgs[] = { + { { STATE_EXCCAUSE }, 'i' }, + { { STATE_XTSYNC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_exccause_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_exccause_stateArgs[] = { + { { STATE_EXCCAUSE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_exccause_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_exccause_stateArgs[] = { + { { STATE_EXCCAUSE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_prid_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_vecbase_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_vecbase_stateArgs[] = { + { { STATE_VECBASE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_vecbase_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_vecbase_stateArgs[] = { + { { STATE_VECBASE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_vecbase_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_vecbase_stateArgs[] = { + { { STATE_VECBASE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_mul16_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_mul32_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfi_args[] = { + { { OPERAND_s }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfi_stateArgs[] = { + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'o' }, + { { STATE_PSINTLEVEL }, 'o' }, + { { STATE_EPC1 }, 'i' }, + { { STATE_EPC2 }, 'i' }, + { { STATE_EPC3 }, 'i' }, + { { STATE_EPS2 }, 'i' }, + { { STATE_EPS3 }, 'i' }, + { { STATE_InOCDMode }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wait_args[] = { + { { OPERAND_s }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wait_stateArgs[] = { + { { STATE_PSINTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_interrupt_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_interrupt_stateArgs[] = { + { { STATE_INTERRUPT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intset_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intset_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intclear_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intclear_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_intenable_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_intenable_stateArgs[] = { + { { STATE_INTENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intenable_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intenable_stateArgs[] = { + { { STATE_INTENABLE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_intenable_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_intenable_stateArgs[] = { + { { STATE_INTENABLE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_args[] = { + { { OPERAND_imms }, 'i' }, + { { OPERAND_immt }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_n_args[] = { + { { OPERAND_imms }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_n_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka0_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka0_stateArgs[] = { + { { STATE_DBREAKA0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka0_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka0_stateArgs[] = { + { { STATE_DBREAKA0 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka0_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka0_stateArgs[] = { + { { STATE_DBREAKA0 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc0_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc0_stateArgs[] = { + { { STATE_DBREAKC0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc0_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc0_stateArgs[] = { + { { STATE_DBREAKC0 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc0_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc0_stateArgs[] = { + { { STATE_DBREAKC0 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka0_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka0_stateArgs[] = { + { { STATE_IBREAKA0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka0_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka0_stateArgs[] = { + { { STATE_IBREAKA0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka0_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka0_stateArgs[] = { + { { STATE_IBREAKA0 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreakenable_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreakenable_stateArgs[] = { + { { STATE_IBREAKENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreakenable_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreakenable_stateArgs[] = { + { { STATE_IBREAKENABLE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreakenable_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreakenable_stateArgs[] = { + { { STATE_IBREAKENABLE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_debugcause_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_debugcause_stateArgs[] = { + { { STATE_DEBUGCAUSE }, 'i' }, + { { STATE_DBNUM }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_debugcause_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_debugcause_stateArgs[] = { + { { STATE_DEBUGCAUSE }, 'o' }, + { { STATE_DBNUM }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_debugcause_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_debugcause_stateArgs[] = { + { { STATE_DEBUGCAUSE }, 'm' }, + { { STATE_DBNUM }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icount_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icount_stateArgs[] = { + { { STATE_ICOUNT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icount_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_ICOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icount_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_ICOUNT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icountlevel_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icountlevel_stateArgs[] = { + { { STATE_ICOUNTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icountlevel_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icountlevel_stateArgs[] = { + { { STATE_ICOUNTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icountlevel_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icountlevel_stateArgs[] = { + { { STATE_ICOUNTLEVEL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ddr_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ddr_stateArgs[] = { + { { STATE_DDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ddr_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ddr_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_DDR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ddr_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ddr_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_DDR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfdo_args[] = { + { { OPERAND_imms }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfdo_stateArgs[] = { + { { STATE_InOCDMode }, 'm' }, + { { STATE_EPC2 }, 'i' }, + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'o' }, + { { STATE_PSINTLEVEL }, 'o' }, + { { STATE_EPS2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfdd_stateArgs[] = { + { { STATE_InOCDMode }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_mmid_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_mmid_stateArgs[] = { + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccount_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccount_stateArgs[] = { + { { STATE_CCOUNT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccount_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_CCOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccount_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_CCOUNT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare0_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare0_stateArgs[] = { + { { STATE_CCOMPARE0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare0_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare0_stateArgs[] = { + { { STATE_CCOMPARE0 }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare0_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare0_stateArgs[] = { + { { STATE_CCOMPARE0 }, 'm' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_idtlb_args[] = { + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_idtlb_stateArgs[] = { + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rdtlb_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wdtlb_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wdtlb_stateArgs[] = { + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_iitlb_args[] = { + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ritlb_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_witlb_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_nsa_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_iclass_internal iclasses[] = { + { 0, 0 /* xt_iclass_excw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_rfe */, + 2, Iclass_xt_iclass_rfe_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfde */, + 1, Iclass_xt_iclass_rfde_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_syscall */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_simcall */, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_add_n_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addi_n_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_bz6_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_ill_n */, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_loadi4_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_mov_n_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_movi_n_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_nopn */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_retn_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_storei4_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addmi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addsub_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bit_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8b_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8u_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bst8_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_bsz12_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_call0_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_callx0_args, + 0, 0, 0, 0 }, + { 4, Iclass_xt_iclass_exti_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_ill */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_jump_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_jumpx_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l16ui_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l16si_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l32i_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_l32r_args, + 2, Iclass_xt_iclass_l32r_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_l8i_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_movi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_movz_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_neg_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_nop */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_return_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s16i_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s32i_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s8i_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_sar_args, + 1, Iclass_xt_iclass_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_sari_args, + 1, Iclass_xt_iclass_sari_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_shifts_args, + 1, Iclass_xt_iclass_shifts_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_shiftst_args, + 1, Iclass_xt_iclass_shiftst_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_shiftt_args, + 1, Iclass_xt_iclass_shiftt_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_slli_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_srai_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_srli_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_memw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_extw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_isync */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_sync */, + 1, Iclass_xt_iclass_sync_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_rsil_args, + 3, Iclass_xt_iclass_rsil_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_sar_args, + 1, Iclass_xt_iclass_rsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_sar_args, + 2, Iclass_xt_iclass_wsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_sar_args, + 1, Iclass_xt_iclass_xsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_litbase_args, + 2, Iclass_xt_iclass_rsr_litbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_litbase_args, + 2, Iclass_xt_iclass_wsr_litbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_litbase_args, + 2, Iclass_xt_iclass_xsr_litbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_176_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_176_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_208_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ps_args, + 3, Iclass_xt_iclass_rsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ps_args, + 3, Iclass_xt_iclass_wsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ps_args, + 3, Iclass_xt_iclass_xsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc1_args, + 1, Iclass_xt_iclass_rsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc1_args, + 1, Iclass_xt_iclass_wsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc1_args, + 1, Iclass_xt_iclass_xsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave1_args, + 1, Iclass_xt_iclass_rsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave1_args, + 1, Iclass_xt_iclass_wsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave1_args, + 1, Iclass_xt_iclass_xsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc2_args, + 1, Iclass_xt_iclass_rsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc2_args, + 1, Iclass_xt_iclass_wsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc2_args, + 1, Iclass_xt_iclass_xsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave2_args, + 1, Iclass_xt_iclass_rsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave2_args, + 1, Iclass_xt_iclass_wsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave2_args, + 1, Iclass_xt_iclass_xsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc3_args, + 1, Iclass_xt_iclass_rsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc3_args, + 1, Iclass_xt_iclass_wsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc3_args, + 1, Iclass_xt_iclass_xsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave3_args, + 1, Iclass_xt_iclass_rsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave3_args, + 1, Iclass_xt_iclass_wsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave3_args, + 1, Iclass_xt_iclass_xsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps2_args, + 1, Iclass_xt_iclass_rsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps2_args, + 1, Iclass_xt_iclass_wsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps2_args, + 1, Iclass_xt_iclass_xsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps3_args, + 1, Iclass_xt_iclass_rsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps3_args, + 1, Iclass_xt_iclass_wsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps3_args, + 1, Iclass_xt_iclass_xsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excvaddr_args, + 1, Iclass_xt_iclass_rsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excvaddr_args, + 1, Iclass_xt_iclass_wsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excvaddr_args, + 1, Iclass_xt_iclass_xsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_depc_args, + 1, Iclass_xt_iclass_rsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_depc_args, + 1, Iclass_xt_iclass_wsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_depc_args, + 1, Iclass_xt_iclass_xsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_exccause_args, + 2, Iclass_xt_iclass_rsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_exccause_args, + 1, Iclass_xt_iclass_wsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_exccause_args, + 1, Iclass_xt_iclass_xsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_prid_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_vecbase_args, + 1, Iclass_xt_iclass_rsr_vecbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_vecbase_args, + 1, Iclass_xt_iclass_wsr_vecbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_vecbase_args, + 1, Iclass_xt_iclass_xsr_vecbase_stateArgs, 0, 0 }, + { 3, Iclass_xt_mul16_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_mul32_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rfi_args, + 9, Iclass_xt_iclass_rfi_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wait_args, + 1, Iclass_xt_iclass_wait_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_interrupt_args, + 1, Iclass_xt_iclass_rsr_interrupt_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intset_args, + 2, Iclass_xt_iclass_wsr_intset_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intclear_args, + 2, Iclass_xt_iclass_wsr_intclear_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_intenable_args, + 1, Iclass_xt_iclass_rsr_intenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intenable_args, + 1, Iclass_xt_iclass_wsr_intenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_intenable_args, + 1, Iclass_xt_iclass_xsr_intenable_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_break_args, + 2, Iclass_xt_iclass_break_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_break_n_args, + 2, Iclass_xt_iclass_break_n_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreaka0_args, + 1, Iclass_xt_iclass_rsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreaka0_args, + 2, Iclass_xt_iclass_wsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreaka0_args, + 2, Iclass_xt_iclass_xsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreakc0_args, + 1, Iclass_xt_iclass_rsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreakc0_args, + 2, Iclass_xt_iclass_wsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreakc0_args, + 2, Iclass_xt_iclass_xsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ibreaka0_args, + 1, Iclass_xt_iclass_rsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ibreaka0_args, + 1, Iclass_xt_iclass_wsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ibreaka0_args, + 1, Iclass_xt_iclass_xsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ibreakenable_args, + 1, Iclass_xt_iclass_rsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ibreakenable_args, + 1, Iclass_xt_iclass_wsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ibreakenable_args, + 1, Iclass_xt_iclass_xsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_debugcause_args, + 2, Iclass_xt_iclass_rsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_debugcause_args, + 2, Iclass_xt_iclass_wsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_debugcause_args, + 2, Iclass_xt_iclass_xsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_icount_args, + 1, Iclass_xt_iclass_rsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_icount_args, + 2, Iclass_xt_iclass_wsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_icount_args, + 2, Iclass_xt_iclass_xsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_icountlevel_args, + 1, Iclass_xt_iclass_rsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_icountlevel_args, + 1, Iclass_xt_iclass_wsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_icountlevel_args, + 1, Iclass_xt_iclass_xsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ddr_args, + 1, Iclass_xt_iclass_rsr_ddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ddr_args, + 2, Iclass_xt_iclass_wsr_ddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ddr_args, + 2, Iclass_xt_iclass_xsr_ddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rfdo_args, + 6, Iclass_xt_iclass_rfdo_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfdd */, + 1, Iclass_xt_iclass_rfdd_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_mmid_args, + 1, Iclass_xt_iclass_wsr_mmid_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccount_args, + 1, Iclass_xt_iclass_rsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccount_args, + 2, Iclass_xt_iclass_wsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccount_args, + 2, Iclass_xt_iclass_xsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccompare0_args, + 1, Iclass_xt_iclass_rsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccompare0_args, + 2, Iclass_xt_iclass_wsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccompare0_args, + 2, Iclass_xt_iclass_xsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_idtlb_args, + 1, Iclass_xt_iclass_idtlb_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_rdtlb_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_wdtlb_args, + 1, Iclass_xt_iclass_wdtlb_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_iitlb_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_ritlb_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_witlb_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_nsa_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_rer */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_wer */, + 0, 0, 0, 0 } +}; + +enum xtensa_iclass_id { + ICLASS_xt_iclass_excw, + ICLASS_xt_iclass_rfe, + ICLASS_xt_iclass_rfde, + ICLASS_xt_iclass_syscall, + ICLASS_xt_iclass_simcall, + ICLASS_xt_iclass_add_n, + ICLASS_xt_iclass_addi_n, + ICLASS_xt_iclass_bz6, + ICLASS_xt_iclass_ill_n, + ICLASS_xt_iclass_loadi4, + ICLASS_xt_iclass_mov_n, + ICLASS_xt_iclass_movi_n, + ICLASS_xt_iclass_nopn, + ICLASS_xt_iclass_retn, + ICLASS_xt_iclass_storei4, + ICLASS_xt_iclass_addi, + ICLASS_xt_iclass_addmi, + ICLASS_xt_iclass_addsub, + ICLASS_xt_iclass_bit, + ICLASS_xt_iclass_bsi8, + ICLASS_xt_iclass_bsi8b, + ICLASS_xt_iclass_bsi8u, + ICLASS_xt_iclass_bst8, + ICLASS_xt_iclass_bsz12, + ICLASS_xt_iclass_call0, + ICLASS_xt_iclass_callx0, + ICLASS_xt_iclass_exti, + ICLASS_xt_iclass_ill, + ICLASS_xt_iclass_jump, + ICLASS_xt_iclass_jumpx, + ICLASS_xt_iclass_l16ui, + ICLASS_xt_iclass_l16si, + ICLASS_xt_iclass_l32i, + ICLASS_xt_iclass_l32r, + ICLASS_xt_iclass_l8i, + ICLASS_xt_iclass_movi, + ICLASS_xt_iclass_movz, + ICLASS_xt_iclass_neg, + ICLASS_xt_iclass_nop, + ICLASS_xt_iclass_return, + ICLASS_xt_iclass_s16i, + ICLASS_xt_iclass_s32i, + ICLASS_xt_iclass_s8i, + ICLASS_xt_iclass_sar, + ICLASS_xt_iclass_sari, + ICLASS_xt_iclass_shifts, + ICLASS_xt_iclass_shiftst, + ICLASS_xt_iclass_shiftt, + ICLASS_xt_iclass_slli, + ICLASS_xt_iclass_srai, + ICLASS_xt_iclass_srli, + ICLASS_xt_iclass_memw, + ICLASS_xt_iclass_extw, + ICLASS_xt_iclass_isync, + ICLASS_xt_iclass_sync, + ICLASS_xt_iclass_rsil, + ICLASS_xt_iclass_rsr_sar, + ICLASS_xt_iclass_wsr_sar, + ICLASS_xt_iclass_xsr_sar, + ICLASS_xt_iclass_rsr_litbase, + ICLASS_xt_iclass_wsr_litbase, + ICLASS_xt_iclass_xsr_litbase, + ICLASS_xt_iclass_rsr_176, + ICLASS_xt_iclass_wsr_176, + ICLASS_xt_iclass_rsr_208, + ICLASS_xt_iclass_rsr_ps, + ICLASS_xt_iclass_wsr_ps, + ICLASS_xt_iclass_xsr_ps, + ICLASS_xt_iclass_rsr_epc1, + ICLASS_xt_iclass_wsr_epc1, + ICLASS_xt_iclass_xsr_epc1, + ICLASS_xt_iclass_rsr_excsave1, + ICLASS_xt_iclass_wsr_excsave1, + ICLASS_xt_iclass_xsr_excsave1, + ICLASS_xt_iclass_rsr_epc2, + ICLASS_xt_iclass_wsr_epc2, + ICLASS_xt_iclass_xsr_epc2, + ICLASS_xt_iclass_rsr_excsave2, + ICLASS_xt_iclass_wsr_excsave2, + ICLASS_xt_iclass_xsr_excsave2, + ICLASS_xt_iclass_rsr_epc3, + ICLASS_xt_iclass_wsr_epc3, + ICLASS_xt_iclass_xsr_epc3, + ICLASS_xt_iclass_rsr_excsave3, + ICLASS_xt_iclass_wsr_excsave3, + ICLASS_xt_iclass_xsr_excsave3, + ICLASS_xt_iclass_rsr_eps2, + ICLASS_xt_iclass_wsr_eps2, + ICLASS_xt_iclass_xsr_eps2, + ICLASS_xt_iclass_rsr_eps3, + ICLASS_xt_iclass_wsr_eps3, + ICLASS_xt_iclass_xsr_eps3, + ICLASS_xt_iclass_rsr_excvaddr, + ICLASS_xt_iclass_wsr_excvaddr, + ICLASS_xt_iclass_xsr_excvaddr, + ICLASS_xt_iclass_rsr_depc, + ICLASS_xt_iclass_wsr_depc, + ICLASS_xt_iclass_xsr_depc, + ICLASS_xt_iclass_rsr_exccause, + ICLASS_xt_iclass_wsr_exccause, + ICLASS_xt_iclass_xsr_exccause, + ICLASS_xt_iclass_rsr_prid, + ICLASS_xt_iclass_rsr_vecbase, + ICLASS_xt_iclass_wsr_vecbase, + ICLASS_xt_iclass_xsr_vecbase, + ICLASS_xt_mul16, + ICLASS_xt_mul32, + ICLASS_xt_iclass_rfi, + ICLASS_xt_iclass_wait, + ICLASS_xt_iclass_rsr_interrupt, + ICLASS_xt_iclass_wsr_intset, + ICLASS_xt_iclass_wsr_intclear, + ICLASS_xt_iclass_rsr_intenable, + ICLASS_xt_iclass_wsr_intenable, + ICLASS_xt_iclass_xsr_intenable, + ICLASS_xt_iclass_break, + ICLASS_xt_iclass_break_n, + ICLASS_xt_iclass_rsr_dbreaka0, + ICLASS_xt_iclass_wsr_dbreaka0, + ICLASS_xt_iclass_xsr_dbreaka0, + ICLASS_xt_iclass_rsr_dbreakc0, + ICLASS_xt_iclass_wsr_dbreakc0, + ICLASS_xt_iclass_xsr_dbreakc0, + ICLASS_xt_iclass_rsr_ibreaka0, + ICLASS_xt_iclass_wsr_ibreaka0, + ICLASS_xt_iclass_xsr_ibreaka0, + ICLASS_xt_iclass_rsr_ibreakenable, + ICLASS_xt_iclass_wsr_ibreakenable, + ICLASS_xt_iclass_xsr_ibreakenable, + ICLASS_xt_iclass_rsr_debugcause, + ICLASS_xt_iclass_wsr_debugcause, + ICLASS_xt_iclass_xsr_debugcause, + ICLASS_xt_iclass_rsr_icount, + ICLASS_xt_iclass_wsr_icount, + ICLASS_xt_iclass_xsr_icount, + ICLASS_xt_iclass_rsr_icountlevel, + ICLASS_xt_iclass_wsr_icountlevel, + ICLASS_xt_iclass_xsr_icountlevel, + ICLASS_xt_iclass_rsr_ddr, + ICLASS_xt_iclass_wsr_ddr, + ICLASS_xt_iclass_xsr_ddr, + ICLASS_xt_iclass_rfdo, + ICLASS_xt_iclass_rfdd, + ICLASS_xt_iclass_wsr_mmid, + ICLASS_xt_iclass_rsr_ccount, + ICLASS_xt_iclass_wsr_ccount, + ICLASS_xt_iclass_xsr_ccount, + ICLASS_xt_iclass_rsr_ccompare0, + ICLASS_xt_iclass_wsr_ccompare0, + ICLASS_xt_iclass_xsr_ccompare0, + ICLASS_xt_iclass_idtlb, + ICLASS_xt_iclass_rdtlb, + ICLASS_xt_iclass_wdtlb, + ICLASS_xt_iclass_iitlb, + ICLASS_xt_iclass_ritlb, + ICLASS_xt_iclass_witlb, + ICLASS_xt_iclass_nsa, + ICLASS_xt_iclass_rer, + ICLASS_xt_iclass_wer +}; + + +/* Opcode encodings. */ + +static void +Opcode_excw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2080; +} + +static void +Opcode_rfe_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3000; +} + +static void +Opcode_rfde_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3200; +} + +static void +Opcode_syscall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5000; +} + +static void +Opcode_simcall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5100; +} + +static void +Opcode_add_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa; +} + +static void +Opcode_addi_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb; +} + +static void +Opcode_beqz_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8c; +} + +static void +Opcode_bnez_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xcc; +} + +static void +Opcode_ill_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf06d; +} + +static void +Opcode_l32i_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8; +} + +static void +Opcode_mov_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd; +} + +static void +Opcode_movi_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc; +} + +static void +Opcode_nop_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf03d; +} + +static void +Opcode_ret_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf00d; +} + +static void +Opcode_s32i_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9; +} + +static void +Opcode_addi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc002; +} + +static void +Opcode_addmi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd002; +} + +static void +Opcode_add_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x800000; +} + +static void +Opcode_sub_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc00000; +} + +static void +Opcode_addx2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x900000; +} + +static void +Opcode_addx4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa00000; +} + +static void +Opcode_addx8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb00000; +} + +static void +Opcode_subx2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd00000; +} + +static void +Opcode_subx4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe00000; +} + +static void +Opcode_subx8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf00000; +} + +static void +Opcode_and_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x100000; +} + +static void +Opcode_or_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200000; +} + +static void +Opcode_xor_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x300000; +} + +static void +Opcode_beqi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x26; +} + +static void +Opcode_bnei_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x66; +} + +static void +Opcode_bgei_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe6; +} + +static void +Opcode_blti_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa6; +} + +static void +Opcode_bbci_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6007; +} + +static void +Opcode_bbsi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe007; +} + +static void +Opcode_bgeui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf6; +} + +static void +Opcode_bltui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb6; +} + +static void +Opcode_beq_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1007; +} + +static void +Opcode_bne_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9007; +} + +static void +Opcode_bge_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa007; +} + +static void +Opcode_blt_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2007; +} + +static void +Opcode_bgeu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb007; +} + +static void +Opcode_bltu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3007; +} + +static void +Opcode_bany_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8007; +} + +static void +Opcode_bnone_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7; +} + +static void +Opcode_ball_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4007; +} + +static void +Opcode_bnall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc007; +} + +static void +Opcode_bbc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5007; +} + +static void +Opcode_bbs_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd007; +} + +static void +Opcode_beqz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x16; +} + +static void +Opcode_bnez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x56; +} + +static void +Opcode_bgez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd6; +} + +static void +Opcode_bltz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x96; +} + +static void +Opcode_call0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5; +} + +static void +Opcode_callx0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc0; +} + +static void +Opcode_extui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x40000; +} + +static void +Opcode_ill_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0; +} + +static void +Opcode_j_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6; +} + +static void +Opcode_jx_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa0; +} + +static void +Opcode_l16ui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1002; +} + +static void +Opcode_l16si_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9002; +} + +static void +Opcode_l32i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2002; +} + +static void +Opcode_l32r_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1; +} + +static void +Opcode_l8ui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2; +} + +static void +Opcode_movi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa002; +} + +static void +Opcode_moveqz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x830000; +} + +static void +Opcode_movnez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x930000; +} + +static void +Opcode_movltz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa30000; +} + +static void +Opcode_movgez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb30000; +} + +static void +Opcode_neg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x600000; +} + +static void +Opcode_abs_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x600100; +} + +static void +Opcode_nop_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20f0; +} + +static void +Opcode_ret_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x80; +} + +static void +Opcode_s16i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5002; +} + +static void +Opcode_s32i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6002; +} + +static void +Opcode_s8i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4002; +} + +static void +Opcode_ssr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x400000; +} + +static void +Opcode_ssl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x401000; +} + +static void +Opcode_ssa8l_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x402000; +} + +static void +Opcode_ssa8b_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x403000; +} + +static void +Opcode_ssai_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x404000; +} + +static void +Opcode_sll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa10000; +} + +static void +Opcode_src_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x810000; +} + +static void +Opcode_srl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x910000; +} + +static void +Opcode_sra_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb10000; +} + +static void +Opcode_slli_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x10000; +} + +static void +Opcode_srai_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x210000; +} + +static void +Opcode_srli_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x410000; +} + +static void +Opcode_memw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20c0; +} + +static void +Opcode_extw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20d0; +} + +static void +Opcode_isync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2000; +} + +static void +Opcode_rsync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2010; +} + +static void +Opcode_esync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2020; +} + +static void +Opcode_dsync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2030; +} + +static void +Opcode_rsil_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6000; +} + +static void +Opcode_rsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30300; +} + +static void +Opcode_wsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130300; +} + +static void +Opcode_xsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610300; +} + +static void +Opcode_rsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30500; +} + +static void +Opcode_wsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130500; +} + +static void +Opcode_xsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610500; +} + +static void +Opcode_rsr_176_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b000; +} + +static void +Opcode_wsr_176_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b000; +} + +static void +Opcode_rsr_208_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d000; +} + +static void +Opcode_rsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e600; +} + +static void +Opcode_wsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e600; +} + +static void +Opcode_xsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e600; +} + +static void +Opcode_rsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b100; +} + +static void +Opcode_wsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b100; +} + +static void +Opcode_xsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b100; +} + +static void +Opcode_rsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d100; +} + +static void +Opcode_wsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d100; +} + +static void +Opcode_xsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d100; +} + +static void +Opcode_rsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b200; +} + +static void +Opcode_wsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b200; +} + +static void +Opcode_xsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b200; +} + +static void +Opcode_rsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d200; +} + +static void +Opcode_wsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d200; +} + +static void +Opcode_xsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d200; +} + +static void +Opcode_rsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b300; +} + +static void +Opcode_wsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b300; +} + +static void +Opcode_xsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b300; +} + +static void +Opcode_rsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d300; +} + +static void +Opcode_wsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d300; +} + +static void +Opcode_xsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d300; +} + +static void +Opcode_rsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c200; +} + +static void +Opcode_wsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c200; +} + +static void +Opcode_xsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c200; +} + +static void +Opcode_rsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c300; +} + +static void +Opcode_wsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c300; +} + +static void +Opcode_xsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c300; +} + +static void +Opcode_rsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ee00; +} + +static void +Opcode_wsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ee00; +} + +static void +Opcode_xsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ee00; +} + +static void +Opcode_rsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c000; +} + +static void +Opcode_wsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c000; +} + +static void +Opcode_xsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c000; +} + +static void +Opcode_rsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e800; +} + +static void +Opcode_wsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e800; +} + +static void +Opcode_xsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e800; +} + +static void +Opcode_rsr_prid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3eb00; +} + +static void +Opcode_rsr_vecbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e700; +} + +static void +Opcode_wsr_vecbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e700; +} + +static void +Opcode_xsr_vecbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e700; +} + +static void +Opcode_mul16u_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc10000; +} + +static void +Opcode_mul16s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd10000; +} + +static void +Opcode_mull_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x820000; +} + +static void +Opcode_rfi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3010; +} + +static void +Opcode_waiti_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7000; +} + +static void +Opcode_rsr_interrupt_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e200; +} + +static void +Opcode_wsr_intset_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e200; +} + +static void +Opcode_wsr_intclear_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e300; +} + +static void +Opcode_rsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e400; +} + +static void +Opcode_wsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e400; +} + +static void +Opcode_xsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e400; +} + +static void +Opcode_break_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4000; +} + +static void +Opcode_break_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf02d; +} + +static void +Opcode_rsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x39000; +} + +static void +Opcode_wsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x139000; +} + +static void +Opcode_xsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x619000; +} + +static void +Opcode_rsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3a000; +} + +static void +Opcode_wsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13a000; +} + +static void +Opcode_xsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61a000; +} + +static void +Opcode_rsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x38000; +} + +static void +Opcode_wsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x138000; +} + +static void +Opcode_xsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x618000; +} + +static void +Opcode_rsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x36000; +} + +static void +Opcode_wsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x136000; +} + +static void +Opcode_xsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x616000; +} + +static void +Opcode_rsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e900; +} + +static void +Opcode_wsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e900; +} + +static void +Opcode_xsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e900; +} + +static void +Opcode_rsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ec00; +} + +static void +Opcode_wsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ec00; +} + +static void +Opcode_xsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ec00; +} + +static void +Opcode_rsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ed00; +} + +static void +Opcode_wsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ed00; +} + +static void +Opcode_xsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ed00; +} + +static void +Opcode_rsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x36800; +} + +static void +Opcode_wsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x136800; +} + +static void +Opcode_xsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x616800; +} + +static void +Opcode_rfdo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf1e000; +} + +static void +Opcode_rfdd_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf1e010; +} + +static void +Opcode_wsr_mmid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x135900; +} + +static void +Opcode_rsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ea00; +} + +static void +Opcode_wsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ea00; +} + +static void +Opcode_xsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ea00; +} + +static void +Opcode_rsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f000; +} + +static void +Opcode_wsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13f000; +} + +static void +Opcode_xsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61f000; +} + +static void +Opcode_idtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50c000; +} + +static void +Opcode_pdtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50d000; +} + +static void +Opcode_rdtlb0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50b000; +} + +static void +Opcode_rdtlb1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50f000; +} + +static void +Opcode_wdtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50e000; +} + +static void +Opcode_iitlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x504000; +} + +static void +Opcode_pitlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x505000; +} + +static void +Opcode_ritlb0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x503000; +} + +static void +Opcode_ritlb1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x507000; +} + +static void +Opcode_witlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x506000; +} + +static void +Opcode_nsa_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x40e000; +} + +static void +Opcode_nsau_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x40f000; +} + +static void +Opcode_rer_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x406000; +} + +static void +Opcode_wer_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x407000; +} + +static xtensa_opcode_encode_fn Opcode_excw_encode_fns[] = { + Opcode_excw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfe_encode_fns[] = { + Opcode_rfe_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfde_encode_fns[] = { + Opcode_rfde_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_syscall_encode_fns[] = { + Opcode_syscall_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_simcall_encode_fns[] = { + Opcode_simcall_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_add_n_encode_fns[] = { + 0, Opcode_add_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addi_n_encode_fns[] = { + 0, Opcode_addi_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beqz_n_encode_fns[] = { + 0, 0, Opcode_beqz_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_bnez_n_encode_fns[] = { + 0, 0, Opcode_bnez_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_ill_n_encode_fns[] = { + 0, 0, Opcode_ill_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_l32i_n_encode_fns[] = { + 0, Opcode_l32i_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mov_n_encode_fns[] = { + 0, 0, Opcode_mov_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_movi_n_encode_fns[] = { + 0, 0, Opcode_movi_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_nop_n_encode_fns[] = { + 0, 0, Opcode_nop_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_ret_n_encode_fns[] = { + 0, 0, Opcode_ret_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_s32i_n_encode_fns[] = { + 0, Opcode_s32i_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addi_encode_fns[] = { + Opcode_addi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addmi_encode_fns[] = { + Opcode_addmi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_add_encode_fns[] = { + Opcode_add_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sub_encode_fns[] = { + Opcode_sub_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addx2_encode_fns[] = { + Opcode_addx2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addx4_encode_fns[] = { + Opcode_addx4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addx8_encode_fns[] = { + Opcode_addx8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_subx2_encode_fns[] = { + Opcode_subx2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_subx4_encode_fns[] = { + Opcode_subx4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_subx8_encode_fns[] = { + Opcode_subx8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_and_encode_fns[] = { + Opcode_and_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_or_encode_fns[] = { + Opcode_or_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xor_encode_fns[] = { + Opcode_xor_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beqi_encode_fns[] = { + Opcode_beqi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnei_encode_fns[] = { + Opcode_bnei_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgei_encode_fns[] = { + Opcode_bgei_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_blti_encode_fns[] = { + Opcode_blti_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbci_encode_fns[] = { + Opcode_bbci_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbsi_encode_fns[] = { + Opcode_bbsi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgeui_encode_fns[] = { + Opcode_bgeui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bltui_encode_fns[] = { + Opcode_bltui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beq_encode_fns[] = { + Opcode_beq_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bne_encode_fns[] = { + Opcode_bne_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bge_encode_fns[] = { + Opcode_bge_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_blt_encode_fns[] = { + Opcode_blt_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgeu_encode_fns[] = { + Opcode_bgeu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bltu_encode_fns[] = { + Opcode_bltu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bany_encode_fns[] = { + Opcode_bany_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnone_encode_fns[] = { + Opcode_bnone_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ball_encode_fns[] = { + Opcode_ball_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnall_encode_fns[] = { + Opcode_bnall_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbc_encode_fns[] = { + Opcode_bbc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbs_encode_fns[] = { + Opcode_bbs_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beqz_encode_fns[] = { + Opcode_beqz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnez_encode_fns[] = { + Opcode_bnez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgez_encode_fns[] = { + Opcode_bgez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bltz_encode_fns[] = { + Opcode_bltz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_call0_encode_fns[] = { + Opcode_call0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_callx0_encode_fns[] = { + Opcode_callx0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_extui_encode_fns[] = { + Opcode_extui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ill_encode_fns[] = { + Opcode_ill_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_j_encode_fns[] = { + Opcode_j_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_jx_encode_fns[] = { + Opcode_jx_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l16ui_encode_fns[] = { + Opcode_l16ui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l16si_encode_fns[] = { + Opcode_l16si_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l32i_encode_fns[] = { + Opcode_l32i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l32r_encode_fns[] = { + Opcode_l32r_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l8ui_encode_fns[] = { + Opcode_l8ui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movi_encode_fns[] = { + Opcode_movi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_moveqz_encode_fns[] = { + Opcode_moveqz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movnez_encode_fns[] = { + Opcode_movnez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movltz_encode_fns[] = { + Opcode_movltz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movgez_encode_fns[] = { + Opcode_movgez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_neg_encode_fns[] = { + Opcode_neg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_abs_encode_fns[] = { + Opcode_abs_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_nop_encode_fns[] = { + Opcode_nop_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ret_encode_fns[] = { + Opcode_ret_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s16i_encode_fns[] = { + Opcode_s16i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s32i_encode_fns[] = { + Opcode_s32i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s8i_encode_fns[] = { + Opcode_s8i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssr_encode_fns[] = { + Opcode_ssr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssl_encode_fns[] = { + Opcode_ssl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssa8l_encode_fns[] = { + Opcode_ssa8l_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssa8b_encode_fns[] = { + Opcode_ssa8b_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssai_encode_fns[] = { + Opcode_ssai_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sll_encode_fns[] = { + Opcode_sll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_src_encode_fns[] = { + Opcode_src_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_srl_encode_fns[] = { + Opcode_srl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sra_encode_fns[] = { + Opcode_sra_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_slli_encode_fns[] = { + Opcode_slli_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_srai_encode_fns[] = { + Opcode_srai_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_srli_encode_fns[] = { + Opcode_srli_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_memw_encode_fns[] = { + Opcode_memw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_extw_encode_fns[] = { + Opcode_extw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_isync_encode_fns[] = { + Opcode_isync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsync_encode_fns[] = { + Opcode_rsync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_esync_encode_fns[] = { + Opcode_esync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dsync_encode_fns[] = { + Opcode_dsync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsil_encode_fns[] = { + Opcode_rsil_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_sar_encode_fns[] = { + Opcode_rsr_sar_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_sar_encode_fns[] = { + Opcode_wsr_sar_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_sar_encode_fns[] = { + Opcode_xsr_sar_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_litbase_encode_fns[] = { + Opcode_rsr_litbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_litbase_encode_fns[] = { + Opcode_wsr_litbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_litbase_encode_fns[] = { + Opcode_xsr_litbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_176_encode_fns[] = { + Opcode_rsr_176_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_176_encode_fns[] = { + Opcode_wsr_176_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_208_encode_fns[] = { + Opcode_rsr_208_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ps_encode_fns[] = { + Opcode_rsr_ps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ps_encode_fns[] = { + Opcode_wsr_ps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ps_encode_fns[] = { + Opcode_xsr_ps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc1_encode_fns[] = { + Opcode_rsr_epc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc1_encode_fns[] = { + Opcode_wsr_epc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc1_encode_fns[] = { + Opcode_xsr_epc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave1_encode_fns[] = { + Opcode_rsr_excsave1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave1_encode_fns[] = { + Opcode_wsr_excsave1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave1_encode_fns[] = { + Opcode_xsr_excsave1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc2_encode_fns[] = { + Opcode_rsr_epc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc2_encode_fns[] = { + Opcode_wsr_epc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc2_encode_fns[] = { + Opcode_xsr_epc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave2_encode_fns[] = { + Opcode_rsr_excsave2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave2_encode_fns[] = { + Opcode_wsr_excsave2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave2_encode_fns[] = { + Opcode_xsr_excsave2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc3_encode_fns[] = { + Opcode_rsr_epc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc3_encode_fns[] = { + Opcode_wsr_epc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc3_encode_fns[] = { + Opcode_xsr_epc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave3_encode_fns[] = { + Opcode_rsr_excsave3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave3_encode_fns[] = { + Opcode_wsr_excsave3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave3_encode_fns[] = { + Opcode_xsr_excsave3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps2_encode_fns[] = { + Opcode_rsr_eps2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps2_encode_fns[] = { + Opcode_wsr_eps2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps2_encode_fns[] = { + Opcode_xsr_eps2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps3_encode_fns[] = { + Opcode_rsr_eps3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps3_encode_fns[] = { + Opcode_wsr_eps3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps3_encode_fns[] = { + Opcode_xsr_eps3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excvaddr_encode_fns[] = { + Opcode_rsr_excvaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excvaddr_encode_fns[] = { + Opcode_wsr_excvaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excvaddr_encode_fns[] = { + Opcode_xsr_excvaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_depc_encode_fns[] = { + Opcode_rsr_depc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_depc_encode_fns[] = { + Opcode_wsr_depc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_depc_encode_fns[] = { + Opcode_xsr_depc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_exccause_encode_fns[] = { + Opcode_rsr_exccause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_exccause_encode_fns[] = { + Opcode_wsr_exccause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_exccause_encode_fns[] = { + Opcode_xsr_exccause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_prid_encode_fns[] = { + Opcode_rsr_prid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_vecbase_encode_fns[] = { + Opcode_rsr_vecbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_vecbase_encode_fns[] = { + Opcode_wsr_vecbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_vecbase_encode_fns[] = { + Opcode_xsr_vecbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul16u_encode_fns[] = { + Opcode_mul16u_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul16s_encode_fns[] = { + Opcode_mul16s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mull_encode_fns[] = { + Opcode_mull_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfi_encode_fns[] = { + Opcode_rfi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_waiti_encode_fns[] = { + Opcode_waiti_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_interrupt_encode_fns[] = { + Opcode_rsr_interrupt_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_intset_encode_fns[] = { + Opcode_wsr_intset_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_intclear_encode_fns[] = { + Opcode_wsr_intclear_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_intenable_encode_fns[] = { + Opcode_rsr_intenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_intenable_encode_fns[] = { + Opcode_wsr_intenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_intenable_encode_fns[] = { + Opcode_xsr_intenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_break_encode_fns[] = { + Opcode_break_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_break_n_encode_fns[] = { + 0, 0, Opcode_break_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreaka0_encode_fns[] = { + Opcode_rsr_dbreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreaka0_encode_fns[] = { + Opcode_wsr_dbreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreaka0_encode_fns[] = { + Opcode_xsr_dbreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreakc0_encode_fns[] = { + Opcode_rsr_dbreakc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreakc0_encode_fns[] = { + Opcode_wsr_dbreakc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreakc0_encode_fns[] = { + Opcode_xsr_dbreakc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ibreaka0_encode_fns[] = { + Opcode_rsr_ibreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ibreaka0_encode_fns[] = { + Opcode_wsr_ibreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ibreaka0_encode_fns[] = { + Opcode_xsr_ibreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ibreakenable_encode_fns[] = { + Opcode_rsr_ibreakenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ibreakenable_encode_fns[] = { + Opcode_wsr_ibreakenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ibreakenable_encode_fns[] = { + Opcode_xsr_ibreakenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_debugcause_encode_fns[] = { + Opcode_rsr_debugcause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_debugcause_encode_fns[] = { + Opcode_wsr_debugcause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_debugcause_encode_fns[] = { + Opcode_xsr_debugcause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_icount_encode_fns[] = { + Opcode_rsr_icount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_icount_encode_fns[] = { + Opcode_wsr_icount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_icount_encode_fns[] = { + Opcode_xsr_icount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_icountlevel_encode_fns[] = { + Opcode_rsr_icountlevel_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_icountlevel_encode_fns[] = { + Opcode_wsr_icountlevel_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_icountlevel_encode_fns[] = { + Opcode_xsr_icountlevel_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ddr_encode_fns[] = { + Opcode_rsr_ddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ddr_encode_fns[] = { + Opcode_wsr_ddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ddr_encode_fns[] = { + Opcode_xsr_ddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfdo_encode_fns[] = { + Opcode_rfdo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfdd_encode_fns[] = { + Opcode_rfdd_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_mmid_encode_fns[] = { + Opcode_wsr_mmid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccount_encode_fns[] = { + Opcode_rsr_ccount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccount_encode_fns[] = { + Opcode_wsr_ccount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccount_encode_fns[] = { + Opcode_xsr_ccount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccompare0_encode_fns[] = { + Opcode_rsr_ccompare0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccompare0_encode_fns[] = { + Opcode_wsr_ccompare0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccompare0_encode_fns[] = { + Opcode_xsr_ccompare0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_idtlb_encode_fns[] = { + Opcode_idtlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_pdtlb_encode_fns[] = { + Opcode_pdtlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rdtlb0_encode_fns[] = { + Opcode_rdtlb0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rdtlb1_encode_fns[] = { + Opcode_rdtlb1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wdtlb_encode_fns[] = { + Opcode_wdtlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_iitlb_encode_fns[] = { + Opcode_iitlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_pitlb_encode_fns[] = { + Opcode_pitlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ritlb0_encode_fns[] = { + Opcode_ritlb0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ritlb1_encode_fns[] = { + Opcode_ritlb1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_witlb_encode_fns[] = { + Opcode_witlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_nsa_encode_fns[] = { + Opcode_nsa_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_nsau_encode_fns[] = { + Opcode_nsau_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rer_encode_fns[] = { + Opcode_rer_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wer_encode_fns[] = { + Opcode_wer_Slot_inst_encode, 0, 0 +}; + + +/* Opcode table. */ + +static xtensa_opcode_internal opcodes[] = { + { "excw", ICLASS_xt_iclass_excw, + 0, + Opcode_excw_encode_fns, 0, 0 }, + { "rfe", ICLASS_xt_iclass_rfe, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfe_encode_fns, 0, 0 }, + { "rfde", ICLASS_xt_iclass_rfde, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfde_encode_fns, 0, 0 }, + { "syscall", ICLASS_xt_iclass_syscall, + 0, + Opcode_syscall_encode_fns, 0, 0 }, + { "simcall", ICLASS_xt_iclass_simcall, + 0, + Opcode_simcall_encode_fns, 0, 0 }, + { "add.n", ICLASS_xt_iclass_add_n, + 0, + Opcode_add_n_encode_fns, 0, 0 }, + { "addi.n", ICLASS_xt_iclass_addi_n, + 0, + Opcode_addi_n_encode_fns, 0, 0 }, + { "beqz.n", ICLASS_xt_iclass_bz6, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqz_n_encode_fns, 0, 0 }, + { "bnez.n", ICLASS_xt_iclass_bz6, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnez_n_encode_fns, 0, 0 }, + { "ill.n", ICLASS_xt_iclass_ill_n, + 0, + Opcode_ill_n_encode_fns, 0, 0 }, + { "l32i.n", ICLASS_xt_iclass_loadi4, + 0, + Opcode_l32i_n_encode_fns, 0, 0 }, + { "mov.n", ICLASS_xt_iclass_mov_n, + 0, + Opcode_mov_n_encode_fns, 0, 0 }, + { "movi.n", ICLASS_xt_iclass_movi_n, + 0, + Opcode_movi_n_encode_fns, 0, 0 }, + { "nop.n", ICLASS_xt_iclass_nopn, + 0, + Opcode_nop_n_encode_fns, 0, 0 }, + { "ret.n", ICLASS_xt_iclass_retn, + XTENSA_OPCODE_IS_JUMP, + Opcode_ret_n_encode_fns, 0, 0 }, + { "s32i.n", ICLASS_xt_iclass_storei4, + 0, + Opcode_s32i_n_encode_fns, 0, 0 }, + { "addi", ICLASS_xt_iclass_addi, + 0, + Opcode_addi_encode_fns, 0, 0 }, + { "addmi", ICLASS_xt_iclass_addmi, + 0, + Opcode_addmi_encode_fns, 0, 0 }, + { "add", ICLASS_xt_iclass_addsub, + 0, + Opcode_add_encode_fns, 0, 0 }, + { "sub", ICLASS_xt_iclass_addsub, + 0, + Opcode_sub_encode_fns, 0, 0 }, + { "addx2", ICLASS_xt_iclass_addsub, + 0, + Opcode_addx2_encode_fns, 0, 0 }, + { "addx4", ICLASS_xt_iclass_addsub, + 0, + Opcode_addx4_encode_fns, 0, 0 }, + { "addx8", ICLASS_xt_iclass_addsub, + 0, + Opcode_addx8_encode_fns, 0, 0 }, + { "subx2", ICLASS_xt_iclass_addsub, + 0, + Opcode_subx2_encode_fns, 0, 0 }, + { "subx4", ICLASS_xt_iclass_addsub, + 0, + Opcode_subx4_encode_fns, 0, 0 }, + { "subx8", ICLASS_xt_iclass_addsub, + 0, + Opcode_subx8_encode_fns, 0, 0 }, + { "and", ICLASS_xt_iclass_bit, + 0, + Opcode_and_encode_fns, 0, 0 }, + { "or", ICLASS_xt_iclass_bit, + 0, + Opcode_or_encode_fns, 0, 0 }, + { "xor", ICLASS_xt_iclass_bit, + 0, + Opcode_xor_encode_fns, 0, 0 }, + { "beqi", ICLASS_xt_iclass_bsi8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqi_encode_fns, 0, 0 }, + { "bnei", ICLASS_xt_iclass_bsi8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnei_encode_fns, 0, 0 }, + { "bgei", ICLASS_xt_iclass_bsi8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgei_encode_fns, 0, 0 }, + { "blti", ICLASS_xt_iclass_bsi8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_blti_encode_fns, 0, 0 }, + { "bbci", ICLASS_xt_iclass_bsi8b, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbci_encode_fns, 0, 0 }, + { "bbsi", ICLASS_xt_iclass_bsi8b, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbsi_encode_fns, 0, 0 }, + { "bgeui", ICLASS_xt_iclass_bsi8u, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgeui_encode_fns, 0, 0 }, + { "bltui", ICLASS_xt_iclass_bsi8u, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltui_encode_fns, 0, 0 }, + { "beq", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beq_encode_fns, 0, 0 }, + { "bne", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bne_encode_fns, 0, 0 }, + { "bge", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bge_encode_fns, 0, 0 }, + { "blt", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_blt_encode_fns, 0, 0 }, + { "bgeu", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgeu_encode_fns, 0, 0 }, + { "bltu", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltu_encode_fns, 0, 0 }, + { "bany", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bany_encode_fns, 0, 0 }, + { "bnone", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnone_encode_fns, 0, 0 }, + { "ball", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_ball_encode_fns, 0, 0 }, + { "bnall", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnall_encode_fns, 0, 0 }, + { "bbc", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbc_encode_fns, 0, 0 }, + { "bbs", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbs_encode_fns, 0, 0 }, + { "beqz", ICLASS_xt_iclass_bsz12, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqz_encode_fns, 0, 0 }, + { "bnez", ICLASS_xt_iclass_bsz12, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnez_encode_fns, 0, 0 }, + { "bgez", ICLASS_xt_iclass_bsz12, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgez_encode_fns, 0, 0 }, + { "bltz", ICLASS_xt_iclass_bsz12, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltz_encode_fns, 0, 0 }, + { "call0", ICLASS_xt_iclass_call0, + XTENSA_OPCODE_IS_CALL, + Opcode_call0_encode_fns, 0, 0 }, + { "callx0", ICLASS_xt_iclass_callx0, + XTENSA_OPCODE_IS_CALL, + Opcode_callx0_encode_fns, 0, 0 }, + { "extui", ICLASS_xt_iclass_exti, + 0, + Opcode_extui_encode_fns, 0, 0 }, + { "ill", ICLASS_xt_iclass_ill, + 0, + Opcode_ill_encode_fns, 0, 0 }, + { "j", ICLASS_xt_iclass_jump, + XTENSA_OPCODE_IS_JUMP, + Opcode_j_encode_fns, 0, 0 }, + { "jx", ICLASS_xt_iclass_jumpx, + XTENSA_OPCODE_IS_JUMP, + Opcode_jx_encode_fns, 0, 0 }, + { "l16ui", ICLASS_xt_iclass_l16ui, + 0, + Opcode_l16ui_encode_fns, 0, 0 }, + { "l16si", ICLASS_xt_iclass_l16si, + 0, + Opcode_l16si_encode_fns, 0, 0 }, + { "l32i", ICLASS_xt_iclass_l32i, + 0, + Opcode_l32i_encode_fns, 0, 0 }, + { "l32r", ICLASS_xt_iclass_l32r, + 0, + Opcode_l32r_encode_fns, 0, 0 }, + { "l8ui", ICLASS_xt_iclass_l8i, + 0, + Opcode_l8ui_encode_fns, 0, 0 }, + { "movi", ICLASS_xt_iclass_movi, + 0, + Opcode_movi_encode_fns, 0, 0 }, + { "moveqz", ICLASS_xt_iclass_movz, + 0, + Opcode_moveqz_encode_fns, 0, 0 }, + { "movnez", ICLASS_xt_iclass_movz, + 0, + Opcode_movnez_encode_fns, 0, 0 }, + { "movltz", ICLASS_xt_iclass_movz, + 0, + Opcode_movltz_encode_fns, 0, 0 }, + { "movgez", ICLASS_xt_iclass_movz, + 0, + Opcode_movgez_encode_fns, 0, 0 }, + { "neg", ICLASS_xt_iclass_neg, + 0, + Opcode_neg_encode_fns, 0, 0 }, + { "abs", ICLASS_xt_iclass_neg, + 0, + Opcode_abs_encode_fns, 0, 0 }, + { "nop", ICLASS_xt_iclass_nop, + 0, + Opcode_nop_encode_fns, 0, 0 }, + { "ret", ICLASS_xt_iclass_return, + XTENSA_OPCODE_IS_JUMP, + Opcode_ret_encode_fns, 0, 0 }, + { "s16i", ICLASS_xt_iclass_s16i, + 0, + Opcode_s16i_encode_fns, 0, 0 }, + { "s32i", ICLASS_xt_iclass_s32i, + 0, + Opcode_s32i_encode_fns, 0, 0 }, + { "s8i", ICLASS_xt_iclass_s8i, + 0, + Opcode_s8i_encode_fns, 0, 0 }, + { "ssr", ICLASS_xt_iclass_sar, + 0, + Opcode_ssr_encode_fns, 0, 0 }, + { "ssl", ICLASS_xt_iclass_sar, + 0, + Opcode_ssl_encode_fns, 0, 0 }, + { "ssa8l", ICLASS_xt_iclass_sar, + 0, + Opcode_ssa8l_encode_fns, 0, 0 }, + { "ssa8b", ICLASS_xt_iclass_sar, + 0, + Opcode_ssa8b_encode_fns, 0, 0 }, + { "ssai", ICLASS_xt_iclass_sari, + 0, + Opcode_ssai_encode_fns, 0, 0 }, + { "sll", ICLASS_xt_iclass_shifts, + 0, + Opcode_sll_encode_fns, 0, 0 }, + { "src", ICLASS_xt_iclass_shiftst, + 0, + Opcode_src_encode_fns, 0, 0 }, + { "srl", ICLASS_xt_iclass_shiftt, + 0, + Opcode_srl_encode_fns, 0, 0 }, + { "sra", ICLASS_xt_iclass_shiftt, + 0, + Opcode_sra_encode_fns, 0, 0 }, + { "slli", ICLASS_xt_iclass_slli, + 0, + Opcode_slli_encode_fns, 0, 0 }, + { "srai", ICLASS_xt_iclass_srai, + 0, + Opcode_srai_encode_fns, 0, 0 }, + { "srli", ICLASS_xt_iclass_srli, + 0, + Opcode_srli_encode_fns, 0, 0 }, + { "memw", ICLASS_xt_iclass_memw, + 0, + Opcode_memw_encode_fns, 0, 0 }, + { "extw", ICLASS_xt_iclass_extw, + 0, + Opcode_extw_encode_fns, 0, 0 }, + { "isync", ICLASS_xt_iclass_isync, + 0, + Opcode_isync_encode_fns, 0, 0 }, + { "rsync", ICLASS_xt_iclass_sync, + 0, + Opcode_rsync_encode_fns, 0, 0 }, + { "esync", ICLASS_xt_iclass_sync, + 0, + Opcode_esync_encode_fns, 0, 0 }, + { "dsync", ICLASS_xt_iclass_sync, + 0, + Opcode_dsync_encode_fns, 0, 0 }, + { "rsil", ICLASS_xt_iclass_rsil, + 0, + Opcode_rsil_encode_fns, 0, 0 }, + { "rsr.sar", ICLASS_xt_iclass_rsr_sar, + 0, + Opcode_rsr_sar_encode_fns, 0, 0 }, + { "wsr.sar", ICLASS_xt_iclass_wsr_sar, + 0, + Opcode_wsr_sar_encode_fns, 0, 0 }, + { "xsr.sar", ICLASS_xt_iclass_xsr_sar, + 0, + Opcode_xsr_sar_encode_fns, 0, 0 }, + { "rsr.litbase", ICLASS_xt_iclass_rsr_litbase, + 0, + Opcode_rsr_litbase_encode_fns, 0, 0 }, + { "wsr.litbase", ICLASS_xt_iclass_wsr_litbase, + 0, + Opcode_wsr_litbase_encode_fns, 0, 0 }, + { "xsr.litbase", ICLASS_xt_iclass_xsr_litbase, + 0, + Opcode_xsr_litbase_encode_fns, 0, 0 }, + { "rsr.176", ICLASS_xt_iclass_rsr_176, + 0, + Opcode_rsr_176_encode_fns, 0, 0 }, + { "wsr.176", ICLASS_xt_iclass_wsr_176, + 0, + Opcode_wsr_176_encode_fns, 0, 0 }, + { "rsr.208", ICLASS_xt_iclass_rsr_208, + 0, + Opcode_rsr_208_encode_fns, 0, 0 }, + { "rsr.ps", ICLASS_xt_iclass_rsr_ps, + 0, + Opcode_rsr_ps_encode_fns, 0, 0 }, + { "wsr.ps", ICLASS_xt_iclass_wsr_ps, + 0, + Opcode_wsr_ps_encode_fns, 0, 0 }, + { "xsr.ps", ICLASS_xt_iclass_xsr_ps, + 0, + Opcode_xsr_ps_encode_fns, 0, 0 }, + { "rsr.epc1", ICLASS_xt_iclass_rsr_epc1, + 0, + Opcode_rsr_epc1_encode_fns, 0, 0 }, + { "wsr.epc1", ICLASS_xt_iclass_wsr_epc1, + 0, + Opcode_wsr_epc1_encode_fns, 0, 0 }, + { "xsr.epc1", ICLASS_xt_iclass_xsr_epc1, + 0, + Opcode_xsr_epc1_encode_fns, 0, 0 }, + { "rsr.excsave1", ICLASS_xt_iclass_rsr_excsave1, + 0, + Opcode_rsr_excsave1_encode_fns, 0, 0 }, + { "wsr.excsave1", ICLASS_xt_iclass_wsr_excsave1, + 0, + Opcode_wsr_excsave1_encode_fns, 0, 0 }, + { "xsr.excsave1", ICLASS_xt_iclass_xsr_excsave1, + 0, + Opcode_xsr_excsave1_encode_fns, 0, 0 }, + { "rsr.epc2", ICLASS_xt_iclass_rsr_epc2, + 0, + Opcode_rsr_epc2_encode_fns, 0, 0 }, + { "wsr.epc2", ICLASS_xt_iclass_wsr_epc2, + 0, + Opcode_wsr_epc2_encode_fns, 0, 0 }, + { "xsr.epc2", ICLASS_xt_iclass_xsr_epc2, + 0, + Opcode_xsr_epc2_encode_fns, 0, 0 }, + { "rsr.excsave2", ICLASS_xt_iclass_rsr_excsave2, + 0, + Opcode_rsr_excsave2_encode_fns, 0, 0 }, + { "wsr.excsave2", ICLASS_xt_iclass_wsr_excsave2, + 0, + Opcode_wsr_excsave2_encode_fns, 0, 0 }, + { "xsr.excsave2", ICLASS_xt_iclass_xsr_excsave2, + 0, + Opcode_xsr_excsave2_encode_fns, 0, 0 }, + { "rsr.epc3", ICLASS_xt_iclass_rsr_epc3, + 0, + Opcode_rsr_epc3_encode_fns, 0, 0 }, + { "wsr.epc3", ICLASS_xt_iclass_wsr_epc3, + 0, + Opcode_wsr_epc3_encode_fns, 0, 0 }, + { "xsr.epc3", ICLASS_xt_iclass_xsr_epc3, + 0, + Opcode_xsr_epc3_encode_fns, 0, 0 }, + { "rsr.excsave3", ICLASS_xt_iclass_rsr_excsave3, + 0, + Opcode_rsr_excsave3_encode_fns, 0, 0 }, + { "wsr.excsave3", ICLASS_xt_iclass_wsr_excsave3, + 0, + Opcode_wsr_excsave3_encode_fns, 0, 0 }, + { "xsr.excsave3", ICLASS_xt_iclass_xsr_excsave3, + 0, + Opcode_xsr_excsave3_encode_fns, 0, 0 }, + { "rsr.eps2", ICLASS_xt_iclass_rsr_eps2, + 0, + Opcode_rsr_eps2_encode_fns, 0, 0 }, + { "wsr.eps2", ICLASS_xt_iclass_wsr_eps2, + 0, + Opcode_wsr_eps2_encode_fns, 0, 0 }, + { "xsr.eps2", ICLASS_xt_iclass_xsr_eps2, + 0, + Opcode_xsr_eps2_encode_fns, 0, 0 }, + { "rsr.eps3", ICLASS_xt_iclass_rsr_eps3, + 0, + Opcode_rsr_eps3_encode_fns, 0, 0 }, + { "wsr.eps3", ICLASS_xt_iclass_wsr_eps3, + 0, + Opcode_wsr_eps3_encode_fns, 0, 0 }, + { "xsr.eps3", ICLASS_xt_iclass_xsr_eps3, + 0, + Opcode_xsr_eps3_encode_fns, 0, 0 }, + { "rsr.excvaddr", ICLASS_xt_iclass_rsr_excvaddr, + 0, + Opcode_rsr_excvaddr_encode_fns, 0, 0 }, + { "wsr.excvaddr", ICLASS_xt_iclass_wsr_excvaddr, + 0, + Opcode_wsr_excvaddr_encode_fns, 0, 0 }, + { "xsr.excvaddr", ICLASS_xt_iclass_xsr_excvaddr, + 0, + Opcode_xsr_excvaddr_encode_fns, 0, 0 }, + { "rsr.depc", ICLASS_xt_iclass_rsr_depc, + 0, + Opcode_rsr_depc_encode_fns, 0, 0 }, + { "wsr.depc", ICLASS_xt_iclass_wsr_depc, + 0, + Opcode_wsr_depc_encode_fns, 0, 0 }, + { "xsr.depc", ICLASS_xt_iclass_xsr_depc, + 0, + Opcode_xsr_depc_encode_fns, 0, 0 }, + { "rsr.exccause", ICLASS_xt_iclass_rsr_exccause, + 0, + Opcode_rsr_exccause_encode_fns, 0, 0 }, + { "wsr.exccause", ICLASS_xt_iclass_wsr_exccause, + 0, + Opcode_wsr_exccause_encode_fns, 0, 0 }, + { "xsr.exccause", ICLASS_xt_iclass_xsr_exccause, + 0, + Opcode_xsr_exccause_encode_fns, 0, 0 }, + { "rsr.prid", ICLASS_xt_iclass_rsr_prid, + 0, + Opcode_rsr_prid_encode_fns, 0, 0 }, + { "rsr.vecbase", ICLASS_xt_iclass_rsr_vecbase, + 0, + Opcode_rsr_vecbase_encode_fns, 0, 0 }, + { "wsr.vecbase", ICLASS_xt_iclass_wsr_vecbase, + 0, + Opcode_wsr_vecbase_encode_fns, 0, 0 }, + { "xsr.vecbase", ICLASS_xt_iclass_xsr_vecbase, + 0, + Opcode_xsr_vecbase_encode_fns, 0, 0 }, + { "mul16u", ICLASS_xt_mul16, + 0, + Opcode_mul16u_encode_fns, 0, 0 }, + { "mul16s", ICLASS_xt_mul16, + 0, + Opcode_mul16s_encode_fns, 0, 0 }, + { "mull", ICLASS_xt_mul32, + 0, + Opcode_mull_encode_fns, 0, 0 }, + { "rfi", ICLASS_xt_iclass_rfi, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfi_encode_fns, 0, 0 }, + { "waiti", ICLASS_xt_iclass_wait, + 0, + Opcode_waiti_encode_fns, 0, 0 }, + { "rsr.interrupt", ICLASS_xt_iclass_rsr_interrupt, + 0, + Opcode_rsr_interrupt_encode_fns, 0, 0 }, + { "wsr.intset", ICLASS_xt_iclass_wsr_intset, + 0, + Opcode_wsr_intset_encode_fns, 0, 0 }, + { "wsr.intclear", ICLASS_xt_iclass_wsr_intclear, + 0, + Opcode_wsr_intclear_encode_fns, 0, 0 }, + { "rsr.intenable", ICLASS_xt_iclass_rsr_intenable, + 0, + Opcode_rsr_intenable_encode_fns, 0, 0 }, + { "wsr.intenable", ICLASS_xt_iclass_wsr_intenable, + 0, + Opcode_wsr_intenable_encode_fns, 0, 0 }, + { "xsr.intenable", ICLASS_xt_iclass_xsr_intenable, + 0, + Opcode_xsr_intenable_encode_fns, 0, 0 }, + { "break", ICLASS_xt_iclass_break, + 0, + Opcode_break_encode_fns, 0, 0 }, + { "break.n", ICLASS_xt_iclass_break_n, + 0, + Opcode_break_n_encode_fns, 0, 0 }, + { "rsr.dbreaka0", ICLASS_xt_iclass_rsr_dbreaka0, + 0, + Opcode_rsr_dbreaka0_encode_fns, 0, 0 }, + { "wsr.dbreaka0", ICLASS_xt_iclass_wsr_dbreaka0, + 0, + Opcode_wsr_dbreaka0_encode_fns, 0, 0 }, + { "xsr.dbreaka0", ICLASS_xt_iclass_xsr_dbreaka0, + 0, + Opcode_xsr_dbreaka0_encode_fns, 0, 0 }, + { "rsr.dbreakc0", ICLASS_xt_iclass_rsr_dbreakc0, + 0, + Opcode_rsr_dbreakc0_encode_fns, 0, 0 }, + { "wsr.dbreakc0", ICLASS_xt_iclass_wsr_dbreakc0, + 0, + Opcode_wsr_dbreakc0_encode_fns, 0, 0 }, + { "xsr.dbreakc0", ICLASS_xt_iclass_xsr_dbreakc0, + 0, + Opcode_xsr_dbreakc0_encode_fns, 0, 0 }, + { "rsr.ibreaka0", ICLASS_xt_iclass_rsr_ibreaka0, + 0, + Opcode_rsr_ibreaka0_encode_fns, 0, 0 }, + { "wsr.ibreaka0", ICLASS_xt_iclass_wsr_ibreaka0, + 0, + Opcode_wsr_ibreaka0_encode_fns, 0, 0 }, + { "xsr.ibreaka0", ICLASS_xt_iclass_xsr_ibreaka0, + 0, + Opcode_xsr_ibreaka0_encode_fns, 0, 0 }, + { "rsr.ibreakenable", ICLASS_xt_iclass_rsr_ibreakenable, + 0, + Opcode_rsr_ibreakenable_encode_fns, 0, 0 }, + { "wsr.ibreakenable", ICLASS_xt_iclass_wsr_ibreakenable, + 0, + Opcode_wsr_ibreakenable_encode_fns, 0, 0 }, + { "xsr.ibreakenable", ICLASS_xt_iclass_xsr_ibreakenable, + 0, + Opcode_xsr_ibreakenable_encode_fns, 0, 0 }, + { "rsr.debugcause", ICLASS_xt_iclass_rsr_debugcause, + 0, + Opcode_rsr_debugcause_encode_fns, 0, 0 }, + { "wsr.debugcause", ICLASS_xt_iclass_wsr_debugcause, + 0, + Opcode_wsr_debugcause_encode_fns, 0, 0 }, + { "xsr.debugcause", ICLASS_xt_iclass_xsr_debugcause, + 0, + Opcode_xsr_debugcause_encode_fns, 0, 0 }, + { "rsr.icount", ICLASS_xt_iclass_rsr_icount, + 0, + Opcode_rsr_icount_encode_fns, 0, 0 }, + { "wsr.icount", ICLASS_xt_iclass_wsr_icount, + 0, + Opcode_wsr_icount_encode_fns, 0, 0 }, + { "xsr.icount", ICLASS_xt_iclass_xsr_icount, + 0, + Opcode_xsr_icount_encode_fns, 0, 0 }, + { "rsr.icountlevel", ICLASS_xt_iclass_rsr_icountlevel, + 0, + Opcode_rsr_icountlevel_encode_fns, 0, 0 }, + { "wsr.icountlevel", ICLASS_xt_iclass_wsr_icountlevel, + 0, + Opcode_wsr_icountlevel_encode_fns, 0, 0 }, + { "xsr.icountlevel", ICLASS_xt_iclass_xsr_icountlevel, + 0, + Opcode_xsr_icountlevel_encode_fns, 0, 0 }, + { "rsr.ddr", ICLASS_xt_iclass_rsr_ddr, + 0, + Opcode_rsr_ddr_encode_fns, 0, 0 }, + { "wsr.ddr", ICLASS_xt_iclass_wsr_ddr, + 0, + Opcode_wsr_ddr_encode_fns, 0, 0 }, + { "xsr.ddr", ICLASS_xt_iclass_xsr_ddr, + 0, + Opcode_xsr_ddr_encode_fns, 0, 0 }, + { "rfdo", ICLASS_xt_iclass_rfdo, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfdo_encode_fns, 0, 0 }, + { "rfdd", ICLASS_xt_iclass_rfdd, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfdd_encode_fns, 0, 0 }, + { "wsr.mmid", ICLASS_xt_iclass_wsr_mmid, + 0, + Opcode_wsr_mmid_encode_fns, 0, 0 }, + { "rsr.ccount", ICLASS_xt_iclass_rsr_ccount, + 0, + Opcode_rsr_ccount_encode_fns, 0, 0 }, + { "wsr.ccount", ICLASS_xt_iclass_wsr_ccount, + 0, + Opcode_wsr_ccount_encode_fns, 0, 0 }, + { "xsr.ccount", ICLASS_xt_iclass_xsr_ccount, + 0, + Opcode_xsr_ccount_encode_fns, 0, 0 }, + { "rsr.ccompare0", ICLASS_xt_iclass_rsr_ccompare0, + 0, + Opcode_rsr_ccompare0_encode_fns, 0, 0 }, + { "wsr.ccompare0", ICLASS_xt_iclass_wsr_ccompare0, + 0, + Opcode_wsr_ccompare0_encode_fns, 0, 0 }, + { "xsr.ccompare0", ICLASS_xt_iclass_xsr_ccompare0, + 0, + Opcode_xsr_ccompare0_encode_fns, 0, 0 }, + { "idtlb", ICLASS_xt_iclass_idtlb, + 0, + Opcode_idtlb_encode_fns, 0, 0 }, + { "pdtlb", ICLASS_xt_iclass_rdtlb, + 0, + Opcode_pdtlb_encode_fns, 0, 0 }, + { "rdtlb0", ICLASS_xt_iclass_rdtlb, + 0, + Opcode_rdtlb0_encode_fns, 0, 0 }, + { "rdtlb1", ICLASS_xt_iclass_rdtlb, + 0, + Opcode_rdtlb1_encode_fns, 0, 0 }, + { "wdtlb", ICLASS_xt_iclass_wdtlb, + 0, + Opcode_wdtlb_encode_fns, 0, 0 }, + { "iitlb", ICLASS_xt_iclass_iitlb, + 0, + Opcode_iitlb_encode_fns, 0, 0 }, + { "pitlb", ICLASS_xt_iclass_ritlb, + 0, + Opcode_pitlb_encode_fns, 0, 0 }, + { "ritlb0", ICLASS_xt_iclass_ritlb, + 0, + Opcode_ritlb0_encode_fns, 0, 0 }, + { "ritlb1", ICLASS_xt_iclass_ritlb, + 0, + Opcode_ritlb1_encode_fns, 0, 0 }, + { "witlb", ICLASS_xt_iclass_witlb, + 0, + Opcode_witlb_encode_fns, 0, 0 }, + { "nsa", ICLASS_xt_iclass_nsa, + 0, + Opcode_nsa_encode_fns, 0, 0 }, + { "nsau", ICLASS_xt_iclass_nsa, + 0, + Opcode_nsau_encode_fns, 0, 0 }, + { "rer", ICLASS_xt_iclass_rer, + 0, + Opcode_rer_encode_fns, 0, 0 }, + { "wer", ICLASS_xt_iclass_wer, + 0, + Opcode_wer_encode_fns, 0, 0 } +}; + +enum xtensa_opcode_id { + OPCODE_EXCW, + OPCODE_RFE, + OPCODE_RFDE, + OPCODE_SYSCALL, + OPCODE_SIMCALL, + OPCODE_ADD_N, + OPCODE_ADDI_N, + OPCODE_BEQZ_N, + OPCODE_BNEZ_N, + OPCODE_ILL_N, + OPCODE_L32I_N, + OPCODE_MOV_N, + OPCODE_MOVI_N, + OPCODE_NOP_N, + OPCODE_RET_N, + OPCODE_S32I_N, + OPCODE_ADDI, + OPCODE_ADDMI, + OPCODE_ADD, + OPCODE_SUB, + OPCODE_ADDX2, + OPCODE_ADDX4, + OPCODE_ADDX8, + OPCODE_SUBX2, + OPCODE_SUBX4, + OPCODE_SUBX8, + OPCODE_AND, + OPCODE_OR, + OPCODE_XOR, + OPCODE_BEQI, + OPCODE_BNEI, + OPCODE_BGEI, + OPCODE_BLTI, + OPCODE_BBCI, + OPCODE_BBSI, + OPCODE_BGEUI, + OPCODE_BLTUI, + OPCODE_BEQ, + OPCODE_BNE, + OPCODE_BGE, + OPCODE_BLT, + OPCODE_BGEU, + OPCODE_BLTU, + OPCODE_BANY, + OPCODE_BNONE, + OPCODE_BALL, + OPCODE_BNALL, + OPCODE_BBC, + OPCODE_BBS, + OPCODE_BEQZ, + OPCODE_BNEZ, + OPCODE_BGEZ, + OPCODE_BLTZ, + OPCODE_CALL0, + OPCODE_CALLX0, + OPCODE_EXTUI, + OPCODE_ILL, + OPCODE_J, + OPCODE_JX, + OPCODE_L16UI, + OPCODE_L16SI, + OPCODE_L32I, + OPCODE_L32R, + OPCODE_L8UI, + OPCODE_MOVI, + OPCODE_MOVEQZ, + OPCODE_MOVNEZ, + OPCODE_MOVLTZ, + OPCODE_MOVGEZ, + OPCODE_NEG, + OPCODE_ABS, + OPCODE_NOP, + OPCODE_RET, + OPCODE_S16I, + OPCODE_S32I, + OPCODE_S8I, + OPCODE_SSR, + OPCODE_SSL, + OPCODE_SSA8L, + OPCODE_SSA8B, + OPCODE_SSAI, + OPCODE_SLL, + OPCODE_SRC, + OPCODE_SRL, + OPCODE_SRA, + OPCODE_SLLI, + OPCODE_SRAI, + OPCODE_SRLI, + OPCODE_MEMW, + OPCODE_EXTW, + OPCODE_ISYNC, + OPCODE_RSYNC, + OPCODE_ESYNC, + OPCODE_DSYNC, + OPCODE_RSIL, + OPCODE_RSR_SAR, + OPCODE_WSR_SAR, + OPCODE_XSR_SAR, + OPCODE_RSR_LITBASE, + OPCODE_WSR_LITBASE, + OPCODE_XSR_LITBASE, + OPCODE_RSR_176, + OPCODE_WSR_176, + OPCODE_RSR_208, + OPCODE_RSR_PS, + OPCODE_WSR_PS, + OPCODE_XSR_PS, + OPCODE_RSR_EPC1, + OPCODE_WSR_EPC1, + OPCODE_XSR_EPC1, + OPCODE_RSR_EXCSAVE1, + OPCODE_WSR_EXCSAVE1, + OPCODE_XSR_EXCSAVE1, + OPCODE_RSR_EPC2, + OPCODE_WSR_EPC2, + OPCODE_XSR_EPC2, + OPCODE_RSR_EXCSAVE2, + OPCODE_WSR_EXCSAVE2, + OPCODE_XSR_EXCSAVE2, + OPCODE_RSR_EPC3, + OPCODE_WSR_EPC3, + OPCODE_XSR_EPC3, + OPCODE_RSR_EXCSAVE3, + OPCODE_WSR_EXCSAVE3, + OPCODE_XSR_EXCSAVE3, + OPCODE_RSR_EPS2, + OPCODE_WSR_EPS2, + OPCODE_XSR_EPS2, + OPCODE_RSR_EPS3, + OPCODE_WSR_EPS3, + OPCODE_XSR_EPS3, + OPCODE_RSR_EXCVADDR, + OPCODE_WSR_EXCVADDR, + OPCODE_XSR_EXCVADDR, + OPCODE_RSR_DEPC, + OPCODE_WSR_DEPC, + OPCODE_XSR_DEPC, + OPCODE_RSR_EXCCAUSE, + OPCODE_WSR_EXCCAUSE, + OPCODE_XSR_EXCCAUSE, + OPCODE_RSR_PRID, + OPCODE_RSR_VECBASE, + OPCODE_WSR_VECBASE, + OPCODE_XSR_VECBASE, + OPCODE_MUL16U, + OPCODE_MUL16S, + OPCODE_MULL, + OPCODE_RFI, + OPCODE_WAITI, + OPCODE_RSR_INTERRUPT, + OPCODE_WSR_INTSET, + OPCODE_WSR_INTCLEAR, + OPCODE_RSR_INTENABLE, + OPCODE_WSR_INTENABLE, + OPCODE_XSR_INTENABLE, + OPCODE_BREAK, + OPCODE_BREAK_N, + OPCODE_RSR_DBREAKA0, + OPCODE_WSR_DBREAKA0, + OPCODE_XSR_DBREAKA0, + OPCODE_RSR_DBREAKC0, + OPCODE_WSR_DBREAKC0, + OPCODE_XSR_DBREAKC0, + OPCODE_RSR_IBREAKA0, + OPCODE_WSR_IBREAKA0, + OPCODE_XSR_IBREAKA0, + OPCODE_RSR_IBREAKENABLE, + OPCODE_WSR_IBREAKENABLE, + OPCODE_XSR_IBREAKENABLE, + OPCODE_RSR_DEBUGCAUSE, + OPCODE_WSR_DEBUGCAUSE, + OPCODE_XSR_DEBUGCAUSE, + OPCODE_RSR_ICOUNT, + OPCODE_WSR_ICOUNT, + OPCODE_XSR_ICOUNT, + OPCODE_RSR_ICOUNTLEVEL, + OPCODE_WSR_ICOUNTLEVEL, + OPCODE_XSR_ICOUNTLEVEL, + OPCODE_RSR_DDR, + OPCODE_WSR_DDR, + OPCODE_XSR_DDR, + OPCODE_RFDO, + OPCODE_RFDD, + OPCODE_WSR_MMID, + OPCODE_RSR_CCOUNT, + OPCODE_WSR_CCOUNT, + OPCODE_XSR_CCOUNT, + OPCODE_RSR_CCOMPARE0, + OPCODE_WSR_CCOMPARE0, + OPCODE_XSR_CCOMPARE0, + OPCODE_IDTLB, + OPCODE_PDTLB, + OPCODE_RDTLB0, + OPCODE_RDTLB1, + OPCODE_WDTLB, + OPCODE_IITLB, + OPCODE_PITLB, + OPCODE_RITLB0, + OPCODE_RITLB1, + OPCODE_WITLB, + OPCODE_NSA, + OPCODE_NSAU, + OPCODE_RER, + OPCODE_WER +}; + + +/* Slot-specific opcode decode functions. */ + +static int +Slot_inst_decode (const xtensa_insnbuf insn) +{ + switch (Field_op0_Slot_inst_get (insn)) + { + case 0: + switch (Field_op1_Slot_inst_get (insn)) + { + case 0: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_n_Slot_inst_get (insn) == 0) + return OPCODE_ILL; + break; + case 2: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return OPCODE_RET; + case 2: + return OPCODE_JX; + } + break; + case 3: + if (Field_n_Slot_inst_get (insn) == 0) + return OPCODE_CALLX0; + break; + } + break; + case 2: + if (Field_s_Slot_inst_get (insn) == 0) + { + switch (Field_t_Slot_inst_get (insn)) + { + case 0: + return OPCODE_ISYNC; + case 1: + return OPCODE_RSYNC; + case 2: + return OPCODE_ESYNC; + case 3: + return OPCODE_DSYNC; + case 8: + return OPCODE_EXCW; + case 12: + return OPCODE_MEMW; + case 13: + return OPCODE_EXTW; + case 15: + return OPCODE_NOP; + } + } + break; + case 3: + switch (Field_t_Slot_inst_get (insn)) + { + case 0: + switch (Field_s_Slot_inst_get (insn)) + { + case 0: + return OPCODE_RFE; + case 2: + return OPCODE_RFDE; + } + break; + case 1: + return OPCODE_RFI; + } + break; + case 4: + return OPCODE_BREAK; + case 5: + switch (Field_s_Slot_inst_get (insn)) + { + case 0: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SYSCALL; + break; + case 1: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SIMCALL; + break; + } + break; + case 6: + return OPCODE_RSIL; + case 7: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_WAITI; + break; + } + break; + case 1: + return OPCODE_AND; + case 2: + return OPCODE_OR; + case 3: + return OPCODE_XOR; + case 4: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SSR; + break; + case 1: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SSL; + break; + case 2: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SSA8L; + break; + case 3: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SSA8B; + break; + case 4: + if (Field_thi3_Slot_inst_get (insn) == 0) + return OPCODE_SSAI; + break; + case 6: + return OPCODE_RER; + case 7: + return OPCODE_WER; + case 14: + return OPCODE_NSA; + case 15: + return OPCODE_NSAU; + } + break; + case 5: + switch (Field_r_Slot_inst_get (insn)) + { + case 3: + return OPCODE_RITLB0; + case 4: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_IITLB; + break; + case 5: + return OPCODE_PITLB; + case 6: + return OPCODE_WITLB; + case 7: + return OPCODE_RITLB1; + case 11: + return OPCODE_RDTLB0; + case 12: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_IDTLB; + break; + case 13: + return OPCODE_PDTLB; + case 14: + return OPCODE_WDTLB; + case 15: + return OPCODE_RDTLB1; + } + break; + case 6: + switch (Field_s_Slot_inst_get (insn)) + { + case 0: + return OPCODE_NEG; + case 1: + return OPCODE_ABS; + } + break; + case 8: + return OPCODE_ADD; + case 9: + return OPCODE_ADDX2; + case 10: + return OPCODE_ADDX4; + case 11: + return OPCODE_ADDX8; + case 12: + return OPCODE_SUB; + case 13: + return OPCODE_SUBX2; + case 14: + return OPCODE_SUBX4; + case 15: + return OPCODE_SUBX8; + } + break; + case 1: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + case 1: + return OPCODE_SLLI; + case 2: + case 3: + return OPCODE_SRAI; + case 4: + return OPCODE_SRLI; + case 6: + switch (Field_sr_Slot_inst_get (insn)) + { + case 3: + return OPCODE_XSR_SAR; + case 5: + return OPCODE_XSR_LITBASE; + case 96: + return OPCODE_XSR_IBREAKENABLE; + case 104: + return OPCODE_XSR_DDR; + case 128: + return OPCODE_XSR_IBREAKA0; + case 144: + return OPCODE_XSR_DBREAKA0; + case 160: + return OPCODE_XSR_DBREAKC0; + case 177: + return OPCODE_XSR_EPC1; + case 178: + return OPCODE_XSR_EPC2; + case 179: + return OPCODE_XSR_EPC3; + case 192: + return OPCODE_XSR_DEPC; + case 194: + return OPCODE_XSR_EPS2; + case 195: + return OPCODE_XSR_EPS3; + case 209: + return OPCODE_XSR_EXCSAVE1; + case 210: + return OPCODE_XSR_EXCSAVE2; + case 211: + return OPCODE_XSR_EXCSAVE3; + case 228: + return OPCODE_XSR_INTENABLE; + case 230: + return OPCODE_XSR_PS; + case 231: + return OPCODE_XSR_VECBASE; + case 232: + return OPCODE_XSR_EXCCAUSE; + case 233: + return OPCODE_XSR_DEBUGCAUSE; + case 234: + return OPCODE_XSR_CCOUNT; + case 236: + return OPCODE_XSR_ICOUNT; + case 237: + return OPCODE_XSR_ICOUNTLEVEL; + case 238: + return OPCODE_XSR_EXCVADDR; + case 240: + return OPCODE_XSR_CCOMPARE0; + } + break; + case 8: + return OPCODE_SRC; + case 9: + if (Field_s_Slot_inst_get (insn) == 0) + return OPCODE_SRL; + break; + case 10: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SLL; + break; + case 11: + if (Field_s_Slot_inst_get (insn) == 0) + return OPCODE_SRA; + break; + case 12: + return OPCODE_MUL16U; + case 13: + return OPCODE_MUL16S; + case 15: + switch (Field_r_Slot_inst_get (insn)) + { + case 14: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_RFDO; + if (Field_t_Slot_inst_get (insn) == 1) + return OPCODE_RFDD; + break; + } + break; + } + break; + case 2: + if (Field_op2_Slot_inst_get (insn) == 8) + return OPCODE_MULL; + break; + case 3: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + switch (Field_sr_Slot_inst_get (insn)) + { + case 3: + return OPCODE_RSR_SAR; + case 5: + return OPCODE_RSR_LITBASE; + case 96: + return OPCODE_RSR_IBREAKENABLE; + case 104: + return OPCODE_RSR_DDR; + case 128: + return OPCODE_RSR_IBREAKA0; + case 144: + return OPCODE_RSR_DBREAKA0; + case 160: + return OPCODE_RSR_DBREAKC0; + case 176: + return OPCODE_RSR_176; + case 177: + return OPCODE_RSR_EPC1; + case 178: + return OPCODE_RSR_EPC2; + case 179: + return OPCODE_RSR_EPC3; + case 192: + return OPCODE_RSR_DEPC; + case 194: + return OPCODE_RSR_EPS2; + case 195: + return OPCODE_RSR_EPS3; + case 208: + return OPCODE_RSR_208; + case 209: + return OPCODE_RSR_EXCSAVE1; + case 210: + return OPCODE_RSR_EXCSAVE2; + case 211: + return OPCODE_RSR_EXCSAVE3; + case 226: + return OPCODE_RSR_INTERRUPT; + case 228: + return OPCODE_RSR_INTENABLE; + case 230: + return OPCODE_RSR_PS; + case 231: + return OPCODE_RSR_VECBASE; + case 232: + return OPCODE_RSR_EXCCAUSE; + case 233: + return OPCODE_RSR_DEBUGCAUSE; + case 234: + return OPCODE_RSR_CCOUNT; + case 235: + return OPCODE_RSR_PRID; + case 236: + return OPCODE_RSR_ICOUNT; + case 237: + return OPCODE_RSR_ICOUNTLEVEL; + case 238: + return OPCODE_RSR_EXCVADDR; + case 240: + return OPCODE_RSR_CCOMPARE0; + } + break; + case 1: + switch (Field_sr_Slot_inst_get (insn)) + { + case 3: + return OPCODE_WSR_SAR; + case 5: + return OPCODE_WSR_LITBASE; + case 89: + return OPCODE_WSR_MMID; + case 96: + return OPCODE_WSR_IBREAKENABLE; + case 104: + return OPCODE_WSR_DDR; + case 128: + return OPCODE_WSR_IBREAKA0; + case 144: + return OPCODE_WSR_DBREAKA0; + case 160: + return OPCODE_WSR_DBREAKC0; + case 176: + return OPCODE_WSR_176; + case 177: + return OPCODE_WSR_EPC1; + case 178: + return OPCODE_WSR_EPC2; + case 179: + return OPCODE_WSR_EPC3; + case 192: + return OPCODE_WSR_DEPC; + case 194: + return OPCODE_WSR_EPS2; + case 195: + return OPCODE_WSR_EPS3; + case 209: + return OPCODE_WSR_EXCSAVE1; + case 210: + return OPCODE_WSR_EXCSAVE2; + case 211: + return OPCODE_WSR_EXCSAVE3; + case 226: + return OPCODE_WSR_INTSET; + case 227: + return OPCODE_WSR_INTCLEAR; + case 228: + return OPCODE_WSR_INTENABLE; + case 230: + return OPCODE_WSR_PS; + case 231: + return OPCODE_WSR_VECBASE; + case 232: + return OPCODE_WSR_EXCCAUSE; + case 233: + return OPCODE_WSR_DEBUGCAUSE; + case 234: + return OPCODE_WSR_CCOUNT; + case 236: + return OPCODE_WSR_ICOUNT; + case 237: + return OPCODE_WSR_ICOUNTLEVEL; + case 238: + return OPCODE_WSR_EXCVADDR; + case 240: + return OPCODE_WSR_CCOMPARE0; + } + break; + case 8: + return OPCODE_MOVEQZ; + case 9: + return OPCODE_MOVNEZ; + case 10: + return OPCODE_MOVLTZ; + case 11: + return OPCODE_MOVGEZ; + } + break; + case 4: + case 5: + return OPCODE_EXTUI; + } + break; + case 1: + return OPCODE_L32R; + case 2: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + return OPCODE_L8UI; + case 1: + return OPCODE_L16UI; + case 2: + return OPCODE_L32I; + case 4: + return OPCODE_S8I; + case 5: + return OPCODE_S16I; + case 6: + return OPCODE_S32I; + case 9: + return OPCODE_L16SI; + case 10: + return OPCODE_MOVI; + case 12: + return OPCODE_ADDI; + case 13: + return OPCODE_ADDMI; + } + break; + case 5: + if (Field_n_Slot_inst_get (insn) == 0) + return OPCODE_CALL0; + break; + case 6: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return OPCODE_J; + case 1: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + return OPCODE_BEQZ; + case 1: + return OPCODE_BNEZ; + case 2: + return OPCODE_BLTZ; + case 3: + return OPCODE_BGEZ; + } + break; + case 2: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + return OPCODE_BEQI; + case 1: + return OPCODE_BNEI; + case 2: + return OPCODE_BLTI; + case 3: + return OPCODE_BGEI; + } + break; + case 3: + switch (Field_m_Slot_inst_get (insn)) + { + case 2: + return OPCODE_BLTUI; + case 3: + return OPCODE_BGEUI; + } + break; + } + break; + case 7: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + return OPCODE_BNONE; + case 1: + return OPCODE_BEQ; + case 2: + return OPCODE_BLT; + case 3: + return OPCODE_BLTU; + case 4: + return OPCODE_BALL; + case 5: + return OPCODE_BBC; + case 6: + case 7: + return OPCODE_BBCI; + case 8: + return OPCODE_BANY; + case 9: + return OPCODE_BNE; + case 10: + return OPCODE_BGE; + case 11: + return OPCODE_BGEU; + case 12: + return OPCODE_BNALL; + case 13: + return OPCODE_BBS; + case 14: + case 15: + return OPCODE_BBSI; + } + break; + } + return XTENSA_UNDEFINED; +} + +static int +Slot_inst16a_decode (const xtensa_insnbuf insn) +{ + switch (Field_op0_Slot_inst16a_get (insn)) + { + case 8: + return OPCODE_L32I_N; + case 9: + return OPCODE_S32I_N; + case 10: + return OPCODE_ADD_N; + case 11: + return OPCODE_ADDI_N; + } + return XTENSA_UNDEFINED; +} + +static int +Slot_inst16b_decode (const xtensa_insnbuf insn) +{ + switch (Field_op0_Slot_inst16b_get (insn)) + { + case 12: + switch (Field_i_Slot_inst16b_get (insn)) + { + case 0: + return OPCODE_MOVI_N; + case 1: + switch (Field_z_Slot_inst16b_get (insn)) + { + case 0: + return OPCODE_BEQZ_N; + case 1: + return OPCODE_BNEZ_N; + } + break; + } + break; + case 13: + switch (Field_r_Slot_inst16b_get (insn)) + { + case 0: + return OPCODE_MOV_N; + case 15: + switch (Field_t_Slot_inst16b_get (insn)) + { + case 0: + return OPCODE_RET_N; + case 2: + return OPCODE_BREAK_N; + case 3: + if (Field_s_Slot_inst16b_get (insn) == 0) + return OPCODE_NOP_N; + break; + case 6: + if (Field_s_Slot_inst16b_get (insn) == 0) + return OPCODE_ILL_N; + break; + } + break; + } + break; + } + return XTENSA_UNDEFINED; +} + + +/* Instruction slots. */ + +static void +Slot_x24_Format_inst_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = (insn[0] & 0xffffff); +} + +static void +Slot_x24_Format_inst_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffffff) | (slotbuf[0] & 0xffffff); +} + +static void +Slot_x16a_Format_inst16a_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = (insn[0] & 0xffff); +} + +static void +Slot_x16a_Format_inst16a_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffff) | (slotbuf[0] & 0xffff); +} + +static void +Slot_x16b_Format_inst16b_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = (insn[0] & 0xffff); +} + +static void +Slot_x16b_Format_inst16b_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffff) | (slotbuf[0] & 0xffff); +} + +static xtensa_get_field_fn +Slot_inst_get_field_fns[] = { + Field_t_Slot_inst_get, + Field_bbi4_Slot_inst_get, + Field_bbi_Slot_inst_get, + Field_imm12_Slot_inst_get, + Field_imm8_Slot_inst_get, + Field_s_Slot_inst_get, + Field_imm12b_Slot_inst_get, + Field_imm16_Slot_inst_get, + Field_m_Slot_inst_get, + Field_n_Slot_inst_get, + Field_offset_Slot_inst_get, + Field_op0_Slot_inst_get, + Field_op1_Slot_inst_get, + Field_op2_Slot_inst_get, + Field_r_Slot_inst_get, + Field_sa4_Slot_inst_get, + Field_sae4_Slot_inst_get, + Field_sae_Slot_inst_get, + Field_sal_Slot_inst_get, + Field_sargt_Slot_inst_get, + Field_sas4_Slot_inst_get, + Field_sas_Slot_inst_get, + Field_sr_Slot_inst_get, + Field_st_Slot_inst_get, + Field_thi3_Slot_inst_get, + Field_imm4_Slot_inst_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_xt_wbr15_imm_Slot_inst_get, + Field_xt_wbr18_imm_Slot_inst_get, + Implicit_Field_ar0_get +}; + +static xtensa_set_field_fn +Slot_inst_set_field_fns[] = { + Field_t_Slot_inst_set, + Field_bbi4_Slot_inst_set, + Field_bbi_Slot_inst_set, + Field_imm12_Slot_inst_set, + Field_imm8_Slot_inst_set, + Field_s_Slot_inst_set, + Field_imm12b_Slot_inst_set, + Field_imm16_Slot_inst_set, + Field_m_Slot_inst_set, + Field_n_Slot_inst_set, + Field_offset_Slot_inst_set, + Field_op0_Slot_inst_set, + Field_op1_Slot_inst_set, + Field_op2_Slot_inst_set, + Field_r_Slot_inst_set, + Field_sa4_Slot_inst_set, + Field_sae4_Slot_inst_set, + Field_sae_Slot_inst_set, + Field_sal_Slot_inst_set, + Field_sargt_Slot_inst_set, + Field_sas4_Slot_inst_set, + Field_sas_Slot_inst_set, + Field_sr_Slot_inst_set, + Field_st_Slot_inst_set, + Field_thi3_Slot_inst_set, + Field_imm4_Slot_inst_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_xt_wbr15_imm_Slot_inst_set, + Field_xt_wbr18_imm_Slot_inst_set, + Implicit_Field_set +}; + +static xtensa_get_field_fn +Slot_inst16a_get_field_fns[] = { + Field_t_Slot_inst16a_get, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16a_get, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16a_get, + 0, + 0, + Field_r_Slot_inst16a_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16a_get, + Field_st_Slot_inst16a_get, + 0, + Field_imm4_Slot_inst16a_get, + Field_i_Slot_inst16a_get, + Field_imm6lo_Slot_inst16a_get, + Field_imm6hi_Slot_inst16a_get, + Field_imm7lo_Slot_inst16a_get, + Field_imm7hi_Slot_inst16a_get, + Field_z_Slot_inst16a_get, + Field_imm6_Slot_inst16a_get, + Field_imm7_Slot_inst16a_get, + 0, + 0, + Implicit_Field_ar0_get +}; + +static xtensa_set_field_fn +Slot_inst16a_set_field_fns[] = { + Field_t_Slot_inst16a_set, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16a_set, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16a_set, + 0, + 0, + Field_r_Slot_inst16a_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16a_set, + Field_st_Slot_inst16a_set, + 0, + Field_imm4_Slot_inst16a_set, + Field_i_Slot_inst16a_set, + Field_imm6lo_Slot_inst16a_set, + Field_imm6hi_Slot_inst16a_set, + Field_imm7lo_Slot_inst16a_set, + Field_imm7hi_Slot_inst16a_set, + Field_z_Slot_inst16a_set, + Field_imm6_Slot_inst16a_set, + Field_imm7_Slot_inst16a_set, + 0, + 0, + Implicit_Field_set +}; + +static xtensa_get_field_fn +Slot_inst16b_get_field_fns[] = { + Field_t_Slot_inst16b_get, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16b_get, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16b_get, + 0, + 0, + Field_r_Slot_inst16b_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16b_get, + Field_st_Slot_inst16b_get, + 0, + Field_imm4_Slot_inst16b_get, + Field_i_Slot_inst16b_get, + Field_imm6lo_Slot_inst16b_get, + Field_imm6hi_Slot_inst16b_get, + Field_imm7lo_Slot_inst16b_get, + Field_imm7hi_Slot_inst16b_get, + Field_z_Slot_inst16b_get, + Field_imm6_Slot_inst16b_get, + Field_imm7_Slot_inst16b_get, + 0, + 0, + Implicit_Field_ar0_get +}; + +static xtensa_set_field_fn +Slot_inst16b_set_field_fns[] = { + Field_t_Slot_inst16b_set, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16b_set, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16b_set, + 0, + 0, + Field_r_Slot_inst16b_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16b_set, + Field_st_Slot_inst16b_set, + 0, + Field_imm4_Slot_inst16b_set, + Field_i_Slot_inst16b_set, + Field_imm6lo_Slot_inst16b_set, + Field_imm6hi_Slot_inst16b_set, + Field_imm7lo_Slot_inst16b_set, + Field_imm7hi_Slot_inst16b_set, + Field_z_Slot_inst16b_set, + Field_imm6_Slot_inst16b_set, + Field_imm7_Slot_inst16b_set, + 0, + 0, + Implicit_Field_set +}; + +static xtensa_slot_internal slots[] = { + { "Inst", "x24", 0, + Slot_x24_Format_inst_0_get, Slot_x24_Format_inst_0_set, + Slot_inst_get_field_fns, Slot_inst_set_field_fns, + Slot_inst_decode, "nop" }, + { "Inst16a", "x16a", 0, + Slot_x16a_Format_inst16a_0_get, Slot_x16a_Format_inst16a_0_set, + Slot_inst16a_get_field_fns, Slot_inst16a_set_field_fns, + Slot_inst16a_decode, "" }, + { "Inst16b", "x16b", 0, + Slot_x16b_Format_inst16b_0_get, Slot_x16b_Format_inst16b_0_set, + Slot_inst16b_get_field_fns, Slot_inst16b_set_field_fns, + Slot_inst16b_decode, "nop.n" } +}; + + +/* Instruction formats. */ + +static void +Format_x24_encode (xtensa_insnbuf insn) +{ + insn[0] = 0; +} + +static void +Format_x16a_encode (xtensa_insnbuf insn) +{ + insn[0] = 0x8; +} + +static void +Format_x16b_encode (xtensa_insnbuf insn) +{ + insn[0] = 0xc; +} + +static int Format_x24_slots[] = { 0 }; + +static int Format_x16a_slots[] = { 1 }; + +static int Format_x16b_slots[] = { 2 }; + +static xtensa_format_internal formats[] = { + { "x24", 3, Format_x24_encode, 1, Format_x24_slots }, + { "x16a", 2, Format_x16a_encode, 1, Format_x16a_slots }, + { "x16b", 2, Format_x16b_encode, 1, Format_x16b_slots } +}; + + +static int +format_decoder (const xtensa_insnbuf insn) +{ + if ((insn[0] & 0x8) == 0) + return 0; /* x24 */ + if ((insn[0] & 0xc) == 0x8) + return 1; /* x16a */ + if ((insn[0] & 0xe) == 0xc) + return 2; /* x16b */ + return -1; +} + +static int length_table[16] = { + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1 +}; + +static int +length_decoder (const unsigned char *insn) +{ + int op0 = insn[0] & 0xf; + return length_table[op0]; +} + + +/* Top-level ISA structure. */ + +static xtensa_isa_internal xtensa_modules = { + 0 /* little-endian */, + 3 /* insn_size */, 0, + 3, formats, format_decoder, length_decoder, + 3, slots, + 37 /* num_fields */, + 65, operands, + 159, iclasses, + 204, opcodes, 0, + 1, regfiles, + NUM_STATES, states, 0, + NUM_SYSREGS, sysregs, 0, + { MAX_SPECIAL_REG, MAX_USER_REG }, { 0, 0 }, + 0, interfaces, 0, + 0, funcUnits, 0 +}; diff --git a/target/xtensa/cores.list b/target/xtensa/cores.list index 5772a00ab2..a526a71cfd 100644 --- a/target/xtensa/cores.list +++ b/target/xtensa/cores.list @@ -4,6 +4,7 @@ core-de212.c core-de233_fpu.c core-dsp3400.c core-fsf.c +core-lx106.c core-sample_controller.c core-test_kc705_be.c core-test_mmuhifi_c3.c From 9e377be1f042e8618c54ee786d1022caa0e2409d Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Sun, 3 Oct 2021 14:31:47 -0700 Subject: [PATCH 087/935] target/xtensa: add clock input to xtensa CPU Create clock input for the xtensa CPU device and initialize its frequency to the default core frequency specified in the config. Signed-off-by: Max Filippov --- target/xtensa/cpu.c | 15 +++++++++++++++ target/xtensa/cpu.h | 5 +++++ target/xtensa/op_helper.c | 7 ++++--- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 224f723236..fd553fdfb5 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -34,6 +34,7 @@ #include "fpu/softfloat.h" #include "qemu/module.h" #include "migration/vmstate.h" +#include "hw/qdev-clock.h" static void xtensa_cpu_set_pc(CPUState *cs, vaddr value) @@ -172,9 +173,23 @@ static void xtensa_cpu_initfn(Object *obj) memory_region_init_io(env->system_er, obj, NULL, env, "er", UINT64_C(0x100000000)); address_space_init(env->address_space_er, env->system_er, "ER"); + + cpu->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, cpu, 0); + clock_set_hz(cpu->clock, env->config->clock_freq_khz * 1000); #endif } +XtensaCPU *xtensa_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk) +{ + DeviceState *cpu; + + cpu = DEVICE(object_new(cpu_type)); + qdev_connect_clock_in(cpu, "clk-in", cpu_refclk); + qdev_realize(cpu, NULL, &error_abort); + + return XTENSA_CPU(cpu); +} + #ifndef CONFIG_USER_ONLY static const VMStateDescription vmstate_xtensa_cpu = { .name = "cpu", diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index d4b8268146..579adcb769 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -31,6 +31,7 @@ #include "cpu-qom.h" #include "qemu/cpu-float.h" #include "exec/cpu-defs.h" +#include "hw/clock.h" #include "xtensa-isa.h" /* Xtensa processors have a weak memory model */ @@ -559,6 +560,7 @@ struct ArchCPU { CPUState parent_obj; /*< public >*/ + Clock *clock; CPUNegativeOffsetState neg; CPUXtensaState env; }; @@ -793,4 +795,7 @@ static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc, } } +XtensaCPU *xtensa_cpu_create_with_clock(const char *cpu_type, + Clock *cpu_refclk); + #endif diff --git a/target/xtensa/op_helper.c b/target/xtensa/op_helper.c index d85d3516d6..1af7becc54 100644 --- a/target/xtensa/op_helper.c +++ b/target/xtensa/op_helper.c @@ -38,12 +38,12 @@ void HELPER(update_ccount)(CPUXtensaState *env) { + XtensaCPU *cpu = XTENSA_CPU(env_cpu(env)); uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); env->ccount_time = now; env->sregs[CCOUNT] = env->ccount_base + - (uint32_t)((now - env->time_base) * - env->config->clock_freq_khz / 1000000); + (uint32_t)clock_ns_to_ticks(cpu->clock, now - env->time_base); } void HELPER(wsr_ccount)(CPUXtensaState *env, uint32_t v) @@ -59,6 +59,7 @@ void HELPER(wsr_ccount)(CPUXtensaState *env, uint32_t v) void HELPER(update_ccompare)(CPUXtensaState *env, uint32_t i) { + XtensaCPU *cpu = XTENSA_CPU(env_cpu(env)); uint64_t dcc; qatomic_and(&env->sregs[INTSET], @@ -66,7 +67,7 @@ void HELPER(update_ccompare)(CPUXtensaState *env, uint32_t i) HELPER(update_ccount)(env); dcc = (uint64_t)(env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] - 1) + 1; timer_mod(env->ccompare[i].timer, - env->ccount_time + (dcc * 1000000) / env->config->clock_freq_khz); + env->ccount_time + clock_ticks_to_ns(cpu->clock, dcc)); env->yield_needed = 1; } From c6f3f334d157ff6b9bdc4e1b9d9874234138836a Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Tue, 26 Apr 2022 09:24:01 -0700 Subject: [PATCH 088/935] hw/xtensa: fix reset value of MIROUT register of MX PIC MX PIC comes out of reset with IRQ routing registers set to 0, thus not delivering any external IRQ to any connected CPU by default. Fix the model to match the hardware. Signed-off-by: Max Filippov --- hw/xtensa/mx_pic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/xtensa/mx_pic.c b/hw/xtensa/mx_pic.c index d889f953d1..8211c993eb 100644 --- a/hw/xtensa/mx_pic.c +++ b/hw/xtensa/mx_pic.c @@ -334,7 +334,7 @@ void xtensa_mx_pic_reset(void *opaque) mx->miasg = 0; mx->mipipart = 0; for (i = 0; i < mx->n_irq; ++i) { - mx->mirout[i] = 1; + mx->mirout[i] = 0; } for (i = 0; i < mx->n_cpu; ++i) { mx->cpu[i].mipicause = 0; From b9400b1fbaeb69af3e3052721fad79b2e46efc65 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Sun, 24 Apr 2022 08:31:29 -0700 Subject: [PATCH 089/935] tests/tcg/xtensa: fix build for cores without windowed registers Don't try to initialize windowbase/windowstart in crt.S if they don't exist. Signed-off-by: Max Filippov --- tests/tcg/xtensa/crt.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/tcg/xtensa/crt.S b/tests/tcg/xtensa/crt.S index d9846acace..909872cd38 100644 --- a/tests/tcg/xtensa/crt.S +++ b/tests/tcg/xtensa/crt.S @@ -8,10 +8,12 @@ .text .global _start _start: +#if XCHAL_HAVE_WINDOWED movi a2, 1 wsr a2, windowstart movi a2, 0 wsr a2, windowbase +#endif movi a1, _fstack movi a2, 0x4000f wsr a2, ps From 8164f14bb98dce986b755af4b3dfee3eb99c95a1 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Sun, 24 Apr 2022 08:33:16 -0700 Subject: [PATCH 090/935] tests/tcg/xtensa: restore vecbase SR after test Writing garbage into the vecbase SR results in hang in the subsequent tests that expect to raise an exception. Restore vecbase SR to its reset value after the test. Signed-off-by: Max Filippov --- tests/tcg/xtensa/test_sr.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/tcg/xtensa/test_sr.S b/tests/tcg/xtensa/test_sr.S index b1a91a0637..34441c7aff 100644 --- a/tests/tcg/xtensa/test_sr.S +++ b/tests/tcg/xtensa/test_sr.S @@ -221,6 +221,8 @@ test_sr_mask /*scompare1*/12, 0, 0 #if XCHAL_HAVE_VECBASE test_sr vecbase, 1 +movi a2, XCHAL_VECBASE_RESET_VADDR +wsr a2, vecbase #else test_sr_mask /*vecbase*/231, 0, 0 #endif From 64407f6a9e0731c11a65119b7372dbe5b3a42eb9 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 25 Apr 2022 17:16:01 -0700 Subject: [PATCH 091/935] tests/tcg/xtensa: fix watchpoint test xtensa core may have only one set of DBREAKA/DBREAKC registers. Don't hardcode register numbers in the test as 0 and 1, use macros that only index valid DBREAK* registers. Signed-off-by: Max Filippov --- tests/tcg/xtensa/test_break.S | 86 +++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 40 deletions(-) diff --git a/tests/tcg/xtensa/test_break.S b/tests/tcg/xtensa/test_break.S index 3379a3f9f0..3aa18b5cec 100644 --- a/tests/tcg/xtensa/test_break.S +++ b/tests/tcg/xtensa/test_break.S @@ -200,64 +200,70 @@ test_end .endm #if XCHAL_NUM_DBREAK +#define DB0 0 +#if XCHAL_NUM_DBREAK > 1 +#define DB1 1 +#else +#define DB1 0 +#endif test dbreak_exact - dbreak_test 0, 0x4000003f, 0xd000007f, 0xd000007f, l8ui - dbreak_test 1, 0x4000003e, 0xd000007e, 0xd000007e, l16ui - dbreak_test 0, 0x4000003c, 0xd000007c, 0xd000007c, l32i + dbreak_test DB0, 0x4000003f, 0xd000007f, 0xd000007f, l8ui + dbreak_test DB1, 0x4000003e, 0xd000007e, 0xd000007e, l16ui + dbreak_test DB0, 0x4000003c, 0xd000007c, 0xd000007c, l32i - dbreak_test 1, 0x8000003f, 0xd000007f, 0xd000007f, s8i - dbreak_test 0, 0x8000003e, 0xd000007e, 0xd000007e, s16i - dbreak_test 1, 0x8000003c, 0xd000007c, 0xd000007c, s32i + dbreak_test DB1, 0x8000003f, 0xd000007f, 0xd000007f, s8i + dbreak_test DB0, 0x8000003e, 0xd000007e, 0xd000007e, s16i + dbreak_test DB1, 0x8000003c, 0xd000007c, 0xd000007c, s32i test_end -test dbreak_overlap - dbreak_test 0, 0x4000003f, 0xd000007d, 0xd000007c, l16ui - dbreak_test 1, 0x4000003f, 0xd000007d, 0xd000007c, l32i +test DBdbreak_overlap + dbreak_test DB0, 0x4000003f, 0xd000007d, 0xd000007c, l16ui + dbreak_test DB1, 0x4000003f, 0xd000007d, 0xd000007c, l32i - dbreak_test 0, 0x4000003e, 0xd000007e, 0xd000007f, l8ui - dbreak_test 1, 0x4000003e, 0xd000007e, 0xd000007c, l32i + dbreak_test DB0, 0x4000003e, 0xd000007e, 0xd000007f, l8ui + dbreak_test DB1, 0x4000003e, 0xd000007e, 0xd000007c, l32i - dbreak_test 0, 0x4000003c, 0xd000007c, 0xd000007d, l8ui - dbreak_test 1, 0x4000003c, 0xd000007c, 0xd000007c, l16ui + dbreak_test DB0, 0x4000003c, 0xd000007c, 0xd000007d, l8ui + dbreak_test DB1, 0x4000003c, 0xd000007c, 0xd000007c, l16ui - dbreak_test 0, 0x40000038, 0xd0000078, 0xd000007b, l8ui - dbreak_test 1, 0x40000038, 0xd0000078, 0xd000007a, l16ui - dbreak_test 0, 0x40000038, 0xd0000078, 0xd000007c, l32i + dbreak_test DB0, 0x40000038, 0xd0000078, 0xd000007b, l8ui + dbreak_test DB1, 0x40000038, 0xd0000078, 0xd000007a, l16ui + dbreak_test DB0, 0x40000038, 0xd0000078, 0xd000007c, l32i - dbreak_test 1, 0x40000030, 0xd0000070, 0xd0000075, l8ui - dbreak_test 0, 0x40000030, 0xd0000070, 0xd0000076, l16ui - dbreak_test 1, 0x40000030, 0xd0000070, 0xd0000078, l32i + dbreak_test DB1, 0x40000030, 0xd0000070, 0xd0000075, l8ui + dbreak_test DB0, 0x40000030, 0xd0000070, 0xd0000076, l16ui + dbreak_test DB1, 0x40000030, 0xd0000070, 0xd0000078, l32i - dbreak_test 0, 0x40000020, 0xd0000060, 0xd000006f, l8ui - dbreak_test 1, 0x40000020, 0xd0000060, 0xd0000070, l16ui - dbreak_test 0, 0x40000020, 0xd0000060, 0xd0000074, l32i + dbreak_test DB0, 0x40000020, 0xd0000060, 0xd000006f, l8ui + dbreak_test DB1, 0x40000020, 0xd0000060, 0xd0000070, l16ui + dbreak_test DB0, 0x40000020, 0xd0000060, 0xd0000074, l32i - dbreak_test 0, 0x8000003f, 0xd000007d, 0xd000007c, s16i - dbreak_test 1, 0x8000003f, 0xd000007d, 0xd000007c, s32i + dbreak_test DB0, 0x8000003f, 0xd000007d, 0xd000007c, s16i + dbreak_test DB1, 0x8000003f, 0xd000007d, 0xd000007c, s32i - dbreak_test 0, 0x8000003e, 0xd000007e, 0xd000007f, s8i - dbreak_test 1, 0x8000003e, 0xd000007e, 0xd000007c, s32i + dbreak_test DB0, 0x8000003e, 0xd000007e, 0xd000007f, s8i + dbreak_test DB1, 0x8000003e, 0xd000007e, 0xd000007c, s32i - dbreak_test 0, 0x8000003c, 0xd000007c, 0xd000007d, s8i - dbreak_test 1, 0x8000003c, 0xd000007c, 0xd000007c, s16i + dbreak_test DB0, 0x8000003c, 0xd000007c, 0xd000007d, s8i + dbreak_test DB1, 0x8000003c, 0xd000007c, 0xd000007c, s16i - dbreak_test 0, 0x80000038, 0xd0000078, 0xd000007b, s8i - dbreak_test 1, 0x80000038, 0xd0000078, 0xd000007a, s16i - dbreak_test 0, 0x80000038, 0xd0000078, 0xd000007c, s32i + dbreak_test DB0, 0x80000038, 0xd0000078, 0xd000007b, s8i + dbreak_test DB1, 0x80000038, 0xd0000078, 0xd000007a, s16i + dbreak_test DB0, 0x80000038, 0xd0000078, 0xd000007c, s32i - dbreak_test 1, 0x80000030, 0xd0000070, 0xd0000075, s8i - dbreak_test 0, 0x80000030, 0xd0000070, 0xd0000076, s16i - dbreak_test 1, 0x80000030, 0xd0000070, 0xd0000078, s32i + dbreak_test DB1, 0x80000030, 0xd0000070, 0xd0000075, s8i + dbreak_test DB0, 0x80000030, 0xd0000070, 0xd0000076, s16i + dbreak_test DB1, 0x80000030, 0xd0000070, 0xd0000078, s32i - dbreak_test 0, 0x80000020, 0xd0000060, 0xd000006f, s8i - dbreak_test 1, 0x80000020, 0xd0000060, 0xd0000070, s16i - dbreak_test 0, 0x80000020, 0xd0000060, 0xd0000074, s32i + dbreak_test DB0, 0x80000020, 0xd0000060, 0xd000006f, s8i + dbreak_test DB1, 0x80000020, 0xd0000060, 0xd0000070, s16i + dbreak_test DB0, 0x80000020, 0xd0000060, 0xd0000074, s32i test_end -test dbreak_invalid - dbreak_test 0, 0x40000030, 0xd0000071, 0xd0000070, l16ui - dbreak_test 1, 0x40000035, 0xd0000072, 0xd0000070, l32i +test DBdbreak_invalid + dbreak_test DB0, 0x40000030, 0xd0000071, 0xd0000070, l16ui + dbreak_test DB1, 0x40000035, 0xd0000072, 0xd0000070, l32i test_end #endif From e120c8335d1dfa9d194e3db8cc5195a6b47fb20c Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 25 Apr 2022 18:12:53 -0700 Subject: [PATCH 092/935] tests/tcg/xtensa: remove dependency on the loop option xtensa core may not have the loop option, but still have timers. Don't use loop opcode in the timer test. Signed-off-by: Max Filippov --- tests/tcg/xtensa/test_timer.S | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/tcg/xtensa/test_timer.S b/tests/tcg/xtensa/test_timer.S index 1ec8e20883..2a383e7719 100644 --- a/tests/tcg/xtensa/test_timer.S +++ b/tests/tcg/xtensa/test_timer.S @@ -115,9 +115,9 @@ test ccompare0_interrupt movi a2, 1 << XCHAL_TIMER0_INTERRUPT wsr a2, intenable rsil a2, 0 - loop a3, 1f - nop 1: + addi a3, a3, -1 + bnez a3, 1b test_fail 2: rsr a2, exccause @@ -148,9 +148,9 @@ test ccompare1_interrupt movi a2, 1 << XCHAL_TIMER1_INTERRUPT wsr a2, intenable rsil a2, INTERRUPT_LEVEL(XCHAL_TIMER1_INTERRUPT) - 1 - loop a3, 1f - nop 1: + addi a3, a3, -1 + bnez a3, 1b test_fail 2: test_end @@ -177,9 +177,9 @@ test ccompare2_interrupt movi a2, 1 << XCHAL_TIMER2_INTERRUPT wsr a2, intenable rsil a2, INTERRUPT_LEVEL(XCHAL_TIMER2_INTERRUPT) - 1 - loop a3, 1f - nop 1: + addi a3, a3, -1 + bnez a3, 1b test_fail 2: test_end @@ -197,7 +197,7 @@ test ccompare_interrupt_masked wsr a2, ccompare2 #endif - movi a3, 2 * WAIT_LOOPS + movi a3, WAIT_LOOPS make_ccount_delta a2, a15 #if XCHAL_NUM_TIMERS > 1 wsr a2, ccompare1 @@ -211,9 +211,10 @@ test ccompare_interrupt_masked movi a2, 1 << XCHAL_TIMER0_INTERRUPT wsr a2, intenable rsil a2, 0 - loop a3, 1f - nop 1: + addi a3, a3, -1 + bnez a3, 1b + test_fail 2: rsr a2, exccause @@ -231,7 +232,6 @@ test ccompare_interrupt_masked_waiti wsr a2, ccompare2 #endif - movi a3, 2 * WAIT_LOOPS make_ccount_delta a2, a15 #if XCHAL_NUM_TIMERS > 1 wsr a2, ccompare1 From 703cebcfac65356aa2b19c0a5e4aa1b4be23a328 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 25 Apr 2022 20:05:18 -0700 Subject: [PATCH 093/935] tests/tcg/xtensa: enable autorefill phys_mem tests for MMUv3 Autorefill tests in the phys_mem test suite are disabled for cores that have spanning TLB way, i.e. for all MMUv3 cores. Instead of disabling it invalidate TLB mappings for entries that conflict with the test. Signed-off-by: Max Filippov --- tests/tcg/xtensa/test_phys_mem.S | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/tcg/xtensa/test_phys_mem.S b/tests/tcg/xtensa/test_phys_mem.S index 9bb3ee3866..f935a70294 100644 --- a/tests/tcg/xtensa/test_phys_mem.S +++ b/tests/tcg/xtensa/test_phys_mem.S @@ -2,7 +2,7 @@ test_suite phys_mem -#if XCHAL_HAVE_PTP_MMU && !XCHAL_HAVE_SPANNING_WAY +#if XCHAL_HAVE_PTP_MMU .purgem test_init @@ -13,6 +13,14 @@ test_suite phys_mem witlb a2, a3 movi a2, 0xc0000000 wsr a2, ptevaddr +#if XCHAL_HAVE_SPANNING_WAY + movi a2, 0xc0000000 | XCHAL_SPANNING_WAY + idtlb a2 + iitlb a2 + movi a2, 0x20000000 | XCHAL_SPANNING_WAY + idtlb a2 + iitlb a2 +#endif .endm test inst_fetch_get_pte_no_phys From da60ecd6d8bf6551a0211714a5abb11711e0222c Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 25 Apr 2022 20:05:18 -0700 Subject: [PATCH 094/935] tests/tcg/xtensa: enable mmu tests for MMUv3 MMU test suite is disabled for cores that have spanning TLB way, i.e. for all MMUv3 cores. Instead of disabling it make testing region virtual addresses explicit and invalidate TLB mappings for entries that conflict with the test. Signed-off-by: Max Filippov --- tests/tcg/xtensa/test_mmu.S | 182 ++++++++++++++++++++---------------- 1 file changed, 103 insertions(+), 79 deletions(-) diff --git a/tests/tcg/xtensa/test_mmu.S b/tests/tcg/xtensa/test_mmu.S index 4cbd6ef4f9..1006c8cf77 100644 --- a/tests/tcg/xtensa/test_mmu.S +++ b/tests/tcg/xtensa/test_mmu.S @@ -2,7 +2,9 @@ test_suite mmu -#if XCHAL_HAVE_PTP_MMU && !XCHAL_HAVE_SPANNING_WAY +#if XCHAL_HAVE_PTP_MMU +#define BASE 0x20000000 +#define TLB_BASE 0x80000000 .purgem test_init @@ -29,17 +31,27 @@ test_suite mmu idtlb a2 movi a2, 0x00000009 idtlb a2 +#if XCHAL_HAVE_SPANNING_WAY + movi a2, BASE | XCHAL_SPANNING_WAY + idtlb a2 + iitlb a2 + movi a2, TLB_BASE | XCHAL_SPANNING_WAY + idtlb a2 + iitlb a2 + movi a2, TLB_BASE + wsr a2, ptevaddr +#endif .endm test tlb_group movi a2, 0x04000002 /* PPN */ - movi a3, 0x01200004 /* VPN */ + movi a3, BASE + 0x01200004 /* VPN */ wdtlb a2, a3 witlb a2, a3 movi a3, 0x00200004 rdtlb0 a1, a3 ritlb0 a2, a3 - movi a3, 0x01000001 + movi a3, BASE + 0x01000001 assert eq, a1, a3 assert eq, a2, a3 movi a3, 0x00200004 @@ -48,17 +60,17 @@ test tlb_group movi a3, 0x04000002 assert eq, a1, a3 assert eq, a2, a3 - movi a3, 0x01234567 + movi a3, BASE + 0x01234567 pdtlb a1, a3 pitlb a2, a3 - movi a3, 0x01234014 + movi a3, BASE + 0x01234014 assert eq, a1, a3 - movi a3, 0x0123400c + movi a3, BASE + 0x0123400c assert eq, a2, a3 movi a3, 0x00200004 idtlb a3 iitlb a3 - movi a3, 0x01234567 + movi a3, BASE + 0x01234567 pdtlb a1, a3 pitlb a2, a3 movi a3, 0x00000010 @@ -72,7 +84,7 @@ test_end test itlb_miss set_vector kernel, 1f - movi a3, 0x00100000 + movi a3, BASE + 0x00100000 jx a3 test_fail 1: @@ -86,7 +98,7 @@ test_end test dtlb_miss set_vector kernel, 1f - movi a3, 0x00100000 + movi a3, BASE + 0x00100000 l8ui a2, a3, 0 test_fail 1: @@ -116,11 +128,11 @@ test dtlb_multi_hit set_vector kernel, 1f movi a2, 0x04000002 /* PPN */ - movi a3, 0x01200004 /* VPN */ + movi a3, BASE + 0x01200004 /* VPN */ wdtlb a2, a3 - movi a3, 0x01200007 /* VPN */ + movi a3, BASE + 0x01200007 /* VPN */ wdtlb a2, a3 - movi a3, 0x01200000 + movi a3, BASE + 0x01200000 pdtlb a2, a3 test_fail 1: @@ -168,15 +180,18 @@ test load_store_privilege and a3, a3, a1 movi a1, 4 or a3, a3, a1 + movi a5, BASE + add a3, a3, a5 witlb a2, a3 movi a3, 10f movi a1, 0x000fffff and a1, a3, a1 + add a1, a1, a5 movi a2, 0x04000003 /* PPN */ - movi a3, 0x01200004 /* VPN */ + movi a3, BASE + 0x01200004 /* VPN */ wdtlb a2, a3 - movi a3, 0x01200001 + movi a3, BASE + 0x01200001 movi a2, 0x4004f jx a1 10: @@ -192,6 +207,7 @@ test load_store_privilege movi a3, 1b movi a1, 0x000fffff and a3, a3, a1 + add a3, a3, a5 assert eq, a2, a3 rsr a2, exccause movi a3, 26 @@ -206,9 +222,9 @@ test cring_load_store_privilege set_vector double, 2f movi a2, 0x04000003 /* PPN */ - movi a3, 0x01200004 /* VPN */ + movi a3, BASE + 0x01200004 /* VPN */ wdtlb a2, a3 - movi a3, 0x01200004 + movi a3, BASE + 0x01200004 movi a2, 0x4005f /* ring 1 + excm => cring == 0 */ wsr a2, ps isync @@ -245,10 +261,13 @@ test inst_fetch_prohibited and a3, a3, a1 movi a1, 4 or a3, a3, a1 + movi a5, BASE + add a3, a3, a5 witlb a2, a3 movi a3, 10f movi a1, 0x000fffff and a1, a3, a1 + add a1, a1, a5 jx a1 .align 4 10: @@ -268,9 +287,9 @@ test load_prohibited set_vector kernel, 2f movi a2, 0x0400000c /* PPN */ - movi a3, 0x01200004 /* VPN */ + movi a3, BASE + 0x01200004 /* VPN */ wdtlb a2, a3 - movi a3, 0x01200002 + movi a3, BASE + 0x01200002 1: l8ui a2, a3, 0 test_fail @@ -289,9 +308,9 @@ test store_prohibited set_vector kernel, 2f movi a2, 0x04000001 /* PPN */ - movi a3, 0x01200004 /* VPN */ + movi a3, BASE + 0x01200004 /* VPN */ wdtlb a2, a3 - movi a3, 0x01200003 + movi a3, BASE + 0x01200003 l8ui a2, a3, 0 1: s8i a2, a3, 0 @@ -311,10 +330,10 @@ test_end * and DTLB way 7 to cover this PTE, ring=pt_ring, attr=pt_attr */ .macro pt_setup pt_ring, pt_attr, pte_ring, vaddr, paddr, pte_attr - movi a2, 0x80000000 + movi a2, TLB_BASE wsr a2, ptevaddr - movi a3, 0x80000007 | (((\vaddr) >> 10) & 0xfffff000) /* way 7 */ + movi a3, TLB_BASE | 7 | (((\vaddr) >> 10) & 0xfffff000) /* way 7 */ movi a4, 0x04000003 | ((\pt_ring) << 4) /* PADDR 64M */ wdtlb a4, a3 isync @@ -324,7 +343,7 @@ test_end add a2, a1, a2 s32i a3, a2, 0 - movi a3, 0x80000007 | (((\vaddr) >> 10) & 0xfffff000) /* way 7 */ + movi a3, TLB_BASE | 7 | (((\vaddr) >> 10) & 0xfffff000) /* way 7 */ movi a4, 0x04000000 | ((\pt_ring) << 4) | (\pt_attr) /* PADDR 64M */ wdtlb a4, a3 isync @@ -343,10 +362,13 @@ test_end and a3, a3, a1 movi a1, 4 or a3, a3, a1 + movi a5, BASE + add a3, a3, a5 witlb a2, a3 movi a3, 10f movi a1, 0x000fffff and a1, a3, a1 + add a1, a1, a5 movi a2, 0 wsr a2, excvaddr @@ -396,6 +418,8 @@ test_end movi a2, (\vaddr) movi a1, 0xfffff and a1, a1, a2 + movi a5, BASE + add a1, a1, a5 rsr a2, epc1 assert eq, a1, a2 .endm @@ -403,7 +427,7 @@ test_end test dtlb_autoload set_vector kernel, 0 - pt_setup 0, 3, 1, 0x1000, 0x1000, 3 + pt_setup 0, 3, 1, BASE + 0x1000, 0x1000, 3 assert_no_auto_tlb l8ui a1, a3, 0 @@ -418,8 +442,8 @@ test autoload_load_store_privilege set_vector kernel, 0 set_vector double, 2f - pt_setup 0, 3, 0, 0x2000, 0x2000, 3 - movi a3, 0x2004 + pt_setup 0, 3, 0, BASE + 0x2000, 0x2000, 3 + movi a3, BASE + 0x2004 assert_no_auto_tlb movi a2, 0x4005f /* ring 1 + excm => cring == 0 */ @@ -441,7 +465,7 @@ test_end test autoload_pte_load_prohibited set_vector kernel, 2f - pt_setup 0, 3, 0, 0x3000, 0, 0xc + pt_setup 0, 3, 0, BASE + 0x3000, 0, 0xc assert_no_auto_tlb 1: l32i a2, a3, 0 @@ -458,7 +482,7 @@ test_end test autoload_pt_load_prohibited set_vector kernel, 2f - pt_setup 0, 0xc, 0, 0x4000, 0x4000, 3 + pt_setup 0, 0xc, 0, BASE + 0x4000, 0x4000, 3 assert_no_auto_tlb 1: l32i a2, a3, 0 @@ -474,8 +498,8 @@ test_end test autoload_pt_privilege set_vector kernel, 2f - pt_setup 0, 3, 1, 0x5000, 0, 3 - go_ring 1, 0, 0x5001 + pt_setup 0, 3, 1, BASE + 0x5000, 0, 3 + go_ring 1, 0, BASE + 0x5001 l8ui a2, a3, 0 1: @@ -491,8 +515,8 @@ test_end test autoload_pte_privilege set_vector kernel, 2f - pt_setup 0, 3, 0, 0x6000, 0, 3 - go_ring 1, 0, 0x6001 + pt_setup 0, 3, 0, BASE + 0x6000, 0, 3 + go_ring 1, 0, BASE + 0x6001 1: l8ui a2, a3, 0 syscall @@ -507,9 +531,9 @@ test_end test autoload_3_level_pt set_vector kernel, 2f - pt_setup 1, 3, 1, 0x00400000, 0, 3 - pt_setup 1, 3, 1, 0x80001000, 0x2000000, 3 - go_ring 1, 0, 0x00400001 + pt_setup 1, 3, 1, BASE + 0x00400000, 0, 3 + pt_setup 1, 3, 1, TLB_BASE + ((BASE + 0x00400000) >> 10), 0x2000000, 3 + go_ring 1, 0, BASE + 0x00400001 1: l8ui a2, a3, 0 syscall @@ -526,14 +550,14 @@ test cross_page_insn set_vector kernel, 2f movi a2, 0x04000003 /* PPN */ - movi a3, 0x00007000 /* VPN */ + movi a3, BASE + 0x00007000 /* VPN */ witlb a2, a3 wdtlb a2, a3 - movi a3, 0x00008000 /* VPN */ + movi a3, BASE + 0x00008000 /* VPN */ witlb a2, a3 wdtlb a2, a3 - movi a2, 0x00007fff + movi a2, BASE + 0x00007fff movi a3, 20f movi a4, 21f sub a4, a4, a3 @@ -543,8 +567,8 @@ test cross_page_insn addi a2, a2, 1 addi a3, a3, 1 1: - movi a2, 0x00007fff - movi a3, 0x00008000 + movi a2, BASE + 0x00007fff + movi a3, BASE + 0x00008000 /* DTLB: OK, ITLB: OK */ jx a2 @@ -560,20 +584,20 @@ test cross_page_insn movi a3, 1 assert eq, a2, a3 rsr a2, epc1 - movi a3, 0x8002 + movi a3, BASE + 0x8002 assert eq, a2, a3 rsr a2, excsave1 - movi a3, 0x00007fff + movi a3, BASE + 0x00007fff assert ne, a2, a3 reset_ps set_vector kernel, 3f movi a2, 0x0400000c /* PPN */ - movi a3, 0x00008000 /* VPN */ + movi a3, BASE + 0x00008000 /* VPN */ wdtlb a2, a3 - movi a2, 0x00007fff - movi a3, 0x00008000 + movi a2, BASE + 0x00007fff + movi a3, BASE + 0x00008000 /* DTLB: FAIL, ITLB: OK */ jx a2 3: @@ -581,22 +605,22 @@ test cross_page_insn movi a3, 28 assert eq, a2, a3 rsr a2, epc1 - movi a3, 0x7fff + movi a3, BASE + 0x7fff assert eq, a2, a3 rsr a2, excsave1 - movi a3, 0x00007fff + movi a3, BASE + 0x00007fff assert eq, a2, a3 reset_ps set_vector kernel, 4f movi a2, 0x0400000c /* PPN */ - movi a3, 0x00008000 /* VPN */ + movi a3, BASE + 0x00008000 /* VPN */ witlb a2, a3 movi a2, 0x04000003 /* PPN */ wdtlb a2, a3 - movi a2, 0x00007fff - movi a3, 0x00008000 + movi a2, BASE + 0x00007fff + movi a3, BASE + 0x00008000 /* DTLB: OK, ITLB: FAIL */ jx a2 4: @@ -604,20 +628,20 @@ test cross_page_insn movi a3, 20 assert eq, a2, a3 rsr a2, epc1 - movi a3, 0x7fff + movi a3, BASE + 0x7fff assert eq, a2, a3 rsr a2, excsave1 - movi a3, 0x00007fff + movi a3, BASE + 0x00007fff assert eq, a2, a3 reset_ps set_vector kernel, 5f movi a2, 0x0400000c /* PPN */ - movi a3, 0x00008000 /* VPN */ + movi a3, BASE + 0x00008000 /* VPN */ wdtlb a2, a3 - movi a2, 0x00007fff - movi a3, 0x00008000 + movi a2, BASE + 0x00007fff + movi a3, BASE + 0x00008000 /* DTLB: FAIL, ITLB: FAIL */ jx a2 5: @@ -625,10 +649,10 @@ test cross_page_insn movi a3, 20 assert eq, a2, a3 rsr a2, epc1 - movi a3, 0x7fff + movi a3, BASE + 0x7fff assert eq, a2, a3 rsr a2, excsave1 - movi a3, 0x00007fff + movi a3, BASE + 0x00007fff assert eq, a2, a3 test_end @@ -636,14 +660,14 @@ test cross_page_tb set_vector kernel, 2f movi a2, 0x04000003 /* PPN */ - movi a3, 0x00007000 /* VPN */ + movi a3, BASE + 0x00007000 /* VPN */ witlb a2, a3 wdtlb a2, a3 - movi a3, 0x00008000 /* VPN */ + movi a3, BASE + 0x00008000 /* VPN */ witlb a2, a3 wdtlb a2, a3 - movi a2, 0x00007ffc + movi a2, BASE + 0x00007ffc movi a3, 20f movi a4, 21f sub a4, a4, a3 @@ -653,8 +677,8 @@ test cross_page_tb addi a2, a2, 1 addi a3, a3, 1 1: - movi a2, 0x00007ffc - movi a3, 0x00008000 + movi a2, BASE + 0x00007ffc + movi a3, BASE + 0x00008000 /* DTLB: OK, ITLB: OK */ jx a2 @@ -670,20 +694,20 @@ test cross_page_tb movi a3, 1 assert eq, a2, a3 rsr a2, epc1 - movi a3, 0x7fff + movi a3, BASE + 0x7fff assert eq, a2, a3 rsr a2, excsave1 - movi a3, 0x00007ffc + movi a3, BASE + 0x00007ffc assert ne, a2, a3 reset_ps set_vector kernel, 3f movi a2, 0x0400000c /* PPN */ - movi a3, 0x00008000 /* VPN */ + movi a3, BASE + 0x00008000 /* VPN */ wdtlb a2, a3 - movi a2, 0x00007ffc - movi a3, 0x00008000 + movi a2, BASE + 0x00007ffc + movi a3, BASE + 0x00008000 /* DTLB: FAIL, ITLB: OK */ jx a2 3: @@ -691,22 +715,22 @@ test cross_page_tb movi a3, 28 assert eq, a2, a3 rsr a2, epc1 - movi a3, 0x7ffc + movi a3, BASE + 0x7ffc assert eq, a2, a3 rsr a2, excsave1 - movi a3, 0x00007ffc + movi a3, BASE + 0x00007ffc assert eq, a2, a3 reset_ps set_vector kernel, 4f movi a2, 0x0400000c /* PPN */ - movi a3, 0x00008000 /* VPN */ + movi a3, BASE + 0x00008000 /* VPN */ witlb a2, a3 movi a2, 0x04000003 /* PPN */ wdtlb a2, a3 - movi a2, 0x00007ffc - movi a3, 0x00008000 + movi a2, BASE + 0x00007ffc + movi a3, BASE + 0x00008000 /* DTLB: OK, ITLB: FAIL */ jx a2 4: @@ -714,20 +738,20 @@ test cross_page_tb movi a3, 20 assert eq, a2, a3 rsr a2, epc1 - movi a3, 0x7fff + movi a3, BASE + 0x7fff assert eq, a2, a3 rsr a2, excsave1 - movi a3, 0x00007ffc + movi a3, BASE + 0x00007ffc assert ne, a2, a3 reset_ps set_vector kernel, 5f movi a2, 0x0400000c /* PPN */ - movi a3, 0x00008000 /* VPN */ + movi a3, BASE + 0x00008000 /* VPN */ wdtlb a2, a3 - movi a2, 0x00007ffc - movi a3, 0x00008000 + movi a2, BASE + 0x00007ffc + movi a3, BASE + 0x00008000 /* DTLB: FAIL, ITLB: FAIL */ jx a2 5: @@ -735,10 +759,10 @@ test cross_page_tb movi a3, 28 assert eq, a2, a3 rsr a2, epc1 - movi a3, 0x7ffc + movi a3, BASE + 0x7ffc assert eq, a2, a3 rsr a2, excsave1 - movi a3, 0x00007ffc + movi a3, BASE + 0x00007ffc assert eq, a2, a3 test_end From 4be4c5b826989bed67a16f6e5b931d8374589c08 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Wed, 27 Apr 2022 10:06:00 -0700 Subject: [PATCH 095/935] tests/tcg/xtensa: fix vectors and checks in timer test Timer test assumes that timer 0 IRQ has level 1 and other timers have higher level IRQs. This assumption is not correct and the levels may be arbitrary. Fix that assumption by providing TIMER*_VECTOR macro and using it for vector selection and by making the check for the timer exception cause conditional. Signed-off-by: Max Filippov --- tests/tcg/xtensa/test_timer.S | 48 ++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/tests/tcg/xtensa/test_timer.S b/tests/tcg/xtensa/test_timer.S index 2a383e7719..2a06eebad8 100644 --- a/tests/tcg/xtensa/test_timer.S +++ b/tests/tcg/xtensa/test_timer.S @@ -38,6 +38,28 @@ test_end #if XCHAL_NUM_TIMERS +#if INTERRUPT_LEVEL(XCHAL_TIMER0_INTERRUPT) == 1 +#define TIMER0_VECTOR kernel +#else +#define TIMER0_VECTOR glue(level, INTERRUPT_LEVEL(XCHAL_TIMER0_INTERRUPT)) +#endif + +#if XCHAL_NUM_TIMERS > 1 +#if INTERRUPT_LEVEL(XCHAL_TIMER1_INTERRUPT) == 1 +#define TIMER1_VECTOR kernel +#else +#define TIMER1_VECTOR glue(level, INTERRUPT_LEVEL(XCHAL_TIMER1_INTERRUPT)) +#endif +#endif + +#if XCHAL_NUM_TIMERS > 2 +#if INTERRUPT_LEVEL(XCHAL_TIMER2_INTERRUPT) == 1 +#define TIMER2_VECTOR kernel +#else +#define TIMER2_VECTOR glue(level, INTERRUPT_LEVEL(XCHAL_TIMER2_INTERRUPT)) +#endif +#endif + test ccount_update_deadline movi a2, 0 wsr a2, intenable @@ -90,9 +112,8 @@ test ccompare assert nei, a5, 0 test_end -#if INTERRUPT_LEVEL(XCHAL_TIMER0_INTERRUPT) == 1 test ccompare0_interrupt - set_vector kernel, 2f + set_vector TIMER0_VECTOR, 2f movi a2, 0 wsr a2, intenable rsr a2, interrupt @@ -120,15 +141,16 @@ test ccompare0_interrupt bnez a3, 1b test_fail 2: +#if INTERRUPT_LEVEL(XCHAL_TIMER0_INTERRUPT) == 1 rsr a2, exccause assert eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */ -test_end #endif +test_end #if XCHAL_NUM_TIMERS > 1 test ccompare1_interrupt - set_vector glue(level, INTERRUPT_LEVEL(XCHAL_TIMER1_INTERRUPT)), 2f + set_vector TIMER1_VECTOR, 2f movi a2, 0 wsr a2, intenable rsr a2, interrupt @@ -153,13 +175,17 @@ test ccompare1_interrupt bnez a3, 1b test_fail 2: +#if INTERRUPT_LEVEL(XCHAL_TIMER1_INTERRUPT) == 1 + rsr a2, exccause + assert eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */ +#endif test_end #endif #if XCHAL_NUM_TIMERS > 2 test ccompare2_interrupt - set_vector glue(level, INTERRUPT_LEVEL(XCHAL_TIMER2_INTERRUPT)), 2f + set_vector TIMER2_VECTOR, 2f movi a2, 0 wsr a2, intenable rsr a2, interrupt @@ -182,12 +208,16 @@ test ccompare2_interrupt bnez a3, 1b test_fail 2: +#if INTERRUPT_LEVEL(XCHAL_TIMER2_INTERRUPT) == 1 + rsr a2, exccause + assert eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */ +#endif test_end #endif test ccompare_interrupt_masked - set_vector kernel, 2f + set_vector TIMER0_VECTOR, 2f movi a2, 0 wsr a2, intenable rsr a2, interrupt @@ -217,12 +247,14 @@ test ccompare_interrupt_masked test_fail 2: +#if INTERRUPT_LEVEL(XCHAL_TIMER0_INTERRUPT) == 1 rsr a2, exccause assert eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */ +#endif test_end test ccompare_interrupt_masked_waiti - set_vector kernel, 2f + set_vector TIMER0_VECTOR, 2f movi a2, 0 wsr a2, intenable rsr a2, interrupt @@ -247,8 +279,10 @@ test ccompare_interrupt_masked_waiti waiti 0 test_fail 2: +#if INTERRUPT_LEVEL(XCHAL_TIMER0_INTERRUPT) == 1 rsr a2, exccause assert eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */ +#endif test_end #endif From 59491e97f89eaeee275f57fb6bb40f0152429fb3 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Sun, 1 May 2022 22:57:49 -0700 Subject: [PATCH 096/935] target/xtensa: implement cache test option opcodes We don't model caches, so for l*ct opcodes return tags with all bits (including Valid) set to 0. For all other opcodes don't do anything. Signed-off-by: Max Filippov --- target/xtensa/translate.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index b0576d90fa..70e11eeb45 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -1766,6 +1766,12 @@ static void translate_ldst(DisasContext *dc, const OpcodeArg arg[], tcg_temp_free(addr); } +static void translate_lct(DisasContext *dc, const OpcodeArg arg[], + const uint32_t par[]) +{ + tcg_gen_movi_i32(arg[0].out, 0); +} + static void translate_l32r(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { @@ -3319,6 +3325,14 @@ static const XtensaOpcodeOps core_ops[] = { .translate = translate_ldst, .par = (const uint32_t[]){MO_UB, false, false}, .op_flags = XTENSA_OP_LOAD, + }, { + .name = "ldct", + .translate = translate_lct, + .op_flags = XTENSA_OP_PRIVILEGED, + }, { + .name = "ldcw", + .translate = translate_nop, + .op_flags = XTENSA_OP_PRIVILEGED, }, { .name = "lddec", .translate = translate_mac16, @@ -3332,6 +3346,14 @@ static const XtensaOpcodeOps core_ops[] = { }, { .name = "ldpte", .op_flags = XTENSA_OP_ILL, + }, { + .name = "lict", + .translate = translate_lct, + .op_flags = XTENSA_OP_PRIVILEGED, + }, { + .name = "licw", + .translate = translate_nop, + .op_flags = XTENSA_OP_PRIVILEGED, }, { .name = (const char * const[]) { "loop", "loop.w15", NULL, @@ -4635,12 +4657,28 @@ static const XtensaOpcodeOps core_ops[] = { .name = "saltu", .translate = translate_salt, .par = (const uint32_t[]){TCG_COND_LTU}, + }, { + .name = "sdct", + .translate = translate_nop, + .op_flags = XTENSA_OP_PRIVILEGED, + }, { + .name = "sdcw", + .translate = translate_nop, + .op_flags = XTENSA_OP_PRIVILEGED, }, { .name = "setb_expstate", .translate = translate_setb_expstate, }, { .name = "sext", .translate = translate_sext, + }, { + .name = "sict", + .translate = translate_nop, + .op_flags = XTENSA_OP_PRIVILEGED, + }, { + .name = "sicw", + .translate = translate_nop, + .op_flags = XTENSA_OP_PRIVILEGED, }, { .name = "simcall", .translate = translate_simcall, From b6b3da999844b710d8d8b97a93c8420e6d46cd44 Mon Sep 17 00:00:00 2001 From: Sunil Muthuswamy Date: Thu, 7 Nov 2019 19:48:32 +0000 Subject: [PATCH 097/935] WHPX: support for xcr0 Support for xcr0 to be able to enable xsave/xrstor. This by itself is not sufficient to enable xsave/xrstor. WHPX XSAVE API's also needs to be hooked up. Signed-off-by: Sunil Muthuswamy Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/whpx/whpx-all.c | 87 ++++++++++++++++++++++++++++++++ target/i386/whpx/whpx-internal.h | 3 ++ 2 files changed, 90 insertions(+) diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index b625ad5bbb..23ae639b23 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -246,9 +246,15 @@ static bool whpx_allowed; static bool whp_dispatch_initialized; static HMODULE hWinHvPlatform, hWinHvEmulation; static uint32_t max_vcpu_index; +static WHV_PROCESSOR_XSAVE_FEATURES whpx_xsave_cap; + struct whpx_state whpx_global; struct WHPDispatch whp_dispatch; +static bool whpx_has_xsave(void) +{ + return whpx_xsave_cap.XsaveSupport; +} /* * VP support @@ -300,6 +306,28 @@ static SegmentCache whpx_seg_h2q(const WHV_X64_SEGMENT_REGISTER *hs) return qs; } +/* X64 Extended Control Registers */ +static void whpx_set_xcrs(CPUState *cpu) +{ + CPUX86State *env = cpu->env_ptr; + HRESULT hr; + struct whpx_state *whpx = &whpx_global; + WHV_REGISTER_VALUE xcr0; + WHV_REGISTER_NAME xcr0_name = WHvX64RegisterXCr0; + + if (!whpx_has_xsave()) { + return; + } + + /* Only xcr0 is supported by the hypervisor currently */ + xcr0.Reg64 = env->xcr0; + hr = whp_dispatch.WHvSetVirtualProcessorRegisters( + whpx->partition, cpu->cpu_index, &xcr0_name, 1, &xcr0); + if (FAILED(hr)) { + error_report("WHPX: Failed to set register xcr0, hr=%08lx", hr); + } +} + static int whpx_set_tsc(CPUState *cpu) { CPUX86State *env = cpu->env_ptr; @@ -435,6 +463,12 @@ static void whpx_set_registers(CPUState *cpu, int level) /* 8 Debug Registers - Skipped */ + /* + * Extended control registers needs to be handled separately depending + * on whether xsave is supported/enabled or not. + */ + whpx_set_xcrs(cpu); + /* 16 XMM registers */ assert(whpx_register_names[idx] == WHvX64RegisterXmm0); idx_next = idx + 16; @@ -541,6 +575,30 @@ static int whpx_get_tsc(CPUState *cpu) return 0; } +/* X64 Extended Control Registers */ +static void whpx_get_xcrs(CPUState *cpu) +{ + CPUX86State *env = cpu->env_ptr; + HRESULT hr; + struct whpx_state *whpx = &whpx_global; + WHV_REGISTER_VALUE xcr0; + WHV_REGISTER_NAME xcr0_name = WHvX64RegisterXCr0; + + if (!whpx_has_xsave()) { + return; + } + + /* Only xcr0 is supported by the hypervisor currently */ + hr = whp_dispatch.WHvGetVirtualProcessorRegisters( + whpx->partition, cpu->cpu_index, &xcr0_name, 1, &xcr0); + if (FAILED(hr)) { + error_report("WHPX: Failed to get register xcr0, hr=%08lx", hr); + return; + } + + env->xcr0 = xcr0.Reg64; +} + static void whpx_get_registers(CPUState *cpu) { struct whpx_state *whpx = &whpx_global; @@ -634,6 +692,12 @@ static void whpx_get_registers(CPUState *cpu) /* 8 Debug Registers - Skipped */ + /* + * Extended control registers needs to be handled separately depending + * on whether xsave is supported/enabled or not. + */ + whpx_get_xcrs(cpu); + /* 16 XMM registers */ assert(whpx_register_names[idx] == WHvX64RegisterXmm0); idx_next = idx + 16; @@ -2513,6 +2577,29 @@ static int whpx_accel_init(MachineState *ms) goto error; } + /* + * Query the XSAVE capability of the partition. Any error here is not + * considered fatal. + */ + hr = whp_dispatch.WHvGetPartitionProperty( + whpx->partition, + WHvPartitionPropertyCodeProcessorXsaveFeatures, + &whpx_xsave_cap, + sizeof(whpx_xsave_cap), + &whpx_cap_size); + + /* + * Windows version which don't support this property will return with the + * specific error code. + */ + if (FAILED(hr) && hr != WHV_E_UNKNOWN_PROPERTY) { + error_report("WHPX: Failed to query XSAVE capability, hr=%08lx", hr); + } + + if (!whpx_has_xsave()) { + printf("WHPX: Partition is not XSAVE capable\n"); + } + memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY)); prop.ProcessorCount = ms->smp.cpus; hr = whp_dispatch.WHvSetPartitionProperty( diff --git a/target/i386/whpx/whpx-internal.h b/target/i386/whpx/whpx-internal.h index 2416ec7922..dbb7e7ba82 100644 --- a/target/i386/whpx/whpx-internal.h +++ b/target/i386/whpx/whpx-internal.h @@ -48,6 +48,9 @@ void whpx_apic_get(DeviceState *s); #define WHV_E_UNKNOWN_CAPABILITY 0x80370300L +/* This should eventually come from the Windows SDK */ +#define WHV_E_UNKNOWN_PROPERTY 0x80370302 + #define LIST_WINHVPLATFORM_FUNCTIONS(X) \ X(HRESULT, WHvGetCapability, (WHV_CAPABILITY_CODE CapabilityCode, VOID* CapabilityBuffer, UINT32 CapabilityBufferSizeInBytes, UINT32* WrittenSizeInBytes)) \ X(HRESULT, WHvCreatePartition, (WHV_PARTITION_HANDLE* Partition)) \ From 158bb2249ed9b1ed0a376f30a89ecedb2f448552 Mon Sep 17 00:00:00 2001 From: Konstantin Kostiuk Date: Thu, 28 Apr 2022 21:15:25 +0300 Subject: [PATCH 098/935] configure: Add cross prefix for widl tool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mingw-w64-tool package in Fedora provides widl tool with a cross prefix, so adds it automatically for cross builds. WIDL env can be used to redefine the path to tool. The same behavior as with windres. Signed-off-by: Konstantin Kostiuk Message-Id: <20220428181525.300521-1-kkostiuk@redhat.com> Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- configure | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configure b/configure index 59c43bea05..8b775492d0 100755 --- a/configure +++ b/configure @@ -415,6 +415,7 @@ ranlib="${RANLIB-${cross_prefix}ranlib}" nm="${NM-${cross_prefix}nm}" smbd="$SMBD" strip="${STRIP-${cross_prefix}strip}" +widl="${WIDL-${cross_prefix}widl}" windres="${WINDRES-${cross_prefix}windres}" pkg_config_exe="${PKG_CONFIG-${cross_prefix}pkg-config}" query_pkg_config() { @@ -2786,6 +2787,7 @@ if test "$skip_meson" = no; then echo "sdl2-config = [$(meson_quote $sdl2_config)]" >> $cross fi echo "strip = [$(meson_quote $strip)]" >> $cross + echo "widl = [$(meson_quote $widl)]" >> $cross echo "windres = [$(meson_quote $windres)]" >> $cross if test "$cross_compile" = "yes"; then cross_arg="--cross-file config-meson.cross" @@ -2907,6 +2909,7 @@ preserve_env PYTHON preserve_env SDL2_CONFIG preserve_env SMBD preserve_env STRIP +preserve_env WIDL preserve_env WINDRES printf "exec" >>config.status From f780a3f4808fa5ba9b822d299ae40a12d23eae6c Mon Sep 17 00:00:00 2001 From: Konstantin Kostiuk Date: Thu, 28 Apr 2022 21:15:41 +0300 Subject: [PATCH 099/935] qga-vss: always build qga-vss.tlb when qga-vss.dll is built MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Konstantin Kostiuk Message-Id: <20220428181541.300619-1-kkostiuk@redhat.com> Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- qga/vss-win32/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qga/vss-win32/meson.build b/qga/vss-win32/meson.build index 71c50d0866..26c5dd6e0e 100644 --- a/qga/vss-win32/meson.build +++ b/qga/vss-win32/meson.build @@ -23,8 +23,6 @@ qga_vss = shared_module( ] ) -all_qga += qga_vss - if midl.found() gen_tlb = custom_target('gen-tlb', input: 'qga-vss.idl', @@ -36,3 +34,5 @@ else output: 'qga-vss.tlb', command: [widl, '-t', '@INPUT@', '-o', '@OUTPUT@']) endif + +all_qga += [ qga_vss, gen_tlb ] From 119fc611eac96d5ad5c407860b29c0fd5d072f6d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:33:48 +0200 Subject: [PATCH 100/935] meson-buildoptions: add support for string options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow using the buildoptions.json file for more options, namely anything that is not a boolean or multiple-choice. The mapping between configure and meson is messy for string options, so allow configure to use to something other than the name in meson_options.txt. This will come in handy anyway for builtin Meson options such as b_lto or b_coverage. Tested-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- meson_options.txt | 2 +- scripts/meson-buildoptions.py | 65 ++++++++++++++++++++++++++++++----- scripts/meson-buildoptions.sh | 6 ++-- 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/meson_options.txt b/meson_options.txt index af432a4ee6..390701517c 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -11,7 +11,7 @@ option('qemu_firmwarepath', type : 'string', value : '', option('smbd', type : 'string', value : '', description: 'Path to smbd for slirp networking') option('sphinx_build', type : 'string', value : '', - description: 'Use specified sphinx-build [$sphinx_build] for building document (default to be empty)') + description: 'Use specified sphinx-build for building document') option('iasl', type : 'string', value : '', description: 'Path to ACPI disassembler') option('default_devices', type : 'boolean', value : true, diff --git a/scripts/meson-buildoptions.py b/scripts/meson-buildoptions.py index 693be7b966..4af8d6e732 100755 --- a/scripts/meson-buildoptions.py +++ b/scripts/meson-buildoptions.py @@ -38,6 +38,11 @@ SKIP_OPTIONS = { "trace_file", } +OPTION_NAMES = { + "malloc": "enable-malloc", + "trace_backends": "enable-trace-backends", +} + BUILTIN_OPTIONS = { "strip", } @@ -75,7 +80,7 @@ def help_line(left, opt, indent, long): right = f'{opt["description"]}' if long: value = value_to_help(opt["value"]) - if value != "auto": + if value != "auto" and value != "": right += f" [{value}]" if "choices" in opt and long: choices = "/".join(sorted(opt["choices"])) @@ -96,6 +101,18 @@ def allow_arg(opt): return not (set(opt["choices"]) <= {"auto", "disabled", "enabled"}) +# Return whether the option (a dictionary) can be used without +# arguments. Booleans can only be used without arguments; +# combos require an argument if they accept neither "enabled" +# nor "disabled" +def require_arg(opt): + if opt["type"] == "boolean": + return False + if opt["type"] != "combo": + return True + return not ({"enabled", "disabled"}.intersection(opt["choices"])) + + def filter_options(json): if ":" in json["name"]: return False @@ -110,20 +127,48 @@ def load_options(json): return sorted(json, key=lambda x: x["name"]) +def cli_option(opt): + name = opt["name"] + if name in OPTION_NAMES: + return OPTION_NAMES[name] + return name.replace("_", "-") + + +def cli_help_key(opt): + key = cli_option(opt) + if require_arg(opt): + return key + if opt["type"] == "boolean" and opt["value"]: + return f"disable-{key}" + return f"enable-{key}" + + +def cli_metavar(opt): + if opt["type"] == "string": + return "VALUE" + if opt["type"] == "array": + return "CHOICES" + return "CHOICE" + + def print_help(options): print("meson_options_help() {") - for opt in options: - key = opt["name"].replace("_", "-") + for opt in sorted(options, key=cli_help_key): + key = cli_help_key(opt) # The first section includes options that have an arguments, # and booleans (i.e., only one of enable/disable makes sense) - if opt["type"] == "boolean": - left = f"--disable-{key}" if opt["value"] else f"--enable-{key}" + if require_arg(opt): + metavar = cli_metavar(opt) + left = f"--{key}={metavar}" + help_line(left, opt, 27, True) + elif opt["type"] == "boolean": + left = f"--{key}" help_line(left, opt, 27, False) elif allow_arg(opt): if opt["type"] == "combo" and "enabled" in opt["choices"]: - left = f"--enable-{key}[=CHOICE]" + left = f"--{key}[=CHOICE]" else: - left = f"--enable-{key}=CHOICE" + left = f"--{key}=CHOICE" help_line(left, opt, 27, True) sh_print() @@ -142,9 +187,11 @@ def print_parse(options): print("_meson_option_parse() {") print(" case $1 in") for opt in options: - key = opt["name"].replace("_", "-") + key = cli_option(opt) name = opt["name"] - if opt["type"] == "boolean": + if require_arg(opt): + print(f' --{key}=*) quote_sh "-D{name}=$2" ;;') + elif opt["type"] == "boolean": print(f' --enable-{key}) printf "%s" -D{name}=true ;;') print(f' --disable-{key}) printf "%s" -D{name}=false ;;') else: diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 21366b2102..2123317654 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -1,5 +1,7 @@ # This file is generated by meson-buildoptions.py, do not edit! meson_options_help() { + printf "%s\n" ' --disable-coroutine-pool coroutine freelist (better performance)' + printf "%s\n" ' --disable-install-blobs install provided firmware blobs' printf "%s\n" ' --enable-block-drv-whitelist-in-tools' printf "%s\n" ' use block whitelist also in tools instead of only' printf "%s\n" ' QEMU' @@ -8,7 +10,6 @@ meson_options_help() { printf "%s\n" ' (choices: auto/disabled/enabled/internal/system)' printf "%s\n" ' --enable-cfi Control-Flow Integrity (CFI)' printf "%s\n" ' --enable-cfi-debug Verbose errors in case of CFI violation' - printf "%s\n" ' --disable-coroutine-pool coroutine freelist (better performance)' printf "%s\n" ' --enable-debug-mutex mutex debugging support' printf "%s\n" ' --enable-debug-stack-usage' printf "%s\n" ' measure coroutine stack usage' @@ -16,7 +17,6 @@ meson_options_help() { printf "%s\n" ' (choices: auto/disabled/enabled/internal/system)' printf "%s\n" ' --enable-fuzzing build fuzzing targets' printf "%s\n" ' --enable-gprof QEMU profiling with gprof' - printf "%s\n" ' --disable-install-blobs install provided firmware blobs' printf "%s\n" ' --enable-malloc=CHOICE choose memory allocator to use [system] (choices:' printf "%s\n" ' jemalloc/system/tcmalloc)' printf "%s\n" ' --enable-module-upgrades try to load modules from alternate paths for' @@ -29,7 +29,7 @@ meson_options_help() { printf "%s\n" ' (choices: auto/disabled/enabled/internal/system)' printf "%s\n" ' --enable-strip Strip targets on install' printf "%s\n" ' --enable-tcg-interpreter TCG with bytecode interpreter (slow)' - printf "%s\n" ' --enable-trace-backends=CHOICE' + printf "%s\n" ' --enable-trace-backends=CHOICES' printf "%s\n" ' Set available tracing backends [log] (choices:' printf "%s\n" ' dtrace/ftrace/log/nop/simple/syslog/ust)' printf "%s\n" '' From 14efd8d3b5fee7027f0ee072aea6620e0655774f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:33:47 +0200 Subject: [PATCH 101/935] meson, configure: move Xen detection to meson This is quite a complicated check. I moved all the test programs to a single file in scripts/, picking the right program with #if and a -D flag in meson.build's cc.links() invocation. Signed-off-by: Paolo Bonzini --- configure | 322 +------------------------------------------ meson.build | 112 ++++++++++++--- scripts/xen-detect.c | 203 +++++++++++++++++++++++++++ 3 files changed, 296 insertions(+), 341 deletions(-) create mode 100644 scripts/xen-detect.c diff --git a/configure b/configure index 8b775492d0..519982800e 100755 --- a/configure +++ b/configure @@ -292,7 +292,6 @@ EXTRA_CXXFLAGS="" EXTRA_OBJCFLAGS="" EXTRA_LDFLAGS="" -xen_ctrl_version="$default_feature" vhost_kernel="$default_feature" vhost_net="$default_feature" vhost_crypto="$default_feature" @@ -346,9 +345,6 @@ default_devices="true" tcg="enabled" cfi="false" -# 4. Detection partly done in configure -xen=${default_feature:+disabled} - # parse CC options second for opt do optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)') @@ -867,10 +863,6 @@ for opt do ;; --enable-slirp=*) slirp="$optarg" ;; - --disable-xen) xen="disabled" - ;; - --enable-xen) xen="enabled" - ;; --disable-tcg) tcg="disabled" plugins="no" ;; @@ -1698,312 +1690,6 @@ if ! has "$pkg_config_exe"; then error_exit "pkg-config binary '$pkg_config_exe' not found" fi -########################################## -# xen probe - -if test "$xen" != "disabled" ; then - # Check whether Xen library path is specified via --extra-ldflags to avoid - # overriding this setting with pkg-config output. If not, try pkg-config - # to obtain all needed flags. - - if ! echo $EXTRA_LDFLAGS | grep tools/libxc > /dev/null && \ - $pkg_config --exists xencontrol ; then - xen_ctrl_version="$(printf '%d%02d%02d' \ - $($pkg_config --modversion xencontrol | sed 's/\./ /g') )" - xen=enabled - xen_pc="xencontrol xenstore xenforeignmemory xengnttab" - xen_pc="$xen_pc xenevtchn xendevicemodel" - if $pkg_config --exists xentoolcore; then - xen_pc="$xen_pc xentoolcore" - fi - xen_cflags="$($pkg_config --cflags $xen_pc)" - xen_libs="$($pkg_config --libs $xen_pc)" - else - - xen_libs="-lxenstore -lxenctrl" - xen_stable_libs="-lxenforeignmemory -lxengnttab -lxenevtchn" - - # First we test whether Xen headers and libraries are available. - # If no, we are done and there is no Xen support. - # If yes, more tests are run to detect the Xen version. - - # Xen (any) - cat > $TMPC < -int main(void) { - return 0; -} -EOF - if ! compile_prog "" "$xen_libs" ; then - # Xen not found - if test "$xen" = "enabled" ; then - feature_not_found "xen" "Install xen devel" - fi - xen=disabled - - # Xen unstable - elif - cat > $TMPC < -#include -int main(void) { - xendevicemodel_handle *xd; - xenforeignmemory_handle *xfmem; - - xd = xendevicemodel_open(0, 0); - xendevicemodel_pin_memory_cacheattr(xd, 0, 0, 0, 0); - - xfmem = xenforeignmemory_open(0, 0); - xenforeignmemory_map_resource(xfmem, 0, 0, 0, 0, 0, NULL, 0, 0); - - return 0; -} -EOF - compile_prog "" "$xen_libs -lxendevicemodel $xen_stable_libs -lxentoolcore" - then - xen_stable_libs="-lxendevicemodel $xen_stable_libs -lxentoolcore" - xen_ctrl_version=41100 - xen=enabled - elif - cat > $TMPC < -#include -int main(void) { - xenforeignmemory_handle *xfmem; - - xfmem = xenforeignmemory_open(0, 0); - xenforeignmemory_map2(xfmem, 0, 0, 0, 0, 0, 0, 0); - xentoolcore_restrict_all(0); - - return 0; -} -EOF - compile_prog "" "$xen_libs -lxendevicemodel $xen_stable_libs -lxentoolcore" - then - xen_stable_libs="-lxendevicemodel $xen_stable_libs -lxentoolcore" - xen_ctrl_version=41000 - xen=enabled - elif - cat > $TMPC < -int main(void) { - xendevicemodel_handle *xd; - - xd = xendevicemodel_open(0, 0); - xendevicemodel_close(xd); - - return 0; -} -EOF - compile_prog "" "$xen_libs -lxendevicemodel $xen_stable_libs" - then - xen_stable_libs="-lxendevicemodel $xen_stable_libs" - xen_ctrl_version=40900 - xen=enabled - elif - cat > $TMPC < -#include -#include -#include -#include -#include -#include -#if !defined(HVM_MAX_VCPUS) -# error HVM_MAX_VCPUS not defined -#endif -int main(void) { - xc_interface *xc = NULL; - xenforeignmemory_handle *xfmem; - xenevtchn_handle *xe; - xengnttab_handle *xg; - xengnttab_grant_copy_segment_t* seg = NULL; - - xs_daemon_open(); - - xc = xc_interface_open(0, 0, 0); - xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); - xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); - xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); - xc_hvm_create_ioreq_server(xc, 0, HVM_IOREQSRV_BUFIOREQ_ATOMIC, NULL); - - xfmem = xenforeignmemory_open(0, 0); - xenforeignmemory_map(xfmem, 0, 0, 0, 0, 0); - - xe = xenevtchn_open(0, 0); - xenevtchn_fd(xe); - - xg = xengnttab_open(0, 0); - xengnttab_grant_copy(xg, 0, seg); - - return 0; -} -EOF - compile_prog "" "$xen_libs $xen_stable_libs" - then - xen_ctrl_version=40800 - xen=enabled - elif - cat > $TMPC < -#include -#include -#include -#include -#include -#include -#if !defined(HVM_MAX_VCPUS) -# error HVM_MAX_VCPUS not defined -#endif -int main(void) { - xc_interface *xc = NULL; - xenforeignmemory_handle *xfmem; - xenevtchn_handle *xe; - xengnttab_handle *xg; - - xs_daemon_open(); - - xc = xc_interface_open(0, 0, 0); - xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); - xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); - xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); - xc_hvm_create_ioreq_server(xc, 0, HVM_IOREQSRV_BUFIOREQ_ATOMIC, NULL); - - xfmem = xenforeignmemory_open(0, 0); - xenforeignmemory_map(xfmem, 0, 0, 0, 0, 0); - - xe = xenevtchn_open(0, 0); - xenevtchn_fd(xe); - - xg = xengnttab_open(0, 0); - xengnttab_map_grant_ref(xg, 0, 0, 0); - - return 0; -} -EOF - compile_prog "" "$xen_libs $xen_stable_libs" - then - xen_ctrl_version=40701 - xen=enabled - - # Xen 4.6 - elif - cat > $TMPC < -#include -#include -#include -#if !defined(HVM_MAX_VCPUS) -# error HVM_MAX_VCPUS not defined -#endif -int main(void) { - xc_interface *xc; - xs_daemon_open(); - xc = xc_interface_open(0, 0, 0); - xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); - xc_gnttab_open(NULL, 0); - xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); - xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); - xc_hvm_create_ioreq_server(xc, 0, HVM_IOREQSRV_BUFIOREQ_ATOMIC, NULL); - xc_reserved_device_memory_map(xc, 0, 0, 0, 0, NULL, 0); - return 0; -} -EOF - compile_prog "" "$xen_libs" - then - xen_ctrl_version=40600 - xen=enabled - - # Xen 4.5 - elif - cat > $TMPC < -#include -#include -#include -#if !defined(HVM_MAX_VCPUS) -# error HVM_MAX_VCPUS not defined -#endif -int main(void) { - xc_interface *xc; - xs_daemon_open(); - xc = xc_interface_open(0, 0, 0); - xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); - xc_gnttab_open(NULL, 0); - xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); - xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); - xc_hvm_create_ioreq_server(xc, 0, 0, NULL); - return 0; -} -EOF - compile_prog "" "$xen_libs" - then - xen_ctrl_version=40500 - xen=enabled - - elif - cat > $TMPC < -#include -#include -#include -#if !defined(HVM_MAX_VCPUS) -# error HVM_MAX_VCPUS not defined -#endif -int main(void) { - xc_interface *xc; - xs_daemon_open(); - xc = xc_interface_open(0, 0, 0); - xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); - xc_gnttab_open(NULL, 0); - xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); - xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); - return 0; -} -EOF - compile_prog "" "$xen_libs" - then - xen_ctrl_version=40200 - xen=enabled - - else - if test "$xen" = "enabled" ; then - feature_not_found "xen (unsupported version)" \ - "Install a supported xen (xen 4.2 or newer)" - fi - xen=disabled - fi - - if test "$xen" = enabled; then - if test $xen_ctrl_version -ge 40701 ; then - xen_libs="$xen_libs $xen_stable_libs " - fi - fi - fi -fi - ########################################## # glib support probe @@ -2555,12 +2241,6 @@ if test "$modules" = "yes"; then fi echo "CONFIG_TLS_PRIORITY=\"$tls_priority\"" >> $config_host_mak -if test "$xen" = "enabled" ; then - echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak - echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak - echo "XEN_CFLAGS=$xen_cflags" >> $config_host_mak - echo "XEN_LIBS=$xen_libs" >> $config_host_mak -fi if test "$vhost_scsi" = "yes" ; then echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak fi @@ -2839,7 +2519,7 @@ if test "$skip_meson" = no; then -Dwerror=$(if test "$werror" = yes; then echo true; else echo false; fi) \ -Db_pie=$(if test "$pie" = yes; then echo true; else echo false; fi) \ -Db_coverage=$(if test "$gcov" = yes; then echo true; else echo false; fi) \ - -Db_lto=$lto -Dcfi=$cfi -Dtcg=$tcg -Dxen=$xen \ + -Db_lto=$lto -Dcfi=$cfi -Dtcg=$tcg \ -Dcapstone=$capstone -Dfdt=$fdt -Dslirp=$slirp \ $(test -n "${LIB_FUZZING_ENGINE+xxx}" && echo "-Dfuzzing_engine=$LIB_FUZZING_ENGINE") \ $(if test "$default_feature" = no; then echo "-Dauto_features=disabled"; fi) \ diff --git a/meson.build b/meson.build index c26aa442d4..2d54513b9f 100644 --- a/meson.build +++ b/meson.build @@ -348,12 +348,6 @@ accelerators = [] if get_option('kvm').allowed() and targetos == 'linux' accelerators += 'CONFIG_KVM' endif -if get_option('xen').allowed() and 'CONFIG_XEN_BACKEND' in config_host - accelerators += 'CONFIG_XEN' - have_xen_pci_passthrough = get_option('xen_pci_passthrough').allowed() and targetos == 'linux' -else - have_xen_pci_passthrough = false -endif if get_option('whpx').allowed() and targetos == 'windows' if get_option('whpx').enabled() and host_machine.cpu() != 'x86_64' error('WHPX requires 64-bit host') @@ -425,13 +419,6 @@ endif if 'CONFIG_WHPX' not in accelerators and get_option('whpx').enabled() error('WHPX not available on this platform') endif -if not have_xen_pci_passthrough and get_option('xen_pci_passthrough').enabled() - if 'CONFIG_XEN' in accelerators - error('Xen PCI passthrough not available on this platform') - else - error('Xen PCI passthrough requested but Xen not enabled') - endif -endif ################ # Dependencies # @@ -1257,10 +1244,86 @@ if not get_option('rdma').auto() or have_system endif xen = not_found -if 'CONFIG_XEN_BACKEND' in config_host - xen = declare_dependency(compile_args: config_host['XEN_CFLAGS'].split(), - link_args: config_host['XEN_LIBS'].split()) +if get_option('xen').enabled() or (get_option('xen').auto() and have_system) + xencontrol = dependency('xencontrol', required: false, + method: 'pkg-config', kwargs: static_kwargs) + if xencontrol.found() + xen_pc = declare_dependency(version: xencontrol.version(), + dependencies: [ + xencontrol, + # disabler: true makes xen_pc.found() return false if any is not found + dependency('xenstore', required: false, + method: 'pkg-config', kwargs: static_kwargs, + disabler: true), + dependency('xenforeignmemory', required: false, + method: 'pkg-config', kwargs: static_kwargs, + disabler: true), + dependency('xengnttab', required: false, + method: 'pkg-config', kwargs: static_kwargs, + disabler: true), + dependency('xenevtchn', required: false, + method: 'pkg-config', kwargs: static_kwargs, + disabler: true), + dependency('xendevicemodel', required: false, + method: 'pkg-config', kwargs: static_kwargs, + disabler: true), + # optional, no "disabler: true" + dependency('xentoolcore', required: false, + method: 'pkg-config', kwargs: static_kwargs)]) + if xen_pc.found() + xen = xen_pc + endif + endif + if not xen.found() + xen_tests = [ '4.11.0', '4.10.0', '4.9.0', '4.8.0', '4.7.1', '4.6.0', '4.5.0', '4.2.0' ] + xen_libs = { + '4.11.0': [ 'xenstore', 'xenctrl', 'xendevicemodel', 'xenforeignmemory', 'xengnttab', 'xenevtchn', 'xentoolcore' ], + '4.10.0': [ 'xenstore', 'xenctrl', 'xendevicemodel', 'xenforeignmemory', 'xengnttab', 'xenevtchn', 'xentoolcore' ], + '4.9.0': [ 'xenstore', 'xenctrl', 'xendevicemodel', 'xenforeignmemory', 'xengnttab', 'xenevtchn' ], + '4.8.0': [ 'xenstore', 'xenctrl', 'xenforeignmemory', 'xengnttab', 'xenevtchn' ], + '4.7.1': [ 'xenstore', 'xenctrl', 'xenforeignmemory', 'xengnttab', 'xenevtchn' ], + '4.6.0': [ 'xenstore', 'xenctrl' ], + '4.5.0': [ 'xenstore', 'xenctrl' ], + '4.2.0': [ 'xenstore', 'xenctrl' ], + } + xen_deps = {} + foreach ver: xen_tests + # cache the various library tests to avoid polluting the logs + xen_test_deps = [] + foreach l: xen_libs[ver] + if l not in xen_deps + xen_deps += { l: cc.find_library(l, required: false) } + endif + xen_test_deps += xen_deps[l] + endforeach + + # Use -D to pick just one of the test programs in scripts/xen-detect.c + xen_version = ver.split('.') + xen_ctrl_version = xen_version[0] + \ + ('0' + xen_version[1]).substring(-2) + \ + ('0' + xen_version[2]).substring(-2) + if cc.links(files('scripts/xen-detect.c'), + args: '-DCONFIG_XEN_CTRL_INTERFACE_VERSION=' + xen_ctrl_version, + dependencies: xen_test_deps) + xen = declare_dependency(version: ver, dependencies: xen_test_deps) + break + endif + endforeach + endif + if xen.found() + accelerators += 'CONFIG_XEN' + elif get_option('xen').enabled() + error('could not compile and link Xen test program') + endif endif +have_xen_pci_passthrough = get_option('xen_pci_passthrough') \ + .require(xen.found(), + error_message: 'Xen PCI passthrough requested but Xen not enabled') \ + .require(targetos == 'linux', + error_message: 'Xen PCI passthrough not available on this platform') \ + .allowed() + + cacard = not_found if not get_option('smartcard').auto() or have_system cacard = dependency('libcacard', required: get_option('smartcard'), @@ -1634,6 +1697,15 @@ config_host_data.set('CONFIG_X11', x11.found()) config_host_data.set('CONFIG_DBUS_DISPLAY', dbus_display) config_host_data.set('CONFIG_CFI', get_option('cfi')) config_host_data.set('CONFIG_SELINUX', selinux.found()) +config_host_data.set('CONFIG_XEN_BACKEND', xen.found()) +if xen.found() + # protect from xen.version() having less than three components + xen_version = xen.version().split('.') + ['0', '0'] + xen_ctrl_version = xen_version[0] + \ + ('0' + xen_version[1]).substring(-2) + \ + ('0' + xen_version[2]).substring(-2) + config_host_data.set('CONFIG_XEN_CTRL_INTERFACE_VERSION', xen_ctrl_version) +endif config_host_data.set('QEMU_VERSION', '"@0@"'.format(meson.project_version())) config_host_data.set('QEMU_VERSION_MAJOR', meson.project_version().split('.')[0]) config_host_data.set('QEMU_VERSION_MINOR', meson.project_version().split('.')[1]) @@ -2359,7 +2431,7 @@ config_all += config_all_devices config_all += config_host config_all += config_all_disas config_all += { - 'CONFIG_XEN': config_host.has_key('CONFIG_XEN_BACKEND'), + 'CONFIG_XEN': xen.found(), 'CONFIG_SOFTMMU': have_system, 'CONFIG_USER_ONLY': have_user, 'CONFIG_ALL': true, @@ -3690,9 +3762,9 @@ if have_system summary_info += {'HVF support': config_all.has_key('CONFIG_HVF')} summary_info += {'WHPX support': config_all.has_key('CONFIG_WHPX')} summary_info += {'NVMM support': config_all.has_key('CONFIG_NVMM')} - summary_info += {'Xen support': config_host.has_key('CONFIG_XEN_BACKEND')} - if config_host.has_key('CONFIG_XEN_BACKEND') - summary_info += {'xen ctrl version': config_host['CONFIG_XEN_CTRL_INTERFACE_VERSION']} + summary_info += {'Xen support': xen.found()} + if xen.found() + summary_info += {'xen ctrl version': xen.version()} endif endif summary_info += {'TCG support': config_all.has_key('CONFIG_TCG')} diff --git a/scripts/xen-detect.c b/scripts/xen-detect.c new file mode 100644 index 0000000000..85e8206490 --- /dev/null +++ b/scripts/xen-detect.c @@ -0,0 +1,203 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* Test programs for various Xen versions that QEMU supports. */ +#if CONFIG_XEN_CTRL_INTERFACE_VERSION == 41100 + #undef XC_WANT_COMPAT_DEVICEMODEL_API + #define __XEN_TOOLS__ + #include + #include + int main(void) { + xendevicemodel_handle *xd; + xenforeignmemory_handle *xfmem; + + xd = xendevicemodel_open(0, 0); + xendevicemodel_pin_memory_cacheattr(xd, 0, 0, 0, 0); + + xfmem = xenforeignmemory_open(0, 0); + xenforeignmemory_map_resource(xfmem, 0, 0, 0, 0, 0, NULL, 0, 0); + + return 0; + } + +#elif CONFIG_XEN_CTRL_INTERFACE_VERSION == 41000 + #undef XC_WANT_COMPAT_MAP_FOREIGN_API + #include + #include + int main(void) { + xenforeignmemory_handle *xfmem; + + xfmem = xenforeignmemory_open(0, 0); + xenforeignmemory_map2(xfmem, 0, 0, 0, 0, 0, 0, 0); + xentoolcore_restrict_all(0); + + return 0; + } + +#elif CONFIG_XEN_CTRL_INTERFACE_VERSION == 40900 + #undef XC_WANT_COMPAT_DEVICEMODEL_API + #define __XEN_TOOLS__ + #include + int main(void) { + xendevicemodel_handle *xd; + + xd = xendevicemodel_open(0, 0); + xendevicemodel_close(xd); + + return 0; + } + +#elif CONFIG_XEN_CTRL_INTERFACE_VERSION == 40800 + /* + * If we have stable libs the we don't want the libxc compat + * layers, regardless of what CFLAGS we may have been given. + * + * Also, check if xengnttab_grant_copy_segment_t is defined and + * grant copy operation is implemented. + */ + #undef XC_WANT_COMPAT_EVTCHN_API + #undef XC_WANT_COMPAT_GNTTAB_API + #undef XC_WANT_COMPAT_MAP_FOREIGN_API + #include + #include + #include + #include + #include + #include + #include + #if !defined(HVM_MAX_VCPUS) + # error HVM_MAX_VCPUS not defined + #endif + int main(void) { + xc_interface *xc = NULL; + xenforeignmemory_handle *xfmem; + xenevtchn_handle *xe; + xengnttab_handle *xg; + xengnttab_grant_copy_segment_t* seg = NULL; + + xs_daemon_open(); + + xc = xc_interface_open(0, 0, 0); + xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); + xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); + xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); + xc_hvm_create_ioreq_server(xc, 0, HVM_IOREQSRV_BUFIOREQ_ATOMIC, NULL); + + xfmem = xenforeignmemory_open(0, 0); + xenforeignmemory_map(xfmem, 0, 0, 0, 0, 0); + + xe = xenevtchn_open(0, 0); + xenevtchn_fd(xe); + + xg = xengnttab_open(0, 0); + xengnttab_grant_copy(xg, 0, seg); + + return 0; + } + +#elif CONFIG_XEN_CTRL_INTERFACE_VERSION == 40701 + /* + * If we have stable libs the we don't want the libxc compat + * layers, regardless of what CFLAGS we may have been given. + */ + #undef XC_WANT_COMPAT_EVTCHN_API + #undef XC_WANT_COMPAT_GNTTAB_API + #undef XC_WANT_COMPAT_MAP_FOREIGN_API + #include + #include + #include + #include + #include + #include + #include + #if !defined(HVM_MAX_VCPUS) + # error HVM_MAX_VCPUS not defined + #endif + int main(void) { + xc_interface *xc = NULL; + xenforeignmemory_handle *xfmem; + xenevtchn_handle *xe; + xengnttab_handle *xg; + + xs_daemon_open(); + + xc = xc_interface_open(0, 0, 0); + xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); + xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); + xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); + xc_hvm_create_ioreq_server(xc, 0, HVM_IOREQSRV_BUFIOREQ_ATOMIC, NULL); + + xfmem = xenforeignmemory_open(0, 0); + xenforeignmemory_map(xfmem, 0, 0, 0, 0, 0); + + xe = xenevtchn_open(0, 0); + xenevtchn_fd(xe); + + xg = xengnttab_open(0, 0); + xengnttab_map_grant_ref(xg, 0, 0, 0); + + return 0; + } + +#elif CONFIG_XEN_CTRL_INTERFACE_VERSION == 40600 + #include + #include + #include + #include + #if !defined(HVM_MAX_VCPUS) + # error HVM_MAX_VCPUS not defined + #endif + int main(void) { + xc_interface *xc; + xs_daemon_open(); + xc = xc_interface_open(0, 0, 0); + xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); + xc_gnttab_open(NULL, 0); + xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); + xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); + xc_hvm_create_ioreq_server(xc, 0, HVM_IOREQSRV_BUFIOREQ_ATOMIC, NULL); + xc_reserved_device_memory_map(xc, 0, 0, 0, 0, NULL, 0); + return 0; + } + +#elif CONFIG_XEN_CTRL_INTERFACE_VERSION == 40500 + #include + #include + #include + #include + #if !defined(HVM_MAX_VCPUS) + # error HVM_MAX_VCPUS not defined + #endif + int main(void) { + xc_interface *xc; + xs_daemon_open(); + xc = xc_interface_open(0, 0, 0); + xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); + xc_gnttab_open(NULL, 0); + xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); + xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); + xc_hvm_create_ioreq_server(xc, 0, 0, NULL); + return 0; + } + +#elif CONFIG_XEN_CTRL_INTERFACE_VERSION == 40200 + #include + #include + #include + #include + #if !defined(HVM_MAX_VCPUS) + # error HVM_MAX_VCPUS not defined + #endif + int main(void) { + xc_interface *xc; + xs_daemon_open(); + xc = xc_interface_open(0, 0, 0); + xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); + xc_gnttab_open(NULL, 0); + xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); + xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); + return 0; + } + +#else +#error invalid CONFIG_XEN_CTRL_INTERFACE_VERSION +#endif From 40c909f534e3f3cd2bcb797b95f96d52e6dd5cdf Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:33:49 +0200 Subject: [PATCH 102/935] configure, meson: move iasl detection to meson MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- configure | 2 +- meson.build | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/configure b/configure index 519982800e..b146763fbd 100755 --- a/configure +++ b/configure @@ -2508,7 +2508,7 @@ if test "$skip_meson" = no; then -Daudio_drv_list=$audio_drv_list \ -Ddefault_devices=$default_devices \ -Ddocdir="$docdir" \ - -Diasl="$($iasl -h >/dev/null 2>&1 && printf %s "$iasl")" \ + -Diasl="$iasl" \ -Dqemu_firmwarepath="$firmwarepath" \ -Dqemu_suffix="$qemu_suffix" \ -Dsmbd="$smbd" \ diff --git a/meson.build b/meson.build index 2d54513b9f..448a8dd2a4 100644 --- a/meson.build +++ b/meson.build @@ -167,6 +167,12 @@ if 'dtrace' in get_option('trace_backends') endif endif +if get_option('iasl') == '' + iasl = find_program('iasl', required: false) +else + iasl = find_program(get_option('iasl'), required: true) +endif + ################## # Compiler flags # ################## @@ -1584,8 +1590,8 @@ foreach k : get_option('trace_backends') config_host_data.set('CONFIG_TRACE_' + k.to_upper(), true) endforeach config_host_data.set_quoted('CONFIG_TRACE_FILE', get_option('trace_file')) -if get_option('iasl') != '' - config_host_data.set_quoted('CONFIG_IASL', get_option('iasl')) +if iasl.found() + config_host_data.set_quoted('CONFIG_IASL', iasl.full_path()) endif config_host_data.set_quoted('CONFIG_BINDIR', get_option('prefix') / get_option('bindir')) config_host_data.set_quoted('CONFIG_PREFIX', get_option('prefix')) @@ -3631,11 +3637,7 @@ summary_info += {'sphinx-build': sphinx_build} if config_host.has_key('HAVE_GDB_BIN') summary_info += {'gdb': config_host['HAVE_GDB_BIN']} endif -if get_option('iasl') != '' - summary_info += {'iasl': get_option('iasl')} -else - summary_info += {'iasl': false} -endif +summary_info += {'iasl': iasl} summary_info += {'genisoimage': config_host['GENISOIMAGE']} if targetos == 'windows' and have_ga summary_info += {'wixl': wixl} From d2147e04f95f24d0535bba600b95be2676558367 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:33:50 +0200 Subject: [PATCH 103/935] configure: move Windows flags detection to meson Signed-off-by: Paolo Bonzini --- configure | 20 -------------------- meson.build | 8 ++++++++ 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/configure b/configure index b146763fbd..c54e10ea26 100755 --- a/configure +++ b/configure @@ -224,10 +224,6 @@ glob() { eval test -z '"${1#'"$2"'}"' } -ld_has() { - $ld --help 2>/dev/null | grep ".$1" >/dev/null 2>&1 -} - if printf %s\\n "$source_path" "$PWD" | grep -q "[[:space:]:]"; then error_exit "main directory cannot contain spaces nor colons" @@ -2089,22 +2085,6 @@ if test "$solaris" = "no" && test "$tsan" = "no"; then fi fi -# Use ASLR, no-SEH and DEP if available -if test "$mingw32" = "yes" ; then - flags="--no-seh --nxcompat" - - # Disable ASLR for debug builds to allow debugging with gdb - if test "$debug" = "no" ; then - flags="--dynamicbase $flags" - fi - - for flag in $flags; do - if ld_has $flag ; then - QEMU_LDFLAGS="-Wl,$flag $QEMU_LDFLAGS" - fi - done -fi - # Guest agent Windows MSI package if test "$QEMU_GA_MANUFACTURER" = ""; then diff --git a/meson.build b/meson.build index 448a8dd2a4..6606c9790f 100644 --- a/meson.build +++ b/meson.build @@ -182,6 +182,14 @@ qemu_cxxflags = config_host['QEMU_CXXFLAGS'].split() qemu_objcflags = config_host['QEMU_OBJCFLAGS'].split() qemu_ldflags = config_host['QEMU_LDFLAGS'].split() +if targetos == 'windows' + qemu_ldflags += cc.get_supported_link_arguments('-Wl,--no-seh', '-Wl,--nxcompat') + # Disable ASLR for debug builds to allow debugging with gdb + if get_option('optimization') == '0' + qemu_ldflags += cc.get_supported_link_arguments('-Wl,--dynamicbase') + endif +endif + if get_option('gprof') qemu_cflags += ['-p'] qemu_cxxflags += ['-p'] From 4fda6011d00619e9a07019d40c92d0de31d47939 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:33:51 +0200 Subject: [PATCH 104/935] configure: switch string options to automatic parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- configure | 24 +----------------------- scripts/meson-buildoptions.py | 5 +---- scripts/meson-buildoptions.sh | 9 +++++++++ 3 files changed, 11 insertions(+), 27 deletions(-) diff --git a/configure b/configure index c54e10ea26..c1eb4923dd 100755 --- a/configure +++ b/configure @@ -231,12 +231,10 @@ fi # default parameters cpu="" -iasl="iasl" interp_prefix="/usr/gnemul/qemu-%M" static="no" cross_compile="no" cross_prefix="" -audio_drv_list="default" block_drv_rw_whitelist="" block_drv_ro_whitelist="" host_cc="cc" @@ -312,7 +310,6 @@ linux_user="" bsd_user="" pkgversion="" pie="" -trace_file="trace" coroutine="" tls_priority="NORMAL" plugins="$default_feature" @@ -714,8 +711,6 @@ for opt do ;; --cxx=*) ;; - --iasl=*) iasl="$optarg" - ;; --objcc=*) objcc="$optarg" ;; --make=*) make="$optarg" @@ -724,8 +719,6 @@ for opt do ;; --python=*) python="$optarg" ; explicit_python=yes ;; - --sphinx-build=*) sphinx_build="$optarg" - ;; --skip-meson) skip_meson=yes ;; --meson=*) meson="$optarg" @@ -766,8 +759,6 @@ for opt do error_exit "Can't mix --target-list-exclude with --target-list" fi ;; - --with-trace-file=*) trace_file="$optarg" - ;; --with-default-devices) default_devices="true" ;; --without-default-devices) default_devices="false" @@ -826,8 +817,6 @@ for opt do # configure to be used by RPM and similar macros that set # lots of directory switches by default. ;; - --audio-drv-list=*) audio_drv_list="$optarg" - ;; --block-drv-rw-whitelist=*|--block-drv-whitelist=*) block_drv_rw_whitelist=$(echo "$optarg" | sed -e 's/,/ /g') ;; --block-drv-ro-whitelist=*) block_drv_ro_whitelist=$(echo "$optarg" | sed -e 's/,/ /g') @@ -1001,12 +990,7 @@ for opt do --enable-jemalloc) meson_option_parse --enable-malloc=jemalloc jemalloc ;; # everything else has the same name in configure and meson - --enable-* | --disable-*) meson_option_parse "$opt" "$optarg" - ;; - *) - echo "ERROR: unknown option $opt" - echo "Try '$0 --help' for more information" - exit 1 + --*) meson_option_parse "$opt" "$optarg" ;; esac done @@ -1129,7 +1113,6 @@ $(echo Available targets: $default_target_list | \ Advanced options (experts only): --cross-prefix=PREFIX use PREFIX for compile tools, PREFIX can be blank [$cross_prefix] --cc=CC use C compiler CC [$cc] - --iasl=IASL use ACPI compiler IASL [$iasl] --host-cc=CC use C compiler CC [$host_cc] for code run at build time --cxx=CXX use C++ compiler CXX [$cxx] @@ -1142,7 +1125,6 @@ Advanced options (experts only): --cross-cc-cflags-ARCH= use compiler flags when building ARCH guest tests --make=MAKE use specified make [$make] --python=PYTHON use specified python [$python] - --sphinx-build=SPHINX use specified sphinx-build [$sphinx_build] --meson=MESON use specified meson [$meson] --ninja=NINJA use specified ninja [$ninja] --smbd=SMBD use specified smbd [$smbd] @@ -2485,15 +2467,11 @@ if test "$skip_meson" = no; then --sysconfdir "$sysconfdir" \ --localedir "$localedir" \ --localstatedir "$local_statedir" \ - -Daudio_drv_list=$audio_drv_list \ -Ddefault_devices=$default_devices \ -Ddocdir="$docdir" \ - -Diasl="$iasl" \ -Dqemu_firmwarepath="$firmwarepath" \ -Dqemu_suffix="$qemu_suffix" \ -Dsmbd="$smbd" \ - -Dsphinx_build="$sphinx_build" \ - -Dtrace_file="$trace_file" \ -Doptimization=$(if test "$debug" = yes; then echo 0; else echo 2; fi) \ -Ddebug=$(if test "$debug_info" = yes; then echo true; else echo false; fi) \ -Dwerror=$(if test "$werror" = yes; then echo true; else echo false; fi) \ diff --git a/scripts/meson-buildoptions.py b/scripts/meson-buildoptions.py index 4af8d6e732..3e540e8bb3 100755 --- a/scripts/meson-buildoptions.py +++ b/scripts/meson-buildoptions.py @@ -26,21 +26,18 @@ import shlex import sys SKIP_OPTIONS = { - "audio_drv_list", "default_devices", "docdir", "fuzzing_engine", - "iasl", "qemu_firmwarepath", "qemu_suffix", "smbd", - "sphinx_build", - "trace_file", } OPTION_NAMES = { "malloc": "enable-malloc", "trace_backends": "enable-trace-backends", + "trace_file": "with-trace-file", } BUILTIN_OPTIONS = { diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 2123317654..bdaa128ee4 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -1,5 +1,7 @@ # This file is generated by meson-buildoptions.py, do not edit! meson_options_help() { + printf "%s\n" ' --audio-drv-list=CHOICES Set audio driver list [default] (choices:' + printf "%s\n" ' alsa/coreaudio/default/dsound/jack/oss/pa/sdl)' printf "%s\n" ' --disable-coroutine-pool coroutine freelist (better performance)' printf "%s\n" ' --disable-install-blobs install provided firmware blobs' printf "%s\n" ' --enable-block-drv-whitelist-in-tools' @@ -32,6 +34,9 @@ meson_options_help() { printf "%s\n" ' --enable-trace-backends=CHOICES' printf "%s\n" ' Set available tracing backends [log] (choices:' printf "%s\n" ' dtrace/ftrace/log/nop/simple/syslog/ust)' + printf "%s\n" ' --iasl=VALUE Path to ACPI disassembler' + printf "%s\n" ' --sphinx-build=VALUE Use specified sphinx-build for building document' + printf "%s\n" ' --with-trace-file=VALUE Trace file prefix for simple backend [trace]' printf "%s\n" '' printf "%s\n" 'Optional features, enabled with --enable-FEATURE and' printf "%s\n" 'disabled with --disable-FEATURE, default is enabled if available' @@ -147,6 +152,7 @@ _meson_option_parse() { --disable-alsa) printf "%s" -Dalsa=disabled ;; --enable-attr) printf "%s" -Dattr=enabled ;; --disable-attr) printf "%s" -Dattr=disabled ;; + --audio-drv-list=*) quote_sh "-Daudio_drv_list=$2" ;; --enable-auth-pam) printf "%s" -Dauth_pam=enabled ;; --disable-auth-pam) printf "%s" -Dauth_pam=disabled ;; --enable-avx2) printf "%s" -Davx2=enabled ;; @@ -229,6 +235,7 @@ _meson_option_parse() { --disable-hax) printf "%s" -Dhax=disabled ;; --enable-hvf) printf "%s" -Dhvf=enabled ;; --disable-hvf) printf "%s" -Dhvf=disabled ;; + --iasl=*) quote_sh "-Diasl=$2" ;; --enable-iconv) printf "%s" -Diconv=enabled ;; --disable-iconv) printf "%s" -Diconv=disabled ;; --enable-install-blobs) printf "%s" -Dinstall_blobs=true ;; @@ -333,6 +340,7 @@ _meson_option_parse() { --disable-snappy) printf "%s" -Dsnappy=disabled ;; --enable-sparse) printf "%s" -Dsparse=enabled ;; --disable-sparse) printf "%s" -Dsparse=disabled ;; + --sphinx-build=*) quote_sh "-Dsphinx_build=$2" ;; --enable-spice) printf "%s" -Dspice=enabled ;; --disable-spice) printf "%s" -Dspice=disabled ;; --enable-spice-protocol) printf "%s" -Dspice_protocol=enabled ;; @@ -348,6 +356,7 @@ _meson_option_parse() { --enable-tpm) printf "%s" -Dtpm=enabled ;; --disable-tpm) printf "%s" -Dtpm=disabled ;; --enable-trace-backends=*) quote_sh "-Dtrace_backends=$2" ;; + --with-trace-file=*) quote_sh "-Dtrace_file=$2" ;; --enable-u2f) printf "%s" -Du2f=enabled ;; --disable-u2f) printf "%s" -Du2f=disabled ;; --enable-usb-redir) printf "%s" -Dusb_redir=enabled ;; From 41f2ae281953c7f7cfc28c5b93f9e0fb65cbd301 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:33:52 +0200 Subject: [PATCH 105/935] meson, configure: move --tls-priority to meson MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the new support for string option parsing. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- configure | 5 ----- meson.build | 3 ++- meson_options.txt | 2 ++ scripts/meson-buildoptions.sh | 3 +++ 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/configure b/configure index c1eb4923dd..9062f9ccd6 100755 --- a/configure +++ b/configure @@ -311,7 +311,6 @@ bsd_user="" pkgversion="" pie="" coroutine="" -tls_priority="NORMAL" plugins="$default_feature" meson="" meson_args="" @@ -939,8 +938,6 @@ for opt do --enable-uuid|--disable-uuid) echo "$0: $opt is obsolete, UUID support is always built" >&2 ;; - --tls-priority=*) tls_priority="$optarg" - ;; --disable-vhost-user) vhost_user="no" ;; --enable-vhost-user) vhost_user="yes" @@ -1170,7 +1167,6 @@ Advanced options (experts only): --with-coroutine=BACKEND coroutine backend. Supported options: ucontext, sigaltstack, windows --enable-gcov enable test coverage analysis with gcov - --tls-priority default TLS protocol/cipher priority string --enable-plugins enable plugins via shared library loading --disable-containers don't use containers for cross-building @@ -2201,7 +2197,6 @@ if test "$modules" = "yes"; then echo "CONFIG_STAMP=_$( (echo $qemu_version; echo $pkgversion; cat $0) | $shacmd - | cut -f1 -d\ )" >> $config_host_mak echo "CONFIG_MODULES=y" >> $config_host_mak fi -echo "CONFIG_TLS_PRIORITY=\"$tls_priority\"" >> $config_host_mak if test "$vhost_scsi" = "yes" ; then echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak diff --git a/meson.build b/meson.build index 6606c9790f..ae3b3a45e7 100644 --- a/meson.build +++ b/meson.build @@ -1598,6 +1598,7 @@ foreach k : get_option('trace_backends') config_host_data.set('CONFIG_TRACE_' + k.to_upper(), true) endforeach config_host_data.set_quoted('CONFIG_TRACE_FILE', get_option('trace_file')) +config_host_data.set_quoted('CONFIG_TLS_PRIORITY', get_option('tls_priority')) if iasl.found() config_host_data.set_quoted('CONFIG_IASL', iasl.full_path()) endif @@ -3820,7 +3821,7 @@ summary(summary_info, bool_yn: true, section: 'Block layer support') # Crypto summary_info = {} -summary_info += {'TLS priority': config_host['CONFIG_TLS_PRIORITY']} +summary_info += {'TLS priority': get_option('tls_priority')} summary_info += {'GNUTLS support': gnutls} if gnutls.found() summary_info += {' GNUTLS crypto': gnutls_crypto.found()} diff --git a/meson_options.txt b/meson_options.txt index 390701517c..c8e0a10d91 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -14,6 +14,8 @@ option('sphinx_build', type : 'string', value : '', description: 'Use specified sphinx-build for building document') option('iasl', type : 'string', value : '', description: 'Path to ACPI disassembler') +option('tls_priority', type : 'string', value : 'NORMAL', + description: 'Default TLS protocol/cipher priority string') option('default_devices', type : 'boolean', value : true, description: 'Include a default selection of devices in emulators') option('audio_drv_list', type: 'array', value: ['default'], diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index bdaa128ee4..3919eeec0b 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -36,6 +36,8 @@ meson_options_help() { printf "%s\n" ' dtrace/ftrace/log/nop/simple/syslog/ust)' printf "%s\n" ' --iasl=VALUE Path to ACPI disassembler' printf "%s\n" ' --sphinx-build=VALUE Use specified sphinx-build for building document' + printf "%s\n" ' --tls-priority=VALUE Default TLS protocol/cipher priority string' + printf "%s\n" ' [NORMAL]' printf "%s\n" ' --with-trace-file=VALUE Trace file prefix for simple backend [trace]' printf "%s\n" '' printf "%s\n" 'Optional features, enabled with --enable-FEATURE and' @@ -351,6 +353,7 @@ _meson_option_parse() { --disable-tcg) printf "%s" -Dtcg=disabled ;; --enable-tcg-interpreter) printf "%s" -Dtcg_interpreter=true ;; --disable-tcg-interpreter) printf "%s" -Dtcg_interpreter=false ;; + --tls-priority=*) quote_sh "-Dtls_priority=$2" ;; --enable-tools) printf "%s" -Dtools=enabled ;; --disable-tools) printf "%s" -Dtools=disabled ;; --enable-tpm) printf "%s" -Dtpm=enabled ;; From 622d64fffe4f287af4f0d5e438d4aa42da377811 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:33:53 +0200 Subject: [PATCH 106/935] meson, configure: move bdrv whitelists to meson MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the new support for string option parsing. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- configure | 14 -------------- meson.build | 27 ++++++++++++++++----------- meson_options.txt | 4 ++++ scripts/meson-buildoptions.sh | 8 ++++++++ 4 files changed, 28 insertions(+), 25 deletions(-) diff --git a/configure b/configure index 9062f9ccd6..e81ea490da 100755 --- a/configure +++ b/configure @@ -235,8 +235,6 @@ interp_prefix="/usr/gnemul/qemu-%M" static="no" cross_compile="no" cross_prefix="" -block_drv_rw_whitelist="" -block_drv_ro_whitelist="" host_cc="cc" lto="false" stack_protector="" @@ -816,10 +814,6 @@ for opt do # configure to be used by RPM and similar macros that set # lots of directory switches by default. ;; - --block-drv-rw-whitelist=*|--block-drv-whitelist=*) block_drv_rw_whitelist=$(echo "$optarg" | sed -e 's/,/ /g') - ;; - --block-drv-ro-whitelist=*) block_drv_ro_whitelist=$(echo "$optarg" | sed -e 's/,/ /g') - ;; --enable-debug-tcg) debug_tcg="yes" ;; --disable-debug-tcg) debug_tcg="no" @@ -1155,12 +1149,6 @@ Advanced options (experts only): --disable-stack-protector disable compiler-provided stack protection --audio-drv-list=LIST set audio drivers to try if -audiodev is not used --block-drv-whitelist=L Same as --block-drv-rw-whitelist=L - --block-drv-rw-whitelist=L - set block driver read-write whitelist - (by default affects only QEMU, not tools like qemu-img) - --block-drv-ro-whitelist=L - set block driver read-only whitelist - (by default affects only QEMU, not tools like qemu-img) --with-trace-file=NAME Full PATH,NAME of file to store traces Default:trace- --cpu=CPU Build for host CPU [$cpu] @@ -2185,8 +2173,6 @@ fi if test "$static" = "yes" ; then echo "CONFIG_STATIC=y" >> $config_host_mak fi -echo "CONFIG_BDRV_RW_WHITELIST=$block_drv_rw_whitelist" >> $config_host_mak -echo "CONFIG_BDRV_RO_WHITELIST=$block_drv_ro_whitelist" >> $config_host_mak qemu_version=$(head $source_path/VERSION) echo "PKGVERSION=$pkgversion" >>$config_host_mak echo "SRC_PATH=$source_path" >> $config_host_mak diff --git a/meson.build b/meson.build index ae3b3a45e7..3604a0d264 100644 --- a/meson.build +++ b/meson.build @@ -1594,6 +1594,19 @@ have_virtfs = get_option('virtfs') \ have_virtfs_proxy_helper = targetos != 'darwin' and have_virtfs and have_tools +if get_option('block_drv_ro_whitelist') == '' + config_host_data.set('CONFIG_BDRV_RO_WHITELIST', '') +else + config_host_data.set('CONFIG_BDRV_RO_WHITELIST', + '"' + get_option('block_drv_ro_whitelist').replace(',', '", "') + '", ') +endif +if get_option('block_drv_rw_whitelist') == '' + config_host_data.set('CONFIG_BDRV_RW_WHITELIST', '') +else + config_host_data.set('CONFIG_BDRV_RW_WHITELIST', + '"' + get_option('block_drv_rw_whitelist').replace(',', '", "') + '", ') +endif + foreach k : get_option('trace_backends') config_host_data.set('CONFIG_TRACE_' + k.to_upper(), true) endforeach @@ -2209,16 +2222,8 @@ config_host_data.set('HAVE_VSS_SDK', have_vss_sdk) ignored = ['CONFIG_QEMU_INTERP_PREFIX', # actually per-target 'HAVE_GDB_BIN'] -arrays = ['CONFIG_BDRV_RW_WHITELIST', 'CONFIG_BDRV_RO_WHITELIST'] foreach k, v: config_host - if ignored.contains(k) - # do nothing - elif arrays.contains(k) - if v != '' - v = '"' + '", "'.join(v.split()) + '", ' - endif - config_host_data.set(k, v) - elif k.startswith('CONFIG_') + if k.startswith('CONFIG_') and not ignored.contains(k) config_host_data.set(k, v == 'y' ? 1 : v) endif endforeach @@ -3800,8 +3805,8 @@ summary_info = {} summary_info += {'coroutine backend': config_host['CONFIG_COROUTINE_BACKEND']} summary_info += {'coroutine pool': have_coroutine_pool} if have_block - summary_info += {'Block whitelist (rw)': config_host['CONFIG_BDRV_RW_WHITELIST']} - summary_info += {'Block whitelist (ro)': config_host['CONFIG_BDRV_RO_WHITELIST']} + summary_info += {'Block whitelist (rw)': get_option('block_drv_rw_whitelist')} + summary_info += {'Block whitelist (ro)': get_option('block_drv_ro_whitelist')} summary_info += {'Use block whitelist in tools': get_option('block_drv_whitelist_in_tools')} summary_info += {'VirtFS support': have_virtfs} summary_info += {'build virtiofs daemon': have_virtiofsd} diff --git a/meson_options.txt b/meson_options.txt index c8e0a10d91..430674522f 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -21,6 +21,10 @@ option('default_devices', type : 'boolean', value : true, option('audio_drv_list', type: 'array', value: ['default'], choices: ['alsa', 'coreaudio', 'default', 'dsound', 'jack', 'oss', 'pa', 'sdl'], description: 'Set audio driver list') +option('block_drv_rw_whitelist', type : 'string', value : '', + description: 'set block driver read-write whitelist (by default affects only QEMU, not tools like qemu-img)') +option('block_drv_ro_whitelist', type : 'string', value : '', + description: 'set block driver read-only whitelist (by default affects only QEMU, not tools like qemu-img)') option('fuzzing_engine', type : 'string', value : '', description: 'fuzzing engine library for OSS-Fuzz') option('trace_file', type: 'string', value: 'trace', diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 3919eeec0b..d5cba2638a 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -2,6 +2,12 @@ meson_options_help() { printf "%s\n" ' --audio-drv-list=CHOICES Set audio driver list [default] (choices:' printf "%s\n" ' alsa/coreaudio/default/dsound/jack/oss/pa/sdl)' + printf "%s\n" ' --block-drv-ro-whitelist=VALUE' + printf "%s\n" ' set block driver read-only whitelist (by default' + printf "%s\n" ' affects only QEMU, not tools like qemu-img)' + printf "%s\n" ' --block-drv-rw-whitelist=VALUE' + printf "%s\n" ' set block driver read-write whitelist (by default' + printf "%s\n" ' affects only QEMU, not tools like qemu-img)' printf "%s\n" ' --disable-coroutine-pool coroutine freelist (better performance)' printf "%s\n" ' --disable-install-blobs install provided firmware blobs' printf "%s\n" ' --enable-block-drv-whitelist-in-tools' @@ -161,6 +167,8 @@ _meson_option_parse() { --disable-avx2) printf "%s" -Davx2=disabled ;; --enable-avx512f) printf "%s" -Davx512f=enabled ;; --disable-avx512f) printf "%s" -Davx512f=disabled ;; + --block-drv-ro-whitelist=*) quote_sh "-Dblock_drv_ro_whitelist=$2" ;; + --block-drv-rw-whitelist=*) quote_sh "-Dblock_drv_rw_whitelist=$2" ;; --enable-block-drv-whitelist-in-tools) printf "%s" -Dblock_drv_whitelist_in_tools=true ;; --disable-block-drv-whitelist-in-tools) printf "%s" -Dblock_drv_whitelist_in_tools=false ;; --enable-bochs) printf "%s" -Dbochs=enabled ;; From b0b4323e3219810d14f36c159e67a8332a86f9fd Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:33:54 +0200 Subject: [PATCH 107/935] meson, configure: move --with-pkgversion, CONFIG_STAMP to meson MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hash is now generated with a Python script. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- configure | 23 ----------------------- docs/meson.build | 2 +- meson.build | 10 +++++++++- meson_options.txt | 2 ++ scripts/meson-buildoptions.py | 1 + scripts/meson-buildoptions.sh | 3 +++ scripts/qemu-stamp.py | 24 ++++++++++++++++++++++++ 7 files changed, 40 insertions(+), 25 deletions(-) create mode 100644 scripts/qemu-stamp.py diff --git a/configure b/configure index e81ea490da..b8d3d04072 100755 --- a/configure +++ b/configure @@ -306,7 +306,6 @@ qemu_suffix="qemu" softmmu="yes" linux_user="" bsd_user="" -pkgversion="" pie="" coroutine="" plugins="$default_feature" @@ -897,8 +896,6 @@ for opt do ;; --enable-fdt=*) fdt="$optarg" ;; - --with-pkgversion=*) pkgversion="$optarg" - ;; --with-coroutine=*) coroutine="$optarg" ;; --disable-vhost-net) vhost_net="no" @@ -1136,7 +1133,6 @@ Advanced options (experts only): --firmwarepath=PATH search PATH for firmware files --efi-aarch64=PATH PATH of efi file to use for aarch64 VMs. --with-suffix=SUFFIX suffix for QEMU data inside datadir/libdir/sysconfdir/docdir [$qemu_suffix] - --with-pkgversion=VERS use specified string as sub-version of the package --without-default-features default all --enable-* options to "disabled" --without-default-devices do not include any device that is not needed to start the emulator (only use if you are including @@ -1723,21 +1719,6 @@ if ! compile_prog "$glib_cflags -Werror" "$glib_libs" ; then fi fi -########################################## -# SHA command probe for modules -if test "$modules" = yes; then - shacmd_probe="sha1sum sha1 shasum" - for c in $shacmd_probe; do - if has $c; then - shacmd="$c" - break - fi - done - if test "$shacmd" = ""; then - error_exit "one of the checksum commands is required to enable modules: $shacmd_probe" - fi -fi - ########################################## # fdt probe @@ -2174,13 +2155,9 @@ if test "$static" = "yes" ; then echo "CONFIG_STATIC=y" >> $config_host_mak fi qemu_version=$(head $source_path/VERSION) -echo "PKGVERSION=$pkgversion" >>$config_host_mak echo "SRC_PATH=$source_path" >> $config_host_mak echo "TARGET_DIRS=$target_list" >> $config_host_mak if test "$modules" = "yes"; then - # $shacmd can generate a hash started with digit, which the compiler doesn't - # like as an symbol. So prefix it with an underscore - echo "CONFIG_STAMP=_$( (echo $qemu_version; echo $pkgversion; cat $0) | $shacmd - | cut -f1 -d\ )" >> $config_host_mak echo "CONFIG_MODULES=y" >> $config_host_mak fi diff --git a/docs/meson.build b/docs/meson.build index 831d4aea2b..9136fed3b7 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -35,7 +35,7 @@ if sphinx_build.found() endif if build_docs - SPHINX_ARGS += ['-Dversion=' + meson.project_version(), '-Drelease=' + config_host['PKGVERSION']] + SPHINX_ARGS += ['-Dversion=' + meson.project_version(), '-Drelease=' + get_option('pkgversion')] man_pages = { 'qemu-ga.8': (have_ga ? 'man8' : ''), diff --git a/meson.build b/meson.build index 3604a0d264..4ddc72f070 100644 --- a/meson.build +++ b/meson.build @@ -1628,6 +1628,14 @@ config_host_data.set_quoted('CONFIG_QEMU_LOCALSTATEDIR', get_option('prefix') / config_host_data.set_quoted('CONFIG_QEMU_MODDIR', get_option('prefix') / qemu_moddir) config_host_data.set_quoted('CONFIG_SYSCONFDIR', get_option('prefix') / get_option('sysconfdir')) +if config_host.has_key('CONFIG_MODULES') + config_host_data.set('CONFIG_STAMP', run_command( + meson.current_source_dir() / 'scripts/qemu-stamp.py', + meson.project_version(), get_option('pkgversion'), '--', + meson.current_source_dir() / 'configure', + capture: true, check: true).stdout().strip()) +endif + have_slirp_smbd = get_option('slirp_smbd') \ .require(targetos != 'windows', error_message: 'Host smbd not supported on this platform.') \ .allowed() @@ -2799,7 +2807,7 @@ tracetool_depends = files( qemu_version_cmd = [find_program('scripts/qemu-version.sh'), meson.current_source_dir(), - config_host['PKGVERSION'], meson.project_version()] + get_option('pkgversion'), meson.project_version()] qemu_version = custom_target('qemu-version.h', output: 'qemu-version.h', command: qemu_version_cmd, diff --git a/meson_options.txt b/meson_options.txt index 430674522f..bdb45092ca 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -8,6 +8,8 @@ option('docdir', type : 'string', value : 'doc', description: 'Base directory for documentation installation (can be empty)') option('qemu_firmwarepath', type : 'string', value : '', description: 'search PATH for firmware files') +option('pkgversion', type : 'string', value : '', + description: 'use specified string as sub-version of the package') option('smbd', type : 'string', value : '', description: 'Path to smbd for slirp networking') option('sphinx_build', type : 'string', value : '', diff --git a/scripts/meson-buildoptions.py b/scripts/meson-buildoptions.py index 3e540e8bb3..0f9603a7f6 100755 --- a/scripts/meson-buildoptions.py +++ b/scripts/meson-buildoptions.py @@ -36,6 +36,7 @@ SKIP_OPTIONS = { OPTION_NAMES = { "malloc": "enable-malloc", + "pkgversion": "with-pkgversion", "trace_backends": "enable-trace-backends", "trace_file": "with-trace-file", } diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index d5cba2638a..3a86dd7271 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -44,6 +44,8 @@ meson_options_help() { printf "%s\n" ' --sphinx-build=VALUE Use specified sphinx-build for building document' printf "%s\n" ' --tls-priority=VALUE Default TLS protocol/cipher priority string' printf "%s\n" ' [NORMAL]' + printf "%s\n" ' --with-pkgversion=VALUE use specified string as sub-version of the' + printf "%s\n" ' package' printf "%s\n" ' --with-trace-file=VALUE Trace file prefix for simple backend [trace]' printf "%s\n" '' printf "%s\n" 'Optional features, enabled with --enable-FEATURE and' @@ -309,6 +311,7 @@ _meson_option_parse() { --disable-pa) printf "%s" -Dpa=disabled ;; --enable-parallels) printf "%s" -Dparallels=enabled ;; --disable-parallels) printf "%s" -Dparallels=disabled ;; + --with-pkgversion=*) quote_sh "-Dpkgversion=$2" ;; --enable-png) printf "%s" -Dpng=enabled ;; --disable-png) printf "%s" -Dpng=disabled ;; --enable-profiler) printf "%s" -Dprofiler=true ;; diff --git a/scripts/qemu-stamp.py b/scripts/qemu-stamp.py new file mode 100644 index 0000000000..7beeeb07ed --- /dev/null +++ b/scripts/qemu-stamp.py @@ -0,0 +1,24 @@ +#! /usr/bin/env python3 + +# Usage: scripts/qemu-stamp.py STRING1 STRING2... -- FILE1 FILE2... +import hashlib +import os +import sys + +sha = hashlib.sha1() +is_file = False +for arg in sys.argv[1:]: + if arg == '--': + is_file = True + continue + if is_file: + with open(arg, 'rb') as f: + for chunk in iter(lambda: f.read(65536), b''): + sha.update(chunk) + else: + sha.update(os.fsencode(arg)) + sha.update(b'\n') + +# The hash can start with a digit, which the compiler doesn't +# like as an symbol. So prefix it with an underscore +print("_" + sha.hexdigest()) From ce6119dc8e025f17c38926aa793f96ed74cb3cc0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:33:55 +0200 Subject: [PATCH 108/935] meson, configure: move --interp-prefix to meson MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the last CONFIG_* entry in config-host.mak that had to be special cased. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- configure | 6 ------ meson.build | 6 ++---- meson_options.txt | 2 ++ scripts/meson-buildoptions.sh | 3 +++ 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/configure b/configure index b8d3d04072..4102683d75 100755 --- a/configure +++ b/configure @@ -231,7 +231,6 @@ fi # default parameters cpu="" -interp_prefix="/usr/gnemul/qemu-%M" static="no" cross_compile="no" cross_prefix="" @@ -697,8 +696,6 @@ for opt do ;; --prefix=*) prefix="$optarg" ;; - --interp-prefix=*) interp_prefix="$optarg" - ;; --cross-prefix=*) ;; --cc=*) @@ -1091,8 +1088,6 @@ Options: [defaults in brackets after descriptions] Standard options: --help print this message --prefix=PREFIX install in PREFIX [$prefix] - --interp-prefix=PREFIX where to find shared libraries, etc. - use %M for cpu name [$interp_prefix] --target-list=LIST set target list (default: build all) $(echo Available targets: $default_target_list | \ fold -s -w 53 | sed -e 's/^/ /') @@ -2289,7 +2284,6 @@ for target in $target_list; do esac done -echo "CONFIG_QEMU_INTERP_PREFIX=$interp_prefix" | sed 's/%M/@0@/' >> $config_host_mak if test "$default_targets" = "yes"; then echo "CONFIG_DEFAULT_TARGETS=y" >> $config_host_mak fi diff --git a/meson.build b/meson.build index 4ddc72f070..20d9074c4f 100644 --- a/meson.build +++ b/meson.build @@ -2228,10 +2228,8 @@ if targetos == 'windows' and link_language == 'cpp' endif config_host_data.set('HAVE_VSS_SDK', have_vss_sdk) -ignored = ['CONFIG_QEMU_INTERP_PREFIX', # actually per-target - 'HAVE_GDB_BIN'] foreach k, v: config_host - if k.startswith('CONFIG_') and not ignored.contains(k) + if k.startswith('CONFIG_') config_host_data.set(k, v == 'y' ? 1 : v) endif endforeach @@ -2337,7 +2335,7 @@ foreach target : target_dirs config_target += { 'CONFIG_USER_ONLY': 'y', 'CONFIG_QEMU_INTERP_PREFIX': - config_host['CONFIG_QEMU_INTERP_PREFIX'].format(config_target['TARGET_NAME']) + get_option('interp_prefix').replace('%M', config_target['TARGET_NAME']) } endif diff --git a/meson_options.txt b/meson_options.txt index bdb45092ca..ae6c4b2475 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -27,6 +27,8 @@ option('block_drv_rw_whitelist', type : 'string', value : '', description: 'set block driver read-write whitelist (by default affects only QEMU, not tools like qemu-img)') option('block_drv_ro_whitelist', type : 'string', value : '', description: 'set block driver read-only whitelist (by default affects only QEMU, not tools like qemu-img)') +option('interp_prefix', type : 'string', value : '/usr/gnemul/qemu-%M', + description: 'where to find shared libraries etc., use %M for cpu name') option('fuzzing_engine', type : 'string', value : '', description: 'fuzzing engine library for OSS-Fuzz') option('trace_file', type: 'string', value: 'trace', diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 3a86dd7271..59c4a27c5a 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -41,6 +41,8 @@ meson_options_help() { printf "%s\n" ' Set available tracing backends [log] (choices:' printf "%s\n" ' dtrace/ftrace/log/nop/simple/syslog/ust)' printf "%s\n" ' --iasl=VALUE Path to ACPI disassembler' + printf "%s\n" ' --interp-prefix=VALUE where to find shared libraries etc., use %M for' + printf "%s\n" ' cpu name [/usr/gnemul/qemu-%M]' printf "%s\n" ' --sphinx-build=VALUE Use specified sphinx-build for building document' printf "%s\n" ' --tls-priority=VALUE Default TLS protocol/cipher priority string' printf "%s\n" ' [NORMAL]' @@ -252,6 +254,7 @@ _meson_option_parse() { --disable-iconv) printf "%s" -Diconv=disabled ;; --enable-install-blobs) printf "%s" -Dinstall_blobs=true ;; --disable-install-blobs) printf "%s" -Dinstall_blobs=false ;; + --interp-prefix=*) quote_sh "-Dinterp_prefix=$2" ;; --enable-jack) printf "%s" -Djack=enabled ;; --disable-jack) printf "%s" -Djack=disabled ;; --enable-keyring) printf "%s" -Dkeyring=enabled ;; From f7fb6c6ad4f6c5dd2e37af9ec60c51d6de24a24e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:33:56 +0200 Subject: [PATCH 109/935] meson: always combine directories with prefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Meson allows directories such as "bindir" to be relative to the prefix. Right now configure is forcing an absolute path, but that is not really necessary: just make sure all uses of the directory variables are prefixed appropriately. Do the same also for the options that are custom for QEMU, i.e. docdir and qemu_firmwarepath. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- meson.build | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/meson.build b/meson.build index 20d9074c4f..65c44ea010 100644 --- a/meson.build +++ b/meson.build @@ -1620,7 +1620,7 @@ config_host_data.set_quoted('CONFIG_PREFIX', get_option('prefix')) config_host_data.set_quoted('CONFIG_QEMU_CONFDIR', get_option('prefix') / qemu_confdir) config_host_data.set_quoted('CONFIG_QEMU_DATADIR', get_option('prefix') / qemu_datadir) config_host_data.set_quoted('CONFIG_QEMU_DESKTOPDIR', get_option('prefix') / qemu_desktopdir) -config_host_data.set_quoted('CONFIG_QEMU_FIRMWAREPATH', get_option('qemu_firmwarepath')) +config_host_data.set_quoted('CONFIG_QEMU_FIRMWAREPATH', get_option('prefix') / get_option('qemu_firmwarepath')) config_host_data.set_quoted('CONFIG_QEMU_HELPERDIR', get_option('prefix') / get_option('libexecdir')) config_host_data.set_quoted('CONFIG_QEMU_ICONDIR', get_option('prefix') / qemu_icondir) config_host_data.set_quoted('CONFIG_QEMU_LOCALEDIR', get_option('prefix') / get_option('localedir')) @@ -3629,20 +3629,20 @@ endif summary_info = {} summary_info += {'Install prefix': get_option('prefix')} summary_info += {'BIOS directory': qemu_datadir} -summary_info += {'firmware path': get_option('qemu_firmwarepath')} -summary_info += {'binary directory': get_option('bindir')} -summary_info += {'library directory': get_option('libdir')} +summary_info += {'firmware path': get_option('prefix') / get_option('qemu_firmwarepath')} +summary_info += {'binary directory': get_option('prefix') / get_option('bindir')} +summary_info += {'library directory': get_option('prefix') / get_option('libdir')} summary_info += {'module directory': qemu_moddir} -summary_info += {'libexec directory': get_option('libexecdir')} -summary_info += {'include directory': get_option('includedir')} -summary_info += {'config directory': get_option('sysconfdir')} +summary_info += {'libexec directory': get_option('prefix') / get_option('libexecdir')} +summary_info += {'include directory': get_option('prefix') / get_option('includedir')} +summary_info += {'config directory': get_option('prefix') / get_option('sysconfdir')} if targetos != 'windows' - summary_info += {'local state directory': get_option('localstatedir')} - summary_info += {'Manual directory': get_option('mandir')} + summary_info += {'local state directory': get_option('prefix') / get_option('localstatedir')} + summary_info += {'Manual directory': get_option('prefix') / get_option('mandir')} else summary_info += {'local state directory': 'queried at runtime'} endif -summary_info += {'Doc directory': get_option('docdir')} +summary_info += {'Doc directory': get_option('prefix') / get_option('docdir')} summary_info += {'Build directory': meson.current_build_dir()} summary_info += {'Source path': meson.current_source_dir()} summary_info += {'GIT submodules': config_host['GIT_SUBMODULES']} From c09c1ce7e9507f8421b01076e1ed94b4c51d8f53 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:33:57 +0200 Subject: [PATCH 110/935] configure: switch directory options to automatic parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While prefix, bindir and qemu_suffix needs special treatment due to differences between Windows and POSIX systems, everything else needs no extra code in configure. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- configure | 58 ++--------------------------------- meson_options.txt | 4 +-- scripts/meson-buildoptions.py | 11 +++++-- scripts/meson-buildoptions.sh | 21 +++++++++++++ 4 files changed, 34 insertions(+), 60 deletions(-) diff --git a/configure b/configure index 4102683d75..b8e3176808 100755 --- a/configure +++ b/configure @@ -311,6 +311,7 @@ plugins="$default_feature" meson="" meson_args="" ninja="" +bindir="bin" skip_meson=no # The following Meson options are handled manually (still they @@ -670,6 +671,7 @@ if test "$mingw32" = "yes" ; then CONFIGURE_CFLAGS="-mthreads $CONFIGURE_CFLAGS" write_c_skeleton; prefix="/qemu" + bindir="" qemu_suffix="" fi @@ -776,30 +778,10 @@ for opt do static="yes" QEMU_PKG_CONFIG_FLAGS="--static $QEMU_PKG_CONFIG_FLAGS" ;; - --mandir=*) mandir="$optarg" - ;; --bindir=*) bindir="$optarg" ;; - --libdir=*) libdir="$optarg" - ;; - --libexecdir=*) libexecdir="$optarg" - ;; - --includedir=*) includedir="$optarg" - ;; - --datadir=*) datadir="$optarg" - ;; --with-suffix=*) qemu_suffix="$optarg" ;; - --docdir=*) docdir="$optarg" - ;; - --localedir=*) localedir="$optarg" - ;; - --sysconfdir=*) sysconfdir="$optarg" - ;; - --localstatedir=*) local_statedir="$optarg" - ;; - --firmwarepath=*) firmwarepath="$optarg" - ;; --host=*|--build=*|\ --disable-dependency-tracking|\ --sbindir=*|--sharedstatedir=*|\ @@ -1022,23 +1004,6 @@ case $git_submodules_action in ;; esac -libdir="${libdir:-$prefix/lib}" -libexecdir="${libexecdir:-$prefix/libexec}" -includedir="${includedir:-$prefix/include}" - -if test "$mingw32" = "yes" ; then - bindir="${bindir:-$prefix}" -else - bindir="${bindir:-$prefix/bin}" -fi -mandir="${mandir:-$prefix/share/man}" -datadir="${datadir:-$prefix/share}" -docdir="${docdir:-$prefix/share/doc}" -sysconfdir="${sysconfdir:-$prefix/etc}" -local_statedir="${local_statedir:-$prefix/var}" -firmwarepath="${firmwarepath:-$datadir/qemu-firmware}" -localedir="${localedir:-$datadir/locale}" - if eval test -z "\${cross_cc_$cpu}"; then eval "cross_cc_${cpu}=\$cc" cross_cc_vars="$cross_cc_vars cross_cc_${cpu}" @@ -1116,16 +1081,7 @@ Advanced options (experts only): --with-git-submodules=validate fail if git submodules are not up to date --with-git-submodules=ignore do not update or check git submodules (default if no .git dir) --static enable static build [$static] - --mandir=PATH install man pages in PATH - --datadir=PATH install firmware in PATH/$qemu_suffix - --localedir=PATH install translation in PATH/$qemu_suffix - --docdir=PATH install documentation in PATH/$qemu_suffix --bindir=PATH install binaries in PATH - --libdir=PATH install libraries in PATH - --libexecdir=PATH install helper binaries in PATH - --sysconfdir=PATH install config in PATH/$qemu_suffix - --localstatedir=PATH install local state in PATH (set at runtime on win32) - --firmwarepath=PATH search PATH for firmware files --efi-aarch64=PATH PATH of efi file to use for aarch64 VMs. --with-suffix=SUFFIX suffix for QEMU data inside datadir/libdir/sysconfdir/docdir [$qemu_suffix] --without-default-features default all --enable-* options to "disabled" @@ -2410,18 +2366,8 @@ if test "$skip_meson" = no; then run_meson() { NINJA=$ninja $meson setup \ --prefix "$prefix" \ - --libdir "$libdir" \ - --libexecdir "$libexecdir" \ --bindir "$bindir" \ - --includedir "$includedir" \ - --datadir "$datadir" \ - --mandir "$mandir" \ - --sysconfdir "$sysconfdir" \ - --localedir "$localedir" \ - --localstatedir "$local_statedir" \ -Ddefault_devices=$default_devices \ - -Ddocdir="$docdir" \ - -Dqemu_firmwarepath="$firmwarepath" \ -Dqemu_suffix="$qemu_suffix" \ -Dsmbd="$smbd" \ -Doptimization=$(if test "$debug" = yes; then echo 0; else echo 2; fi) \ diff --git a/meson_options.txt b/meson_options.txt index ae6c4b2475..15fe40c700 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -4,9 +4,9 @@ option('qemu_suffix', type : 'string', value: 'qemu', description: 'Suffix for QEMU data/modules/config directories (can be empty)') -option('docdir', type : 'string', value : 'doc', +option('docdir', type : 'string', value : 'share/doc', description: 'Base directory for documentation installation (can be empty)') -option('qemu_firmwarepath', type : 'string', value : '', +option('qemu_firmwarepath', type : 'string', value : 'qemu-firmware', description: 'search PATH for firmware files') option('pkgversion', type : 'string', value : '', description: 'use specified string as sub-version of the package') diff --git a/scripts/meson-buildoptions.py b/scripts/meson-buildoptions.py index 0f9603a7f6..45cda8cd84 100755 --- a/scripts/meson-buildoptions.py +++ b/scripts/meson-buildoptions.py @@ -27,9 +27,7 @@ import sys SKIP_OPTIONS = { "default_devices", - "docdir", "fuzzing_engine", - "qemu_firmwarepath", "qemu_suffix", "smbd", } @@ -37,12 +35,21 @@ SKIP_OPTIONS = { OPTION_NAMES = { "malloc": "enable-malloc", "pkgversion": "with-pkgversion", + "qemu_firmwarepath": "firmwarepath", "trace_backends": "enable-trace-backends", "trace_file": "with-trace-file", } BUILTIN_OPTIONS = { + "datadir", + "includedir", + "libdir", + "libexecdir", + "localedir", + "localstatedir", + "mandir", "strip", + "sysconfdir", } LINE_WIDTH = 76 diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 59c4a27c5a..f6a9b05c40 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -8,8 +8,11 @@ meson_options_help() { printf "%s\n" ' --block-drv-rw-whitelist=VALUE' printf "%s\n" ' set block driver read-write whitelist (by default' printf "%s\n" ' affects only QEMU, not tools like qemu-img)' + printf "%s\n" ' --datadir=VALUE Data file directory [share]' printf "%s\n" ' --disable-coroutine-pool coroutine freelist (better performance)' printf "%s\n" ' --disable-install-blobs install provided firmware blobs' + printf "%s\n" ' --docdir=VALUE Base directory for documentation installation' + printf "%s\n" ' (can be empty) [share/doc]' printf "%s\n" ' --enable-block-drv-whitelist-in-tools' printf "%s\n" ' use block whitelist also in tools instead of only' printf "%s\n" ' QEMU' @@ -40,10 +43,18 @@ meson_options_help() { printf "%s\n" ' --enable-trace-backends=CHOICES' printf "%s\n" ' Set available tracing backends [log] (choices:' printf "%s\n" ' dtrace/ftrace/log/nop/simple/syslog/ust)' + printf "%s\n" ' --firmwarepath=VALUE search PATH for firmware files [qemu-firmware]' printf "%s\n" ' --iasl=VALUE Path to ACPI disassembler' + printf "%s\n" ' --includedir=VALUE Header file directory [include]' printf "%s\n" ' --interp-prefix=VALUE where to find shared libraries etc., use %M for' printf "%s\n" ' cpu name [/usr/gnemul/qemu-%M]' + printf "%s\n" ' --libdir=VALUE Library directory [lib64]' + printf "%s\n" ' --libexecdir=VALUE Library executable directory [libexec]' + printf "%s\n" ' --localedir=VALUE Locale data directory [share/locale]' + printf "%s\n" ' --localstatedir=VALUE Localstate data directory [/var/local]' + printf "%s\n" ' --mandir=VALUE Manual page directory [share/man]' printf "%s\n" ' --sphinx-build=VALUE Use specified sphinx-build for building document' + printf "%s\n" ' --sysconfdir=VALUE Sysconf data directory [etc]' printf "%s\n" ' --tls-priority=VALUE Default TLS protocol/cipher priority string' printf "%s\n" ' [NORMAL]' printf "%s\n" ' --with-pkgversion=VALUE use specified string as sub-version of the' @@ -206,6 +217,7 @@ _meson_option_parse() { --disable-curl) printf "%s" -Dcurl=disabled ;; --enable-curses) printf "%s" -Dcurses=enabled ;; --disable-curses) printf "%s" -Dcurses=disabled ;; + --datadir=*) quote_sh "-Ddatadir=$2" ;; --enable-dbus-display) printf "%s" -Ddbus_display=enabled ;; --disable-dbus-display) printf "%s" -Ddbus_display=disabled ;; --enable-debug-mutex) printf "%s" -Ddebug_mutex=true ;; @@ -214,6 +226,7 @@ _meson_option_parse() { --disable-debug-stack-usage) printf "%s" -Ddebug_stack_usage=false ;; --enable-dmg) printf "%s" -Ddmg=enabled ;; --disable-dmg) printf "%s" -Ddmg=disabled ;; + --docdir=*) quote_sh "-Ddocdir=$2" ;; --enable-docs) printf "%s" -Ddocs=enabled ;; --disable-docs) printf "%s" -Ddocs=disabled ;; --enable-dsound) printf "%s" -Ddsound=enabled ;; @@ -252,6 +265,7 @@ _meson_option_parse() { --iasl=*) quote_sh "-Diasl=$2" ;; --enable-iconv) printf "%s" -Diconv=enabled ;; --disable-iconv) printf "%s" -Diconv=disabled ;; + --includedir=*) quote_sh "-Dincludedir=$2" ;; --enable-install-blobs) printf "%s" -Dinstall_blobs=true ;; --disable-install-blobs) printf "%s" -Dinstall_blobs=false ;; --interp-prefix=*) quote_sh "-Dinterp_prefix=$2" ;; @@ -265,6 +279,8 @@ _meson_option_parse() { --disable-l2tpv3) printf "%s" -Dl2tpv3=disabled ;; --enable-libdaxctl) printf "%s" -Dlibdaxctl=enabled ;; --disable-libdaxctl) printf "%s" -Dlibdaxctl=disabled ;; + --libdir=*) quote_sh "-Dlibdir=$2" ;; + --libexecdir=*) quote_sh "-Dlibexecdir=$2" ;; --enable-libiscsi) printf "%s" -Dlibiscsi=enabled ;; --disable-libiscsi) printf "%s" -Dlibiscsi=disabled ;; --enable-libnfs) printf "%s" -Dlibnfs=enabled ;; @@ -283,6 +299,8 @@ _meson_option_parse() { --disable-linux-io-uring) printf "%s" -Dlinux_io_uring=disabled ;; --enable-live-block-migration) printf "%s" -Dlive_block_migration=enabled ;; --disable-live-block-migration) printf "%s" -Dlive_block_migration=disabled ;; + --localedir=*) quote_sh "-Dlocaledir=$2" ;; + --localstatedir=*) quote_sh "-Dlocalstatedir=$2" ;; --enable-lzfse) printf "%s" -Dlzfse=enabled ;; --disable-lzfse) printf "%s" -Dlzfse=disabled ;; --enable-lzo) printf "%s" -Dlzo=enabled ;; @@ -290,6 +308,7 @@ _meson_option_parse() { --enable-malloc=*) quote_sh "-Dmalloc=$2" ;; --enable-malloc-trim) printf "%s" -Dmalloc_trim=enabled ;; --disable-malloc-trim) printf "%s" -Dmalloc_trim=disabled ;; + --mandir=*) quote_sh "-Dmandir=$2" ;; --enable-membarrier) printf "%s" -Dmembarrier=enabled ;; --disable-membarrier) printf "%s" -Dmembarrier=disabled ;; --enable-module-upgrades) printf "%s" -Dmodule_upgrades=true ;; @@ -325,6 +344,7 @@ _meson_option_parse() { --disable-qcow1) printf "%s" -Dqcow1=disabled ;; --enable-qed) printf "%s" -Dqed=enabled ;; --disable-qed) printf "%s" -Dqed=disabled ;; + --firmwarepath=*) quote_sh "-Dqemu_firmwarepath=$2" ;; --enable-qga-vss) printf "%s" -Dqga_vss=enabled ;; --disable-qga-vss) printf "%s" -Dqga_vss=disabled ;; --enable-qom-cast-debug) printf "%s" -Dqom_cast_debug=true ;; @@ -363,6 +383,7 @@ _meson_option_parse() { --disable-spice-protocol) printf "%s" -Dspice_protocol=disabled ;; --enable-strip) printf "%s" -Dstrip=true ;; --disable-strip) printf "%s" -Dstrip=false ;; + --sysconfdir=*) quote_sh "-Dsysconfdir=$2" ;; --enable-tcg) printf "%s" -Dtcg=enabled ;; --disable-tcg) printf "%s" -Dtcg=disabled ;; --enable-tcg-interpreter) printf "%s" -Dtcg_interpreter=true ;; From c54b59ee0da90dfb169c05e43ebf0c01a7dd5215 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:33:58 +0200 Subject: [PATCH 111/935] meson: pass more options directly as -D MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If an option is not used anywhere by the configure script, it can be just added to $meson_options even if it is not parsed by the automatically generated bits in scripts/meson-buildoptions.sh. The only slightly tricky case is $debug, where the if test "$fortify_source" = "yes" ; then QEMU_CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $QEMU_CFLAGS" debug=no fi assignment is dead; configure sets fortify_source=no whenever debug=yes. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- configure | 39 ++++++++++------------------------- meson.build | 2 +- scripts/meson-buildoptions.py | 4 ++++ scripts/meson-buildoptions.sh | 6 ++++++ 4 files changed, 22 insertions(+), 29 deletions(-) diff --git a/configure b/configure index b8e3176808..fc7868948b 100755 --- a/configure +++ b/configure @@ -235,7 +235,6 @@ static="no" cross_compile="no" cross_prefix="" host_cc="cc" -lto="false" stack_protector="" safe_stack="" use_containers="yes" @@ -291,13 +290,10 @@ vhost_vsock="$default_feature" vhost_user="no" vhost_user_fs="$default_feature" vhost_vdpa="$default_feature" -debug_info="yes" debug_tcg="no" -debug="no" sanitizers="no" tsan="no" fortify_source="yes" -gcov="no" EXESUF="" modules="no" prefix="/usr/local" @@ -327,10 +323,7 @@ else fi fdt="auto" -# 2. Support --with/--without option -default_devices="true" - -# 3. Automatically enable/disable other options +# 2. Automatically enable/disable other options tcg="enabled" cfi="false" @@ -680,6 +673,9 @@ werror="" . $source_path/scripts/meson-buildoptions.sh meson_options= +meson_option_add() { + meson_options="$meson_options $(quote_sh "$1")" +} meson_option_parse() { meson_options="$meson_options $(_meson_option_parse "$@")" if test $? -eq 1; then @@ -732,9 +728,9 @@ for opt do ;; --cross-cc-*) ;; - --enable-debug-info) debug_info="yes" + --enable-debug-info) meson_option_add -Ddebug=true ;; - --disable-debug-info) debug_info="no" + --disable-debug-info) meson_option_add -Ddebug=false ;; --enable-modules) modules="yes" @@ -754,9 +750,9 @@ for opt do error_exit "Can't mix --target-list-exclude with --target-list" fi ;; - --with-default-devices) default_devices="true" + --with-default-devices) meson_option_add -Ddefault_devices=true ;; - --without-default-devices) default_devices="false" + --without-default-devices) meson_option_add -Ddefault_devices=false ;; --with-devices-*[!a-zA-Z0-9_-]*=*) error_exit "Passed bad --with-devices-FOO option" ;; @@ -772,8 +768,6 @@ for opt do ;; --without-default-features) # processed above ;; - --enable-gcov) gcov="yes" - ;; --static) static="yes" QEMU_PKG_CONFIG_FLAGS="--static $QEMU_PKG_CONFIG_FLAGS" @@ -800,7 +794,7 @@ for opt do # Enable debugging options that aren't excessively noisy debug_tcg="yes" meson_option_parse --enable-debug-mutex "" - debug="yes" + meson_option_add -Doptimization=0 fortify_source="no" ;; --enable-sanitizers) sanitizers="yes" @@ -849,10 +843,6 @@ for opt do ;; --disable-werror) werror="no" ;; - --enable-lto) lto="true" - ;; - --disable-lto) lto="false" - ;; --enable-stack-protector) stack_protector="yes" ;; --disable-stack-protector) stack_protector="no" @@ -863,7 +853,7 @@ for opt do ;; --enable-cfi) cfi="true"; - lto="true"; + meson_option_add -Db_lto=true ;; --disable-cfi) cfi="false" ;; @@ -1101,7 +1091,6 @@ Advanced options (experts only): --cpu=CPU Build for host CPU [$cpu] --with-coroutine=BACKEND coroutine backend. Supported options: ucontext, sigaltstack, windows - --enable-gcov enable test coverage analysis with gcov --enable-plugins enable plugins via shared library loading --disable-containers don't use containers for cross-building @@ -1117,7 +1106,6 @@ cat << EOF modules modules support (non-Windows) debug-tcg TCG debugging (default is disabled) debug-info debugging information - lto Enable Link-Time Optimization. safe-stack SafeStack Stack Smash Protection. Depends on clang/llvm >= 3.7 and requires coroutine backend ucontext. vhost-net vhost-net kernel acceleration support @@ -1938,7 +1926,6 @@ write_c_skeleton if test "$fortify_source" = "yes" ; then QEMU_CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $QEMU_CFLAGS" - debug=no fi case "$ARCH" in @@ -2367,15 +2354,11 @@ if test "$skip_meson" = no; then NINJA=$ninja $meson setup \ --prefix "$prefix" \ --bindir "$bindir" \ - -Ddefault_devices=$default_devices \ -Dqemu_suffix="$qemu_suffix" \ -Dsmbd="$smbd" \ - -Doptimization=$(if test "$debug" = yes; then echo 0; else echo 2; fi) \ - -Ddebug=$(if test "$debug_info" = yes; then echo true; else echo false; fi) \ -Dwerror=$(if test "$werror" = yes; then echo true; else echo false; fi) \ -Db_pie=$(if test "$pie" = yes; then echo true; else echo false; fi) \ - -Db_coverage=$(if test "$gcov" = yes; then echo true; else echo false; fi) \ - -Db_lto=$lto -Dcfi=$cfi -Dtcg=$tcg \ + -Dcfi=$cfi -Dtcg=$tcg \ -Dcapstone=$capstone -Dfdt=$fdt -Dslirp=$slirp \ $(test -n "${LIB_FUZZING_ENGINE+xxx}" && echo "-Dfuzzing_engine=$LIB_FUZZING_ENGINE") \ $(if test "$default_feature" = no; then echo "-Dauto_features=disabled"; fi) \ diff --git a/meson.build b/meson.build index 65c44ea010..44f3ca3218 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('qemu', ['c'], meson_version: '>=0.59.3', default_options: ['warning_level=1', 'c_std=gnu11', 'cpp_std=gnu++11', 'b_colorout=auto', - 'b_staticpic=false', 'stdsplit=false'], + 'b_staticpic=false', 'stdsplit=false', 'optimization=2'], version: files('VERSION')) add_test_setup('quick', exclude_suites: ['slow', 'thorough'], is_default: true) diff --git a/scripts/meson-buildoptions.py b/scripts/meson-buildoptions.py index 45cda8cd84..e624c16b01 100755 --- a/scripts/meson-buildoptions.py +++ b/scripts/meson-buildoptions.py @@ -33,6 +33,8 @@ SKIP_OPTIONS = { } OPTION_NAMES = { + "b_coverage": "gcov", + "b_lto": "lto", "malloc": "enable-malloc", "pkgversion": "with-pkgversion", "qemu_firmwarepath": "firmwarepath", @@ -41,6 +43,8 @@ OPTION_NAMES = { } BUILTIN_OPTIONS = { + "b_coverage", + "b_lto", "datadir", "includedir", "libdir", diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index f6a9b05c40..4b0770a9e0 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -27,7 +27,9 @@ meson_options_help() { printf "%s\n" ' --enable-fdt[=CHOICE] Whether and how to find the libfdt library' printf "%s\n" ' (choices: auto/disabled/enabled/internal/system)' printf "%s\n" ' --enable-fuzzing build fuzzing targets' + printf "%s\n" ' --enable-gcov Enable coverage tracking.' printf "%s\n" ' --enable-gprof QEMU profiling with gprof' + printf "%s\n" ' --enable-lto Use link time optimization' printf "%s\n" ' --enable-malloc=CHOICE choose memory allocator to use [system] (choices:' printf "%s\n" ' jemalloc/system/tcmalloc)' printf "%s\n" ' --enable-module-upgrades try to load modules from alternate paths for' @@ -182,6 +184,10 @@ _meson_option_parse() { --disable-avx2) printf "%s" -Davx2=disabled ;; --enable-avx512f) printf "%s" -Davx512f=enabled ;; --disable-avx512f) printf "%s" -Davx512f=disabled ;; + --enable-gcov) printf "%s" -Db_coverage=true ;; + --disable-gcov) printf "%s" -Db_coverage=false ;; + --enable-lto) printf "%s" -Db_lto=true ;; + --disable-lto) printf "%s" -Db_lto=false ;; --block-drv-ro-whitelist=*) quote_sh "-Dblock_drv_ro_whitelist=$2" ;; --block-drv-rw-whitelist=*) quote_sh "-Dblock_drv_rw_whitelist=$2" ;; --enable-block-drv-whitelist-in-tools) printf "%s" -Dblock_drv_whitelist_in_tools=true ;; From 0a31e3a0a00f7cd3d1d7e8885a9b1f979fed3c20 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:33:59 +0200 Subject: [PATCH 112/935] configure: omit options with default values from meson command line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This has no functional change, it only makes the command line shorter and nicer. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- configure | 29 +++++++++++++++++------------ meson.build | 2 +- meson_options.txt | 2 +- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/configure b/configure index fc7868948b..1c88e697c5 100755 --- a/configure +++ b/configure @@ -2350,19 +2350,24 @@ if test "$skip_meson" = no; then mv $cross config-meson.cross rm -rf meson-private meson-info meson-logs + + # Built-in options + test "$bindir" != "bin" && meson_option_add "-Dbindir=$bindir" + test "$default_feature" = no && meson_option_add -Dauto_features=disabled + test "$pie" = no && meson_option_add -Db_pie=false + test "$werror" = yes && meson_option_add -Dwerror=true + + # QEMU options + test "$capstone" != auto && meson_option_add "-Dcapstone=$capstone" + test "$cfi" != false && meson_option_add "-Dcfi=$cfi" + test "$fdt" != auto && meson_option_add "-Dfdt=$fdt" + test -n "${LIB_FUZZING_ENGINE+xxx}" && meson_option_add "-Dfuzzing_engine=$LIB_FUZZING_ENGINE" + test "$qemu_suffix" != qemu && meson_option_add "-Dqemu_suffix=$qemu_suffix" + test "$slirp" != auto && meson_option_add "-Dslirp=$slirp" + test "$smbd" != '' && meson_option_add "-Dsmbd=$smbd" + test "$tcg" != enabled && meson_option_add "-Dtcg=$tcg" run_meson() { - NINJA=$ninja $meson setup \ - --prefix "$prefix" \ - --bindir "$bindir" \ - -Dqemu_suffix="$qemu_suffix" \ - -Dsmbd="$smbd" \ - -Dwerror=$(if test "$werror" = yes; then echo true; else echo false; fi) \ - -Db_pie=$(if test "$pie" = yes; then echo true; else echo false; fi) \ - -Dcfi=$cfi -Dtcg=$tcg \ - -Dcapstone=$capstone -Dfdt=$fdt -Dslirp=$slirp \ - $(test -n "${LIB_FUZZING_ENGINE+xxx}" && echo "-Dfuzzing_engine=$LIB_FUZZING_ENGINE") \ - $(if test "$default_feature" = no; then echo "-Dauto_features=disabled"; fi) \ - "$@" $cross_arg "$PWD" "$source_path" + NINJA=$ninja $meson setup --prefix "$prefix" "$@" $cross_arg "$PWD" "$source_path" } eval run_meson $meson_options if test "$?" -ne 0 ; then diff --git a/meson.build b/meson.build index 44f3ca3218..215be030d1 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('qemu', ['c'], meson_version: '>=0.59.3', default_options: ['warning_level=1', 'c_std=gnu11', 'cpp_std=gnu++11', 'b_colorout=auto', - 'b_staticpic=false', 'stdsplit=false', 'optimization=2'], + 'b_staticpic=false', 'stdsplit=false', 'optimization=2', 'b_pie=true'], version: files('VERSION')) add_test_setup('quick', exclude_suites: ['slow', 'thorough'], is_default: true) diff --git a/meson_options.txt b/meson_options.txt index 15fe40c700..35f5a72507 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -78,7 +78,7 @@ option('xen', type: 'feature', value: 'auto', description: 'Xen backend support') option('xen_pci_passthrough', type: 'feature', value: 'auto', description: 'Xen PCI passthrough support') -option('tcg', type: 'feature', value: 'auto', +option('tcg', type: 'feature', value: 'enabled', description: 'TCG support') option('tcg_interpreter', type: 'boolean', value: false, description: 'TCG with bytecode interpreter (slow)') From 10925d06173e076ed80f3108a8a9ed15a8b5b4ab Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:34:00 +0200 Subject: [PATCH 113/935] meson, virtio: place all virtio-pci devices under virtio_pci_ss MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since a sourceset already exists for this, avoid unnecessary repeat of CONFIG_VIRTIO_PCI. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- hw/virtio/meson.build | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index 67dc77e00f..f371404b04 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -16,9 +16,7 @@ virtio_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user.c')) virtio_ss.add(when: 'CONFIG_VHOST_VDPA', if_true: files('vhost-shadow-virtqueue.c', 'vhost-vdpa.c')) virtio_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon.c')) virtio_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto.c')) -virtio_ss.add(when: ['CONFIG_VIRTIO_CRYPTO', 'CONFIG_VIRTIO_PCI'], if_true: files('virtio-crypto-pci.c')) virtio_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs.c')) -virtio_ss.add(when: ['CONFIG_VHOST_USER_FS', 'CONFIG_VIRTIO_PCI'], if_true: files('vhost-user-fs-pci.c')) virtio_ss.add(when: 'CONFIG_VIRTIO_PMEM', if_true: files('virtio-pmem.c')) virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock.c', 'vhost-vsock-common.c')) virtio_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-vsock.c', 'vhost-vsock-common.c')) @@ -26,17 +24,20 @@ virtio_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng.c')) virtio_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: files('virtio-iommu.c')) virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem.c')) virtio_ss.add(when: 'CONFIG_VHOST_USER_I2C', if_true: files('vhost-user-i2c.c')) -virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_I2C'], if_true: files('vhost-user-i2c-pci.c')) virtio_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng.c')) -virtio_ss.add(when: ['CONFIG_VHOST_USER_RNG', 'CONFIG_VIRTIO_PCI'], if_true: files('vhost-user-rng-pci.c')) virtio_pci_ss = ss.source_set() virtio_pci_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-vsock-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk-pci.c')) +virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_I2C', if_true: files('vhost-user-i2c-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_INPUT', if_true: files('vhost-user-input-pci.c')) +virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_SCSI', if_true: files('vhost-user-scsi-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VHOST_SCSI', if_true: files('vhost-scsi-pci.c')) +virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs-pci.c')) + +virtio_pci_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VIRTIO_INPUT_HOST', if_true: files('virtio-input-host-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VIRTIO_INPUT', if_true: files('virtio-input-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng-pci.c')) From 5e7b5ebaec4c2bcc2754ab1e8ac5a05b88fef073 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:34:01 +0200 Subject: [PATCH 114/935] configure: simplify vhost-net-{user, vdpa} configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleanup to ease review of the conversion to meson. vhost_net_user and vhost_net_vdpa are never assigned anything in the command line parsing loop, so they are always equal to $vhost_user and $vhost_vdpa. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- configure | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/configure b/configure index 1c88e697c5..d6ddd4f05f 100755 --- a/configure +++ b/configure @@ -1555,10 +1555,6 @@ if test "$vhost_vsock" = "yes" && test "$vhost_kernel" != "yes"; then fi # vhost-user backends -test "$vhost_net_user" = "" && vhost_net_user=$vhost_user -if test "$vhost_net_user" = "yes" && test "$vhost_user" = "no"; then - error_exit "--enable-vhost-net-user requires --enable-vhost-user" -fi test "$vhost_crypto" = "" && vhost_crypto=$vhost_user if test "$vhost_crypto" = "yes" && test "$vhost_user" = "no"; then error_exit "--enable-vhost-crypto requires --enable-vhost-user" @@ -1567,16 +1563,11 @@ test "$vhost_user_fs" = "" && vhost_user_fs=$vhost_user if test "$vhost_user_fs" = "yes" && test "$vhost_user" = "no"; then error_exit "--enable-vhost-user-fs requires --enable-vhost-user" fi -#vhost-vdpa backends -test "$vhost_net_vdpa" = "" && vhost_net_vdpa=$vhost_vdpa -if test "$vhost_net_vdpa" = "yes" && test "$vhost_vdpa" = "no"; then - error_exit "--enable-vhost-net-vdpa requires --enable-vhost-vdpa" -fi # OR the vhost-kernel, vhost-vdpa and vhost-user values for simplicity if test "$vhost_net" = ""; then - test "$vhost_net_user" = "yes" && vhost_net=yes - test "$vhost_net_vdpa" = "yes" && vhost_net=yes + test "$vhost_user" = "yes" && vhost_net=yes + test "$vhost_vdpa" = "yes" && vhost_net=yes test "$vhost_kernel" = "yes" && vhost_net=yes fi @@ -2105,10 +2096,10 @@ fi if test "$vhost_net" = "yes" ; then echo "CONFIG_VHOST_NET=y" >> $config_host_mak fi -if test "$vhost_net_user" = "yes" ; then +if test "$vhost_user" = "yes" ; then echo "CONFIG_VHOST_NET_USER=y" >> $config_host_mak fi -if test "$vhost_net_vdpa" = "yes" ; then +if test "$vhost_vdpa" = "yes" ; then echo "CONFIG_VHOST_NET_VDPA=y" >> $config_host_mak fi if test "$vhost_crypto" = "yes" ; then From 9972ae314fc38b7e47ee7ccdbc8556b7cad8a930 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:34:02 +0200 Subject: [PATCH 115/935] build: move vhost-vsock configuration to Kconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vhost-vsock and vhost-user-vsock are two devices of their own; it should be possible to enable/disable them with --without-default-devices, not --without-default-features. Compute their default value in Kconfig to obtain the more intuitive behavior. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- configure | 16 ---------------- hw/virtio/Kconfig | 10 ++++++++++ meson.build | 1 - scripts/ci/org.centos/stream/8/x86_64/configure | 2 -- 4 files changed, 10 insertions(+), 19 deletions(-) diff --git a/configure b/configure index d6ddd4f05f..603434fc7f 100755 --- a/configure +++ b/configure @@ -286,7 +286,6 @@ vhost_kernel="$default_feature" vhost_net="$default_feature" vhost_crypto="$default_feature" vhost_scsi="$default_feature" -vhost_vsock="$default_feature" vhost_user="no" vhost_user_fs="$default_feature" vhost_vdpa="$default_feature" @@ -879,10 +878,6 @@ for opt do ;; --enable-vhost-scsi) vhost_scsi="yes" ;; - --disable-vhost-vsock) vhost_vsock="no" - ;; - --enable-vhost-vsock) vhost_vsock="yes" - ;; --disable-vhost-user-fs) vhost_user_fs="no" ;; --enable-vhost-user-fs) vhost_user_fs="yes" @@ -1109,7 +1104,6 @@ cat << EOF safe-stack SafeStack Stack Smash Protection. Depends on clang/llvm >= 3.7 and requires coroutine backend ucontext. vhost-net vhost-net kernel acceleration support - vhost-vsock virtio sockets device support vhost-scsi vhost-scsi kernel target support vhost-crypto vhost-user-crypto backend support vhost-kernel vhost kernel backend support @@ -1549,10 +1543,6 @@ test "$vhost_scsi" = "" && vhost_scsi=$vhost_kernel if test "$vhost_scsi" = "yes" && test "$vhost_kernel" != "yes"; then error_exit "--enable-vhost-scsi requires --enable-vhost-kernel" fi -test "$vhost_vsock" = "" && vhost_vsock=$vhost_kernel -if test "$vhost_vsock" = "yes" && test "$vhost_kernel" != "yes"; then - error_exit "--enable-vhost-vsock requires --enable-vhost-kernel" -fi # vhost-user backends test "$vhost_crypto" = "" && vhost_crypto=$vhost_user @@ -2105,12 +2095,6 @@ fi if test "$vhost_crypto" = "yes" ; then echo "CONFIG_VHOST_CRYPTO=y" >> $config_host_mak fi -if test "$vhost_vsock" = "yes" ; then - echo "CONFIG_VHOST_VSOCK=y" >> $config_host_mak - if test "$vhost_user" = "yes" ; then - echo "CONFIG_VHOST_USER_VSOCK=y" >> $config_host_mak - fi -fi if test "$vhost_kernel" = "yes" ; then echo "CONFIG_VHOST_KERNEL=y" >> $config_host_mak fi diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig index c144d42f9b..b642ae1081 100644 --- a/hw/virtio/Kconfig +++ b/hw/virtio/Kconfig @@ -59,6 +59,16 @@ config VIRTIO_MEM depends on VIRTIO_MEM_SUPPORTED select MEM_DEVICE +config VHOST_VSOCK + bool + default y + depends on VIRTIO && VHOST_KERNEL + +config VHOST_USER_VSOCK + bool + default y + depends on VIRTIO && VHOST_USER + config VHOST_USER_I2C bool default y diff --git a/meson.build b/meson.build index 215be030d1..fd7d529a8e 100644 --- a/meson.build +++ b/meson.build @@ -3692,7 +3692,6 @@ summary_info += {'vhost-kernel support': config_host.has_key('CONFIG_VHOST_KERNE summary_info += {'vhost-net support': config_host.has_key('CONFIG_VHOST_NET')} summary_info += {'vhost-crypto support': config_host.has_key('CONFIG_VHOST_CRYPTO')} summary_info += {'vhost-scsi support': config_host.has_key('CONFIG_VHOST_SCSI')} -summary_info += {'vhost-vsock support': config_host.has_key('CONFIG_VHOST_VSOCK')} summary_info += {'vhost-user support': config_host.has_key('CONFIG_VHOST_USER')} summary_info += {'vhost-user-blk server support': have_vhost_user_blk_server} summary_info += {'vhost-user-fs support': config_host.has_key('CONFIG_VHOST_USER_FS')} diff --git a/scripts/ci/org.centos/stream/8/x86_64/configure b/scripts/ci/org.centos/stream/8/x86_64/configure index 08225ee514..e6ac2e5877 100755 --- a/scripts/ci/org.centos/stream/8/x86_64/configure +++ b/scripts/ci/org.centos/stream/8/x86_64/configure @@ -136,7 +136,6 @@ --disable-vhost-user \ --disable-vhost-user-blk-server \ --disable-vhost-vdpa \ ---disable-vhost-vsock \ --disable-virglrenderer \ --disable-virtfs \ --disable-virtiofsd \ @@ -198,7 +197,6 @@ --enable-vhost-user \ --enable-vhost-user-blk-server \ --enable-vhost-vdpa \ ---enable-vhost-vsock \ --enable-vnc \ --enable-png \ --enable-vnc-sasl \ From d13b200253cbd9cb933a1cfead9106abd564ae4a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:34:03 +0200 Subject: [PATCH 116/935] build: move vhost-scsi configuration to Kconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vhost-scsi and vhost-user-scsi are two devices of their own; it should be possible to enable/disable them with --without-default-devices, not --without-default-features. Compute their default value in Kconfig to obtain the more intuitive behavior. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- configure | 15 --------------- hw/scsi/Kconfig | 5 +++++ include/hw/virtio/virtio-scsi.h | 2 -- meson.build | 1 - scripts/ci/org.centos/stream/8/x86_64/configure | 1 - 5 files changed, 5 insertions(+), 19 deletions(-) diff --git a/configure b/configure index 603434fc7f..d268a9cf49 100755 --- a/configure +++ b/configure @@ -285,7 +285,6 @@ EXTRA_LDFLAGS="" vhost_kernel="$default_feature" vhost_net="$default_feature" vhost_crypto="$default_feature" -vhost_scsi="$default_feature" vhost_user="no" vhost_user_fs="$default_feature" vhost_vdpa="$default_feature" @@ -874,10 +873,6 @@ for opt do ;; --enable-vhost-crypto) vhost_crypto="yes" ;; - --disable-vhost-scsi) vhost_scsi="no" - ;; - --enable-vhost-scsi) vhost_scsi="yes" - ;; --disable-vhost-user-fs) vhost_user_fs="no" ;; --enable-vhost-user-fs) vhost_user_fs="yes" @@ -1104,7 +1099,6 @@ cat << EOF safe-stack SafeStack Stack Smash Protection. Depends on clang/llvm >= 3.7 and requires coroutine backend ucontext. vhost-net vhost-net kernel acceleration support - vhost-scsi vhost-scsi kernel target support vhost-crypto vhost-user-crypto backend support vhost-kernel vhost kernel backend support vhost-user vhost-user backend support @@ -1538,12 +1532,6 @@ if test "$vhost_kernel" = "yes" && test "$linux" != "yes"; then error_exit "vhost-kernel is only available on Linux" fi -# vhost-kernel devices -test "$vhost_scsi" = "" && vhost_scsi=$vhost_kernel -if test "$vhost_scsi" = "yes" && test "$vhost_kernel" != "yes"; then - error_exit "--enable-vhost-scsi requires --enable-vhost-kernel" -fi - # vhost-user backends test "$vhost_crypto" = "" && vhost_crypto=$vhost_user if test "$vhost_crypto" = "yes" && test "$vhost_user" = "no"; then @@ -2080,9 +2068,6 @@ if test "$modules" = "yes"; then echo "CONFIG_MODULES=y" >> $config_host_mak fi -if test "$vhost_scsi" = "yes" ; then - echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak -fi if test "$vhost_net" = "yes" ; then echo "CONFIG_VHOST_NET=y" >> $config_host_mak fi diff --git a/hw/scsi/Kconfig b/hw/scsi/Kconfig index 77d397c949..e7b34dc8e2 100644 --- a/hw/scsi/Kconfig +++ b/hw/scsi/Kconfig @@ -48,6 +48,11 @@ config VIRTIO_SCSI depends on VIRTIO select SCSI +config VHOST_SCSI + bool + default y + depends on VIRTIO && VHOST_KERNEL + config VHOST_USER_SCSI bool # Only PCI devices are provided for now diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 543681bc18..0997313f0a 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -55,10 +55,8 @@ struct VirtIOSCSIConf { bool seg_max_adjust; uint32_t max_sectors; uint32_t cmd_per_lun; -#ifdef CONFIG_VHOST_SCSI char *vhostfd; char *wwpn; -#endif CharBackend chardev; uint32_t boot_tpgt; IOThread *iothread; diff --git a/meson.build b/meson.build index fd7d529a8e..d56dd70cb7 100644 --- a/meson.build +++ b/meson.build @@ -3691,7 +3691,6 @@ summary_info += {'QOM debugging': get_option('qom_cast_debug')} summary_info += {'vhost-kernel support': config_host.has_key('CONFIG_VHOST_KERNEL')} summary_info += {'vhost-net support': config_host.has_key('CONFIG_VHOST_NET')} summary_info += {'vhost-crypto support': config_host.has_key('CONFIG_VHOST_CRYPTO')} -summary_info += {'vhost-scsi support': config_host.has_key('CONFIG_VHOST_SCSI')} summary_info += {'vhost-user support': config_host.has_key('CONFIG_VHOST_USER')} summary_info += {'vhost-user-blk server support': have_vhost_user_blk_server} summary_info += {'vhost-user-fs support': config_host.has_key('CONFIG_VHOST_USER_FS')} diff --git a/scripts/ci/org.centos/stream/8/x86_64/configure b/scripts/ci/org.centos/stream/8/x86_64/configure index e6ac2e5877..a7f92aff90 100755 --- a/scripts/ci/org.centos/stream/8/x86_64/configure +++ b/scripts/ci/org.centos/stream/8/x86_64/configure @@ -132,7 +132,6 @@ --disable-vhost-crypto \ --disable-vhost-kernel \ --disable-vhost-net \ ---disable-vhost-scsi \ --disable-vhost-user \ --disable-vhost-user-blk-server \ --disable-vhost-vdpa \ From 5166dabf4fe4c33e9595b0aaf2c03ccf411199e2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:34:04 +0200 Subject: [PATCH 117/935] build: move vhost-user-fs configuration to Kconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vhost-user-fs is a device and it should be possible to enable/disable it with --without-default-devices, not --without-default-features. Compute its default value in Kconfig to obtain the more intuitive behavior. In this case the configure options were undocumented, too. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- configure | 12 ------------ hw/virtio/Kconfig | 5 +++++ meson.build | 1 - 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/configure b/configure index d268a9cf49..9a83d64c9d 100755 --- a/configure +++ b/configure @@ -286,7 +286,6 @@ vhost_kernel="$default_feature" vhost_net="$default_feature" vhost_crypto="$default_feature" vhost_user="no" -vhost_user_fs="$default_feature" vhost_vdpa="$default_feature" debug_tcg="no" sanitizers="no" @@ -873,10 +872,6 @@ for opt do ;; --enable-vhost-crypto) vhost_crypto="yes" ;; - --disable-vhost-user-fs) vhost_user_fs="no" - ;; - --enable-vhost-user-fs) vhost_user_fs="yes" - ;; --disable-zlib-test) ;; --disable-virtio-blk-data-plane|--enable-virtio-blk-data-plane) @@ -1537,10 +1532,6 @@ test "$vhost_crypto" = "" && vhost_crypto=$vhost_user if test "$vhost_crypto" = "yes" && test "$vhost_user" = "no"; then error_exit "--enable-vhost-crypto requires --enable-vhost-user" fi -test "$vhost_user_fs" = "" && vhost_user_fs=$vhost_user -if test "$vhost_user_fs" = "yes" && test "$vhost_user" = "no"; then - error_exit "--enable-vhost-user-fs requires --enable-vhost-user" -fi # OR the vhost-kernel, vhost-vdpa and vhost-user values for simplicity if test "$vhost_net" = ""; then @@ -2089,9 +2080,6 @@ fi if test "$vhost_vdpa" = "yes" ; then echo "CONFIG_VHOST_VDPA=y" >> $config_host_mak fi -if test "$vhost_user_fs" = "yes" ; then - echo "CONFIG_VHOST_USER_FS=y" >> $config_host_mak -fi # XXX: suppress that if [ "$bsd" = "yes" ] ; then diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig index b642ae1081..f8e235f814 100644 --- a/hw/virtio/Kconfig +++ b/hw/virtio/Kconfig @@ -78,3 +78,8 @@ config VHOST_USER_RNG bool default y depends on VIRTIO && VHOST_USER + +config VHOST_USER_FS + bool + default y + depends on VIRTIO && VHOST_USER diff --git a/meson.build b/meson.build index d56dd70cb7..aba7167544 100644 --- a/meson.build +++ b/meson.build @@ -3693,7 +3693,6 @@ summary_info += {'vhost-net support': config_host.has_key('CONFIG_VHOST_NET')} summary_info += {'vhost-crypto support': config_host.has_key('CONFIG_VHOST_CRYPTO')} summary_info += {'vhost-user support': config_host.has_key('CONFIG_VHOST_USER')} summary_info += {'vhost-user-blk server support': have_vhost_user_blk_server} -summary_info += {'vhost-user-fs support': config_host.has_key('CONFIG_VHOST_USER_FS')} summary_info += {'vhost-vdpa support': config_host.has_key('CONFIG_VHOST_VDPA')} summary_info += {'build guest agent': have_ga} summary(summary_info, bool_yn: true, section: 'Configurable features') From 2a3129a37652e5e81d12f6e16dd3c447f09831f9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:34:05 +0200 Subject: [PATCH 118/935] meson: create have_vhost_* variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using Meson options rather than config-host.h, the "when" clauses have to be changed to if statements (which is not necessarily great, though at least it highlights which parts of the build are per-target and which are not). Do that before moving vhost logic to meson.build, though for now the variables are just based on config-host.mak data. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- meson.build | 31 ++++++++++++++++++++----------- tests/meson.build | 2 +- tools/meson.build | 2 +- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/meson.build b/meson.build index aba7167544..108292e50f 100644 --- a/meson.build +++ b/meson.build @@ -312,6 +312,15 @@ have_tpm = get_option('tpm') \ .require(targetos != 'windows', error_message: 'TPM emulation only available on POSIX systems') \ .allowed() +# vhost +have_vhost_user = 'CONFIG_VHOST_USER' in config_host +have_vhost_vdpa = 'CONFIG_VHOST_VDPA' in config_host +have_vhost_kernel = 'CONFIG_VHOST_KERNEL' in config_host +have_vhost_net_user = 'CONFIG_VHOST_NET_USER' in config_host +have_vhost_net_vdpa = 'CONFIG_VHOST_NET_VDPA' in config_host +have_vhost_net = 'CONFIG_VHOST_NET' in config_host +have_vhost_user_crypto = 'CONFIG_VHOST_CRYPTO' in config_host + # Target-specific libraries and flags libm = cc.find_library('m', required: false) threads = dependency('threads') @@ -1442,7 +1451,7 @@ has_statx_mnt_id = cc.links(statx_mnt_id_test) have_vhost_user_blk_server = get_option('vhost_user_blk_server') \ .require(targetos == 'linux', error_message: 'vhost_user_blk_server requires linux') \ - .require('CONFIG_VHOST_USER' in config_host, + .require(have_vhost_user, error_message: 'vhost_user_blk_server requires vhost-user support') \ .disable_auto_if(not have_system) \ .allowed() @@ -2297,9 +2306,9 @@ host_kconfig = \ (have_ivshmem ? ['CONFIG_IVSHMEM=y'] : []) + \ (opengl.found() ? ['CONFIG_OPENGL=y'] : []) + \ (x11.found() ? ['CONFIG_X11=y'] : []) + \ - ('CONFIG_VHOST_USER' in config_host ? ['CONFIG_VHOST_USER=y'] : []) + \ - ('CONFIG_VHOST_VDPA' in config_host ? ['CONFIG_VHOST_VDPA=y'] : []) + \ - ('CONFIG_VHOST_KERNEL' in config_host ? ['CONFIG_VHOST_KERNEL=y'] : []) + \ + (have_vhost_user ? ['CONFIG_VHOST_USER=y'] : []) + \ + (have_vhost_vdpa ? ['CONFIG_VHOST_VDPA=y'] : []) + \ + (have_vhost_kernel ? ['CONFIG_VHOST_KERNEL=y'] : []) + \ (have_virtfs ? ['CONFIG_VIRTFS=y'] : []) + \ ('CONFIG_LINUX' in config_host ? ['CONFIG_LINUX=y'] : []) + \ (have_pvrdma ? ['CONFIG_PVRDMA=y'] : []) + \ @@ -2981,7 +2990,7 @@ if have_system or have_user endif vhost_user = not_found -if targetos == 'linux' and 'CONFIG_VHOST_USER' in config_host +if targetos == 'linux' and have_vhost_user libvhost_user = subproject('libvhost-user') vhost_user = libvhost_user.get_variable('vhost_user_dep') endif @@ -3562,7 +3571,7 @@ if have_tools dependencies: qemuutil, install: true) - if 'CONFIG_VHOST_USER' in config_host + if have_vhost_user subdir('contrib/vhost-user-blk') subdir('contrib/vhost-user-gpu') subdir('contrib/vhost-user-input') @@ -3688,12 +3697,12 @@ if 'simple' in get_option('trace_backends') endif summary_info += {'D-Bus display': dbus_display} summary_info += {'QOM debugging': get_option('qom_cast_debug')} -summary_info += {'vhost-kernel support': config_host.has_key('CONFIG_VHOST_KERNEL')} -summary_info += {'vhost-net support': config_host.has_key('CONFIG_VHOST_NET')} -summary_info += {'vhost-crypto support': config_host.has_key('CONFIG_VHOST_CRYPTO')} -summary_info += {'vhost-user support': config_host.has_key('CONFIG_VHOST_USER')} +summary_info += {'vhost-kernel support': have_vhost_kernel} +summary_info += {'vhost-net support': have_vhost_net} +summary_info += {'vhost-user support': have_vhost_user} +summary_info += {'vhost-user-crypto support': have_vhost_user_crypto} summary_info += {'vhost-user-blk server support': have_vhost_user_blk_server} -summary_info += {'vhost-vdpa support': config_host.has_key('CONFIG_VHOST_VDPA')} +summary_info += {'vhost-vdpa support': have_vhost_vdpa} summary_info += {'build guest agent': have_ga} summary(summary_info, bool_yn: true, section: 'Configurable features') diff --git a/tests/meson.build b/tests/meson.build index 4f691e8465..8e318ec513 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -68,7 +68,7 @@ test_deps = { 'test-qht-par': qht_bench, } -if have_tools and 'CONFIG_VHOST_USER' in config_host and 'CONFIG_LINUX' in config_host +if have_tools and have_vhost_user and 'CONFIG_LINUX' in config_host executable('vhost-user-bridge', sources: files('vhost-user-bridge.c'), dependencies: [qemuutil, vhost_user]) diff --git a/tools/meson.build b/tools/meson.build index 46977af84f..10eb3a043f 100644 --- a/tools/meson.build +++ b/tools/meson.build @@ -3,7 +3,7 @@ have_virtiofsd = get_option('virtiofsd') \ error_message: 'virtiofsd requires Linux') \ .require(seccomp.found() and libcap_ng.found(), error_message: 'virtiofsd requires libcap-ng-devel and seccomp-devel') \ - .require('CONFIG_VHOST_USER' in config_host, + .require(have_vhost_user, error_message: 'virtiofsd needs vhost-user-support') \ .disable_auto_if(not have_tools and not have_system) \ .allowed() From 43b6d7ee1fbc5b5fb7c85d8131fdac1863214ad6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:34:06 +0200 Subject: [PATCH 119/935] meson: use have_vhost_* variables to pick sources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- Kconfig.host | 3 --- backends/meson.build | 8 ++++++-- hw/net/meson.build | 8 ++++++-- hw/virtio/Kconfig | 3 --- hw/virtio/meson.build | 25 ++++++++++++++++--------- meson.build | 1 + net/meson.build | 12 +++++++----- tests/qtest/meson.build | 4 +++- 8 files changed, 39 insertions(+), 25 deletions(-) diff --git a/Kconfig.host b/Kconfig.host index 60b9c07b5e..1165c4eacd 100644 --- a/Kconfig.host +++ b/Kconfig.host @@ -22,15 +22,12 @@ config TPM config VHOST_USER bool - select VHOST config VHOST_VDPA bool - select VHOST config VHOST_KERNEL bool - select VHOST config VIRTFS bool diff --git a/backends/meson.build b/backends/meson.build index 535c3ca7dd..b1884a88ec 100644 --- a/backends/meson.build +++ b/backends/meson.build @@ -12,9 +12,13 @@ softmmu_ss.add([files( softmmu_ss.add(when: 'CONFIG_POSIX', if_true: files('rng-random.c')) softmmu_ss.add(when: 'CONFIG_POSIX', if_true: files('hostmem-file.c')) softmmu_ss.add(when: 'CONFIG_LINUX', if_true: files('hostmem-memfd.c')) -softmmu_ss.add(when: ['CONFIG_VHOST_USER', 'CONFIG_VIRTIO'], if_true: files('vhost-user.c')) +if have_vhost_user + softmmu_ss.add(when: 'CONFIG_VIRTIO', if_true: files('vhost-user.c')) +endif softmmu_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('cryptodev-vhost.c')) -softmmu_ss.add(when: ['CONFIG_VIRTIO_CRYPTO', 'CONFIG_VHOST_CRYPTO'], if_true: files('cryptodev-vhost-user.c')) +if have_vhost_user_crypto + softmmu_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('cryptodev-vhost-user.c')) +endif softmmu_ss.add(when: gio, if_true: files('dbus-vmstate.c')) softmmu_ss.add(when: 'CONFIG_SGX', if_true: files('hostmem-epc.c')) diff --git a/hw/net/meson.build b/hw/net/meson.build index 685b75badb..ebac261542 100644 --- a/hw/net/meson.build +++ b/hw/net/meson.build @@ -46,8 +46,12 @@ specific_ss.add(when: 'CONFIG_XILINX_ETHLITE', if_true: files('xilinx_ethlite.c' softmmu_ss.add(when: 'CONFIG_VIRTIO_NET', if_true: files('net_rx_pkt.c')) specific_ss.add(when: 'CONFIG_VIRTIO_NET', if_true: files('virtio-net.c')) -softmmu_ss.add(when: ['CONFIG_VIRTIO_NET', 'CONFIG_VHOST_NET'], if_true: files('vhost_net.c'), if_false: files('vhost_net-stub.c')) -softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost_net-stub.c')) +if have_vhost_net + softmmu_ss.add(when: 'CONFIG_VIRTIO_NET', if_true: files('vhost_net.c'), if_false: files('vhost_net-stub.c')) + softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost_net-stub.c')) +else + softmmu_ss.add(files('vhost_net-stub.c')) +endif softmmu_ss.add(when: 'CONFIG_ETSEC', if_true: files( 'fsl_etsec/etsec.c', diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig index f8e235f814..e9ecae1f50 100644 --- a/hw/virtio/Kconfig +++ b/hw/virtio/Kconfig @@ -1,6 +1,3 @@ -config VHOST - bool - config VIRTIO bool diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index f371404b04..7e8877fd64 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -2,18 +2,22 @@ softmmu_virtio_ss = ss.source_set() softmmu_virtio_ss.add(files('virtio-bus.c')) softmmu_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('virtio-pci.c')) softmmu_virtio_ss.add(when: 'CONFIG_VIRTIO_MMIO', if_true: files('virtio-mmio.c')) -softmmu_virtio_ss.add(when: 'CONFIG_VHOST', if_false: files('vhost-stub.c')) - -softmmu_ss.add_all(when: 'CONFIG_VIRTIO', if_true: softmmu_virtio_ss) -softmmu_ss.add(when: 'CONFIG_VIRTIO', if_false: files('vhost-stub.c')) - -softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-stub.c')) virtio_ss = ss.source_set() virtio_ss.add(files('virtio.c')) -virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c', 'vhost-iova-tree.c')) -virtio_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user.c')) -virtio_ss.add(when: 'CONFIG_VHOST_VDPA', if_true: files('vhost-shadow-virtqueue.c', 'vhost-vdpa.c')) + +if have_vhost + virtio_ss.add(files('vhost.c', 'vhost-backend.c', 'vhost-iova-tree.c')) + if have_vhost_user + virtio_ss.add(files('vhost-user.c')) + endif + if have_vhost_vdpa + virtio_ss.add(files('vhost-vdpa.c', 'vhost-shadow-virtqueue.c')) + endif +else + softmmu_virtio_ss.add(files('vhost-stub.c')) +endif + virtio_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon.c')) virtio_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto.c')) virtio_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs.c')) @@ -54,3 +58,6 @@ virtio_pci_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem-pci.c')) virtio_ss.add_all(when: 'CONFIG_VIRTIO_PCI', if_true: virtio_pci_ss) specific_ss.add_all(when: 'CONFIG_VIRTIO', if_true: virtio_ss) +softmmu_ss.add_all(when: 'CONFIG_VIRTIO', if_true: softmmu_virtio_ss) +softmmu_ss.add(when: 'CONFIG_VIRTIO', if_false: files('vhost-stub.c')) +softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-stub.c')) diff --git a/meson.build b/meson.build index 108292e50f..6627bf02ee 100644 --- a/meson.build +++ b/meson.build @@ -319,6 +319,7 @@ have_vhost_kernel = 'CONFIG_VHOST_KERNEL' in config_host have_vhost_net_user = 'CONFIG_VHOST_NET_USER' in config_host have_vhost_net_vdpa = 'CONFIG_VHOST_NET_VDPA' in config_host have_vhost_net = 'CONFIG_VHOST_NET' in config_host +have_vhost = have_vhost_user or have_vhost_vdpa or have_vhost_kernel have_vhost_user_crypto = 'CONFIG_VHOST_CRYPTO' in config_host # Target-specific libraries and flags diff --git a/net/meson.build b/net/meson.build index 847bc2ac85..c965e83b26 100644 --- a/net/meson.build +++ b/net/meson.build @@ -26,10 +26,10 @@ softmmu_ss.add(when: vde, if_true: files('vde.c')) if have_netmap softmmu_ss.add(files('netmap.c')) endif -vhost_user_ss = ss.source_set() -vhost_user_ss.add(when: 'CONFIG_VIRTIO_NET', if_true: files('vhost-user.c'), if_false: files('vhost-user-stub.c')) -softmmu_ss.add_all(when: 'CONFIG_VHOST_NET_USER', if_true: vhost_user_ss) -softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-user-stub.c')) +if have_vhost_net_user + softmmu_ss.add(when: 'CONFIG_VIRTIO_NET', if_true: files('vhost-user.c'), if_false: files('vhost-user-stub.c')) + softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-user-stub.c')) +endif softmmu_ss.add(when: 'CONFIG_LINUX', if_true: files('tap-linux.c')) softmmu_ss.add(when: 'CONFIG_BSD', if_true: files('tap-bsd.c')) @@ -40,6 +40,8 @@ if not config_host.has_key('CONFIG_LINUX') and not config_host.has_key('CONFIG_B endif softmmu_ss.add(when: 'CONFIG_POSIX', if_true: files(tap_posix)) softmmu_ss.add(when: 'CONFIG_WIN32', if_true: files('tap-win32.c')) -softmmu_ss.add(when: 'CONFIG_VHOST_NET_VDPA', if_true: files('vhost-vdpa.c')) +if have_vhost_net_vdpa + softmmu_ss.add(files('vhost-vdpa.c')) +endif subdir('can') diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 32fb8cf755..3551b9c946 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -264,7 +264,9 @@ qos_test_ss.add( if have_virtfs qos_test_ss.add(files('virtio-9p-test.c')) endif -qos_test_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user-test.c')) +if have_vhost_user + qos_test_ss.add(files('vhost-user-test.c')) +endif if have_tools and have_vhost_user_blk_server qos_test_ss.add(files('vhost-user-blk-test.c')) endif From 2df89d542000819f0dd45134e24174997aca214e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Apr 2022 17:34:07 +0200 Subject: [PATCH 120/935] configure, meson: move vhost options to Meson MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Finish the conversion by moving all the definitions and the constraint checks to meson_options.txt and meson.build respectively. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- configure | 82 ----------------------------------- meson.build | 33 +++++++++++--- meson_options.txt | 10 +++++ scripts/meson-buildoptions.sh | 15 +++++++ 4 files changed, 51 insertions(+), 89 deletions(-) diff --git a/configure b/configure index 9a83d64c9d..e77b29b093 100755 --- a/configure +++ b/configure @@ -282,11 +282,6 @@ EXTRA_CXXFLAGS="" EXTRA_OBJCFLAGS="" EXTRA_LDFLAGS="" -vhost_kernel="$default_feature" -vhost_net="$default_feature" -vhost_crypto="$default_feature" -vhost_user="no" -vhost_vdpa="$default_feature" debug_tcg="no" sanitizers="no" tsan="no" @@ -527,7 +522,6 @@ haiku) ;; linux) linux="yes" - vhost_user=${default_feature:-yes} ;; esac @@ -864,14 +858,6 @@ for opt do ;; --with-coroutine=*) coroutine="$optarg" ;; - --disable-vhost-net) vhost_net="no" - ;; - --enable-vhost-net) vhost_net="yes" - ;; - --disable-vhost-crypto) vhost_crypto="no" - ;; - --enable-vhost-crypto) vhost_crypto="yes" - ;; --disable-zlib-test) ;; --disable-virtio-blk-data-plane|--enable-virtio-blk-data-plane) @@ -883,18 +869,6 @@ for opt do --enable-uuid|--disable-uuid) echo "$0: $opt is obsolete, UUID support is always built" >&2 ;; - --disable-vhost-user) vhost_user="no" - ;; - --enable-vhost-user) vhost_user="yes" - ;; - --disable-vhost-vdpa) vhost_vdpa="no" - ;; - --enable-vhost-vdpa) vhost_vdpa="yes" - ;; - --disable-vhost-kernel) vhost_kernel="no" - ;; - --enable-vhost-kernel) vhost_kernel="yes" - ;; --disable-capstone) capstone="disabled" ;; --enable-capstone) capstone="enabled" @@ -1093,11 +1067,6 @@ cat << EOF debug-info debugging information safe-stack SafeStack Stack Smash Protection. Depends on clang/llvm >= 3.7 and requires coroutine backend ucontext. - vhost-net vhost-net kernel acceleration support - vhost-crypto vhost-user-crypto backend support - vhost-kernel vhost kernel backend support - vhost-user vhost-user backend support - vhost-vdpa vhost-vdpa kernel backend support NOTE: The object files are built at the place where configure is launched EOF @@ -1511,35 +1480,6 @@ else exit 1 fi -######################################### -# vhost interdependencies and host support - -# vhost backends -if test "$vhost_user" = "yes" && test "$mingw32" = "yes"; then - error_exit "vhost-user is not available on Windows" -fi -test "$vhost_vdpa" = "" && vhost_vdpa=$linux -if test "$vhost_vdpa" = "yes" && test "$linux" != "yes"; then - error_exit "vhost-vdpa is only available on Linux" -fi -test "$vhost_kernel" = "" && vhost_kernel=$linux -if test "$vhost_kernel" = "yes" && test "$linux" != "yes"; then - error_exit "vhost-kernel is only available on Linux" -fi - -# vhost-user backends -test "$vhost_crypto" = "" && vhost_crypto=$vhost_user -if test "$vhost_crypto" = "yes" && test "$vhost_user" = "no"; then - error_exit "--enable-vhost-crypto requires --enable-vhost-user" -fi - -# OR the vhost-kernel, vhost-vdpa and vhost-user values for simplicity -if test "$vhost_net" = ""; then - test "$vhost_user" = "yes" && vhost_net=yes - test "$vhost_vdpa" = "yes" && vhost_net=yes - test "$vhost_kernel" = "yes" && vhost_net=yes -fi - ########################################## # pkg-config probe @@ -2059,28 +1999,6 @@ if test "$modules" = "yes"; then echo "CONFIG_MODULES=y" >> $config_host_mak fi -if test "$vhost_net" = "yes" ; then - echo "CONFIG_VHOST_NET=y" >> $config_host_mak -fi -if test "$vhost_user" = "yes" ; then - echo "CONFIG_VHOST_NET_USER=y" >> $config_host_mak -fi -if test "$vhost_vdpa" = "yes" ; then - echo "CONFIG_VHOST_NET_VDPA=y" >> $config_host_mak -fi -if test "$vhost_crypto" = "yes" ; then - echo "CONFIG_VHOST_CRYPTO=y" >> $config_host_mak -fi -if test "$vhost_kernel" = "yes" ; then - echo "CONFIG_VHOST_KERNEL=y" >> $config_host_mak -fi -if test "$vhost_user" = "yes" ; then - echo "CONFIG_VHOST_USER=y" >> $config_host_mak -fi -if test "$vhost_vdpa" = "yes" ; then - echo "CONFIG_VHOST_VDPA=y" >> $config_host_mak -fi - # XXX: suppress that if [ "$bsd" = "yes" ] ; then echo "CONFIG_BSD=y" >> $config_host_mak diff --git a/meson.build b/meson.build index 6627bf02ee..40132b4804 100644 --- a/meson.build +++ b/meson.build @@ -313,14 +313,26 @@ have_tpm = get_option('tpm') \ .allowed() # vhost -have_vhost_user = 'CONFIG_VHOST_USER' in config_host -have_vhost_vdpa = 'CONFIG_VHOST_VDPA' in config_host -have_vhost_kernel = 'CONFIG_VHOST_KERNEL' in config_host -have_vhost_net_user = 'CONFIG_VHOST_NET_USER' in config_host -have_vhost_net_vdpa = 'CONFIG_VHOST_NET_VDPA' in config_host -have_vhost_net = 'CONFIG_VHOST_NET' in config_host +have_vhost_user = get_option('vhost_user') \ + .disable_auto_if(targetos != 'linux') \ + .require(targetos != 'windows', + error_message: 'vhost-user is not available on Windows').allowed() +have_vhost_vdpa = get_option('vhost_vdpa') \ + .require(targetos == 'linux', + error_message: 'vhost-vdpa is only available on Linux').allowed() +have_vhost_kernel = get_option('vhost_kernel') \ + .require(targetos == 'linux', + error_message: 'vhost-kernel is only available on Linux').allowed() +have_vhost_user_crypto = get_option('vhost_crypto') \ + .require(have_vhost_user, + error_message: 'vhost-crypto requires vhost-user to be enabled').allowed() + have_vhost = have_vhost_user or have_vhost_vdpa or have_vhost_kernel -have_vhost_user_crypto = 'CONFIG_VHOST_CRYPTO' in config_host + +have_vhost_net_user = have_vhost_user and get_option('vhost_net').allowed() +have_vhost_net_vdpa = have_vhost_vdpa and get_option('vhost_net').allowed() +have_vhost_net_kernel = have_vhost_kernel and get_option('vhost_net').allowed() +have_vhost_net = have_vhost_net_kernel or have_vhost_net_user or have_vhost_net_vdpa # Target-specific libraries and flags libm = cc.find_library('m', required: false) @@ -1711,6 +1723,13 @@ config_host_data.set('CONFIG_SNAPPY', snappy.found()) config_host_data.set('CONFIG_TPM', have_tpm) config_host_data.set('CONFIG_USB_LIBUSB', libusb.found()) config_host_data.set('CONFIG_VDE', vde.found()) +config_host_data.set('CONFIG_VHOST_NET', have_vhost_net) +config_host_data.set('CONFIG_VHOST_NET_USER', have_vhost_net_user) +config_host_data.set('CONFIG_VHOST_NET_VDPA', have_vhost_net_vdpa) +config_host_data.set('CONFIG_VHOST_KERNEL', have_vhost_kernel) +config_host_data.set('CONFIG_VHOST_USER', have_vhost_user) +config_host_data.set('CONFIG_VHOST_CRYPTO', have_vhost_user_crypto) +config_host_data.set('CONFIG_VHOST_VDPA', have_vhost_vdpa) config_host_data.set('CONFIG_VHOST_USER_BLK_SERVER', have_vhost_user_blk_server) config_host_data.set('CONFIG_PNG', png.found()) config_host_data.set('CONFIG_VNC', vnc.found()) diff --git a/meson_options.txt b/meson_options.txt index 35f5a72507..29c6b90cec 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -235,6 +235,16 @@ option('oss', type: 'feature', value: 'auto', option('pa', type: 'feature', value: 'auto', description: 'PulseAudio sound support') +option('vhost_kernel', type: 'feature', value: 'auto', + description: 'vhost kernel backend support') +option('vhost_net', type: 'feature', value: 'auto', + description: 'vhost-net kernel acceleration support') +option('vhost_user', type: 'feature', value: 'auto', + description: 'vhost-user backend support') +option('vhost_crypto', type: 'feature', value: 'auto', + description: 'vhost-user crypto backend support') +option('vhost_vdpa', type: 'feature', value: 'auto', + description: 'vhost-vdpa kernel backend support') option('vhost_user_blk_server', type: 'feature', value: 'auto', description: 'build vhost-user-blk server') option('virtfs', type: 'feature', value: 'auto', diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 4b0770a9e0..5d2172bfb4 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -154,8 +154,13 @@ meson_options_help() { printf "%s\n" ' usb-redir libusbredir support' printf "%s\n" ' vde vde network backend support' printf "%s\n" ' vdi vdi image format support' + printf "%s\n" ' vhost-crypto vhost-user crypto backend support' + printf "%s\n" ' vhost-kernel vhost kernel backend support' + printf "%s\n" ' vhost-net vhost-net kernel acceleration support' + printf "%s\n" ' vhost-user vhost-user backend support' printf "%s\n" ' vhost-user-blk-server' printf "%s\n" ' build vhost-user-blk server' + printf "%s\n" ' vhost-vdpa vhost-vdpa kernel backend support' printf "%s\n" ' virglrenderer virgl rendering support' printf "%s\n" ' virtfs virtio-9p support' printf "%s\n" ' virtiofsd build virtiofs daemon (virtiofsd)' @@ -409,8 +414,18 @@ _meson_option_parse() { --disable-vde) printf "%s" -Dvde=disabled ;; --enable-vdi) printf "%s" -Dvdi=enabled ;; --disable-vdi) printf "%s" -Dvdi=disabled ;; + --enable-vhost-crypto) printf "%s" -Dvhost_crypto=enabled ;; + --disable-vhost-crypto) printf "%s" -Dvhost_crypto=disabled ;; + --enable-vhost-kernel) printf "%s" -Dvhost_kernel=enabled ;; + --disable-vhost-kernel) printf "%s" -Dvhost_kernel=disabled ;; + --enable-vhost-net) printf "%s" -Dvhost_net=enabled ;; + --disable-vhost-net) printf "%s" -Dvhost_net=disabled ;; + --enable-vhost-user) printf "%s" -Dvhost_user=enabled ;; + --disable-vhost-user) printf "%s" -Dvhost_user=disabled ;; --enable-vhost-user-blk-server) printf "%s" -Dvhost_user_blk_server=enabled ;; --disable-vhost-user-blk-server) printf "%s" -Dvhost_user_blk_server=disabled ;; + --enable-vhost-vdpa) printf "%s" -Dvhost_vdpa=enabled ;; + --disable-vhost-vdpa) printf "%s" -Dvhost_vdpa=disabled ;; --enable-virglrenderer) printf "%s" -Dvirglrenderer=enabled ;; --disable-virglrenderer) printf "%s" -Dvirglrenderer=disabled ;; --enable-virtfs) printf "%s" -Dvirtfs=enabled ;; From 6033b9ecd4f6a26b78f44a94813e1e464f5b0549 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 27 Apr 2022 12:01:48 +0200 Subject: [PATCH 121/935] pc: remove -soundhw pcspk The pcspk device is the only user of the init_isa function, and the only -soundhw option which does not create a new device (it hacks into the PCSpkState by hand). Remove it, since it was deprecated. Signed-off-by: Paolo Bonzini --- hw/audio/pcspk.c | 10 ---------- hw/audio/soundhw.c | 27 ++++----------------------- include/hw/audio/soundhw.h | 3 --- 3 files changed, 4 insertions(+), 36 deletions(-) diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c index dfc7ebca4e..daf92a4ce1 100644 --- a/hw/audio/pcspk.c +++ b/hw/audio/pcspk.c @@ -245,18 +245,8 @@ static const TypeInfo pcspk_info = { .class_init = pcspk_class_initfn, }; -static int pcspk_audio_init_soundhw(ISABus *bus) -{ - PCSpkState *s = pcspk_state; - - warn_report("'-soundhw pcspk' is deprecated, " - "please set a backend using '-machine pcspk-audiodev=' instead"); - return pcspk_audio_init(s); -} - static void pcspk_register(void) { type_register_static(&pcspk_info); - isa_register_soundhw("pcspk", "PC speaker", pcspk_audio_init_soundhw); } type_init(pcspk_register) diff --git a/hw/audio/soundhw.c b/hw/audio/soundhw.c index 173b674ff5..f7d94d7dfa 100644 --- a/hw/audio/soundhw.c +++ b/hw/audio/soundhw.c @@ -36,26 +36,12 @@ struct soundhw { const char *typename; int enabled; int isa; - union { - int (*init_isa) (ISABus *bus); - int (*init_pci) (PCIBus *bus); - } init; + int (*init_pci) (PCIBus *bus); }; static struct soundhw soundhw[9]; static int soundhw_count; -void isa_register_soundhw(const char *name, const char *descr, - int (*init_isa)(ISABus *bus)) -{ - assert(soundhw_count < ARRAY_SIZE(soundhw) - 1); - soundhw[soundhw_count].name = name; - soundhw[soundhw_count].descr = descr; - soundhw[soundhw_count].isa = 1; - soundhw[soundhw_count].init.init_isa = init_isa; - soundhw_count++; -} - void pci_register_soundhw(const char *name, const char *descr, int (*init_pci)(PCIBus *bus)) { @@ -63,7 +49,7 @@ void pci_register_soundhw(const char *name, const char *descr, soundhw[soundhw_count].name = name; soundhw[soundhw_count].descr = descr; soundhw[soundhw_count].isa = 0; - soundhw[soundhw_count].init.init_pci = init_pci; + soundhw[soundhw_count].init_pci = init_pci; soundhw_count++; } @@ -158,18 +144,13 @@ void soundhw_init(void) } else { pci_create_simple(pci_bus, -1, c->typename); } - } else if (c->isa) { - if (!isa_bus) { - error_report("ISA bus not available for %s", c->name); - exit(1); - } - c->init.init_isa(isa_bus); } else { + assert(!c->isa); if (!pci_bus) { error_report("PCI bus not available for %s", c->name); exit(1); } - c->init.init_pci(pci_bus); + c->init_pci(pci_bus); } } } diff --git a/include/hw/audio/soundhw.h b/include/hw/audio/soundhw.h index f09a297854..e68685fcda 100644 --- a/include/hw/audio/soundhw.h +++ b/include/hw/audio/soundhw.h @@ -1,9 +1,6 @@ #ifndef HW_SOUNDHW_H #define HW_SOUNDHW_H -void isa_register_soundhw(const char *name, const char *descr, - int (*init_isa)(ISABus *bus)); - void pci_register_soundhw(const char *name, const char *descr, int (*init_pci)(PCIBus *bus)); void deprecated_register_soundhw(const char *name, const char *descr, From 17bd42896d31bf57cb3cc16abefb3221391eb288 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:11 +0100 Subject: [PATCH 122/935] dino: checkpatch fixes Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Acked-by: Helge Deller Message-Id: <20220504092600.10048-2-mark.cave-ayland@ilande.co.uk> Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index eab96dd84e..4031cfb7f0 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -101,8 +101,10 @@ static const uint32_t reg800_keep_bits[DINO800_REGS] = { struct DinoState { PCIHostState parent_obj; - /* PCI_CONFIG_ADDR is parent_obj.config_reg, via pci_host_conf_be_ops, - so that we can map PCI_CONFIG_DATA to pci_host_data_be_ops. */ + /* + * PCI_CONFIG_ADDR is parent_obj.config_reg, via pci_host_conf_be_ops, + * so that we can map PCI_CONFIG_DATA to pci_host_data_be_ops. + */ uint32_t config_reg_dino; /* keep original copy, including 2 lowest bits */ uint32_t iar0; From 7cdfa94166fb5aa25681152675c85c709e927602 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:12 +0100 Subject: [PATCH 123/935] dino: move registers from dino_init() to DINO_PCI_BRIDGE init function Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-3-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.c | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index 4031cfb7f0..9401b68ff7 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -526,21 +526,6 @@ PCIBus *dino_init(MemoryRegion *addr_space, s->iar0 = s->iar1 = CPU_HPA + 3; s->toc_addr = 0xFFFA0030; /* IO_COMMAND of CPU */ - /* Dino PCI access from main memory. */ - memory_region_init_io(&s->this_mem, OBJECT(s), &dino_chip_ops, - s, "dino", 4096); - memory_region_add_subregion(addr_space, DINO_HPA, &s->this_mem); - - /* Dino PCI config. */ - memory_region_init_io(&s->parent_obj.conf_mem, OBJECT(&s->parent_obj), - &dino_config_addr_ops, dev, "pci-conf-idx", 4); - memory_region_init_io(&s->parent_obj.data_mem, OBJECT(&s->parent_obj), - &dino_config_data_ops, dev, "pci-conf-data", 4); - memory_region_add_subregion(&s->this_mem, DINO_PCI_CONFIG_ADDR, - &s->parent_obj.conf_mem); - memory_region_add_subregion(&s->this_mem, DINO_CONFIG_DATA, - &s->parent_obj.data_mem); - /* Dino PCI bus memory. */ memory_region_init(&s->pci_mem, OBJECT(s), "pci-memory", 4 * GiB); @@ -550,6 +535,9 @@ PCIBus *dino_init(MemoryRegion *addr_space, s->parent_obj.bus = b; sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + memory_region_add_subregion(addr_space, DINO_HPA, + sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0)); + /* Set up windows into PCI bus memory. */ for (i = 1; i < 31; i++) { uint32_t addr = 0xf0000000 + i * DINO_MEM_CHUNK_SIZE; @@ -588,6 +576,31 @@ PCIBus *dino_init(MemoryRegion *addr_space, return b; } +static void dino_pcihost_init(Object *obj) +{ + DinoState *s = DINO_PCI_HOST_BRIDGE(obj); + PCIHostState *phb = PCI_HOST_BRIDGE(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + /* Dino PCI access from main memory. */ + memory_region_init_io(&s->this_mem, OBJECT(s), &dino_chip_ops, + s, "dino", 4096); + + /* Dino PCI config. */ + memory_region_init_io(&phb->conf_mem, OBJECT(phb), + &dino_config_addr_ops, DEVICE(s), + "pci-conf-idx", 4); + memory_region_init_io(&phb->data_mem, OBJECT(phb), + &dino_config_data_ops, DEVICE(s), + "pci-conf-data", 4); + memory_region_add_subregion(&s->this_mem, DINO_PCI_CONFIG_ADDR, + &phb->conf_mem); + memory_region_add_subregion(&s->this_mem, DINO_CONFIG_DATA, + &phb->data_mem); + + sysbus_init_mmio(sbd, &s->this_mem); +} + static void dino_pcihost_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -598,6 +611,7 @@ static void dino_pcihost_class_init(ObjectClass *klass, void *data) static const TypeInfo dino_pcihost_info = { .name = TYPE_DINO_PCI_HOST_BRIDGE, .parent = TYPE_PCI_HOST_BRIDGE, + .instance_init = dino_pcihost_init, .instance_size = sizeof(DinoState), .class_init = dino_pcihost_class_init, }; From 63901b6cc4d8b471ac4b92826220db914b908368 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:13 +0100 Subject: [PATCH 124/935] dino: move PCI bus initialisation to dino_pcihost_init() Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-4-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index 9401b68ff7..c6c01ea14c 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -526,13 +526,7 @@ PCIBus *dino_init(MemoryRegion *addr_space, s->iar0 = s->iar1 = CPU_HPA + 3; s->toc_addr = 0xFFFA0030; /* IO_COMMAND of CPU */ - /* Dino PCI bus memory. */ - memory_region_init(&s->pci_mem, OBJECT(s), "pci-memory", 4 * GiB); - - b = pci_register_root_bus(dev, "pci", dino_set_irq, dino_pci_map_irq, s, - &s->pci_mem, get_system_io(), - PCI_DEVFN(0, 0), 32, TYPE_PCI_BUS); - s->parent_obj.bus = b; + b = s->parent_obj.bus; sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); memory_region_add_subregion(addr_space, DINO_HPA, @@ -598,6 +592,14 @@ static void dino_pcihost_init(Object *obj) memory_region_add_subregion(&s->this_mem, DINO_CONFIG_DATA, &phb->data_mem); + /* Dino PCI bus memory. */ + memory_region_init(&s->pci_mem, OBJECT(s), "pci-memory", 4 * GiB); + + phb->bus = pci_register_root_bus(DEVICE(s), "pci", + dino_set_irq, dino_pci_map_irq, s, + &s->pci_mem, get_system_io(), + PCI_DEVFN(0, 0), 32, TYPE_PCI_BUS); + sysbus_init_mmio(sbd, &s->this_mem); } From cc363c4a10b99709ea4e9e185c7b71de72f88a17 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:14 +0100 Subject: [PATCH 125/935] dino: move PCI windows initialisation to dino_pcihost_init() Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-5-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index c6c01ea14c..bc27aad5dc 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -519,7 +519,6 @@ PCIBus *dino_init(MemoryRegion *addr_space, DeviceState *dev; DinoState *s; PCIBus *b; - int i; dev = qdev_new(TYPE_DINO_PCI_HOST_BRIDGE); s = DINO_PCI_HOST_BRIDGE(dev); @@ -532,16 +531,6 @@ PCIBus *dino_init(MemoryRegion *addr_space, memory_region_add_subregion(addr_space, DINO_HPA, sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0)); - /* Set up windows into PCI bus memory. */ - for (i = 1; i < 31; i++) { - uint32_t addr = 0xf0000000 + i * DINO_MEM_CHUNK_SIZE; - char *name = g_strdup_printf("PCI Outbound Window %d", i); - memory_region_init_alias(&s->pci_mem_alias[i], OBJECT(s), - name, &s->pci_mem, addr, - DINO_MEM_CHUNK_SIZE); - g_free(name); - } - /* Set up PCI view of memory: Bus master address space. */ memory_region_init(&s->bm, OBJECT(s), "bm-dino", 4 * GiB); memory_region_init_alias(&s->bm_ram_alias, OBJECT(s), @@ -575,6 +564,7 @@ static void dino_pcihost_init(Object *obj) DinoState *s = DINO_PCI_HOST_BRIDGE(obj); PCIHostState *phb = PCI_HOST_BRIDGE(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + int i; /* Dino PCI access from main memory. */ memory_region_init_io(&s->this_mem, OBJECT(s), &dino_chip_ops, @@ -600,6 +590,16 @@ static void dino_pcihost_init(Object *obj) &s->pci_mem, get_system_io(), PCI_DEVFN(0, 0), 32, TYPE_PCI_BUS); + /* Set up windows into PCI bus memory. */ + for (i = 1; i < 31; i++) { + uint32_t addr = 0xf0000000 + i * DINO_MEM_CHUNK_SIZE; + char *name = g_strdup_printf("PCI Outbound Window %d", i); + memory_region_init_alias(&s->pci_mem_alias[i], OBJECT(s), + name, &s->pci_mem, addr, + DINO_MEM_CHUNK_SIZE); + g_free(name); + } + sysbus_init_mmio(sbd, &s->this_mem); } From 270b29587f4705aa8d6b46ba2c0ff5bf712cc637 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:15 +0100 Subject: [PATCH 126/935] dino: add memory-as property containing a link to the memory address space Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-6-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index bc27aad5dc..13b2210462 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -17,6 +17,7 @@ #include "hw/irq.h" #include "hw/pci/pci.h" #include "hw/pci/pci_bus.h" +#include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "hppa_sys.h" #include "trace.h" @@ -124,6 +125,8 @@ struct DinoState { MemoryRegion pci_mem; MemoryRegion pci_mem_alias[32]; + MemoryRegion *memory_as; + AddressSpace bm_as; MemoryRegion bm; MemoryRegion bm_ram_alias; @@ -521,6 +524,8 @@ PCIBus *dino_init(MemoryRegion *addr_space, PCIBus *b; dev = qdev_new(TYPE_DINO_PCI_HOST_BRIDGE); + object_property_set_link(OBJECT(dev), "memory-as", OBJECT(addr_space), + &error_fatal); s = DINO_PCI_HOST_BRIDGE(dev); s->iar0 = s->iar1 = CPU_HPA + 3; s->toc_addr = 0xFFFA0030; /* IO_COMMAND of CPU */ @@ -603,10 +608,17 @@ static void dino_pcihost_init(Object *obj) sysbus_init_mmio(sbd, &s->this_mem); } +static Property dino_pcihost_properties[] = { + DEFINE_PROP_LINK("memory-as", DinoState, memory_as, TYPE_MEMORY_REGION, + MemoryRegion *), + DEFINE_PROP_END_OF_LIST(), +}; + static void dino_pcihost_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + device_class_set_props(dc, dino_pcihost_properties); dc->vmsd = &vmstate_dino; } From 5ac6c43c856a81e0ca1a1bab8f2fbd7b3a66274d Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:16 +0100 Subject: [PATCH 127/935] dino: move pci_setup_iommu() to dino_pcihost_init() Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-7-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index 13b2210462..dcebb9f98f 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -556,7 +556,6 @@ PCIBus *dino_init(MemoryRegion *addr_space, memory_region_add_subregion(&s->bm, 0xfff00000, &s->bm_cpu_alias); address_space_init(&s->bm_as, &s->bm, "pci-bm"); - pci_setup_iommu(b, dino_pcihost_set_iommu, s); *p_rtc_irq = qemu_allocate_irq(dino_set_timer_irq, s, 0); *p_ser_irq = qemu_allocate_irq(dino_set_serial_irq, s, 0); @@ -605,6 +604,8 @@ static void dino_pcihost_init(Object *obj) g_free(name); } + pci_setup_iommu(phb->bus, dino_pcihost_set_iommu, s); + sysbus_init_mmio(sbd, &s->this_mem); } From 9cf69f444c4034e5278ec52ae9869f13ae9a2bd2 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:17 +0100 Subject: [PATCH 128/935] dino: move PCI bus master address space setup to dino_pcihost_realize() Add a new dino_pcihost_unrealize() function to remove the address space when the device is unrealized. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-8-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index dcebb9f98f..ae79ddbf5c 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -536,17 +536,27 @@ PCIBus *dino_init(MemoryRegion *addr_space, memory_region_add_subregion(addr_space, DINO_HPA, sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0)); + *p_rtc_irq = qemu_allocate_irq(dino_set_timer_irq, s, 0); + *p_ser_irq = qemu_allocate_irq(dino_set_serial_irq, s, 0); + + return b; +} + +static void dino_pcihost_realize(DeviceState *dev, Error **errp) +{ + DinoState *s = DINO_PCI_HOST_BRIDGE(dev); + /* Set up PCI view of memory: Bus master address space. */ memory_region_init(&s->bm, OBJECT(s), "bm-dino", 4 * GiB); memory_region_init_alias(&s->bm_ram_alias, OBJECT(s), - "bm-system", addr_space, 0, + "bm-system", s->memory_as, 0, 0xf0000000 + DINO_MEM_CHUNK_SIZE); memory_region_init_alias(&s->bm_pci_alias, OBJECT(s), "bm-pci", &s->pci_mem, 0xf0000000 + DINO_MEM_CHUNK_SIZE, 30 * DINO_MEM_CHUNK_SIZE); memory_region_init_alias(&s->bm_cpu_alias, OBJECT(s), - "bm-cpu", addr_space, 0xfff00000, + "bm-cpu", s->memory_as, 0xfff00000, 0xfffff); memory_region_add_subregion(&s->bm, 0, &s->bm_ram_alias); @@ -555,12 +565,15 @@ PCIBus *dino_init(MemoryRegion *addr_space, &s->bm_pci_alias); memory_region_add_subregion(&s->bm, 0xfff00000, &s->bm_cpu_alias); + address_space_init(&s->bm_as, &s->bm, "pci-bm"); +} - *p_rtc_irq = qemu_allocate_irq(dino_set_timer_irq, s, 0); - *p_ser_irq = qemu_allocate_irq(dino_set_serial_irq, s, 0); +static void dino_pcihost_unrealize(DeviceState *dev) +{ + DinoState *s = DINO_PCI_HOST_BRIDGE(dev); - return b; + address_space_destroy(&s->bm_as); } static void dino_pcihost_init(Object *obj) @@ -619,6 +632,8 @@ static void dino_pcihost_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + dc->realize = dino_pcihost_realize; + dc->unrealize = dino_pcihost_unrealize; device_class_set_props(dc, dino_pcihost_properties); dc->vmsd = &vmstate_dino; } From 98d168f359319ddd20b21058a081ec77837f7347 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:18 +0100 Subject: [PATCH 129/935] dino: move initial register configuration to new dino_pcihost_reset() function Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-9-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index ae79ddbf5c..d3cd8578a1 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -527,8 +527,6 @@ PCIBus *dino_init(MemoryRegion *addr_space, object_property_set_link(OBJECT(dev), "memory-as", OBJECT(addr_space), &error_fatal); s = DINO_PCI_HOST_BRIDGE(dev); - s->iar0 = s->iar1 = CPU_HPA + 3; - s->toc_addr = 0xFFFA0030; /* IO_COMMAND of CPU */ b = s->parent_obj.bus; sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); @@ -542,6 +540,14 @@ PCIBus *dino_init(MemoryRegion *addr_space, return b; } +static void dino_pcihost_reset(DeviceState *dev) +{ + DinoState *s = DINO_PCI_HOST_BRIDGE(dev); + + s->iar0 = s->iar1 = CPU_HPA + 3; + s->toc_addr = 0xFFFA0030; /* IO_COMMAND of CPU */ +} + static void dino_pcihost_realize(DeviceState *dev, Error **errp) { DinoState *s = DINO_PCI_HOST_BRIDGE(dev); @@ -632,6 +638,7 @@ static void dino_pcihost_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + dc->reset = dino_pcihost_reset; dc->realize = dino_pcihost_realize; dc->unrealize = dino_pcihost_unrealize; device_class_set_props(dc, dino_pcihost_properties); From ee313d5abb1f911c426f8fbcb3abb4b1d8e281ce Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:19 +0100 Subject: [PATCH 130/935] dino: use QOM cast instead of directly referencing parent_obj Use a QOM cast in both dino_chip_read_with_attrs() and dino_chip_write_with_attrs() instead of directly referencing parent_obj. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-10-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index d3cd8578a1..77b8089664 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -205,6 +205,7 @@ static MemTxResult dino_chip_read_with_attrs(void *opaque, hwaddr addr, MemTxAttrs attrs) { DinoState *s = opaque; + PCIHostState *phb = PCI_HOST_BRIDGE(s); MemTxResult ret = MEMTX_OK; AddressSpace *io; uint16_t ioaddr; @@ -214,7 +215,7 @@ static MemTxResult dino_chip_read_with_attrs(void *opaque, hwaddr addr, case DINO_PCI_IO_DATA ... DINO_PCI_IO_DATA + 3: /* Read from PCI IO space. */ io = &address_space_io; - ioaddr = s->parent_obj.config_reg + (addr & 3); + ioaddr = phb->config_reg + (addr & 3); switch (size) { case 1: val = address_space_ldub(io, ioaddr, attrs, &ret); @@ -297,6 +298,7 @@ static MemTxResult dino_chip_write_with_attrs(void *opaque, hwaddr addr, MemTxAttrs attrs) { DinoState *s = opaque; + PCIHostState *phb = PCI_HOST_BRIDGE(s); AddressSpace *io; MemTxResult ret; uint16_t ioaddr; @@ -308,7 +310,7 @@ static MemTxResult dino_chip_write_with_attrs(void *opaque, hwaddr addr, case DINO_IO_DATA ... DINO_PCI_IO_DATA + 3: /* Write into PCI IO space. */ io = &address_space_io; - ioaddr = s->parent_obj.config_reg + (addr & 3); + ioaddr = phb->config_reg + (addr & 3); switch (size) { case 1: address_space_stb(io, ioaddr, val, attrs, &ret); From 079e7ad989e3902ac7ecb70086d3b380faeeaf63 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:20 +0100 Subject: [PATCH 131/935] dino: return PCIBus from dino_init() using qdev_get_child_bus() This allows access to the PCI bus without having to reference parent_obj directly. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-11-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index 77b8089664..d89b48493f 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -523,14 +523,12 @@ PCIBus *dino_init(MemoryRegion *addr_space, { DeviceState *dev; DinoState *s; - PCIBus *b; + PCIBus *pci_bus; dev = qdev_new(TYPE_DINO_PCI_HOST_BRIDGE); object_property_set_link(OBJECT(dev), "memory-as", OBJECT(addr_space), &error_fatal); s = DINO_PCI_HOST_BRIDGE(dev); - - b = s->parent_obj.bus; sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); memory_region_add_subregion(addr_space, DINO_HPA, @@ -539,7 +537,8 @@ PCIBus *dino_init(MemoryRegion *addr_space, *p_rtc_irq = qemu_allocate_irq(dino_set_timer_irq, s, 0); *p_ser_irq = qemu_allocate_irq(dino_set_serial_irq, s, 0); - return b; + pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci")); + return pci_bus; } static void dino_pcihost_reset(DeviceState *dev) From 14e275efcbe9cc8653a90f2085e2cdf0f7f7e24f Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:21 +0100 Subject: [PATCH 132/935] dino: split declarations from dino.c into dino.h This is to allow access to DinoState from outside dino.c. With the changes to the headers it is now possible to remove the duplicate definition for TYPE_DINO_PCI_HOST_BRIDGE from hppa_sys.h. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-12-mark.cave-ayland@ilande.co.uk> Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.c | 111 +-------------------------------------- hw/hppa/dino.h | 127 +++++++++++++++++++++++++++++++++++++++++++++ hw/hppa/hppa_sys.h | 2 - 3 files changed, 128 insertions(+), 112 deletions(-) create mode 100644 hw/hppa/dino.h diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index d89b48493f..01546ff6fc 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -18,122 +18,13 @@ #include "hw/pci/pci.h" #include "hw/pci/pci_bus.h" #include "hw/qdev-properties.h" +#include "dino.h" #include "migration/vmstate.h" #include "hppa_sys.h" #include "trace.h" #include "qom/object.h" -#define TYPE_DINO_PCI_HOST_BRIDGE "dino-pcihost" - -#define DINO_IAR0 0x004 -#define DINO_IODC 0x008 -#define DINO_IRR0 0x00C /* RO */ -#define DINO_IAR1 0x010 -#define DINO_IRR1 0x014 /* RO */ -#define DINO_IMR 0x018 -#define DINO_IPR 0x01C -#define DINO_TOC_ADDR 0x020 -#define DINO_ICR 0x024 -#define DINO_ILR 0x028 /* RO */ -#define DINO_IO_COMMAND 0x030 /* WO */ -#define DINO_IO_STATUS 0x034 /* RO */ -#define DINO_IO_CONTROL 0x038 -#define DINO_IO_GSC_ERR_RESP 0x040 /* RO */ -#define DINO_IO_ERR_INFO 0x044 /* RO */ -#define DINO_IO_PCI_ERR_RESP 0x048 /* RO */ -#define DINO_IO_FBB_EN 0x05c -#define DINO_IO_ADDR_EN 0x060 -#define DINO_PCI_CONFIG_ADDR 0x064 -#define DINO_PCI_CONFIG_DATA 0x068 -#define DINO_PCI_IO_DATA 0x06c -#define DINO_PCI_MEM_DATA 0x070 /* Dino 3.x only */ -#define DINO_GSC2X_CONFIG 0x7b4 /* RO */ -#define DINO_GMASK 0x800 -#define DINO_PAMR 0x804 -#define DINO_PAPR 0x808 -#define DINO_DAMODE 0x80c -#define DINO_PCICMD 0x810 -#define DINO_PCISTS 0x814 /* R/WC */ -#define DINO_MLTIM 0x81c -#define DINO_BRDG_FEAT 0x820 -#define DINO_PCIROR 0x824 -#define DINO_PCIWOR 0x828 -#define DINO_TLTIM 0x830 - -#define DINO_IRQS 11 /* bits 0-10 are architected */ -#define DINO_IRR_MASK 0x5ff /* only 10 bits are implemented */ -#define DINO_LOCAL_IRQS (DINO_IRQS + 1) -#define DINO_MASK_IRQ(x) (1 << (x)) - -#define PCIINTA 0x001 -#define PCIINTB 0x002 -#define PCIINTC 0x004 -#define PCIINTD 0x008 -#define PCIINTE 0x010 -#define PCIINTF 0x020 -#define GSCEXTINT 0x040 -/* #define xxx 0x080 - bit 7 is "default" */ -/* #define xxx 0x100 - bit 8 not used */ -/* #define xxx 0x200 - bit 9 not used */ -#define RS232INT 0x400 - -#define DINO_MEM_CHUNK_SIZE (8 * MiB) - -OBJECT_DECLARE_SIMPLE_TYPE(DinoState, DINO_PCI_HOST_BRIDGE) - -#define DINO800_REGS (1 + (DINO_TLTIM - DINO_GMASK) / 4) -static const uint32_t reg800_keep_bits[DINO800_REGS] = { - MAKE_64BIT_MASK(0, 1), /* GMASK */ - MAKE_64BIT_MASK(0, 7), /* PAMR */ - MAKE_64BIT_MASK(0, 7), /* PAPR */ - MAKE_64BIT_MASK(0, 8), /* DAMODE */ - MAKE_64BIT_MASK(0, 7), /* PCICMD */ - MAKE_64BIT_MASK(0, 9), /* PCISTS */ - MAKE_64BIT_MASK(0, 32), /* Undefined */ - MAKE_64BIT_MASK(0, 8), /* MLTIM */ - MAKE_64BIT_MASK(0, 30), /* BRDG_FEAT */ - MAKE_64BIT_MASK(0, 24), /* PCIROR */ - MAKE_64BIT_MASK(0, 22), /* PCIWOR */ - MAKE_64BIT_MASK(0, 32), /* Undocumented */ - MAKE_64BIT_MASK(0, 9), /* TLTIM */ -}; - -struct DinoState { - PCIHostState parent_obj; - - /* - * PCI_CONFIG_ADDR is parent_obj.config_reg, via pci_host_conf_be_ops, - * so that we can map PCI_CONFIG_DATA to pci_host_data_be_ops. - */ - uint32_t config_reg_dino; /* keep original copy, including 2 lowest bits */ - - uint32_t iar0; - uint32_t iar1; - uint32_t imr; - uint32_t ipr; - uint32_t icr; - uint32_t ilr; - uint32_t io_fbb_en; - uint32_t io_addr_en; - uint32_t io_control; - uint32_t toc_addr; - - uint32_t reg800[DINO800_REGS]; - - MemoryRegion this_mem; - MemoryRegion pci_mem; - MemoryRegion pci_mem_alias[32]; - - MemoryRegion *memory_as; - - AddressSpace bm_as; - MemoryRegion bm; - MemoryRegion bm_ram_alias; - MemoryRegion bm_pci_alias; - MemoryRegion bm_cpu_alias; -}; - /* * Dino can forward memory accesses from the CPU in the range between * 0xf0800000 and 0xff000000 to the PCI bus. diff --git a/hw/hppa/dino.h b/hw/hppa/dino.h new file mode 100644 index 0000000000..1a26667377 --- /dev/null +++ b/hw/hppa/dino.h @@ -0,0 +1,127 @@ +/* + * HP-PARISC Dino PCI chipset emulation, as in B160L and similiar machines + * + * (C) 2017-2019 by Helge Deller + * + * This work is licensed under the GNU GPL license version 2 or later. + * + * Documentation available at: + * https://parisc.wiki.kernel.org/images-parisc/9/91/Dino_ers.pdf + * https://parisc.wiki.kernel.org/images-parisc/7/70/Dino_3_1_Errata.pdf + */ + +#ifndef DINO_H +#define DINO_H + +#include "hw/pci/pci_host.h" + +#define TYPE_DINO_PCI_HOST_BRIDGE "dino-pcihost" +OBJECT_DECLARE_SIMPLE_TYPE(DinoState, DINO_PCI_HOST_BRIDGE) + +#define DINO_IAR0 0x004 +#define DINO_IODC 0x008 +#define DINO_IRR0 0x00C /* RO */ +#define DINO_IAR1 0x010 +#define DINO_IRR1 0x014 /* RO */ +#define DINO_IMR 0x018 +#define DINO_IPR 0x01C +#define DINO_TOC_ADDR 0x020 +#define DINO_ICR 0x024 +#define DINO_ILR 0x028 /* RO */ +#define DINO_IO_COMMAND 0x030 /* WO */ +#define DINO_IO_STATUS 0x034 /* RO */ +#define DINO_IO_CONTROL 0x038 +#define DINO_IO_GSC_ERR_RESP 0x040 /* RO */ +#define DINO_IO_ERR_INFO 0x044 /* RO */ +#define DINO_IO_PCI_ERR_RESP 0x048 /* RO */ +#define DINO_IO_FBB_EN 0x05c +#define DINO_IO_ADDR_EN 0x060 +#define DINO_PCI_CONFIG_ADDR 0x064 +#define DINO_PCI_CONFIG_DATA 0x068 +#define DINO_PCI_IO_DATA 0x06c +#define DINO_PCI_MEM_DATA 0x070 /* Dino 3.x only */ +#define DINO_GSC2X_CONFIG 0x7b4 /* RO */ +#define DINO_GMASK 0x800 +#define DINO_PAMR 0x804 +#define DINO_PAPR 0x808 +#define DINO_DAMODE 0x80c +#define DINO_PCICMD 0x810 +#define DINO_PCISTS 0x814 /* R/WC */ +#define DINO_MLTIM 0x81c +#define DINO_BRDG_FEAT 0x820 +#define DINO_PCIROR 0x824 +#define DINO_PCIWOR 0x828 +#define DINO_TLTIM 0x830 + +#define DINO_IRQS 11 /* bits 0-10 are architected */ +#define DINO_IRR_MASK 0x5ff /* only 10 bits are implemented */ +#define DINO_LOCAL_IRQS (DINO_IRQS + 1) +#define DINO_MASK_IRQ(x) (1 << (x)) + +#define PCIINTA 0x001 +#define PCIINTB 0x002 +#define PCIINTC 0x004 +#define PCIINTD 0x008 +#define PCIINTE 0x010 +#define PCIINTF 0x020 +#define GSCEXTINT 0x040 +/* #define xxx 0x080 - bit 7 is "default" */ +/* #define xxx 0x100 - bit 8 not used */ +/* #define xxx 0x200 - bit 9 not used */ +#define RS232INT 0x400 + +#define DINO_MEM_CHUNK_SIZE (8 * MiB) + +#define DINO800_REGS (1 + (DINO_TLTIM - DINO_GMASK) / 4) +static const uint32_t reg800_keep_bits[DINO800_REGS] = { + MAKE_64BIT_MASK(0, 1), /* GMASK */ + MAKE_64BIT_MASK(0, 7), /* PAMR */ + MAKE_64BIT_MASK(0, 7), /* PAPR */ + MAKE_64BIT_MASK(0, 8), /* DAMODE */ + MAKE_64BIT_MASK(0, 7), /* PCICMD */ + MAKE_64BIT_MASK(0, 9), /* PCISTS */ + MAKE_64BIT_MASK(0, 32), /* Undefined */ + MAKE_64BIT_MASK(0, 8), /* MLTIM */ + MAKE_64BIT_MASK(0, 30), /* BRDG_FEAT */ + MAKE_64BIT_MASK(0, 24), /* PCIROR */ + MAKE_64BIT_MASK(0, 22), /* PCIWOR */ + MAKE_64BIT_MASK(0, 32), /* Undocumented */ + MAKE_64BIT_MASK(0, 9), /* TLTIM */ +}; + +struct DinoState { + PCIHostState parent_obj; + + /* + * PCI_CONFIG_ADDR is parent_obj.config_reg, via pci_host_conf_be_ops, + * so that we can map PCI_CONFIG_DATA to pci_host_data_be_ops. + */ + uint32_t config_reg_dino; /* keep original copy, including 2 lowest bits */ + + uint32_t iar0; + uint32_t iar1; + uint32_t imr; + uint32_t ipr; + uint32_t icr; + uint32_t ilr; + uint32_t io_fbb_en; + uint32_t io_addr_en; + uint32_t io_control; + uint32_t toc_addr; + + uint32_t reg800[DINO800_REGS]; + + MemoryRegion this_mem; + MemoryRegion pci_mem; + MemoryRegion pci_mem_alias[32]; + + MemoryRegion *memory_as; + + AddressSpace bm_as; + MemoryRegion bm; + MemoryRegion bm_ram_alias; + MemoryRegion bm_pci_alias; + MemoryRegion bm_cpu_alias; +}; + +#endif diff --git a/hw/hppa/hppa_sys.h b/hw/hppa/hppa_sys.h index 0b18271cc9..9d8b28ec01 100644 --- a/hw/hppa/hppa_sys.h +++ b/hw/hppa/hppa_sys.h @@ -14,8 +14,6 @@ PCIBus *dino_init(MemoryRegion *, qemu_irq *, qemu_irq *); DeviceState *lasi_init(MemoryRegion *); #define enable_lasi_lan() 0 -#define TYPE_DINO_PCI_HOST_BRIDGE "dino-pcihost" - /* hppa_pci.c. */ extern const MemoryRegionOps hppa_pci_ignore_ops; extern const MemoryRegionOps hppa_pci_conf1_ops; From 0d98fbb57d4facff538a8155d1f3fa1eaf0111f0 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:22 +0100 Subject: [PATCH 133/935] hppa: use new CONFIG_HPPA_B160L option instead of CONFIG_DINO to build hppa machine DINO refers to the GSC-PCI bridge device which will soon be handled separately, however the QEMU HPPA machine is actually based upon the HPPA B160L as indicated by the Linux kernel dmesg output when booted in qemu-system-hppa and the QEMU MAINTAINERS file. Update the machine configuration to use CONFIG_HPPA_B160L instead of CONFIG_DINO and also update the machine description accordingly. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-13-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- configs/devices/hppa-softmmu/default.mak | 2 +- hw/hppa/Kconfig | 2 +- hw/hppa/machine.c | 2 +- hw/hppa/meson.build | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configs/devices/hppa-softmmu/default.mak b/configs/devices/hppa-softmmu/default.mak index b64c5eb3ff..b0364bb88f 100644 --- a/configs/devices/hppa-softmmu/default.mak +++ b/configs/devices/hppa-softmmu/default.mak @@ -6,4 +6,4 @@ # Boards: # -CONFIG_DINO=y +CONFIG_HPPA_B160L=y diff --git a/hw/hppa/Kconfig b/hw/hppa/Kconfig index 22948db025..8d64ead217 100644 --- a/hw/hppa/Kconfig +++ b/hw/hppa/Kconfig @@ -1,4 +1,4 @@ -config DINO +config HPPA_B160L bool imply PCI_DEVICES imply E1000_PCI diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index f7595c0857..971d7ffcfe 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -366,7 +366,7 @@ static void hppa_nmi(NMIState *n, int cpu_index, Error **errp) static void machine_hppa_machine_init(MachineClass *mc) { - mc->desc = "HPPA generic machine"; + mc->desc = "HPPA B160L machine"; mc->default_cpu_type = TYPE_HPPA_CPU; mc->init = machine_hppa_init; mc->reset = hppa_machine_reset; diff --git a/hw/hppa/meson.build b/hw/hppa/meson.build index 1deae83aee..32072bf204 100644 --- a/hw/hppa/meson.build +++ b/hw/hppa/meson.build @@ -1,4 +1,4 @@ hppa_ss = ss.source_set() -hppa_ss.add(when: 'CONFIG_DINO', if_true: files('pci.c', 'machine.c', 'dino.c', 'lasi.c')) +hppa_ss.add(when: 'CONFIG_HPPA_B160L', if_true: files('pci.c', 'machine.c', 'dino.c', 'lasi.c')) hw_arch += {'hppa': hppa_ss} From 05245daf47b7c645d9952b476d63531f6d8aa7f8 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:23 +0100 Subject: [PATCH 134/935] dino: change dino_init() to return the DINO device instead of PCIBus This is in preparation for using more qdev APIs during the configuration of the HPPA generic machine. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-14-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.c | 8 +++----- hw/hppa/hppa_sys.h | 3 ++- hw/hppa/machine.c | 6 ++++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index 01546ff6fc..6c488c908e 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -409,12 +409,11 @@ static void dino_set_serial_irq(void *opaque, int irq, int level) dino_set_irq(opaque, 10, level); } -PCIBus *dino_init(MemoryRegion *addr_space, - qemu_irq *p_rtc_irq, qemu_irq *p_ser_irq) +DinoState *dino_init(MemoryRegion *addr_space, + qemu_irq *p_rtc_irq, qemu_irq *p_ser_irq) { DeviceState *dev; DinoState *s; - PCIBus *pci_bus; dev = qdev_new(TYPE_DINO_PCI_HOST_BRIDGE); object_property_set_link(OBJECT(dev), "memory-as", OBJECT(addr_space), @@ -428,8 +427,7 @@ PCIBus *dino_init(MemoryRegion *addr_space, *p_rtc_irq = qemu_allocate_irq(dino_set_timer_irq, s, 0); *p_ser_irq = qemu_allocate_irq(dino_set_serial_irq, s, 0); - pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci")); - return pci_bus; + return s; } static void dino_pcihost_reset(DeviceState *dev) diff --git a/hw/hppa/hppa_sys.h b/hw/hppa/hppa_sys.h index 9d8b28ec01..88773d2c35 100644 --- a/hw/hppa/hppa_sys.h +++ b/hw/hppa/hppa_sys.h @@ -9,8 +9,9 @@ #include "hw/intc/i8259.h" #include "hppa_hardware.h" +#include "dino.h" -PCIBus *dino_init(MemoryRegion *, qemu_irq *, qemu_irq *); +DinoState *dino_init(MemoryRegion *, qemu_irq *, qemu_irq *); DeviceState *lasi_init(MemoryRegion *); #define enable_lasi_lan() 0 diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 971d7ffcfe..94bc1b202a 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -17,6 +17,7 @@ #include "hw/char/serial.h" #include "hw/net/lasi_82596.h" #include "hw/nmi.h" +#include "dino.h" #include "hppa_sys.h" #include "qemu/units.h" #include "qapi/error.h" @@ -126,7 +127,7 @@ static void machine_hppa_init(MachineState *machine) const char *kernel_filename = machine->kernel_filename; const char *kernel_cmdline = machine->kernel_cmdline; const char *initrd_filename = machine->initrd_filename; - DeviceState *dev; + DeviceState *dev, *dino_dev; PCIBus *pci_bus; ISABus *isa_bus; qemu_irq rtc_irq, serial_irq; @@ -166,7 +167,8 @@ static void machine_hppa_init(MachineState *machine) lasi_init(addr_space); /* Init Dino (PCI host bus chip). */ - pci_bus = dino_init(addr_space, &rtc_irq, &serial_irq); + dino_dev = DEVICE(dino_init(addr_space, &rtc_irq, &serial_irq)); + pci_bus = PCI_BUS(qdev_get_child_bus(dino_dev, "pci")); assert(pci_bus); /* Create ISA bus. */ From efdb3ce2de8e5d3e27fbb7d403616be71b950130 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:24 +0100 Subject: [PATCH 135/935] machine.c: map DINO device during board configuration Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-15-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.c | 3 --- hw/hppa/machine.c | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index 6c488c908e..82f301653b 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -421,9 +421,6 @@ DinoState *dino_init(MemoryRegion *addr_space, s = DINO_PCI_HOST_BRIDGE(dev); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - memory_region_add_subregion(addr_space, DINO_HPA, - sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0)); - *p_rtc_irq = qemu_allocate_irq(dino_set_timer_irq, s, 0); *p_ser_irq = qemu_allocate_irq(dino_set_serial_irq, s, 0); diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 94bc1b202a..5a490a9c37 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -168,6 +168,9 @@ static void machine_hppa_init(MachineState *machine) /* Init Dino (PCI host bus chip). */ dino_dev = DEVICE(dino_init(addr_space, &rtc_irq, &serial_irq)); + memory_region_add_subregion(addr_space, DINO_HPA, + sysbus_mmio_get_region( + SYS_BUS_DEVICE(dino_dev), 0)); pci_bus = PCI_BUS(qdev_get_child_bus(dino_dev, "pci")); assert(pci_bus); From 10c5264172bea2d7f55e013095a80000f00d05c0 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:25 +0100 Subject: [PATCH 136/935] dino.h: add defines for DINO IRQ numbers This is to allow the DINO IRQs to be defined as qdev GPIOs. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-16-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hw/hppa/dino.h b/hw/hppa/dino.h index 1a26667377..70fb8c52c8 100644 --- a/hw/hppa/dino.h +++ b/hw/hppa/dino.h @@ -58,6 +58,18 @@ OBJECT_DECLARE_SIMPLE_TYPE(DinoState, DINO_PCI_HOST_BRIDGE) #define DINO_LOCAL_IRQS (DINO_IRQS + 1) #define DINO_MASK_IRQ(x) (1 << (x)) +#define DINO_IRQ_PCIINTA 0 +#define DINO_IRQ_PCIINTB 1 +#define DINO_IRQ_PCIINTC 2 +#define DINO_IRQ_PCIINTD 3 +#define DINO_IRQ_PCIINTE 4 +#define DINO_IRQ_PCIINTF 5 +#define DINO_IRQ_GSCEXTINT 6 +#define DINO_IRQ_BUSERRINT 7 +#define DINO_IRQ_PS2INT 8 +#define DINO_IRQ_UNUSED 9 +#define DINO_IRQ_RS232INT 10 + #define PCIINTA 0x001 #define PCIINTB 0x002 #define PCIINTC 0x004 From 4b5faaf94ff3cf47a6c63393ed1332ef4928dadf Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:26 +0100 Subject: [PATCH 137/935] dino: define IRQ inputs as qdev GPIOs Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-17-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.c | 2 ++ hw/hppa/dino.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index 82f301653b..f58aebf94d 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -513,6 +513,8 @@ static void dino_pcihost_init(Object *obj) pci_setup_iommu(phb->bus, dino_pcihost_set_iommu, s); sysbus_init_mmio(sbd, &s->this_mem); + + qdev_init_gpio_in(DEVICE(obj), dino_set_irq, DINO_IRQS); } static Property dino_pcihost_properties[] = { diff --git a/hw/hppa/dino.h b/hw/hppa/dino.h index 70fb8c52c8..ca380515f2 100644 --- a/hw/hppa/dino.h +++ b/hw/hppa/dino.h @@ -134,6 +134,8 @@ struct DinoState { MemoryRegion bm_ram_alias; MemoryRegion bm_pci_alias; MemoryRegion bm_cpu_alias; + + qemu_irq irqs[DINO_IRQS]; }; #endif From a4b74c1924b79b91ca6aeb20cdd39156b5c7b4f7 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:27 +0100 Subject: [PATCH 138/935] dino: wire up serial IRQ using a qdev GPIO in machine.c This makes it unnecessary to allocate a separate IRQ for the serial port. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-18-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.c | 8 +------- hw/hppa/hppa_sys.h | 2 +- hw/hppa/machine.c | 7 ++++--- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index f58aebf94d..80ffe27188 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -404,13 +404,8 @@ static void dino_set_timer_irq(void *opaque, int irq, int level) /* ??? Not connected. */ } -static void dino_set_serial_irq(void *opaque, int irq, int level) -{ - dino_set_irq(opaque, 10, level); -} - DinoState *dino_init(MemoryRegion *addr_space, - qemu_irq *p_rtc_irq, qemu_irq *p_ser_irq) + qemu_irq *p_rtc_irq) { DeviceState *dev; DinoState *s; @@ -422,7 +417,6 @@ DinoState *dino_init(MemoryRegion *addr_space, sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); *p_rtc_irq = qemu_allocate_irq(dino_set_timer_irq, s, 0); - *p_ser_irq = qemu_allocate_irq(dino_set_serial_irq, s, 0); return s; } diff --git a/hw/hppa/hppa_sys.h b/hw/hppa/hppa_sys.h index 88773d2c35..c238e7ebc8 100644 --- a/hw/hppa/hppa_sys.h +++ b/hw/hppa/hppa_sys.h @@ -11,7 +11,7 @@ #include "hppa_hardware.h" #include "dino.h" -DinoState *dino_init(MemoryRegion *, qemu_irq *, qemu_irq *); +DinoState *dino_init(MemoryRegion *, qemu_irq *); DeviceState *lasi_init(MemoryRegion *); #define enable_lasi_lan() 0 diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 5a490a9c37..f757aecda0 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -130,7 +130,7 @@ static void machine_hppa_init(MachineState *machine) DeviceState *dev, *dino_dev; PCIBus *pci_bus; ISABus *isa_bus; - qemu_irq rtc_irq, serial_irq; + qemu_irq rtc_irq; char *firmware_filename; uint64_t firmware_low, firmware_high; long size; @@ -167,7 +167,7 @@ static void machine_hppa_init(MachineState *machine) lasi_init(addr_space); /* Init Dino (PCI host bus chip). */ - dino_dev = DEVICE(dino_init(addr_space, &rtc_irq, &serial_irq)); + dino_dev = DEVICE(dino_init(addr_space, &rtc_irq)); memory_region_add_subregion(addr_space, DINO_HPA, sysbus_mmio_get_region( SYS_BUS_DEVICE(dino_dev), 0)); @@ -184,7 +184,8 @@ static void machine_hppa_init(MachineState *machine) /* Serial code setup. */ if (serial_hd(0)) { uint32_t addr = DINO_UART_HPA + 0x800; - serial_mm_init(addr_space, addr, 0, serial_irq, + serial_mm_init(addr_space, addr, 0, + qdev_get_gpio_in(dino_dev, DINO_IRQ_RS232INT), 115200, serial_hd(0), DEVICE_BIG_ENDIAN); } From 36f9bbdb1717eeb9b10cbfa3135c942c43d13d25 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:28 +0100 Subject: [PATCH 139/935] dino: remove unused dino_set_timer_irq() IRQ handler According to the comments in dino.c the timer IRQ is unused, so remove the empty dino_set_timer_irq() handler function and simply pass NULL to mc146818_rtc_init() in machine.c instead. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-19-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.c | 10 +--------- hw/hppa/hppa_sys.h | 2 +- hw/hppa/machine.c | 5 ++--- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index 80ffe27188..d8baf139d6 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -399,13 +399,7 @@ static int dino_pci_map_irq(PCIDevice *d, int irq_num) return slot & 0x03; } -static void dino_set_timer_irq(void *opaque, int irq, int level) -{ - /* ??? Not connected. */ -} - -DinoState *dino_init(MemoryRegion *addr_space, - qemu_irq *p_rtc_irq) +DinoState *dino_init(MemoryRegion *addr_space) { DeviceState *dev; DinoState *s; @@ -416,8 +410,6 @@ DinoState *dino_init(MemoryRegion *addr_space, s = DINO_PCI_HOST_BRIDGE(dev); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - *p_rtc_irq = qemu_allocate_irq(dino_set_timer_irq, s, 0); - return s; } diff --git a/hw/hppa/hppa_sys.h b/hw/hppa/hppa_sys.h index c238e7ebc8..ebedecf1c8 100644 --- a/hw/hppa/hppa_sys.h +++ b/hw/hppa/hppa_sys.h @@ -11,7 +11,7 @@ #include "hppa_hardware.h" #include "dino.h" -DinoState *dino_init(MemoryRegion *, qemu_irq *); +DinoState *dino_init(MemoryRegion *); DeviceState *lasi_init(MemoryRegion *); #define enable_lasi_lan() 0 diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index f757aecda0..49ecb971be 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -130,7 +130,6 @@ static void machine_hppa_init(MachineState *machine) DeviceState *dev, *dino_dev; PCIBus *pci_bus; ISABus *isa_bus; - qemu_irq rtc_irq; char *firmware_filename; uint64_t firmware_low, firmware_high; long size; @@ -167,7 +166,7 @@ static void machine_hppa_init(MachineState *machine) lasi_init(addr_space); /* Init Dino (PCI host bus chip). */ - dino_dev = DEVICE(dino_init(addr_space, &rtc_irq)); + dino_dev = DEVICE(dino_init(addr_space)); memory_region_add_subregion(addr_space, DINO_HPA, sysbus_mmio_get_region( SYS_BUS_DEVICE(dino_dev), 0)); @@ -179,7 +178,7 @@ static void machine_hppa_init(MachineState *machine) assert(isa_bus); /* Realtime clock, used by firmware for PDC_TOD call. */ - mc146818_rtc_init(isa_bus, 2000, rtc_irq); + mc146818_rtc_init(isa_bus, 2000, NULL); /* Serial code setup. */ if (serial_hd(0)) { From 0d068996310c33c2f40dd347746304054fdfa16d Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:29 +0100 Subject: [PATCH 140/935] hppa: move dino_init() from dino.c to machine.c Now that dino_init() is completely decoupled from dino.c it can be moved to machine.c with the rest of the board configuration. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-20-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.c | 14 -------------- hw/hppa/hppa_sys.h | 2 -- hw/hppa/machine.c | 12 ++++++++++++ 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index d8baf139d6..6d12c385aa 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -399,20 +399,6 @@ static int dino_pci_map_irq(PCIDevice *d, int irq_num) return slot & 0x03; } -DinoState *dino_init(MemoryRegion *addr_space) -{ - DeviceState *dev; - DinoState *s; - - dev = qdev_new(TYPE_DINO_PCI_HOST_BRIDGE); - object_property_set_link(OBJECT(dev), "memory-as", OBJECT(addr_space), - &error_fatal); - s = DINO_PCI_HOST_BRIDGE(dev); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - - return s; -} - static void dino_pcihost_reset(DeviceState *dev) { DinoState *s = DINO_PCI_HOST_BRIDGE(dev); diff --git a/hw/hppa/hppa_sys.h b/hw/hppa/hppa_sys.h index ebedecf1c8..7c31dd8396 100644 --- a/hw/hppa/hppa_sys.h +++ b/hw/hppa/hppa_sys.h @@ -9,9 +9,7 @@ #include "hw/intc/i8259.h" #include "hppa_hardware.h" -#include "dino.h" -DinoState *dino_init(MemoryRegion *); DeviceState *lasi_init(MemoryRegion *); #define enable_lasi_lan() 0 diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 49ecb971be..4b753fa346 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -122,6 +122,18 @@ static FWCfgState *create_fw_cfg(MachineState *ms) return fw_cfg; } +static DinoState *dino_init(MemoryRegion *addr_space) +{ + DeviceState *dev; + + dev = qdev_new(TYPE_DINO_PCI_HOST_BRIDGE); + object_property_set_link(OBJECT(dev), "memory-as", OBJECT(addr_space), + &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + return DINO_PCI_HOST_BRIDGE(dev); +} + static void machine_hppa_init(MachineState *machine) { const char *kernel_filename = machine->kernel_filename; From 2fb11c7cac7f6074f42d821cfbff4d7b80b3ab6f Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:30 +0100 Subject: [PATCH 141/935] dino: use numerical constant for iar0 and iar1 reset values This is to allow us to decouple the DINO device from the board logic. The choice of using a hard-coded constant (along with a comment) is to match how this is already done for toc_addr. If it is decided later that these values need to be configurable then they can easily be converted to qdev properties. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-21-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index 6d12c385aa..aa7f812e22 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -403,7 +403,7 @@ static void dino_pcihost_reset(DeviceState *dev) { DinoState *s = DINO_PCI_HOST_BRIDGE(dev); - s->iar0 = s->iar1 = CPU_HPA + 3; + s->iar0 = s->iar1 = 0xFFFB0000 + 3; /* CPU_HPA + 3 */ s->toc_addr = 0xFFFA0030; /* IO_COMMAND of CPU */ } From e111f288d9264dae070bd144a60f43162e34a7be Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:31 +0100 Subject: [PATCH 142/935] dino: move DINO HPA constants from hppa_hardware.h to dino.h This is to allow us to decouple the DINO device from the board logic. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-22-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/dino.h | 5 +++++ hw/hppa/hppa_hardware.h | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/hppa/dino.h b/hw/hppa/dino.h index ca380515f2..a1b0184940 100644 --- a/hw/hppa/dino.h +++ b/hw/hppa/dino.h @@ -101,6 +101,11 @@ static const uint32_t reg800_keep_bits[DINO800_REGS] = { MAKE_64BIT_MASK(0, 9), /* TLTIM */ }; +/* offsets to DINO HPA: */ +#define DINO_PCI_ADDR 0x064 +#define DINO_CONFIG_DATA 0x068 +#define DINO_IO_DATA 0x06c + struct DinoState { PCIHostState parent_obj; diff --git a/hw/hppa/hppa_hardware.h b/hw/hppa/hppa_hardware.h index 5edf577563..8b6b9222cb 100644 --- a/hw/hppa/hppa_hardware.h +++ b/hw/hppa/hppa_hardware.h @@ -30,11 +30,6 @@ #define PCI_HPA DINO_HPA /* PCI bus */ #define IDE_HPA 0xf9000000 /* Boot disc controller */ -/* offsets to DINO HPA: */ -#define DINO_PCI_ADDR 0x064 -#define DINO_CONFIG_DATA 0x068 -#define DINO_IO_DATA 0x06c - #define PORT_PCI_CMD (PCI_HPA + DINO_PCI_ADDR) #define PORT_PCI_DATA (PCI_HPA + DINO_CONFIG_DATA) From 0db9350e6e5aba3dc864d36756b01fb0922ad7cb Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:32 +0100 Subject: [PATCH 143/935] dino: move from hw/hppa to hw/pci-host Move the DINO device implementation from hw/hppa to hw/pci-host so that it is located with all the other PCI host bridges. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-23-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- MAINTAINERS | 2 ++ hw/hppa/Kconfig | 2 +- hw/hppa/machine.c | 2 +- hw/hppa/meson.build | 2 +- hw/hppa/trace-events | 5 ----- hw/pci-host/Kconfig | 4 ++++ hw/{hppa => pci-host}/dino.c | 3 +-- hw/pci-host/meson.build | 3 +++ hw/pci-host/trace-events | 5 +++++ {hw/hppa => include/hw/pci-host}/dino.h | 0 10 files changed, 18 insertions(+), 10 deletions(-) rename hw/{hppa => pci-host}/dino.c (99%) rename {hw/hppa => include/hw/pci-host}/dino.h (100%) diff --git a/MAINTAINERS b/MAINTAINERS index 218c9459b6..59210b093a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1113,7 +1113,9 @@ S: Odd Fixes F: configs/devices/hppa-softmmu/default.mak F: hw/hppa/ F: hw/net/*i82596* +F: hw/pci-host/dino.c F: include/hw/net/lasi_82596.h +F: include/hw/pci-host/dino.h F: pc-bios/hppa-firmware.img M68K Machines diff --git a/hw/hppa/Kconfig b/hw/hppa/Kconfig index 8d64ead217..724380ecec 100644 --- a/hw/hppa/Kconfig +++ b/hw/hppa/Kconfig @@ -3,7 +3,7 @@ config HPPA_B160L imply PCI_DEVICES imply E1000_PCI imply VIRTIO_VGA - select PCI + select DINO select SERIAL select ISA_BUS select I8259 diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 4b753fa346..c847febe5d 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -17,7 +17,7 @@ #include "hw/char/serial.h" #include "hw/net/lasi_82596.h" #include "hw/nmi.h" -#include "dino.h" +#include "hw/pci-host/dino.h" #include "hppa_sys.h" #include "qemu/units.h" #include "qapi/error.h" diff --git a/hw/hppa/meson.build b/hw/hppa/meson.build index 32072bf204..a6f9db455c 100644 --- a/hw/hppa/meson.build +++ b/hw/hppa/meson.build @@ -1,4 +1,4 @@ hppa_ss = ss.source_set() -hppa_ss.add(when: 'CONFIG_HPPA_B160L', if_true: files('pci.c', 'machine.c', 'dino.c', 'lasi.c')) +hppa_ss.add(when: 'CONFIG_HPPA_B160L', if_true: files('pci.c', 'machine.c', 'lasi.c')) hw_arch += {'hppa': hppa_ss} diff --git a/hw/hppa/trace-events b/hw/hppa/trace-events index 3f42be9056..871a473771 100644 --- a/hw/hppa/trace-events +++ b/hw/hppa/trace-events @@ -3,11 +3,6 @@ # pci.c hppa_pci_iack_write(void) "" -# dino.c -dino_chip_mem_valid(uint64_t addr, uint32_t val) "access to addr 0x%"PRIx64" is %d" -dino_chip_read(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" -dino_chip_write(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" - # lasi.c lasi_chip_mem_valid(uint64_t addr, uint32_t val) "access to addr 0x%"PRIx64" is %d" lasi_chip_read(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig index 2b5f7d58cc..38fd2ee8f3 100644 --- a/hw/pci-host/Kconfig +++ b/hw/pci-host/Kconfig @@ -77,3 +77,7 @@ config MV64361 bool select PCI select I8259 + +config DINO + bool + select PCI diff --git a/hw/hppa/dino.c b/hw/pci-host/dino.c similarity index 99% rename from hw/hppa/dino.c rename to hw/pci-host/dino.c index aa7f812e22..f257c24e64 100644 --- a/hw/hppa/dino.c +++ b/hw/pci-host/dino.c @@ -18,9 +18,8 @@ #include "hw/pci/pci.h" #include "hw/pci/pci_bus.h" #include "hw/qdev-properties.h" -#include "dino.h" +#include "hw/pci-host/dino.h" #include "migration/vmstate.h" -#include "hppa_sys.h" #include "trace.h" #include "qom/object.h" diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build index 4c4f39c15c..c07596d0d1 100644 --- a/hw/pci-host/meson.build +++ b/hw/pci-host/meson.build @@ -25,6 +25,9 @@ pci_ss.add(when: 'CONFIG_MV64361', if_true: files('mv64361.c')) # ARM devices pci_ss.add(when: 'CONFIG_VERSATILE_PCI', if_true: files('versatile.c')) +# HPPA devices +pci_ss.add(when: 'CONFIG_DINO', if_true: files('dino.c')) + softmmu_ss.add_all(when: 'CONFIG_PCI', if_true: pci_ss) specific_ss.add(when: 'CONFIG_PCI_POWERNV', if_true: files( diff --git a/hw/pci-host/trace-events b/hw/pci-host/trace-events index 6e5d8d3355..437e66ff50 100644 --- a/hw/pci-host/trace-events +++ b/hw/pci-host/trace-events @@ -34,3 +34,8 @@ unin_read(uint64_t addr, uint64_t value) "addr=0x%" PRIx64 " val=0x%"PRIx64 pnv_phb4_xive_notify(uint64_t notif_port, uint64_t data) "notif=@0x%"PRIx64" data=0x%"PRIx64 pnv_phb4_xive_notify_ic(uint64_t addr, uint64_t data) "addr=@0x%"PRIx64" data=0x%"PRIx64 pnv_phb4_xive_notify_abt(uint64_t notif_port, uint64_t data) "notif=@0x%"PRIx64" data=0x%"PRIx64 + +# dino.c +dino_chip_mem_valid(uint64_t addr, uint32_t val) "access to addr 0x%"PRIx64" is %d" +dino_chip_read(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" +dino_chip_write(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" diff --git a/hw/hppa/dino.h b/include/hw/pci-host/dino.h similarity index 100% rename from hw/hppa/dino.h rename to include/hw/pci-host/dino.h From 63588da809704c8e674d8ffb01f66597cf5e6150 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:33 +0100 Subject: [PATCH 144/935] lasi: checkpatch fixes Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-24-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/lasi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index 88c3791eb6..3b77fba1c6 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -169,10 +169,11 @@ static MemTxResult lasi_chip_write_with_attrs(void *opaque, hwaddr addr, break; case LASI_IMR: s->imr = val; - if (((val & LASI_IRQ_BITS) != val) && (val != 0xffffffff)) + if (((val & LASI_IRQ_BITS) != val) && (val != 0xffffffff)) { qemu_log_mask(LOG_GUEST_ERROR, "LASI: tried to set invalid %lx IMR value.\n", (unsigned long) val); + } break; case LASI_IPR: /* Any write to IPR clears the register. */ @@ -200,8 +201,9 @@ static MemTxResult lasi_chip_write_with_attrs(void *opaque, hwaddr addr, break; case LASI_PCR: - if (val == 0x02) /* immediately power off */ + if (val == 0x02) { /* immediately power off */ qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); + } break; case LASI_ERRLOG: s->errlog = val; From 46f2594cfca9e888531a5d45a1e33d5446f75578 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:34 +0100 Subject: [PATCH 145/935] lasi: move memory region initialisation to new lasi_init() function Create a new lasi_init() instance initialisation function and move the LASI memory region initialisation into it. Rename the existing lasi_init() function to lasi_initfn() for now. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-25-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/hppa_sys.h | 2 +- hw/hppa/lasi.c | 13 ++++++++++--- hw/hppa/machine.c | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/hw/hppa/hppa_sys.h b/hw/hppa/hppa_sys.h index 7c31dd8396..0929dedded 100644 --- a/hw/hppa/hppa_sys.h +++ b/hw/hppa/hppa_sys.h @@ -10,7 +10,7 @@ #include "hppa_hardware.h" -DeviceState *lasi_init(MemoryRegion *); +DeviceState *lasi_initfn(MemoryRegion *); #define enable_lasi_lan() 0 /* hppa_pci.c. */ diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index 3b77fba1c6..c028b7786e 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -296,7 +296,7 @@ static int lasi_get_irq(unsigned long hpa) } } -DeviceState *lasi_init(MemoryRegion *address_space) +DeviceState *lasi_initfn(MemoryRegion *address_space) { DeviceState *dev; LasiState *s; @@ -306,8 +306,6 @@ DeviceState *lasi_init(MemoryRegion *address_space) s->iar = CPU_HPA + 3; /* Lasi access from main memory. */ - memory_region_init_io(&s->this_mem, OBJECT(s), &lasi_chip_ops, - s, "lasi", 0x100000); memory_region_add_subregion(address_space, LASI_HPA, &s->this_mem); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); @@ -347,6 +345,14 @@ DeviceState *lasi_init(MemoryRegion *address_space) return dev; } +static void lasi_init(Object *obj) +{ + LasiState *s = LASI_CHIP(obj); + + memory_region_init_io(&s->this_mem, OBJECT(s), &lasi_chip_ops, + s, "lasi", 0x100000); +} + static void lasi_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -357,6 +363,7 @@ static void lasi_class_init(ObjectClass *klass, void *data) static const TypeInfo lasi_pcihost_info = { .name = TYPE_LASI_CHIP, .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = lasi_init, .instance_size = sizeof(LasiState), .class_init = lasi_class_init, }; diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index c847febe5d..2fa55de549 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -175,7 +175,7 @@ static void machine_hppa_init(MachineState *machine) /* Init Lasi chip */ - lasi_init(addr_space); + lasi_initfn(addr_space); /* Init Dino (PCI host bus chip). */ dino_dev = DEVICE(dino_init(addr_space)); From 2683758c7c48718d032ed8bffdeb2c37f3a357c8 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:35 +0100 Subject: [PATCH 146/935] lasi: move register memory mapping from lasi.c to machine.c The device register should be mapped directly by the board code. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-26-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/lasi.c | 7 +++---- hw/hppa/machine.c | 7 +++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index c028b7786e..08ebe7c6d9 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -304,10 +304,6 @@ DeviceState *lasi_initfn(MemoryRegion *address_space) dev = qdev_new(TYPE_LASI_CHIP); s = LASI_CHIP(dev); s->iar = CPU_HPA + 3; - - /* Lasi access from main memory. */ - memory_region_add_subregion(address_space, LASI_HPA, &s->this_mem); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* LAN */ @@ -348,9 +344,12 @@ DeviceState *lasi_initfn(MemoryRegion *address_space) static void lasi_init(Object *obj) { LasiState *s = LASI_CHIP(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); memory_region_init_io(&s->this_mem, OBJECT(s), &lasi_chip_ops, s, "lasi", 0x100000); + + sysbus_init_mmio(sbd, &s->this_mem); } static void lasi_class_init(ObjectClass *klass, void *data) diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 2fa55de549..6618bce435 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -139,7 +139,7 @@ static void machine_hppa_init(MachineState *machine) const char *kernel_filename = machine->kernel_filename; const char *kernel_cmdline = machine->kernel_cmdline; const char *initrd_filename = machine->initrd_filename; - DeviceState *dev, *dino_dev; + DeviceState *dev, *dino_dev, *lasi_dev; PCIBus *pci_bus; ISABus *isa_bus; char *firmware_filename; @@ -175,7 +175,10 @@ static void machine_hppa_init(MachineState *machine) /* Init Lasi chip */ - lasi_initfn(addr_space); + lasi_dev = lasi_initfn(addr_space); + memory_region_add_subregion(addr_space, LASI_HPA, + sysbus_mmio_get_region( + SYS_BUS_DEVICE(lasi_dev), 0)); /* Init Dino (PCI host bus chip). */ dino_dev = DEVICE(dino_init(addr_space)); From b3cdb7e4b29a4f1824ff6c1c12ddcf65857bfb9e Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:36 +0100 Subject: [PATCH 147/935] lasi: move initialisation of iar and rtc to new lasi_reset() function Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-27-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/lasi.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index 08ebe7c6d9..242713c7bd 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -303,7 +303,6 @@ DeviceState *lasi_initfn(MemoryRegion *address_space) dev = qdev_new(TYPE_LASI_CHIP); s = LASI_CHIP(dev); - s->iar = CPU_HPA + 3; sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* LAN */ @@ -319,11 +318,6 @@ DeviceState *lasi_initfn(MemoryRegion *address_space) parallel_mm_init(address_space, LASI_LPT_HPA + 0x800, 0, lpt_irq, parallel_hds[0]); - /* Real time clock (RTC), it's only one 32-bit counter @9000 */ - - s->rtc = time(NULL); - s->rtc_ref = 0; - if (serial_hd(1)) { /* Serial port */ qemu_irq serial_irq = qemu_allocate_irq(lasi_set_irq, s, @@ -341,6 +335,17 @@ DeviceState *lasi_initfn(MemoryRegion *address_space) return dev; } +static void lasi_reset(DeviceState *dev) +{ + LasiState *s = LASI_CHIP(dev); + + s->iar = CPU_HPA + 3; + + /* Real time clock (RTC), it's only one 32-bit counter @9000 */ + s->rtc = time(NULL); + s->rtc_ref = 0; +} + static void lasi_init(Object *obj) { LasiState *s = LASI_CHIP(obj); @@ -356,6 +361,7 @@ static void lasi_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + dc->reset = lasi_reset; dc->vmsd = &vmstate_lasi; } From b514f432445608c516cd82a93ae7c761454f17ea Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:37 +0100 Subject: [PATCH 148/935] lasi: move LASIState and associated QOM structures to lasi.h Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-28-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/lasi.c | 44 +------------------------------------- hw/hppa/lasi.h | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 43 deletions(-) create mode 100644 hw/hppa/lasi.h diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index 242713c7bd..c1dfd5310f 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -24,50 +24,8 @@ #include "hw/input/lasips2.h" #include "migration/vmstate.h" #include "qom/object.h" +#include "lasi.h" -#define TYPE_LASI_CHIP "lasi-chip" - -#define LASI_IRR 0x00 /* RO */ -#define LASI_IMR 0x04 -#define LASI_IPR 0x08 -#define LASI_ICR 0x0c -#define LASI_IAR 0x10 - -#define LASI_PCR 0x0C000 /* LASI Power Control register */ -#define LASI_ERRLOG 0x0C004 /* LASI Error Logging register */ -#define LASI_VER 0x0C008 /* LASI Version Control register */ -#define LASI_IORESET 0x0C00C /* LASI I/O Reset register */ -#define LASI_AMR 0x0C010 /* LASI Arbitration Mask register */ -#define LASI_IO_CONF 0x7FFFE /* LASI primary configuration register */ -#define LASI_IO_CONF2 0x7FFFF /* LASI secondary configuration register */ - -#define LASI_BIT(x) (1ul << (x)) -#define LASI_IRQ_BITS (LASI_BIT(5) | LASI_BIT(7) | LASI_BIT(8) | LASI_BIT(9) \ - | LASI_BIT(13) | LASI_BIT(14) | LASI_BIT(16) | LASI_BIT(17) \ - | LASI_BIT(18) | LASI_BIT(19) | LASI_BIT(20) | LASI_BIT(21) \ - | LASI_BIT(26)) - -#define ICR_BUS_ERROR_BIT LASI_BIT(8) /* bit 8 in ICR */ -#define ICR_TOC_BIT LASI_BIT(1) /* bit 1 in ICR */ - -OBJECT_DECLARE_SIMPLE_TYPE(LasiState, LASI_CHIP) - -struct LasiState { - PCIHostState parent_obj; - - uint32_t irr; - uint32_t imr; - uint32_t ipr; - uint32_t icr; - uint32_t iar; - - uint32_t errlog; - uint32_t amr; - uint32_t rtc; - time_t rtc_ref; - - MemoryRegion this_mem; -}; static bool lasi_chip_mem_valid(void *opaque, hwaddr addr, unsigned size, bool is_write, diff --git a/hw/hppa/lasi.h b/hw/hppa/lasi.h new file mode 100644 index 0000000000..559aae2560 --- /dev/null +++ b/hw/hppa/lasi.h @@ -0,0 +1,58 @@ +/* + * HP-PARISC Lasi chipset emulation. + * + * (C) 2019 by Helge Deller + * + * This work is licensed under the GNU GPL license version 2 or later. + * + * Documentation available at: + * https://parisc.wiki.kernel.org/images-parisc/7/79/Lasi_ers.pdf + */ + +#ifndef LASI_H +#define LASI_H + +#define TYPE_LASI_CHIP "lasi-chip" +OBJECT_DECLARE_SIMPLE_TYPE(LasiState, LASI_CHIP) + +#define LASI_IRR 0x00 /* RO */ +#define LASI_IMR 0x04 +#define LASI_IPR 0x08 +#define LASI_ICR 0x0c +#define LASI_IAR 0x10 + +#define LASI_PCR 0x0C000 /* LASI Power Control register */ +#define LASI_ERRLOG 0x0C004 /* LASI Error Logging register */ +#define LASI_VER 0x0C008 /* LASI Version Control register */ +#define LASI_IORESET 0x0C00C /* LASI I/O Reset register */ +#define LASI_AMR 0x0C010 /* LASI Arbitration Mask register */ +#define LASI_IO_CONF 0x7FFFE /* LASI primary configuration register */ +#define LASI_IO_CONF2 0x7FFFF /* LASI secondary configuration register */ + +#define LASI_BIT(x) (1ul << (x)) +#define LASI_IRQ_BITS (LASI_BIT(5) | LASI_BIT(7) | LASI_BIT(8) | LASI_BIT(9) \ + | LASI_BIT(13) | LASI_BIT(14) | LASI_BIT(16) | LASI_BIT(17) \ + | LASI_BIT(18) | LASI_BIT(19) | LASI_BIT(20) | LASI_BIT(21) \ + | LASI_BIT(26)) + +#define ICR_BUS_ERROR_BIT LASI_BIT(8) /* bit 8 in ICR */ +#define ICR_TOC_BIT LASI_BIT(1) /* bit 1 in ICR */ + +struct LasiState { + PCIHostState parent_obj; + + uint32_t irr; + uint32_t imr; + uint32_t ipr; + uint32_t icr; + uint32_t iar; + + uint32_t errlog; + uint32_t amr; + uint32_t rtc; + time_t rtc_ref; + + MemoryRegion this_mem; +}; + +#endif From 0f04d5777b7c3b1fe260838f3c1f05a6c6452a8d Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:38 +0100 Subject: [PATCH 149/935] lasi: replace lasi_get_irq() with defined constants Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-29-mark.cave-ayland@ilande.co.uk> Signed-off-by: Mark Cave-Ayland --- hw/hppa/lasi.c | 31 ++++--------------------------- hw/hppa/lasi.h | 9 +++++++++ 2 files changed, 13 insertions(+), 27 deletions(-) diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index c1dfd5310f..ec079601a1 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -231,29 +231,6 @@ static void lasi_set_irq(void *opaque, int irq, int level) } } -static int lasi_get_irq(unsigned long hpa) -{ - switch (hpa) { - case LASI_HPA: - return 14; - case LASI_UART_HPA: - return 5; - case LASI_LPT_HPA: - return 7; - case LASI_LAN_HPA: - return 8; - case LASI_SCSI_HPA: - return 9; - case LASI_AUDIO_HPA: - return 13; - case LASI_PS2KBD_HPA: - case LASI_PS2MOU_HPA: - return 26; - default: - g_assert_not_reached(); - } -} - DeviceState *lasi_initfn(MemoryRegion *address_space) { DeviceState *dev; @@ -266,20 +243,20 @@ DeviceState *lasi_initfn(MemoryRegion *address_space) /* LAN */ if (enable_lasi_lan()) { qemu_irq lan_irq = qemu_allocate_irq(lasi_set_irq, s, - lasi_get_irq(LASI_LAN_HPA)); + LASI_IRQ_LAN_HPA); lasi_82596_init(address_space, LASI_LAN_HPA, lan_irq); } /* Parallel port */ qemu_irq lpt_irq = qemu_allocate_irq(lasi_set_irq, s, - lasi_get_irq(LASI_LPT_HPA)); + LASI_IRQ_LPT_HPA); parallel_mm_init(address_space, LASI_LPT_HPA + 0x800, 0, lpt_irq, parallel_hds[0]); if (serial_hd(1)) { /* Serial port */ qemu_irq serial_irq = qemu_allocate_irq(lasi_set_irq, s, - lasi_get_irq(LASI_UART_HPA)); + LASI_IRQ_UART_HPA); serial_mm_init(address_space, LASI_UART_HPA + 0x800, 0, serial_irq, 8000000 / 16, serial_hd(0), DEVICE_NATIVE_ENDIAN); @@ -287,7 +264,7 @@ DeviceState *lasi_initfn(MemoryRegion *address_space) /* PS/2 Keyboard/Mouse */ qemu_irq ps2kbd_irq = qemu_allocate_irq(lasi_set_irq, s, - lasi_get_irq(LASI_PS2KBD_HPA)); + LASI_IRQ_PS2KBD_HPA); lasips2_init(address_space, LASI_PS2KBD_HPA, ps2kbd_irq); return dev; diff --git a/hw/hppa/lasi.h b/hw/hppa/lasi.h index 559aae2560..f40546da6e 100644 --- a/hw/hppa/lasi.h +++ b/hw/hppa/lasi.h @@ -38,6 +38,15 @@ OBJECT_DECLARE_SIMPLE_TYPE(LasiState, LASI_CHIP) #define ICR_BUS_ERROR_BIT LASI_BIT(8) /* bit 8 in ICR */ #define ICR_TOC_BIT LASI_BIT(1) /* bit 1 in ICR */ +#define LASI_IRQ_HPA 14 +#define LASI_IRQ_UART_HPA 5 +#define LASI_IRQ_LPT_HPA 7 +#define LASI_IRQ_LAN_HPA 8 +#define LASI_IRQ_SCSI_HPA 9 +#define LASI_IRQ_AUDIO_HPA 13 +#define LASI_IRQ_PS2KBD_HPA 26 +#define LASI_IRQ_PS2MOU_HPA 26 + struct LasiState { PCIHostState parent_obj; From cb9f6c4b65d48717be251dcb2a171152d00885e9 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:39 +0100 Subject: [PATCH 150/935] lasi: define IRQ inputs as qdev GPIOs Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-30-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/lasi.c | 2 ++ hw/hppa/lasi.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index ec079601a1..9489a80bad 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -290,6 +290,8 @@ static void lasi_init(Object *obj) s, "lasi", 0x100000); sysbus_init_mmio(sbd, &s->this_mem); + + qdev_init_gpio_in(DEVICE(obj), lasi_set_irq, LASI_IRQS); } static void lasi_class_init(ObjectClass *klass, void *data) diff --git a/hw/hppa/lasi.h b/hw/hppa/lasi.h index f40546da6e..63a2be3740 100644 --- a/hw/hppa/lasi.h +++ b/hw/hppa/lasi.h @@ -38,6 +38,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(LasiState, LASI_CHIP) #define ICR_BUS_ERROR_BIT LASI_BIT(8) /* bit 8 in ICR */ #define ICR_TOC_BIT LASI_BIT(1) /* bit 1 in ICR */ +#define LASI_IRQS 27 + #define LASI_IRQ_HPA 14 #define LASI_IRQ_UART_HPA 5 #define LASI_IRQ_LPT_HPA 7 From e004499fd52f0bb10e1e77bedc3be0dbdd2e0f52 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:40 +0100 Subject: [PATCH 151/935] lasi: use qdev GPIOs to wire up IRQs in lasi_initfn() Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-31-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/lasi.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index 9489a80bad..32c7514d3a 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -234,38 +234,31 @@ static void lasi_set_irq(void *opaque, int irq, int level) DeviceState *lasi_initfn(MemoryRegion *address_space) { DeviceState *dev; - LasiState *s; dev = qdev_new(TYPE_LASI_CHIP); - s = LASI_CHIP(dev); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* LAN */ if (enable_lasi_lan()) { - qemu_irq lan_irq = qemu_allocate_irq(lasi_set_irq, s, - LASI_IRQ_LAN_HPA); - lasi_82596_init(address_space, LASI_LAN_HPA, lan_irq); + lasi_82596_init(address_space, LASI_LAN_HPA, + qdev_get_gpio_in(dev, LASI_IRQ_LAN_HPA)); } /* Parallel port */ - qemu_irq lpt_irq = qemu_allocate_irq(lasi_set_irq, s, - LASI_IRQ_LPT_HPA); parallel_mm_init(address_space, LASI_LPT_HPA + 0x800, 0, - lpt_irq, parallel_hds[0]); + qdev_get_gpio_in(dev, LASI_IRQ_LAN_HPA), + parallel_hds[0]); if (serial_hd(1)) { /* Serial port */ - qemu_irq serial_irq = qemu_allocate_irq(lasi_set_irq, s, - LASI_IRQ_UART_HPA); serial_mm_init(address_space, LASI_UART_HPA + 0x800, 0, - serial_irq, 8000000 / 16, + qdev_get_gpio_in(dev, LASI_IRQ_UART_HPA), 8000000 / 16, serial_hd(0), DEVICE_NATIVE_ENDIAN); } /* PS/2 Keyboard/Mouse */ - qemu_irq ps2kbd_irq = qemu_allocate_irq(lasi_set_irq, s, - LASI_IRQ_PS2KBD_HPA); - lasips2_init(address_space, LASI_PS2KBD_HPA, ps2kbd_irq); + lasips2_init(address_space, LASI_PS2KBD_HPA, + qdev_get_gpio_in(dev, LASI_IRQ_PS2KBD_HPA)); return dev; } From fe744ca3eee65e5d666a06e72c1e6b671eb2c74a Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:41 +0100 Subject: [PATCH 152/935] lasi: fix serial port initialisation The existing code checks for serial_hd(1) but sets the LASI serial port chardev to serial_hd(0). Use serial_hd(1) for the LASI serial port and also set the serial port endian to DEVICE_BIG_ENDIAN (which also matches the endian of the existing serial port). Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-32-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/lasi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index 32c7514d3a..219eb779f3 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -253,7 +253,7 @@ DeviceState *lasi_initfn(MemoryRegion *address_space) /* Serial port */ serial_mm_init(address_space, LASI_UART_HPA + 0x800, 0, qdev_get_gpio_in(dev, LASI_IRQ_UART_HPA), 8000000 / 16, - serial_hd(0), DEVICE_NATIVE_ENDIAN); + serial_hd(1), DEVICE_BIG_ENDIAN); } /* PS/2 Keyboard/Mouse */ From 954f6f7564ef48688d2146e498cb012605d461c6 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:42 +0100 Subject: [PATCH 153/935] lasi: update lasi_initfn() to return LASIState Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-33-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/hppa_sys.h | 3 ++- hw/hppa/lasi.c | 4 ++-- hw/hppa/machine.c | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/hppa/hppa_sys.h b/hw/hppa/hppa_sys.h index 0929dedded..3832b787d1 100644 --- a/hw/hppa/hppa_sys.h +++ b/hw/hppa/hppa_sys.h @@ -7,10 +7,11 @@ #include "hw/pci/pci_host.h" #include "hw/boards.h" #include "hw/intc/i8259.h" +#include "lasi.h" #include "hppa_hardware.h" -DeviceState *lasi_initfn(MemoryRegion *); +LasiState *lasi_initfn(MemoryRegion *); #define enable_lasi_lan() 0 /* hppa_pci.c. */ diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index 219eb779f3..65139bb29b 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -231,7 +231,7 @@ static void lasi_set_irq(void *opaque, int irq, int level) } } -DeviceState *lasi_initfn(MemoryRegion *address_space) +LasiState *lasi_initfn(MemoryRegion *address_space) { DeviceState *dev; @@ -260,7 +260,7 @@ DeviceState *lasi_initfn(MemoryRegion *address_space) lasips2_init(address_space, LASI_PS2KBD_HPA, qdev_get_gpio_in(dev, LASI_IRQ_PS2KBD_HPA)); - return dev; + return LASI_CHIP(dev); } static void lasi_reset(DeviceState *dev) diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 6618bce435..c815dde305 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -18,6 +18,7 @@ #include "hw/net/lasi_82596.h" #include "hw/nmi.h" #include "hw/pci-host/dino.h" +#include "lasi.h" #include "hppa_sys.h" #include "qemu/units.h" #include "qapi/error.h" @@ -175,7 +176,7 @@ static void machine_hppa_init(MachineState *machine) /* Init Lasi chip */ - lasi_dev = lasi_initfn(addr_space); + lasi_dev = DEVICE(lasi_initfn(addr_space)); memory_region_add_subregion(addr_space, LASI_HPA, sysbus_mmio_get_region( SYS_BUS_DEVICE(lasi_dev), 0)); From c3c3fe47086221de21cc387ef4c876f316463876 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:43 +0100 Subject: [PATCH 154/935] lasi: move LAN initialisation to machine.c Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-34-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/lasi.c | 7 ------- hw/hppa/machine.c | 5 +++++ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index 65139bb29b..88ff9141e4 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -18,7 +18,6 @@ #include "sysemu/sysemu.h" #include "sysemu/runstate.h" #include "hppa_sys.h" -#include "hw/net/lasi_82596.h" #include "hw/char/parallel.h" #include "hw/char/serial.h" #include "hw/input/lasips2.h" @@ -238,12 +237,6 @@ LasiState *lasi_initfn(MemoryRegion *address_space) dev = qdev_new(TYPE_LASI_CHIP); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - /* LAN */ - if (enable_lasi_lan()) { - lasi_82596_init(address_space, LASI_LAN_HPA, - qdev_get_gpio_in(dev, LASI_IRQ_LAN_HPA)); - } - /* Parallel port */ parallel_mm_init(address_space, LASI_LPT_HPA + 0x800, 0, qdev_get_gpio_in(dev, LASI_IRQ_LAN_HPA), diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index c815dde305..b3b4a00ad6 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -221,6 +221,11 @@ static void machine_hppa_init(MachineState *machine) } /* Network setup. */ + if (enable_lasi_lan()) { + lasi_82596_init(addr_space, LASI_LAN_HPA, + qdev_get_gpio_in(lasi_dev, LASI_IRQ_LAN_HPA)); + } + for (i = 0; i < nb_nics; i++) { if (!enable_lasi_lan()) { pci_nic_init_nofail(&nd_table[i], pci_bus, "tulip", NULL); From 9701e56943282ea94876c1e4202ed30ce3a3c706 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:44 +0100 Subject: [PATCH 155/935] lasi: move parallel port initialisation to machine.c Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-35-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/lasi.c | 6 ------ hw/hppa/machine.c | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index 88ff9141e4..6faa98dca5 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -18,7 +18,6 @@ #include "sysemu/sysemu.h" #include "sysemu/runstate.h" #include "hppa_sys.h" -#include "hw/char/parallel.h" #include "hw/char/serial.h" #include "hw/input/lasips2.h" #include "migration/vmstate.h" @@ -237,11 +236,6 @@ LasiState *lasi_initfn(MemoryRegion *address_space) dev = qdev_new(TYPE_LASI_CHIP); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - /* Parallel port */ - parallel_mm_init(address_space, LASI_LPT_HPA + 0x800, 0, - qdev_get_gpio_in(dev, LASI_IRQ_LAN_HPA), - parallel_hds[0]); - if (serial_hd(1)) { /* Serial port */ serial_mm_init(address_space, LASI_UART_HPA + 0x800, 0, diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index b3b4a00ad6..5244178aaf 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -15,6 +15,7 @@ #include "hw/rtc/mc146818rtc.h" #include "hw/timer/i8254.h" #include "hw/char/serial.h" +#include "hw/char/parallel.h" #include "hw/net/lasi_82596.h" #include "hw/nmi.h" #include "hw/pci-host/dino.h" @@ -204,6 +205,11 @@ static void machine_hppa_init(MachineState *machine) 115200, serial_hd(0), DEVICE_BIG_ENDIAN); } + /* Parallel port */ + parallel_mm_init(addr_space, LASI_LPT_HPA + 0x800, 0, + qdev_get_gpio_in(lasi_dev, LASI_IRQ_LAN_HPA), + parallel_hds[0]); + /* fw_cfg configuration interface */ create_fw_cfg(machine); From 2da547b81968f601ca870ace0a1e1528c4402d09 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:45 +0100 Subject: [PATCH 156/935] lasi: move second serial port initialisation to machine.c Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-36-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/lasi.c | 8 -------- hw/hppa/machine.c | 7 +++++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index 6faa98dca5..753a08d454 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -18,7 +18,6 @@ #include "sysemu/sysemu.h" #include "sysemu/runstate.h" #include "hppa_sys.h" -#include "hw/char/serial.h" #include "hw/input/lasips2.h" #include "migration/vmstate.h" #include "qom/object.h" @@ -236,13 +235,6 @@ LasiState *lasi_initfn(MemoryRegion *address_space) dev = qdev_new(TYPE_LASI_CHIP); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - if (serial_hd(1)) { - /* Serial port */ - serial_mm_init(address_space, LASI_UART_HPA + 0x800, 0, - qdev_get_gpio_in(dev, LASI_IRQ_UART_HPA), 8000000 / 16, - serial_hd(1), DEVICE_BIG_ENDIAN); - } - /* PS/2 Keyboard/Mouse */ lasips2_init(address_space, LASI_PS2KBD_HPA, qdev_get_gpio_in(dev, LASI_IRQ_PS2KBD_HPA)); diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 5244178aaf..5b43ae2960 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -205,6 +205,13 @@ static void machine_hppa_init(MachineState *machine) 115200, serial_hd(0), DEVICE_BIG_ENDIAN); } + if (serial_hd(1)) { + /* Serial port */ + serial_mm_init(addr_space, LASI_UART_HPA + 0x800, 0, + qdev_get_gpio_in(lasi_dev, LASI_IRQ_UART_HPA), 8000000 / 16, + serial_hd(1), DEVICE_BIG_ENDIAN); + } + /* Parallel port */ parallel_mm_init(addr_space, LASI_LPT_HPA + 0x800, 0, qdev_get_gpio_in(lasi_dev, LASI_IRQ_LAN_HPA), From d26c575c44379d9df7843677c7d59729ffe18764 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:46 +0100 Subject: [PATCH 157/935] lasi: move PS2 initialisation to machine.c Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-37-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/lasi.c | 5 ----- hw/hppa/machine.c | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index 753a08d454..9d8c9e3936 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -18,7 +18,6 @@ #include "sysemu/sysemu.h" #include "sysemu/runstate.h" #include "hppa_sys.h" -#include "hw/input/lasips2.h" #include "migration/vmstate.h" #include "qom/object.h" #include "lasi.h" @@ -235,10 +234,6 @@ LasiState *lasi_initfn(MemoryRegion *address_space) dev = qdev_new(TYPE_LASI_CHIP); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - /* PS/2 Keyboard/Mouse */ - lasips2_init(address_space, LASI_PS2KBD_HPA, - qdev_get_gpio_in(dev, LASI_IRQ_PS2KBD_HPA)); - return LASI_CHIP(dev); } diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 5b43ae2960..1d48ec341d 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -16,6 +16,7 @@ #include "hw/timer/i8254.h" #include "hw/char/serial.h" #include "hw/char/parallel.h" +#include "hw/input/lasips2.h" #include "hw/net/lasi_82596.h" #include "hw/nmi.h" #include "hw/pci-host/dino.h" @@ -245,6 +246,10 @@ static void machine_hppa_init(MachineState *machine) } } + /* PS/2 Keyboard/Mouse */ + lasips2_init(addr_space, LASI_PS2KBD_HPA, + qdev_get_gpio_in(lasi_dev, LASI_IRQ_PS2KBD_HPA)); + /* register power switch emulation */ qemu_register_powerdown_notifier(&hppa_system_powerdown_notifier); From deaa5d3b4e8eccf4010c9099b99c267ff1f2223e Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:47 +0100 Subject: [PATCH 158/935] lasi: remove address space parameter from lasi_initfn() Now that all of the LASI devices are mapped by the board, this parameter is no longer required. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-38-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/hppa_sys.h | 2 +- hw/hppa/lasi.c | 2 +- hw/hppa/machine.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/hppa/hppa_sys.h b/hw/hppa/hppa_sys.h index 3832b787d1..31e3856059 100644 --- a/hw/hppa/hppa_sys.h +++ b/hw/hppa/hppa_sys.h @@ -11,7 +11,7 @@ #include "hppa_hardware.h" -LasiState *lasi_initfn(MemoryRegion *); +LasiState *lasi_initfn(void); #define enable_lasi_lan() 0 /* hppa_pci.c. */ diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index 9d8c9e3936..81c8e4d2d9 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -227,7 +227,7 @@ static void lasi_set_irq(void *opaque, int irq, int level) } } -LasiState *lasi_initfn(MemoryRegion *address_space) +LasiState *lasi_initfn(void) { DeviceState *dev; diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 1d48ec341d..52f12f6604 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -178,7 +178,7 @@ static void machine_hppa_init(MachineState *machine) /* Init Lasi chip */ - lasi_dev = DEVICE(lasi_initfn(addr_space)); + lasi_dev = DEVICE(lasi_initfn()); memory_region_add_subregion(addr_space, LASI_HPA, sysbus_mmio_get_region( SYS_BUS_DEVICE(lasi_dev), 0)); From e881e3c83a47214d5d5d4141a1bc4ad99486f80a Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:48 +0100 Subject: [PATCH 159/935] lasi: move lasi_initfn() to machine.c Move the simplified lasi_initfn() back to machine.c whilst also renaming it back to its original lasi_init() name. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-39-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/hppa_sys.h | 2 -- hw/hppa/lasi.c | 10 ---------- hw/hppa/machine.c | 12 +++++++++++- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/hw/hppa/hppa_sys.h b/hw/hppa/hppa_sys.h index 31e3856059..f7a127be19 100644 --- a/hw/hppa/hppa_sys.h +++ b/hw/hppa/hppa_sys.h @@ -7,11 +7,9 @@ #include "hw/pci/pci_host.h" #include "hw/boards.h" #include "hw/intc/i8259.h" -#include "lasi.h" #include "hppa_hardware.h" -LasiState *lasi_initfn(void); #define enable_lasi_lan() 0 /* hppa_pci.c. */ diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index 81c8e4d2d9..ad50880a13 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -227,16 +227,6 @@ static void lasi_set_irq(void *opaque, int irq, int level) } } -LasiState *lasi_initfn(void) -{ - DeviceState *dev; - - dev = qdev_new(TYPE_LASI_CHIP); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - - return LASI_CHIP(dev); -} - static void lasi_reset(DeviceState *dev) { LasiState *s = LASI_CHIP(dev); diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 52f12f6604..58b25ca5bc 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -125,6 +125,16 @@ static FWCfgState *create_fw_cfg(MachineState *ms) return fw_cfg; } +static LasiState *lasi_init(void) +{ + DeviceState *dev; + + dev = qdev_new(TYPE_LASI_CHIP); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + return LASI_CHIP(dev); +} + static DinoState *dino_init(MemoryRegion *addr_space) { DeviceState *dev; @@ -178,7 +188,7 @@ static void machine_hppa_init(MachineState *machine) /* Init Lasi chip */ - lasi_dev = DEVICE(lasi_initfn()); + lasi_dev = DEVICE(lasi_init()); memory_region_add_subregion(addr_space, LASI_HPA, sysbus_mmio_get_region( SYS_BUS_DEVICE(lasi_dev), 0)); From ca7b468be8944d2c166f6b7cf25cd5e8e006bc03 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:49 +0100 Subject: [PATCH 160/935] lasi: use constants for device register offsets Instead of generating the offset based upon the physical address of the register, add constants for each of the device registers to lasi.h and update lasi.c to use them. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-40-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/lasi.c | 28 ++++++++++++++-------------- hw/hppa/lasi.h | 5 +++++ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index ad50880a13..11ca33fba3 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -36,10 +36,10 @@ static bool lasi_chip_mem_valid(void *opaque, hwaddr addr, case LASI_ICR: case LASI_IAR: - case (LASI_LAN_HPA - LASI_HPA): - case (LASI_LPT_HPA - LASI_HPA): - case (LASI_UART_HPA - LASI_HPA): - case (LASI_RTC_HPA - LASI_HPA): + case LASI_LPT: + case LASI_UART: + case LASI_LAN: + case LASI_RTC: case LASI_PCR ... LASI_AMR: ret = true; @@ -76,12 +76,12 @@ static MemTxResult lasi_chip_read_with_attrs(void *opaque, hwaddr addr, val = s->iar; break; - case (LASI_LAN_HPA - LASI_HPA): - case (LASI_LPT_HPA - LASI_HPA): - case (LASI_UART_HPA - LASI_HPA): + case LASI_LPT: + case LASI_UART: + case LASI_LAN: val = 0; break; - case (LASI_RTC_HPA - LASI_HPA): + case LASI_RTC: val = time(NULL); val += s->rtc_ref; break; @@ -141,16 +141,16 @@ static MemTxResult lasi_chip_write_with_attrs(void *opaque, hwaddr addr, s->iar = val; break; - case (LASI_LAN_HPA - LASI_HPA): - /* XXX: reset LAN card */ - break; - case (LASI_LPT_HPA - LASI_HPA): + case LASI_LPT: /* XXX: reset parallel port */ break; - case (LASI_UART_HPA - LASI_HPA): + case LASI_UART: /* XXX: reset serial port */ break; - case (LASI_RTC_HPA - LASI_HPA): + case LASI_LAN: + /* XXX: reset LAN card */ + break; + case LASI_RTC: s->rtc_ref = val - time(NULL); break; diff --git a/hw/hppa/lasi.h b/hw/hppa/lasi.h index 63a2be3740..11cf7d6b0b 100644 --- a/hw/hppa/lasi.h +++ b/hw/hppa/lasi.h @@ -21,6 +21,11 @@ OBJECT_DECLARE_SIMPLE_TYPE(LasiState, LASI_CHIP) #define LASI_ICR 0x0c #define LASI_IAR 0x10 +#define LASI_LPT 0x02000 +#define LASI_UART 0x05000 +#define LASI_LAN 0x07000 +#define LASI_RTC 0x09000 + #define LASI_PCR 0x0C000 /* LASI Power Control register */ #define LASI_ERRLOG 0x0C004 /* LASI Error Logging register */ #define LASI_VER 0x0C008 /* LASI Version Control register */ From 8e81ffe32070490b27d8e9ccac48a3f470e19c96 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:50 +0100 Subject: [PATCH 161/935] lasi: use numerical constant for iar reset value This is to allow us to decouple the LASI device from the board logic. If it is decided later that this value needs to be configurable then it can easily be converted to a qdev property. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-41-mark.cave-ayland@ilande.co.uk> Acked-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/lasi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index 11ca33fba3..5ef36f3f58 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -231,7 +231,7 @@ static void lasi_reset(DeviceState *dev) { LasiState *s = LASI_CHIP(dev); - s->iar = CPU_HPA + 3; + s->iar = 0xFFFB0000 + 3; /* CPU_HPA + 3 */ /* Real time clock (RTC), it's only one 32-bit counter @9000 */ s->rtc = time(NULL); From 134ba73f32036256e0a89bcd166ddbe1fd19b824 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:51 +0100 Subject: [PATCH 162/935] hppa: move device headers from hppa_sys.h into individual .c files Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-42-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/hppa_sys.h | 3 --- hw/hppa/lasi.h | 4 ++++ hw/hppa/machine.c | 2 ++ hw/hppa/pci.c | 3 +++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/hw/hppa/hppa_sys.h b/hw/hppa/hppa_sys.h index f7a127be19..9964d4a7a7 100644 --- a/hw/hppa/hppa_sys.h +++ b/hw/hppa/hppa_sys.h @@ -3,10 +3,7 @@ #ifndef HW_HPPA_SYS_H #define HW_HPPA_SYS_H -#include "hw/pci/pci.h" -#include "hw/pci/pci_host.h" #include "hw/boards.h" -#include "hw/intc/i8259.h" #include "hppa_hardware.h" diff --git a/hw/hppa/lasi.h b/hw/hppa/lasi.h index 11cf7d6b0b..ecc7065ce8 100644 --- a/hw/hppa/lasi.h +++ b/hw/hppa/lasi.h @@ -12,6 +12,10 @@ #ifndef LASI_H #define LASI_H +#include "exec/address-spaces.h" +#include "hw/pci/pci_host.h" +#include "hw/boards.h" + #define TYPE_LASI_CHIP "lasi-chip" OBJECT_DECLARE_SIMPLE_TYPE(LasiState, LASI_CHIP) diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 58b25ca5bc..9d904b7a60 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -16,9 +16,11 @@ #include "hw/timer/i8254.h" #include "hw/char/serial.h" #include "hw/char/parallel.h" +#include "hw/intc/i8259.h" #include "hw/input/lasips2.h" #include "hw/net/lasi_82596.h" #include "hw/nmi.h" +#include "hw/pci/pci.h" #include "hw/pci-host/dino.h" #include "lasi.h" #include "hppa_sys.h" diff --git a/hw/hppa/pci.c b/hw/hppa/pci.c index 32609aba63..a92dcb6b9e 100644 --- a/hw/hppa/pci.c +++ b/hw/hppa/pci.c @@ -6,6 +6,9 @@ #include "qemu/osdep.h" #include "hppa_sys.h" #include "qemu/log.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" +#include "hw/intc/i8259.h" #include "trace.h" From 45f569a11666051f98edc678616d135c9feaf506 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:52 +0100 Subject: [PATCH 163/935] lasi: move from hw/hppa to hw/misc Move the LASI device implementation from hw/hppa to hw/misc so that it is located with all the other miscellaneous devices. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-43-mark.cave-ayland@ilande.co.uk> Signed-off-by: Mark Cave-Ayland --- MAINTAINERS | 2 ++ hw/hppa/Kconfig | 1 + hw/hppa/machine.c | 2 +- hw/hppa/meson.build | 2 +- hw/hppa/trace-events | 5 ----- hw/misc/Kconfig | 3 +++ hw/{hppa => misc}/lasi.c | 3 +-- hw/misc/meson.build | 3 +++ hw/misc/trace-events | 5 +++++ {hw/hppa => include/hw/misc}/lasi.h | 0 10 files changed, 17 insertions(+), 9 deletions(-) rename hw/{hppa => misc}/lasi.c (99%) rename {hw/hppa => include/hw/misc}/lasi.h (100%) diff --git a/MAINTAINERS b/MAINTAINERS index 59210b093a..662ec47246 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1113,7 +1113,9 @@ S: Odd Fixes F: configs/devices/hppa-softmmu/default.mak F: hw/hppa/ F: hw/net/*i82596* +F: hw/misc/lasi.c F: hw/pci-host/dino.c +F: include/hw/misc/lasi.h F: include/hw/net/lasi_82596.h F: include/hw/pci-host/dino.h F: pc-bios/hppa-firmware.img diff --git a/hw/hppa/Kconfig b/hw/hppa/Kconfig index 724380ecec..5dd8b5b21e 100644 --- a/hw/hppa/Kconfig +++ b/hw/hppa/Kconfig @@ -4,6 +4,7 @@ config HPPA_B160L imply E1000_PCI imply VIRTIO_VGA select DINO + select LASI select SERIAL select ISA_BUS select I8259 diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 9d904b7a60..f3d72b4c35 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -22,7 +22,7 @@ #include "hw/nmi.h" #include "hw/pci/pci.h" #include "hw/pci-host/dino.h" -#include "lasi.h" +#include "hw/misc/lasi.h" #include "hppa_sys.h" #include "qemu/units.h" #include "qapi/error.h" diff --git a/hw/hppa/meson.build b/hw/hppa/meson.build index a6f9db455c..bd5a1fb1d2 100644 --- a/hw/hppa/meson.build +++ b/hw/hppa/meson.build @@ -1,4 +1,4 @@ hppa_ss = ss.source_set() -hppa_ss.add(when: 'CONFIG_HPPA_B160L', if_true: files('pci.c', 'machine.c', 'lasi.c')) +hppa_ss.add(when: 'CONFIG_HPPA_B160L', if_true: files('pci.c', 'machine.c')) hw_arch += {'hppa': hppa_ss} diff --git a/hw/hppa/trace-events b/hw/hppa/trace-events index 871a473771..1a4fbe2fa8 100644 --- a/hw/hppa/trace-events +++ b/hw/hppa/trace-events @@ -2,8 +2,3 @@ # pci.c hppa_pci_iack_write(void) "" - -# lasi.c -lasi_chip_mem_valid(uint64_t addr, uint32_t val) "access to addr 0x%"PRIx64" is %d" -lasi_chip_read(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" -lasi_chip_write(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 507058d8bf..cbabe9f78c 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -171,4 +171,7 @@ config SIFIVE_U_PRCI config VIRT_CTRL bool +config LASI + bool + source macio/Kconfig diff --git a/hw/hppa/lasi.c b/hw/misc/lasi.c similarity index 99% rename from hw/hppa/lasi.c rename to hw/misc/lasi.c index 5ef36f3f58..23a7634a8c 100644 --- a/hw/hppa/lasi.c +++ b/hw/misc/lasi.c @@ -17,10 +17,9 @@ #include "hw/irq.h" #include "sysemu/sysemu.h" #include "sysemu/runstate.h" -#include "hppa_sys.h" #include "migration/vmstate.h" #include "qom/object.h" -#include "lasi.h" +#include "hw/misc/lasi.h" static bool lasi_chip_mem_valid(void *opaque, hwaddr addr, diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 2ff05c7afa..132b7b7344 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -134,3 +134,6 @@ specific_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_cmgcr.c', 'mips_cp specific_ss.add(when: 'CONFIG_MIPS_ITU', if_true: files('mips_itu.c')) specific_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c')) + +# HPPA devices +softmmu_ss.add(when: 'CONFIG_LASI', if_true: files('lasi.c')) diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 4e0c7973a4..c5e37b0154 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -263,3 +263,8 @@ virt_ctrl_write(void *dev, unsigned int addr, unsigned int size, uint64_t value) virt_ctrl_reset(void *dev) "ctrl: %p" virt_ctrl_realize(void *dev) "ctrl: %p" virt_ctrl_instance_init(void *dev) "ctrl: %p" + +# lasi.c +lasi_chip_mem_valid(uint64_t addr, uint32_t val) "access to addr 0x%"PRIx64" is %d" +lasi_chip_read(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" +lasi_chip_write(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x" diff --git a/hw/hppa/lasi.h b/include/hw/misc/lasi.h similarity index 100% rename from hw/hppa/lasi.h rename to include/hw/misc/lasi.h From 28f5332ae9283fa76f736e9011ae647799b9cdc0 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:53 +0100 Subject: [PATCH 164/935] hppa: move hppa_pci_ignore_ops from pci.c to machine.c The memory region only has one user which is for ensuring accesses to the ISA bus memory do not fault. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-44-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/hppa_sys.h | 1 - hw/hppa/machine.c | 23 +++++++++++++++++++++++ hw/hppa/pci.c | 26 -------------------------- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/hw/hppa/hppa_sys.h b/hw/hppa/hppa_sys.h index 9964d4a7a7..d984b2895d 100644 --- a/hw/hppa/hppa_sys.h +++ b/hw/hppa/hppa_sys.h @@ -10,7 +10,6 @@ #define enable_lasi_lan() 0 /* hppa_pci.c. */ -extern const MemoryRegionOps hppa_pci_ignore_ops; extern const MemoryRegionOps hppa_pci_conf1_ops; extern const MemoryRegionOps hppa_pci_iack_ops; diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index f3d72b4c35..ca595d343e 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -57,6 +57,29 @@ static Notifier hppa_system_powerdown_notifier = { .notify = hppa_powerdown_req }; +/* Fallback for unassigned PCI I/O operations. Avoids MCHK. */ +static uint64_t ignore_read(void *opaque, hwaddr addr, unsigned size) +{ + return 0; +} + +static void ignore_write(void *opaque, hwaddr addr, uint64_t v, unsigned size) +{ +} + +static const MemoryRegionOps hppa_pci_ignore_ops = { + .read = ignore_read, + .write = ignore_write, + .endianness = DEVICE_BIG_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, +}; static ISABus *hppa_isa_bus(void) { diff --git a/hw/hppa/pci.c b/hw/hppa/pci.c index a92dcb6b9e..4d62d54c22 100644 --- a/hw/hppa/pci.c +++ b/hw/hppa/pci.c @@ -12,32 +12,6 @@ #include "trace.h" -/* Fallback for unassigned PCI I/O operations. Avoids MCHK. */ - -static uint64_t ignore_read(void *opaque, hwaddr addr, unsigned size) -{ - return 0; -} - -static void ignore_write(void *opaque, hwaddr addr, uint64_t v, unsigned size) -{ -} - -const MemoryRegionOps hppa_pci_ignore_ops = { - .read = ignore_read, - .write = ignore_write, - .endianness = DEVICE_BIG_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 8, - }, - .impl = { - .min_access_size = 1, - .max_access_size = 8, - }, -}; - - /* PCI config space reads/writes, to byte-word addressable memory. */ static uint64_t bw_conf1_read(void *opaque, hwaddr addr, unsigned size) From 3c2ce5bba379aa87a3098bffc06101c8a9544940 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:54 +0100 Subject: [PATCH 165/935] hppa: remove hw/hppa/pci.c The functions and definitions in this file are not used anywhere within the generic hppa machine. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-45-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/hppa_sys.h | 6 ---- hw/hppa/meson.build | 2 +- hw/hppa/pci.c | 65 -------------------------------------------- hw/hppa/trace-events | 3 -- 4 files changed, 1 insertion(+), 75 deletions(-) delete mode 100644 hw/hppa/pci.c diff --git a/hw/hppa/hppa_sys.h b/hw/hppa/hppa_sys.h index d984b2895d..17e2c6dec1 100644 --- a/hw/hppa/hppa_sys.h +++ b/hw/hppa/hppa_sys.h @@ -3,14 +3,8 @@ #ifndef HW_HPPA_SYS_H #define HW_HPPA_SYS_H -#include "hw/boards.h" - #include "hppa_hardware.h" #define enable_lasi_lan() 0 -/* hppa_pci.c. */ -extern const MemoryRegionOps hppa_pci_conf1_ops; -extern const MemoryRegionOps hppa_pci_iack_ops; - #endif diff --git a/hw/hppa/meson.build b/hw/hppa/meson.build index bd5a1fb1d2..3d0c586c30 100644 --- a/hw/hppa/meson.build +++ b/hw/hppa/meson.build @@ -1,4 +1,4 @@ hppa_ss = ss.source_set() -hppa_ss.add(when: 'CONFIG_HPPA_B160L', if_true: files('pci.c', 'machine.c')) +hppa_ss.add(when: 'CONFIG_HPPA_B160L', if_true: files('machine.c')) hw_arch += {'hppa': hppa_ss} diff --git a/hw/hppa/pci.c b/hw/hppa/pci.c deleted file mode 100644 index 4d62d54c22..0000000000 --- a/hw/hppa/pci.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * QEMU HP-PARISC PCI support functions. - * - */ - -#include "qemu/osdep.h" -#include "hppa_sys.h" -#include "qemu/log.h" -#include "hw/pci/pci.h" -#include "hw/pci/pci_host.h" -#include "hw/intc/i8259.h" -#include "trace.h" - - -/* PCI config space reads/writes, to byte-word addressable memory. */ -static uint64_t bw_conf1_read(void *opaque, hwaddr addr, - unsigned size) -{ - PCIBus *b = opaque; - return pci_data_read(b, addr, size); -} - -static void bw_conf1_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - PCIBus *b = opaque; - pci_data_write(b, addr, val, size); -} - -const MemoryRegionOps hppa_pci_conf1_ops = { - .read = bw_conf1_read, - .write = bw_conf1_write, - .endianness = DEVICE_BIG_ENDIAN, - .impl = { - .min_access_size = 1, - .max_access_size = 4, - }, -}; - -/* PCI/EISA Interrupt Acknowledge Cycle. */ - -static uint64_t iack_read(void *opaque, hwaddr addr, unsigned size) -{ - return pic_read_irq(isa_pic); -} - -static void special_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - trace_hppa_pci_iack_write(); -} - -const MemoryRegionOps hppa_pci_iack_ops = { - .read = iack_read, - .write = special_write, - .endianness = DEVICE_BIG_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; diff --git a/hw/hppa/trace-events b/hw/hppa/trace-events index 1a4fbe2fa8..23bc9b19b9 100644 --- a/hw/hppa/trace-events +++ b/hw/hppa/trace-events @@ -1,4 +1 @@ # See docs/devel/tracing.rst for syntax documentation. - -# pci.c -hppa_pci_iack_write(void) "" From 192e32284b15827e056ff504e0eeb19c2e164759 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:55 +0100 Subject: [PATCH 166/935] hppa: remove unused trace-events from from hw/hppa Now that there are no longer any devices in hw/hppa the trace-events file is empty and can be removed. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-46-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/trace-events | 1 - meson.build | 1 - 2 files changed, 2 deletions(-) delete mode 100644 hw/hppa/trace-events diff --git a/hw/hppa/trace-events b/hw/hppa/trace-events deleted file mode 100644 index 23bc9b19b9..0000000000 --- a/hw/hppa/trace-events +++ /dev/null @@ -1 +0,0 @@ -# See docs/devel/tracing.rst for syntax documentation. diff --git a/meson.build b/meson.build index 40132b4804..fa672e57bc 100644 --- a/meson.build +++ b/meson.build @@ -2944,7 +2944,6 @@ if have_system 'hw/char', 'hw/display', 'hw/dma', - 'hw/hppa', 'hw/hyperv', 'hw/i2c', 'hw/i386', From 932befaa557d9f4ab3d830107ada66dfe3cffba2 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:56 +0100 Subject: [PATCH 167/935] hppa: move enable_lan() define from hppa_sys.h to machine.c Now that the board configuration is in one place, the define is only needed when wiring up the board in machine.c. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-47-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/hppa_sys.h | 2 -- hw/hppa/machine.c | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/hppa/hppa_sys.h b/hw/hppa/hppa_sys.h index 17e2c6dec1..e7f65cad75 100644 --- a/hw/hppa/hppa_sys.h +++ b/hw/hppa/hppa_sys.h @@ -5,6 +5,4 @@ #include "hppa_hardware.h" -#define enable_lasi_lan() 0 - #endif diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index ca595d343e..e6431aa541 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -36,6 +36,9 @@ #define HPA_POWER_BUTTON (FIRMWARE_END - 0x10) +#define enable_lasi_lan() 0 + + static void hppa_powerdown_req(Notifier *n, void *opaque) { hwaddr soft_power_reg = HPA_POWER_BUTTON; From 148da6708580c46c87f8e917d6bfd53b8e6a59ab Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:57 +0100 Subject: [PATCH 168/935] hppa: remove the empty hppa_sys.h file This file is now just a simple wrapper that includes hppa_hardware.h so remove the file completely, and update its single user in machine.c to include hppa_hardware.h directly. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-48-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/hppa_sys.h | 8 -------- hw/hppa/machine.c | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) delete mode 100644 hw/hppa/hppa_sys.h diff --git a/hw/hppa/hppa_sys.h b/hw/hppa/hppa_sys.h deleted file mode 100644 index e7f65cad75..0000000000 --- a/hw/hppa/hppa_sys.h +++ /dev/null @@ -1,8 +0,0 @@ -/* HPPA cores and system support chips. */ - -#ifndef HW_HPPA_SYS_H -#define HW_HPPA_SYS_H - -#include "hppa_hardware.h" - -#endif diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index e6431aa541..75820838bf 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -23,7 +23,7 @@ #include "hw/pci/pci.h" #include "hw/pci-host/dino.h" #include "hw/misc/lasi.h" -#include "hppa_sys.h" +#include "hppa_hardware.h" #include "qemu/units.h" #include "qapi/error.h" #include "net/net.h" From c165905c1764bebf90e31527fafbe0f1fa7c888e Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:58 +0100 Subject: [PATCH 169/935] hppa: use MACHINE QOM macros for defining the hppa machine Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-49-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/machine.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 75820838bf..2393335a64 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -471,8 +471,8 @@ static void machine_hppa_machine_init_class_init(ObjectClass *oc, void *data) } static const TypeInfo machine_hppa_machine_init_typeinfo = { - .name = ("hppa" "-machine"), - .parent = "machine", + .name = MACHINE_TYPE_NAME("hppa"), + .parent = TYPE_MACHINE, .class_init = machine_hppa_machine_init_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_NMI }, From 42cc2bf63c2b61b43300e70a4965aa9d48eda790 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:25:59 +0100 Subject: [PATCH 170/935] hppa: fold machine_hppa_machine_init() into machine_hppa_machine_init_class_init() There is no need for a separate function to set the machine class properties separately from the others. Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-50-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/machine.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 2393335a64..724ee24795 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -446,8 +446,11 @@ static void hppa_nmi(NMIState *n, int cpu_index, Error **errp) } } -static void machine_hppa_machine_init(MachineClass *mc) +static void machine_hppa_machine_init_class_init(ObjectClass *oc, void *data) { + MachineClass *mc = MACHINE_CLASS(oc); + NMIClass *nc = NMI_CLASS(oc); + mc->desc = "HPPA B160L machine"; mc->default_cpu_type = TYPE_HPPA_CPU; mc->init = machine_hppa_init; @@ -459,14 +462,7 @@ static void machine_hppa_machine_init(MachineClass *mc) mc->default_ram_size = 512 * MiB; mc->default_boot_order = "cd"; mc->default_ram_id = "ram"; -} -static void machine_hppa_machine_init_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - machine_hppa_machine_init(mc); - - NMIClass *nc = NMI_CLASS(oc); nc->nmi_monitor_handler = hppa_nmi; } From 297d410387cb5a93bb32469aef34b02843d99b71 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 10:26:00 +0100 Subject: [PATCH 171/935] hppa: simplify machine function names in machine.c Signed-off-by: Mark Cave-Ayland Acked-by: Helge Deller Message-Id: <20220504092600.10048-51-mark.cave-ayland@ilande.co.uk> Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- hw/hppa/machine.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 724ee24795..ae0bc07e75 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -446,7 +446,7 @@ static void hppa_nmi(NMIState *n, int cpu_index, Error **errp) } } -static void machine_hppa_machine_init_class_init(ObjectClass *oc, void *data) +static void hppa_machine_init_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); NMIClass *nc = NMI_CLASS(oc); @@ -466,19 +466,19 @@ static void machine_hppa_machine_init_class_init(ObjectClass *oc, void *data) nc->nmi_monitor_handler = hppa_nmi; } -static const TypeInfo machine_hppa_machine_init_typeinfo = { +static const TypeInfo hppa_machine_init_typeinfo = { .name = MACHINE_TYPE_NAME("hppa"), .parent = TYPE_MACHINE, - .class_init = machine_hppa_machine_init_class_init, + .class_init = hppa_machine_init_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_NMI }, { } }, }; -static void machine_hppa_machine_init_register_types(void) +static void hppa_machine_init_register_types(void) { - type_register_static(&machine_hppa_machine_init_typeinfo); + type_register_static(&hppa_machine_init_typeinfo); } -type_init(machine_hppa_machine_init_register_types) +type_init(hppa_machine_init_register_types) From 5d61789e04bf3313d012eb5c04d9de234013ff39 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 16:37:06 +0100 Subject: [PATCH 172/935] artist: checkpatch and newline style fixes Ensure that subsequent patches do not cause checkpatch to fail and also tidy up extra/missing newlines. Signed-off-by: Mark Cave-Ayland Message-Id: <20220504153708.10352-2-mark.cave-ayland@ilande.co.uk> Reviewed-by: Peter Maydell Reviewed-by: Helge Deller Reviewed-by: Sven Schnelle Signed-off-by: Mark Cave-Ayland --- hw/display/artist.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/hw/display/artist.c b/hw/display/artist.c index 8e121bb0b4..be92113494 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -211,8 +211,9 @@ static void artist_invalidate_lines(struct vram_buffer *buf, int start = starty * buf->width; int size; - if (starty + height > buf->height) + if (starty + height > buf->height) { height = buf->height - starty; + } size = height * buf->width; @@ -321,8 +322,9 @@ static void artist_get_cursor_pos(ARTISTState *s, int *x, int *y) } lx = artist_get_x(s->cursor_pos); - if (lx < offset) + if (lx < offset) { offset = lx; + } *x = (lx - offset) / 2; *y = 1146 - artist_get_y(s->cursor_pos); @@ -343,6 +345,7 @@ static void artist_get_cursor_pos(ARTISTState *s, int *x, int *y) static void artist_invalidate_cursor(ARTISTState *s) { int x, y; + artist_get_cursor_pos(s, &x, &y); artist_invalidate_lines(&s->vram_buffer[ARTIST_BUFFER_AP], y, s->cursor_height); @@ -470,10 +473,9 @@ static void draw_line(ARTISTState *s, if ((x1 >= buf->width && x2 >= buf->width) || (y1 >= buf->height && y2 >= buf->height)) { - return; + return; } - if (update_start) { s->vram_start = (x2 << 16) | y2; } @@ -553,15 +555,15 @@ static void draw_line(ARTISTState *s, x++; } while (x <= x2 && (max_pix == -1 || --max_pix > 0)); - if (c1) + if (c1) { artist_invalidate_lines(buf, x1, x2 - x1); - else + } else { artist_invalidate_lines(buf, y1 > y2 ? y2 : y1, x2 - x1); + } } static void draw_line_pattern_start(ARTISTState *s) { - int startx = artist_get_x(s->vram_start); int starty = artist_get_y(s->vram_start); int endx = artist_get_x(s->blockmove_size); @@ -574,7 +576,6 @@ static void draw_line_pattern_start(ARTISTState *s) static void draw_line_pattern_next(ARTISTState *s) { - int startx = artist_get_x(s->vram_start); int starty = artist_get_y(s->vram_start); int endx = artist_get_x(s->blockmove_size); @@ -589,7 +590,6 @@ static void draw_line_pattern_next(ARTISTState *s) static void draw_line_size(ARTISTState *s, bool update_start) { - int startx = artist_get_x(s->vram_start); int starty = artist_get_y(s->vram_start); int endx = artist_get_x(s->line_size); @@ -600,7 +600,6 @@ static void draw_line_size(ARTISTState *s, bool update_start) static void draw_line_xy(ARTISTState *s, bool update_start) { - int startx = artist_get_x(s->vram_start); int starty = artist_get_y(s->vram_start); int sizex = artist_get_x(s->blockmove_size); @@ -650,7 +649,6 @@ static void draw_line_xy(ARTISTState *s, bool update_start) static void draw_line_end(ARTISTState *s, bool update_start) { - int startx = artist_get_x(s->vram_start); int starty = artist_get_y(s->vram_start); int endx = artist_get_x(s->line_end); @@ -835,6 +833,7 @@ static void artist_vram_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { ARTISTState *s = opaque; + s->vram_char_y = 0; trace_artist_vram_write(size, addr, val); vram_bit_write(opaque, addr, 0, val, size); @@ -1244,7 +1243,6 @@ static void artist_update_display(void *opaque) DisplaySurface *surface = qemu_console_surface(s->con); int first = 0, last; - framebuffer_update_display(surface, &s->fbsection, s->width, s->height, s->width, s->width * 4, 0, 0, artist_draw_line, s, &first, &last); @@ -1258,6 +1256,7 @@ static void artist_invalidate(void *opaque) { ARTISTState *s = ARTIST(opaque); struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP]; + memory_region_set_dirty(&buf->mr, 0, buf->size); } From ada804eb8972c42418a8052c0a1e0493714c75f5 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 16:37:07 +0100 Subject: [PATCH 173/935] artist: remove unused ROP8OFF() macro This macro is unused and so can simply be removed. Signed-off-by: Mark Cave-Ayland Message-Id: <20220504153708.10352-3-mark.cave-ayland@ilande.co.uk> Reviewed-by: Peter Maydell Reviewed-by: Helge Deller Reviewed-by: Sven Schnelle Signed-off-by: Mark Cave-Ayland --- hw/display/artist.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/hw/display/artist.c b/hw/display/artist.c index be92113494..4a9f7b5e59 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -25,12 +25,6 @@ #define TYPE_ARTIST "artist" OBJECT_DECLARE_SIMPLE_TYPE(ARTISTState, ARTIST) -#if HOST_BIG_ENDIAN -#define ROP8OFF(_i) (3 - (_i)) -#else -#define ROP8OFF -#endif - struct vram_buffer { MemoryRegion mr; uint8_t *data; From 1f110516190f146df40f49aef2f1ef5903b8f540 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 4 May 2022 16:37:08 +0100 Subject: [PATCH 174/935] artist: only render dirty scanlines on the display surface The framebuffer_update_display() function returns the dirty scanlines that were touched since the last display update, however artist_update_display() always calls dpy_gfx_update() with start and end scanlines of 0 and s->height causing the entire display surface to be rendered on every update. Update artist_update_display() so that dpy_gfx_update() only renders the dirty scanlines on the display surface, bypassing the display surface rendering completely if framebuffer_update_display() indicates no changes occurred. This noticeably improves boot performance when the framebuffer is enabled on my rather modest laptop here, including making the GTK UI usable. Signed-off-by: Mark Cave-Ayland Message-Id: <20220504153708.10352-4-mark.cave-ayland@ilande.co.uk> Reviewed-by: Helge Deller Reviewed-by: Sven Schnelle Signed-off-by: Mark Cave-Ayland --- hw/display/artist.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/display/artist.c b/hw/display/artist.c index 4a9f7b5e59..39fc0c4ca5 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -1243,7 +1243,9 @@ static void artist_update_display(void *opaque) artist_draw_cursor(s); - dpy_gfx_update(s->con, 0, 0, s->width, s->height); + if (first >= 0) { + dpy_gfx_update(s->con, 0, first, s->width, last - first + 1); + } } static void artist_invalidate(void *opaque) From 82f96346e1fc8eb81eb8e80fe0b95405a8cf42ee Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 12 Apr 2022 18:58:35 +0200 Subject: [PATCH 175/935] disas: Remove old libopcode arm disassembler Capstone should be superior to the old libopcode disassembler, so we can drop the old file nowadays. Signed-off-by: Thomas Huth Reviewed-by: Richard Henderson Message-Id: <20220412165836.355850-3-thuth@redhat.com> Signed-off-by: Thomas Huth --- MAINTAINERS | 2 - disas.c | 1 - disas/arm.c | 4012 --------------------------------------- disas/meson.build | 1 - include/disas/dis-asm.h | 1 - target/arm/cpu.c | 8 - 6 files changed, 4025 deletions(-) delete mode 100644 disas/arm.c diff --git a/MAINTAINERS b/MAINTAINERS index 662ec47246..7f3788b694 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -165,7 +165,6 @@ F: tests/qtest/arm-cpu-features.c F: hw/arm/ F: hw/cpu/a*mpcore.c F: include/hw/cpu/a*mpcore.h -F: disas/arm.c F: disas/arm-a64.cc F: disas/libvixl/ F: docs/system/target-arm.rst @@ -3271,7 +3270,6 @@ M: Richard Henderson S: Maintained L: qemu-arm@nongnu.org F: tcg/arm/ -F: disas/arm.c i386 TCG target M: Richard Henderson diff --git a/disas.c b/disas.c index d41f34915d..4e443b4d49 100644 --- a/disas.c +++ b/disas.c @@ -192,7 +192,6 @@ static void initialize_debug_host(CPUDebug *s) s->info.mach = bfd_mach_sparc_v9b; #elif defined(__arm__) /* TCG only generates code for arm mode. */ - s->info.print_insn = print_insn_arm; s->info.cap_arch = CS_ARCH_ARM; #elif defined(__MIPSEB__) s->info.print_insn = print_insn_big_mips; diff --git a/disas/arm.c b/disas/arm.c deleted file mode 100644 index 7d940f2396..0000000000 --- a/disas/arm.c +++ /dev/null @@ -1,4012 +0,0 @@ -/* Instruction printing code for the ARM - Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 - 2007, Free Software Foundation, Inc. - Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) - Modification by James G. Smith (jsmith@cygnus.co.uk) - - This file is part of libopcodes. - - This program is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . */ - -/* Start of qemu specific additions. Mostly this is stub definitions - for things we don't care about. */ - -#include "qemu/osdep.h" -#include "disas/dis-asm.h" - -#define ARM_EXT_V1 0 -#define ARM_EXT_V2 0 -#define ARM_EXT_V2S 0 -#define ARM_EXT_V3 0 -#define ARM_EXT_V3M 0 -#define ARM_EXT_V4 0 -#define ARM_EXT_V4T 0 -#define ARM_EXT_V5 0 -#define ARM_EXT_V5T 0 -#define ARM_EXT_V5ExP 0 -#define ARM_EXT_V5E 0 -#define ARM_EXT_V5J 0 -#define ARM_EXT_V6 0 -#define ARM_EXT_V6K 0 -#define ARM_EXT_V6Z 0 -#define ARM_EXT_V6T2 0 -#define ARM_EXT_V7 0 -#define ARM_EXT_DIV 0 - -/* Co-processor space extensions. */ -#define ARM_CEXT_XSCALE 0 -#define ARM_CEXT_MAVERICK 0 -#define ARM_CEXT_IWMMXT 0 - -#define FPU_FPA_EXT_V1 0 -#define FPU_FPA_EXT_V2 0 -#define FPU_VFP_EXT_NONE 0 -#define FPU_VFP_EXT_V1xD 0 -#define FPU_VFP_EXT_V1 0 -#define FPU_VFP_EXT_V2 0 -#define FPU_MAVERICK 0 -#define FPU_VFP_EXT_V3 0 -#define FPU_NEON_EXT_V1 0 - -/* Assume host uses ieee float. */ -static void floatformat_to_double (unsigned char *data, double *dest) -{ - union { - uint32_t i; - float f; - } u; - u.i = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); - *dest = u.f; -} - -static int arm_read_memory(bfd_vma memaddr, bfd_byte *b, int length, - struct disassemble_info *info) -{ - assert((info->flags & INSN_ARM_BE32) == 0 || length == 2 || length == 4); - - if ((info->flags & INSN_ARM_BE32) != 0 && length == 2) { - memaddr ^= 2; - } - return info->read_memory_func(memaddr, b, length, info); -} - -/* End of qemu specific additions. */ - -struct opcode32 -{ - unsigned long arch; /* Architecture defining this insn. */ - unsigned long value, mask; /* Recognise insn if (op&mask)==value. */ - const char *assembler; /* How to disassemble this insn. */ -}; - -struct opcode16 -{ - unsigned long arch; /* Architecture defining this insn. */ - unsigned short value, mask; /* Recognise insn if (op&mask)==value. */ - const char *assembler; /* How to disassemble this insn. */ -}; - -/* print_insn_coprocessor recognizes the following format control codes: - - %% % - - %c print condition code (always bits 28-31 in ARM mode) - %q print shifter argument - %u print condition code (unconditional in ARM mode) - %A print address for ldc/stc/ldf/stf instruction - %B print vstm/vldm register list - %C print vstr/vldr address operand - %I print cirrus signed shift immediate: bits 0..3|4..6 - %F print the COUNT field of a LFM/SFM instruction. - %P print floating point precision in arithmetic insn - %Q print floating point precision in ldf/stf insn - %R print floating point rounding mode - - %r print as an ARM register - %d print the bitfield in decimal - %k print immediate for VFPv3 conversion instruction - %x print the bitfield in hex - %X print the bitfield as 1 hex digit without leading "0x" - %f print a floating point constant if >7 else a - floating point register - %w print as an iWMMXt width field - [bhwd]ss/us - %g print as an iWMMXt 64-bit register - %G print as an iWMMXt general purpose or control register - %D print as a NEON D register - %Q print as a NEON Q register - - %y print a single precision VFP reg. - Codes: 0=>Sm, 1=>Sd, 2=>Sn, 3=>multi-list, 4=>Sm pair - %z print a double precision VFP reg - Codes: 0=>Dm, 1=>Dd, 2=>Dn, 3=>multi-list - - %'c print specified char iff bitfield is all ones - %`c print specified char iff bitfield is all zeroes - %?ab... select from array of values in big endian order - - %L print as an iWMMXt N/M width field. - %Z print the Immediate of a WSHUFH instruction. - %l like 'A' except use byte offsets for 'B' & 'H' - versions. - %i print 5-bit immediate in bits 8,3..0 - (print "32" when 0) - %r print register offset address for wldt/wstr instruction -*/ - -/* Common coprocessor opcodes shared between Arm and Thumb-2. */ - -static const struct opcode32 coprocessor_opcodes[] = -{ - /* XScale instructions. */ - {ARM_CEXT_XSCALE, 0x0e200010, 0x0fff0ff0, "mia%c\tacc0, %0-3r, %12-15r"}, - {ARM_CEXT_XSCALE, 0x0e280010, 0x0fff0ff0, "miaph%c\tacc0, %0-3r, %12-15r"}, - {ARM_CEXT_XSCALE, 0x0e2c0010, 0x0ffc0ff0, "mia%17'T%17`B%16'T%16`B%c\tacc0, %0-3r, %12-15r"}, - {ARM_CEXT_XSCALE, 0x0c400000, 0x0ff00fff, "mar%c\tacc0, %12-15r, %16-19r"}, - {ARM_CEXT_XSCALE, 0x0c500000, 0x0ff00fff, "mra%c\t%12-15r, %16-19r, acc0"}, - - /* Intel Wireless MMX technology instructions. */ -#define FIRST_IWMMXT_INSN 0x0e130130 -#define IWMMXT_INSN_COUNT 73 - {ARM_CEXT_IWMMXT, 0x0e130130, 0x0f3f0fff, "tandc%22-23w%c\t%12-15r"}, - {ARM_CEXT_XSCALE, 0x0e400010, 0x0ff00f3f, "tbcst%6-7w%c\t%16-19g, %12-15r"}, - {ARM_CEXT_XSCALE, 0x0e130170, 0x0f3f0ff8, "textrc%22-23w%c\t%12-15r, #%0-2d"}, - {ARM_CEXT_XSCALE, 0x0e100070, 0x0f300ff0, "textrm%3?su%22-23w%c\t%12-15r, %16-19g, #%0-2d"}, - {ARM_CEXT_XSCALE, 0x0e600010, 0x0ff00f38, "tinsr%6-7w%c\t%16-19g, %12-15r, #%0-2d"}, - {ARM_CEXT_XSCALE, 0x0e000110, 0x0ff00fff, "tmcr%c\t%16-19G, %12-15r"}, - {ARM_CEXT_XSCALE, 0x0c400000, 0x0ff00ff0, "tmcrr%c\t%0-3g, %12-15r, %16-19r"}, - {ARM_CEXT_XSCALE, 0x0e2c0010, 0x0ffc0e10, "tmia%17?tb%16?tb%c\t%5-8g, %0-3r, %12-15r"}, - {ARM_CEXT_XSCALE, 0x0e200010, 0x0fff0e10, "tmia%c\t%5-8g, %0-3r, %12-15r"}, - {ARM_CEXT_XSCALE, 0x0e280010, 0x0fff0e10, "tmiaph%c\t%5-8g, %0-3r, %12-15r"}, - {ARM_CEXT_XSCALE, 0x0e100030, 0x0f300fff, "tmovmsk%22-23w%c\t%12-15r, %16-19g"}, - {ARM_CEXT_XSCALE, 0x0e100110, 0x0ff00ff0, "tmrc%c\t%12-15r, %16-19G"}, - {ARM_CEXT_XSCALE, 0x0c500000, 0x0ff00ff0, "tmrrc%c\t%12-15r, %16-19r, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e130150, 0x0f3f0fff, "torc%22-23w%c\t%12-15r"}, - {ARM_CEXT_XSCALE, 0x0e130190, 0x0f3f0fff, "torvsc%22-23w%c\t%12-15r"}, - {ARM_CEXT_XSCALE, 0x0e2001c0, 0x0f300fff, "wabs%22-23w%c\t%12-15g, %16-19g"}, - {ARM_CEXT_XSCALE, 0x0e0001c0, 0x0f300fff, "wacc%22-23w%c\t%12-15g, %16-19g"}, - {ARM_CEXT_XSCALE, 0x0e000180, 0x0f000ff0, "wadd%20-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e2001a0, 0x0f300ff0, "waddbhus%22?ml%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0ea001a0, 0x0ff00ff0, "waddsubhx%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e000020, 0x0f800ff0, "waligni%c\t%12-15g, %16-19g, %0-3g, #%20-22d"}, - {ARM_CEXT_XSCALE, 0x0e800020, 0x0fc00ff0, "walignr%20-21d%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e200000, 0x0fe00ff0, "wand%20'n%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e800000, 0x0fa00ff0, "wavg2%22?hb%20'r%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e400000, 0x0fe00ff0, "wavg4%20'r%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e000060, 0x0f300ff0, "wcmpeq%22-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e100060, 0x0f100ff0, "wcmpgt%21?su%22-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0xfc500100, 0xfe500f00, "wldrd\t%12-15g, %r"}, - {ARM_CEXT_XSCALE, 0xfc100100, 0xfe500f00, "wldrw\t%12-15G, %A"}, - {ARM_CEXT_XSCALE, 0x0c100000, 0x0e100e00, "wldr%L%c\t%12-15g, %l"}, - {ARM_CEXT_XSCALE, 0x0e400100, 0x0fc00ff0, "wmac%21?su%20'z%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e800100, 0x0fc00ff0, "wmadd%21?su%20'x%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0ec00100, 0x0fd00ff0, "wmadd%21?sun%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e000160, 0x0f100ff0, "wmax%21?su%22-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e000080, 0x0f100fe0, "wmerge%c\t%12-15g, %16-19g, %0-3g, #%21-23d"}, - {ARM_CEXT_XSCALE, 0x0e0000a0, 0x0f800ff0, "wmia%21?tb%20?tb%22'n%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e800120, 0x0f800ff0, "wmiaw%21?tb%20?tb%22'n%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e100160, 0x0f100ff0, "wmin%21?su%22-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e000100, 0x0fc00ff0, "wmul%21?su%20?ml%23'r%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0ed00100, 0x0fd00ff0, "wmul%21?sumr%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0ee000c0, 0x0fe00ff0, "wmulwsm%20`r%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0ec000c0, 0x0fe00ff0, "wmulwum%20`r%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0eb000c0, 0x0ff00ff0, "wmulwl%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e8000a0, 0x0f800ff0, "wqmia%21?tb%20?tb%22'n%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e100080, 0x0fd00ff0, "wqmulm%21'r%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0ec000e0, 0x0fd00ff0, "wqmulwm%21'r%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e000000, 0x0ff00ff0, "wor%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e000080, 0x0f000ff0, "wpack%20-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0xfe300040, 0xff300ef0, "wror%22-23w\t%12-15g, %16-19g, #%i"}, - {ARM_CEXT_XSCALE, 0x0e300040, 0x0f300ff0, "wror%22-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e300140, 0x0f300ff0, "wror%22-23wg%c\t%12-15g, %16-19g, %0-3G"}, - {ARM_CEXT_XSCALE, 0x0e000120, 0x0fa00ff0, "wsad%22?hb%20'z%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e0001e0, 0x0f000ff0, "wshufh%c\t%12-15g, %16-19g, #%Z"}, - {ARM_CEXT_XSCALE, 0xfe100040, 0xff300ef0, "wsll%22-23w\t%12-15g, %16-19g, #%i"}, - {ARM_CEXT_XSCALE, 0x0e100040, 0x0f300ff0, "wsll%22-23w%8'g%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e100148, 0x0f300ffc, "wsll%22-23w%8'g%c\t%12-15g, %16-19g, %0-3G"}, - {ARM_CEXT_XSCALE, 0xfe000040, 0xff300ef0, "wsra%22-23w\t%12-15g, %16-19g, #%i"}, - {ARM_CEXT_XSCALE, 0x0e000040, 0x0f300ff0, "wsra%22-23w%8'g%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e000148, 0x0f300ffc, "wsra%22-23w%8'g%c\t%12-15g, %16-19g, %0-3G"}, - {ARM_CEXT_XSCALE, 0xfe200040, 0xff300ef0, "wsrl%22-23w\t%12-15g, %16-19g, #%i"}, - {ARM_CEXT_XSCALE, 0x0e200040, 0x0f300ff0, "wsrl%22-23w%8'g%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e200148, 0x0f300ffc, "wsrl%22-23w%8'g%c\t%12-15g, %16-19g, %0-3G"}, - {ARM_CEXT_XSCALE, 0xfc400100, 0xfe500f00, "wstrd\t%12-15g, %r"}, - {ARM_CEXT_XSCALE, 0xfc000100, 0xfe500f00, "wstrw\t%12-15G, %A"}, - {ARM_CEXT_XSCALE, 0x0c000000, 0x0e100e00, "wstr%L%c\t%12-15g, %l"}, - {ARM_CEXT_XSCALE, 0x0e0001a0, 0x0f000ff0, "wsub%20-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0ed001c0, 0x0ff00ff0, "wsubaddhx%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e1001c0, 0x0f300ff0, "wabsdiff%22-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e0000c0, 0x0fd00fff, "wunpckeh%21?sub%c\t%12-15g, %16-19g"}, - {ARM_CEXT_XSCALE, 0x0e4000c0, 0x0fd00fff, "wunpckeh%21?suh%c\t%12-15g, %16-19g"}, - {ARM_CEXT_XSCALE, 0x0e8000c0, 0x0fd00fff, "wunpckeh%21?suw%c\t%12-15g, %16-19g"}, - {ARM_CEXT_XSCALE, 0x0e0000e0, 0x0f100fff, "wunpckel%21?su%22-23w%c\t%12-15g, %16-19g"}, - {ARM_CEXT_XSCALE, 0x0e1000c0, 0x0f300ff0, "wunpckih%22-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e1000e0, 0x0f300ff0, "wunpckil%22-23w%c\t%12-15g, %16-19g, %0-3g"}, - {ARM_CEXT_XSCALE, 0x0e100000, 0x0ff00ff0, "wxor%c\t%12-15g, %16-19g, %0-3g"}, - - /* Floating point coprocessor (FPA) instructions */ - {FPU_FPA_EXT_V1, 0x0e000100, 0x0ff08f10, "adf%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e100100, 0x0ff08f10, "muf%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e200100, 0x0ff08f10, "suf%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e300100, 0x0ff08f10, "rsf%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e400100, 0x0ff08f10, "dvf%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e500100, 0x0ff08f10, "rdf%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e600100, 0x0ff08f10, "pow%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e700100, 0x0ff08f10, "rpw%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e800100, 0x0ff08f10, "rmf%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e900100, 0x0ff08f10, "fml%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0ea00100, 0x0ff08f10, "fdv%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0eb00100, 0x0ff08f10, "frd%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0ec00100, 0x0ff08f10, "pol%c%P%R\t%12-14f, %16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e008100, 0x0ff08f10, "mvf%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e108100, 0x0ff08f10, "mnf%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e208100, 0x0ff08f10, "abs%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e308100, 0x0ff08f10, "rnd%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e408100, 0x0ff08f10, "sqt%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e508100, 0x0ff08f10, "log%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e608100, 0x0ff08f10, "lgn%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e708100, 0x0ff08f10, "exp%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e808100, 0x0ff08f10, "sin%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e908100, 0x0ff08f10, "cos%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0ea08100, 0x0ff08f10, "tan%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0eb08100, 0x0ff08f10, "asn%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0ec08100, 0x0ff08f10, "acs%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0ed08100, 0x0ff08f10, "atn%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0ee08100, 0x0ff08f10, "urd%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0ef08100, 0x0ff08f10, "nrm%c%P%R\t%12-14f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0e000110, 0x0ff00f1f, "flt%c%P%R\t%16-18f, %12-15r"}, - {FPU_FPA_EXT_V1, 0x0e100110, 0x0fff0f98, "fix%c%R\t%12-15r, %0-2f"}, - {FPU_FPA_EXT_V1, 0x0e200110, 0x0fff0fff, "wfs%c\t%12-15r"}, - {FPU_FPA_EXT_V1, 0x0e300110, 0x0fff0fff, "rfs%c\t%12-15r"}, - {FPU_FPA_EXT_V1, 0x0e400110, 0x0fff0fff, "wfc%c\t%12-15r"}, - {FPU_FPA_EXT_V1, 0x0e500110, 0x0fff0fff, "rfc%c\t%12-15r"}, - {FPU_FPA_EXT_V1, 0x0e90f110, 0x0ff8fff0, "cmf%c\t%16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0eb0f110, 0x0ff8fff0, "cnf%c\t%16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0ed0f110, 0x0ff8fff0, "cmfe%c\t%16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0ef0f110, 0x0ff8fff0, "cnfe%c\t%16-18f, %0-3f"}, - {FPU_FPA_EXT_V1, 0x0c000100, 0x0e100f00, "stf%c%Q\t%12-14f, %A"}, - {FPU_FPA_EXT_V1, 0x0c100100, 0x0e100f00, "ldf%c%Q\t%12-14f, %A"}, - {FPU_FPA_EXT_V2, 0x0c000200, 0x0e100f00, "sfm%c\t%12-14f, %F, %A"}, - {FPU_FPA_EXT_V2, 0x0c100200, 0x0e100f00, "lfm%c\t%12-14f, %F, %A"}, - - /* Register load/store */ - {FPU_NEON_EXT_V1, 0x0d200b00, 0x0fb00f01, "vstmdb%c\t%16-19r%21'!, %B"}, - {FPU_NEON_EXT_V1, 0x0d300b00, 0x0fb00f01, "vldmdb%c\t%16-19r%21'!, %B"}, - {FPU_NEON_EXT_V1, 0x0c800b00, 0x0f900f01, "vstmia%c\t%16-19r%21'!, %B"}, - {FPU_NEON_EXT_V1, 0x0c900b00, 0x0f900f01, "vldmia%c\t%16-19r%21'!, %B"}, - {FPU_NEON_EXT_V1, 0x0d000b00, 0x0f300f00, "vstr%c\t%12-15,22D, %C"}, - {FPU_NEON_EXT_V1, 0x0d100b00, 0x0f300f00, "vldr%c\t%12-15,22D, %C"}, - - /* Data transfer between ARM and NEON registers */ - {FPU_NEON_EXT_V1, 0x0e800b10, 0x0ff00f70, "vdup%c.32\t%16-19,7D, %12-15r"}, - {FPU_NEON_EXT_V1, 0x0e800b30, 0x0ff00f70, "vdup%c.16\t%16-19,7D, %12-15r"}, - {FPU_NEON_EXT_V1, 0x0ea00b10, 0x0ff00f70, "vdup%c.32\t%16-19,7Q, %12-15r"}, - {FPU_NEON_EXT_V1, 0x0ea00b30, 0x0ff00f70, "vdup%c.16\t%16-19,7Q, %12-15r"}, - {FPU_NEON_EXT_V1, 0x0ec00b10, 0x0ff00f70, "vdup%c.8\t%16-19,7D, %12-15r"}, - {FPU_NEON_EXT_V1, 0x0ee00b10, 0x0ff00f70, "vdup%c.8\t%16-19,7Q, %12-15r"}, - {FPU_NEON_EXT_V1, 0x0c400b10, 0x0ff00fd0, "vmov%c\t%0-3,5D, %12-15r, %16-19r"}, - {FPU_NEON_EXT_V1, 0x0c500b10, 0x0ff00fd0, "vmov%c\t%12-15r, %16-19r, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0x0e000b10, 0x0fd00f70, "vmov%c.32\t%16-19,7D[%21d], %12-15r"}, - {FPU_NEON_EXT_V1, 0x0e100b10, 0x0f500f70, "vmov%c.32\t%12-15r, %16-19,7D[%21d]"}, - {FPU_NEON_EXT_V1, 0x0e000b30, 0x0fd00f30, "vmov%c.16\t%16-19,7D[%6,21d], %12-15r"}, - {FPU_NEON_EXT_V1, 0x0e100b30, 0x0f500f30, "vmov%c.%23?us16\t%12-15r, %16-19,7D[%6,21d]"}, - {FPU_NEON_EXT_V1, 0x0e400b10, 0x0fd00f10, "vmov%c.8\t%16-19,7D[%5,6,21d], %12-15r"}, - {FPU_NEON_EXT_V1, 0x0e500b10, 0x0f500f10, "vmov%c.%23?us8\t%12-15r, %16-19,7D[%5,6,21d]"}, - - /* Floating point coprocessor (VFP) instructions */ - {FPU_VFP_EXT_V1xD, 0x0ef1fa10, 0x0fffffff, "fmstat%c"}, - {FPU_VFP_EXT_V1xD, 0x0ee00a10, 0x0fff0fff, "fmxr%c\tfpsid, %12-15r"}, - {FPU_VFP_EXT_V1xD, 0x0ee10a10, 0x0fff0fff, "fmxr%c\tfpscr, %12-15r"}, - {FPU_VFP_EXT_V1xD, 0x0ee60a10, 0x0fff0fff, "fmxr%c\tmvfr1, %12-15r"}, - {FPU_VFP_EXT_V1xD, 0x0ee70a10, 0x0fff0fff, "fmxr%c\tmvfr0, %12-15r"}, - {FPU_VFP_EXT_V1xD, 0x0ee80a10, 0x0fff0fff, "fmxr%c\tfpexc, %12-15r"}, - {FPU_VFP_EXT_V1xD, 0x0ee90a10, 0x0fff0fff, "fmxr%c\tfpinst, %12-15r\t@ Impl def"}, - {FPU_VFP_EXT_V1xD, 0x0eea0a10, 0x0fff0fff, "fmxr%c\tfpinst2, %12-15r\t@ Impl def"}, - {FPU_VFP_EXT_V1xD, 0x0ef00a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpsid"}, - {FPU_VFP_EXT_V1xD, 0x0ef10a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpscr"}, - {FPU_VFP_EXT_V1xD, 0x0ef60a10, 0x0fff0fff, "fmrx%c\t%12-15r, mvfr1"}, - {FPU_VFP_EXT_V1xD, 0x0ef70a10, 0x0fff0fff, "fmrx%c\t%12-15r, mvfr0"}, - {FPU_VFP_EXT_V1xD, 0x0ef80a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpexc"}, - {FPU_VFP_EXT_V1xD, 0x0ef90a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpinst\t@ Impl def"}, - {FPU_VFP_EXT_V1xD, 0x0efa0a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpinst2\t@ Impl def"}, - {FPU_VFP_EXT_V1, 0x0e000b10, 0x0ff00fff, "fmdlr%c\t%z2, %12-15r"}, - {FPU_VFP_EXT_V1, 0x0e100b10, 0x0ff00fff, "fmrdl%c\t%12-15r, %z2"}, - {FPU_VFP_EXT_V1, 0x0e200b10, 0x0ff00fff, "fmdhr%c\t%z2, %12-15r"}, - {FPU_VFP_EXT_V1, 0x0e300b10, 0x0ff00fff, "fmrdh%c\t%12-15r, %z2"}, - {FPU_VFP_EXT_V1xD, 0x0ee00a10, 0x0ff00fff, "fmxr%c\t, %12-15r"}, - {FPU_VFP_EXT_V1xD, 0x0ef00a10, 0x0ff00fff, "fmrx%c\t%12-15r, "}, - {FPU_VFP_EXT_V1xD, 0x0e000a10, 0x0ff00f7f, "fmsr%c\t%y2, %12-15r"}, - {FPU_VFP_EXT_V1xD, 0x0e100a10, 0x0ff00f7f, "fmrs%c\t%12-15r, %y2"}, - {FPU_VFP_EXT_V1xD, 0x0eb50a40, 0x0fbf0f70, "fcmp%7'ezs%c\t%y1"}, - {FPU_VFP_EXT_V1, 0x0eb50b40, 0x0fbf0f70, "fcmp%7'ezd%c\t%z1"}, - {FPU_VFP_EXT_V1xD, 0x0eb00a40, 0x0fbf0fd0, "fcpys%c\t%y1, %y0"}, - {FPU_VFP_EXT_V1xD, 0x0eb00ac0, 0x0fbf0fd0, "fabss%c\t%y1, %y0"}, - {FPU_VFP_EXT_V1, 0x0eb00b40, 0x0fbf0fd0, "fcpyd%c\t%z1, %z0"}, - {FPU_VFP_EXT_V1, 0x0eb00bc0, 0x0fbf0fd0, "fabsd%c\t%z1, %z0"}, - {FPU_VFP_EXT_V1xD, 0x0eb10a40, 0x0fbf0fd0, "fnegs%c\t%y1, %y0"}, - {FPU_VFP_EXT_V1xD, 0x0eb10ac0, 0x0fbf0fd0, "fsqrts%c\t%y1, %y0"}, - {FPU_VFP_EXT_V1, 0x0eb10b40, 0x0fbf0fd0, "fnegd%c\t%z1, %z0"}, - {FPU_VFP_EXT_V1, 0x0eb10bc0, 0x0fbf0fd0, "fsqrtd%c\t%z1, %z0"}, - {FPU_VFP_EXT_V1, 0x0eb70ac0, 0x0fbf0fd0, "fcvtds%c\t%z1, %y0"}, - {FPU_VFP_EXT_V1, 0x0eb70bc0, 0x0fbf0fd0, "fcvtsd%c\t%y1, %z0"}, - {FPU_VFP_EXT_V1xD, 0x0eb80a40, 0x0fbf0fd0, "fuitos%c\t%y1, %y0"}, - {FPU_VFP_EXT_V1xD, 0x0eb80ac0, 0x0fbf0fd0, "fsitos%c\t%y1, %y0"}, - {FPU_VFP_EXT_V1, 0x0eb80b40, 0x0fbf0fd0, "fuitod%c\t%z1, %y0"}, - {FPU_VFP_EXT_V1, 0x0eb80bc0, 0x0fbf0fd0, "fsitod%c\t%z1, %y0"}, - {FPU_VFP_EXT_V1xD, 0x0eb40a40, 0x0fbf0f50, "fcmp%7'es%c\t%y1, %y0"}, - {FPU_VFP_EXT_V1, 0x0eb40b40, 0x0fbf0f50, "fcmp%7'ed%c\t%z1, %z0"}, - {FPU_VFP_EXT_V3, 0x0eba0a40, 0x0fbe0f50, "f%16?us%7?lhtos%c\t%y1, #%5,0-3k"}, - {FPU_VFP_EXT_V3, 0x0eba0b40, 0x0fbe0f50, "f%16?us%7?lhtod%c\t%z1, #%5,0-3k"}, - {FPU_VFP_EXT_V1xD, 0x0ebc0a40, 0x0fbe0f50, "fto%16?sui%7'zs%c\t%y1, %y0"}, - {FPU_VFP_EXT_V1, 0x0ebc0b40, 0x0fbe0f50, "fto%16?sui%7'zd%c\t%y1, %z0"}, - {FPU_VFP_EXT_V3, 0x0ebe0a40, 0x0fbe0f50, "fto%16?us%7?lhs%c\t%y1, #%5,0-3k"}, - {FPU_VFP_EXT_V3, 0x0ebe0b40, 0x0fbe0f50, "fto%16?us%7?lhd%c\t%z1, #%5,0-3k"}, - {FPU_VFP_EXT_V1, 0x0c500b10, 0x0fb00ff0, "fmrrd%c\t%12-15r, %16-19r, %z0"}, - {FPU_VFP_EXT_V3, 0x0eb00a00, 0x0fb00ff0, "fconsts%c\t%y1, #%0-3,16-19d"}, - {FPU_VFP_EXT_V3, 0x0eb00b00, 0x0fb00ff0, "fconstd%c\t%z1, #%0-3,16-19d"}, - {FPU_VFP_EXT_V2, 0x0c400a10, 0x0ff00fd0, "fmsrr%c\t%y4, %12-15r, %16-19r"}, - {FPU_VFP_EXT_V2, 0x0c400b10, 0x0ff00fd0, "fmdrr%c\t%z0, %12-15r, %16-19r"}, - {FPU_VFP_EXT_V2, 0x0c500a10, 0x0ff00fd0, "fmrrs%c\t%12-15r, %16-19r, %y4"}, - {FPU_VFP_EXT_V1xD, 0x0e000a00, 0x0fb00f50, "fmacs%c\t%y1, %y2, %y0"}, - {FPU_VFP_EXT_V1xD, 0x0e000a40, 0x0fb00f50, "fnmacs%c\t%y1, %y2, %y0"}, - {FPU_VFP_EXT_V1, 0x0e000b00, 0x0fb00f50, "fmacd%c\t%z1, %z2, %z0"}, - {FPU_VFP_EXT_V1, 0x0e000b40, 0x0fb00f50, "fnmacd%c\t%z1, %z2, %z0"}, - {FPU_VFP_EXT_V1xD, 0x0e100a00, 0x0fb00f50, "fmscs%c\t%y1, %y2, %y0"}, - {FPU_VFP_EXT_V1xD, 0x0e100a40, 0x0fb00f50, "fnmscs%c\t%y1, %y2, %y0"}, - {FPU_VFP_EXT_V1, 0x0e100b00, 0x0fb00f50, "fmscd%c\t%z1, %z2, %z0"}, - {FPU_VFP_EXT_V1, 0x0e100b40, 0x0fb00f50, "fnmscd%c\t%z1, %z2, %z0"}, - {FPU_VFP_EXT_V1xD, 0x0e200a00, 0x0fb00f50, "fmuls%c\t%y1, %y2, %y0"}, - {FPU_VFP_EXT_V1xD, 0x0e200a40, 0x0fb00f50, "fnmuls%c\t%y1, %y2, %y0"}, - {FPU_VFP_EXT_V1, 0x0e200b00, 0x0fb00f50, "fmuld%c\t%z1, %z2, %z0"}, - {FPU_VFP_EXT_V1, 0x0e200b40, 0x0fb00f50, "fnmuld%c\t%z1, %z2, %z0"}, - {FPU_VFP_EXT_V1xD, 0x0e300a00, 0x0fb00f50, "fadds%c\t%y1, %y2, %y0"}, - {FPU_VFP_EXT_V1xD, 0x0e300a40, 0x0fb00f50, "fsubs%c\t%y1, %y2, %y0"}, - {FPU_VFP_EXT_V1, 0x0e300b00, 0x0fb00f50, "faddd%c\t%z1, %z2, %z0"}, - {FPU_VFP_EXT_V1, 0x0e300b40, 0x0fb00f50, "fsubd%c\t%z1, %z2, %z0"}, - {FPU_VFP_EXT_V1xD, 0x0e800a00, 0x0fb00f50, "fdivs%c\t%y1, %y2, %y0"}, - {FPU_VFP_EXT_V1, 0x0e800b00, 0x0fb00f50, "fdivd%c\t%z1, %z2, %z0"}, - {FPU_VFP_EXT_V1xD, 0x0d200a00, 0x0fb00f00, "fstmdbs%c\t%16-19r!, %y3"}, - {FPU_VFP_EXT_V1xD, 0x0d200b00, 0x0fb00f00, "fstmdb%0?xd%c\t%16-19r!, %z3"}, - {FPU_VFP_EXT_V1xD, 0x0d300a00, 0x0fb00f00, "fldmdbs%c\t%16-19r!, %y3"}, - {FPU_VFP_EXT_V1xD, 0x0d300b00, 0x0fb00f00, "fldmdb%0?xd%c\t%16-19r!, %z3"}, - {FPU_VFP_EXT_V1xD, 0x0d000a00, 0x0f300f00, "fsts%c\t%y1, %A"}, - {FPU_VFP_EXT_V1, 0x0d000b00, 0x0f300f00, "fstd%c\t%z1, %A"}, - {FPU_VFP_EXT_V1xD, 0x0d100a00, 0x0f300f00, "flds%c\t%y1, %A"}, - {FPU_VFP_EXT_V1, 0x0d100b00, 0x0f300f00, "fldd%c\t%z1, %A"}, - {FPU_VFP_EXT_V1xD, 0x0c800a00, 0x0f900f00, "fstmias%c\t%16-19r%21'!, %y3"}, - {FPU_VFP_EXT_V1xD, 0x0c800b00, 0x0f900f00, "fstmia%0?xd%c\t%16-19r%21'!, %z3"}, - {FPU_VFP_EXT_V1xD, 0x0c900a00, 0x0f900f00, "fldmias%c\t%16-19r%21'!, %y3"}, - {FPU_VFP_EXT_V1xD, 0x0c900b00, 0x0f900f00, "fldmia%0?xd%c\t%16-19r%21'!, %z3"}, - - /* Cirrus coprocessor instructions. */ - {ARM_CEXT_MAVERICK, 0x0d100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0c100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0d500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0c500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0d100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0c100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0d500500, 0x0f500f00, "cfldr64%c\tmvdx%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0c500500, 0x0f500f00, "cfldr64%c\tmvdx%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0d000400, 0x0f500f00, "cfstrs%c\tmvf%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0c000400, 0x0f500f00, "cfstrs%c\tmvf%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0d400400, 0x0f500f00, "cfstrd%c\tmvd%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0c400400, 0x0f500f00, "cfstrd%c\tmvd%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0d000500, 0x0f500f00, "cfstr32%c\tmvfx%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0c000500, 0x0f500f00, "cfstr32%c\tmvfx%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0d400500, 0x0f500f00, "cfstr64%c\tmvdx%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0c400500, 0x0f500f00, "cfstr64%c\tmvdx%12-15d, %A"}, - {ARM_CEXT_MAVERICK, 0x0e000450, 0x0ff00ff0, "cfmvsr%c\tmvf%16-19d, %12-15r"}, - {ARM_CEXT_MAVERICK, 0x0e100450, 0x0ff00ff0, "cfmvrs%c\t%12-15r, mvf%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e000410, 0x0ff00ff0, "cfmvdlr%c\tmvd%16-19d, %12-15r"}, - {ARM_CEXT_MAVERICK, 0x0e100410, 0x0ff00ff0, "cfmvrdl%c\t%12-15r, mvd%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e000430, 0x0ff00ff0, "cfmvdhr%c\tmvd%16-19d, %12-15r"}, - {ARM_CEXT_MAVERICK, 0x0e100430, 0x0ff00fff, "cfmvrdh%c\t%12-15r, mvd%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e000510, 0x0ff00fff, "cfmv64lr%c\tmvdx%16-19d, %12-15r"}, - {ARM_CEXT_MAVERICK, 0x0e100510, 0x0ff00fff, "cfmvr64l%c\t%12-15r, mvdx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e000530, 0x0ff00fff, "cfmv64hr%c\tmvdx%16-19d, %12-15r"}, - {ARM_CEXT_MAVERICK, 0x0e100530, 0x0ff00fff, "cfmvr64h%c\t%12-15r, mvdx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e200440, 0x0ff00fff, "cfmval32%c\tmvax%12-15d, mvfx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e100440, 0x0ff00fff, "cfmv32al%c\tmvfx%12-15d, mvax%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e200460, 0x0ff00fff, "cfmvam32%c\tmvax%12-15d, mvfx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e100460, 0x0ff00fff, "cfmv32am%c\tmvfx%12-15d, mvax%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e200480, 0x0ff00fff, "cfmvah32%c\tmvax%12-15d, mvfx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e100480, 0x0ff00fff, "cfmv32ah%c\tmvfx%12-15d, mvax%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e2004a0, 0x0ff00fff, "cfmva32%c\tmvax%12-15d, mvfx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e1004a0, 0x0ff00fff, "cfmv32a%c\tmvfx%12-15d, mvax%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e2004c0, 0x0ff00fff, "cfmva64%c\tmvax%12-15d, mvdx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e1004c0, 0x0ff00fff, "cfmv64a%c\tmvdx%12-15d, mvax%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e2004e0, 0x0fff0fff, "cfmvsc32%c\tdspsc, mvdx%12-15d"}, - {ARM_CEXT_MAVERICK, 0x0e1004e0, 0x0fff0fff, "cfmv32sc%c\tmvdx%12-15d, dspsc"}, - {ARM_CEXT_MAVERICK, 0x0e000400, 0x0ff00fff, "cfcpys%c\tmvf%12-15d, mvf%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e000420, 0x0ff00fff, "cfcpyd%c\tmvd%12-15d, mvd%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e000460, 0x0ff00fff, "cfcvtsd%c\tmvd%12-15d, mvf%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e000440, 0x0ff00fff, "cfcvtds%c\tmvf%12-15d, mvd%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e000480, 0x0ff00fff, "cfcvt32s%c\tmvf%12-15d, mvfx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e0004a0, 0x0ff00fff, "cfcvt32d%c\tmvd%12-15d, mvfx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e0004c0, 0x0ff00fff, "cfcvt64s%c\tmvf%12-15d, mvdx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e0004e0, 0x0ff00fff, "cfcvt64d%c\tmvd%12-15d, mvdx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e100580, 0x0ff00fff, "cfcvts32%c\tmvfx%12-15d, mvf%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e1005a0, 0x0ff00fff, "cfcvtd32%c\tmvfx%12-15d, mvd%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e1005c0, 0x0ff00fff, "cftruncs32%c\tmvfx%12-15d, mvf%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e1005e0, 0x0ff00fff, "cftruncd32%c\tmvfx%12-15d, mvd%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e000550, 0x0ff00ff0, "cfrshl32%c\tmvfx%16-19d, mvfx%0-3d, %12-15r"}, - {ARM_CEXT_MAVERICK, 0x0e000570, 0x0ff00ff0, "cfrshl64%c\tmvdx%16-19d, mvdx%0-3d, %12-15r"}, - {ARM_CEXT_MAVERICK, 0x0e000500, 0x0ff00f10, "cfsh32%c\tmvfx%12-15d, mvfx%16-19d, #%I"}, - {ARM_CEXT_MAVERICK, 0x0e200500, 0x0ff00f10, "cfsh64%c\tmvdx%12-15d, mvdx%16-19d, #%I"}, - {ARM_CEXT_MAVERICK, 0x0e100490, 0x0ff00ff0, "cfcmps%c\t%12-15r, mvf%16-19d, mvf%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e1004b0, 0x0ff00ff0, "cfcmpd%c\t%12-15r, mvd%16-19d, mvd%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e100590, 0x0ff00ff0, "cfcmp32%c\t%12-15r, mvfx%16-19d, mvfx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e1005b0, 0x0ff00ff0, "cfcmp64%c\t%12-15r, mvdx%16-19d, mvdx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e300400, 0x0ff00fff, "cfabss%c\tmvf%12-15d, mvf%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e300420, 0x0ff00fff, "cfabsd%c\tmvd%12-15d, mvd%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e300440, 0x0ff00fff, "cfnegs%c\tmvf%12-15d, mvf%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e300460, 0x0ff00fff, "cfnegd%c\tmvd%12-15d, mvd%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e300480, 0x0ff00ff0, "cfadds%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e3004a0, 0x0ff00ff0, "cfaddd%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e3004c0, 0x0ff00ff0, "cfsubs%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e3004e0, 0x0ff00ff0, "cfsubd%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e100400, 0x0ff00ff0, "cfmuls%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e100420, 0x0ff00ff0, "cfmuld%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e300500, 0x0ff00fff, "cfabs32%c\tmvfx%12-15d, mvfx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e300520, 0x0ff00fff, "cfabs64%c\tmvdx%12-15d, mvdx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e300540, 0x0ff00fff, "cfneg32%c\tmvfx%12-15d, mvfx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e300560, 0x0ff00fff, "cfneg64%c\tmvdx%12-15d, mvdx%16-19d"}, - {ARM_CEXT_MAVERICK, 0x0e300580, 0x0ff00ff0, "cfadd32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e3005a0, 0x0ff00ff0, "cfadd64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e3005c0, 0x0ff00ff0, "cfsub32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e3005e0, 0x0ff00ff0, "cfsub64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e100500, 0x0ff00ff0, "cfmul32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e100520, 0x0ff00ff0, "cfmul64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e100540, 0x0ff00ff0, "cfmac32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e100560, 0x0ff00ff0, "cfmsc32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e000600, 0x0ff00f10, "cfmadd32%c\tmvax%5-7d, mvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e100600, 0x0ff00f10, "cfmsub32%c\tmvax%5-7d, mvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e200600, 0x0ff00f10, "cfmadda32%c\tmvax%5-7d, mvax%12-15d, mvfx%16-19d, mvfx%0-3d"}, - {ARM_CEXT_MAVERICK, 0x0e300600, 0x0ff00f10, "cfmsuba32%c\tmvax%5-7d, mvax%12-15d, mvfx%16-19d, mvfx%0-3d"}, - - /* Generic coprocessor instructions */ - {ARM_EXT_V2, 0x0c400000, 0x0ff00000, "mcrr%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, - {ARM_EXT_V2, 0x0c500000, 0x0ff00000, "mrrc%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, - {ARM_EXT_V2, 0x0e000000, 0x0f000010, "cdp%c\t%8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}"}, - {ARM_EXT_V2, 0x0e100010, 0x0f100010, "mrc%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, - {ARM_EXT_V2, 0x0e000010, 0x0f100010, "mcr%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, - {ARM_EXT_V2, 0x0c000000, 0x0e100000, "stc%22'l%c\t%8-11d, cr%12-15d, %A"}, - {ARM_EXT_V2, 0x0c100000, 0x0e100000, "ldc%22'l%c\t%8-11d, cr%12-15d, %A"}, - - /* V6 coprocessor instructions */ - {ARM_EXT_V6, 0xfc500000, 0xfff00000, "mrrc2%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, - {ARM_EXT_V6, 0xfc400000, 0xfff00000, "mcrr2%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, - - /* V5 coprocessor instructions */ - {ARM_EXT_V5, 0xfc100000, 0xfe100000, "ldc2%22'l%c\t%8-11d, cr%12-15d, %A"}, - {ARM_EXT_V5, 0xfc000000, 0xfe100000, "stc2%22'l%c\t%8-11d, cr%12-15d, %A"}, - {ARM_EXT_V5, 0xfe000000, 0xff000010, "cdp2%c\t%8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}"}, - {ARM_EXT_V5, 0xfe000010, 0xff100010, "mcr2%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, - {ARM_EXT_V5, 0xfe100010, 0xff100010, "mrc2%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, - - {0, 0, 0, 0} -}; - -/* Neon opcode table: This does not encode the top byte -- that is - checked by the print_insn_neon routine, as it depends on whether we are - doing thumb32 or arm32 disassembly. */ - -/* print_insn_neon recognizes the following format control codes: - - %% % - - %c print condition code - %A print v{st,ld}[1234] operands - %B print v{st,ld}[1234] any one operands - %C print v{st,ld}[1234] single->all operands - %D print scalar - %E print vmov, vmvn, vorr, vbic encoded constant - %F print vtbl,vtbx register list - - %r print as an ARM register - %d print the bitfield in decimal - %e print the 2^N - bitfield in decimal - %D print as a NEON D register - %Q print as a NEON Q register - %R print as a NEON D or Q register - %Sn print byte scaled width limited by n - %Tn print short scaled width limited by n - %Un print long scaled width limited by n - - %'c print specified char iff bitfield is all ones - %`c print specified char iff bitfield is all zeroes - %?ab... select from array of values in big endian order */ - -static const struct opcode32 neon_opcodes[] = -{ - /* Extract */ - {FPU_NEON_EXT_V1, 0xf2b00840, 0xffb00850, "vext%c.8\t%12-15,22R, %16-19,7R, %0-3,5R, #%8-11d"}, - {FPU_NEON_EXT_V1, 0xf2b00000, 0xffb00810, "vext%c.8\t%12-15,22R, %16-19,7R, %0-3,5R, #%8-11d"}, - - /* Move data element to all lanes */ - {FPU_NEON_EXT_V1, 0xf3b40c00, 0xffb70f90, "vdup%c.32\t%12-15,22R, %0-3,5D[%19d]"}, - {FPU_NEON_EXT_V1, 0xf3b20c00, 0xffb30f90, "vdup%c.16\t%12-15,22R, %0-3,5D[%18-19d]"}, - {FPU_NEON_EXT_V1, 0xf3b10c00, 0xffb10f90, "vdup%c.8\t%12-15,22R, %0-3,5D[%17-19d]"}, - - /* Table lookup */ - {FPU_NEON_EXT_V1, 0xf3b00800, 0xffb00c50, "vtbl%c.8\t%12-15,22D, %F, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf3b00840, 0xffb00c50, "vtbx%c.8\t%12-15,22D, %F, %0-3,5D"}, - - /* Two registers, miscellaneous */ - {FPU_NEON_EXT_V1, 0xf2880a10, 0xfebf0fd0, "vmovl%c.%24?us8\t%12-15,22Q, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2900a10, 0xfebf0fd0, "vmovl%c.%24?us16\t%12-15,22Q, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2a00a10, 0xfebf0fd0, "vmovl%c.%24?us32\t%12-15,22Q, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf3b00500, 0xffbf0f90, "vcnt%c.8\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00580, 0xffbf0f90, "vmvn%c\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b20000, 0xffbf0f90, "vswp%c\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b20200, 0xffb30fd0, "vmovn%c.i%18-19T2\t%12-15,22D, %0-3,5Q"}, - {FPU_NEON_EXT_V1, 0xf3b20240, 0xffb30fd0, "vqmovun%c.s%18-19T2\t%12-15,22D, %0-3,5Q"}, - {FPU_NEON_EXT_V1, 0xf3b20280, 0xffb30fd0, "vqmovn%c.s%18-19T2\t%12-15,22D, %0-3,5Q"}, - {FPU_NEON_EXT_V1, 0xf3b202c0, 0xffb30fd0, "vqmovn%c.u%18-19T2\t%12-15,22D, %0-3,5Q"}, - {FPU_NEON_EXT_V1, 0xf3b20300, 0xffb30fd0, "vshll%c.i%18-19S2\t%12-15,22Q, %0-3,5D, #%18-19S2"}, - {FPU_NEON_EXT_V1, 0xf3bb0400, 0xffbf0e90, "vrecpe%c.%8?fu%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3bb0480, 0xffbf0e90, "vrsqrte%c.%8?fu%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00000, 0xffb30f90, "vrev64%c.%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00080, 0xffb30f90, "vrev32%c.%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00100, 0xffb30f90, "vrev16%c.%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00400, 0xffb30f90, "vcls%c.s%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00480, 0xffb30f90, "vclz%c.i%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00700, 0xffb30f90, "vqabs%c.s%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00780, 0xffb30f90, "vqneg%c.s%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b20080, 0xffb30f90, "vtrn%c.%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b20100, 0xffb30f90, "vuzp%c.%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b20180, 0xffb30f90, "vzip%c.%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b10000, 0xffb30b90, "vcgt%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, - {FPU_NEON_EXT_V1, 0xf3b10080, 0xffb30b90, "vcge%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, - {FPU_NEON_EXT_V1, 0xf3b10100, 0xffb30b90, "vceq%c.%10?fi%18-19S2\t%12-15,22R, %0-3,5R, #0"}, - {FPU_NEON_EXT_V1, 0xf3b10180, 0xffb30b90, "vcle%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, - {FPU_NEON_EXT_V1, 0xf3b10200, 0xffb30b90, "vclt%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, - {FPU_NEON_EXT_V1, 0xf3b10300, 0xffb30b90, "vabs%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b10380, 0xffb30b90, "vneg%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00200, 0xffb30f10, "vpaddl%c.%7?us%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b00600, 0xffb30f10, "vpadal%c.%7?us%18-19S2\t%12-15,22R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3b30600, 0xffb30e10, "vcvt%c.%7-8?usff%18-19Sa.%7-8?ffus%18-19Sa\t%12-15,22R, %0-3,5R"}, - - /* Three registers of the same length */ - {FPU_NEON_EXT_V1, 0xf2000110, 0xffb00f10, "vand%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2100110, 0xffb00f10, "vbic%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2200110, 0xffb00f10, "vorr%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2300110, 0xffb00f10, "vorn%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000110, 0xffb00f10, "veor%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3100110, 0xffb00f10, "vbsl%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3200110, 0xffb00f10, "vbit%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3300110, 0xffb00f10, "vbif%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000d00, 0xffa00f10, "vadd%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000d10, 0xffa00f10, "vmla%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000e00, 0xffa00f10, "vceq%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000f00, 0xffa00f10, "vmax%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000f10, 0xffa00f10, "vrecps%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2200d00, 0xffa00f10, "vsub%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2200d10, 0xffa00f10, "vmls%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2200f00, 0xffa00f10, "vmin%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2200f10, 0xffa00f10, "vrsqrts%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000d00, 0xffa00f10, "vpadd%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000d10, 0xffa00f10, "vmul%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000e00, 0xffa00f10, "vcge%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000e10, 0xffa00f10, "vacge%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000f00, 0xffa00f10, "vpmax%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3200d00, 0xffa00f10, "vabd%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3200e00, 0xffa00f10, "vcgt%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3200e10, 0xffa00f10, "vacgt%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3200f00, 0xffa00f10, "vpmin%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000800, 0xff800f10, "vadd%c.i%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000810, 0xff800f10, "vtst%c.%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000900, 0xff800f10, "vmla%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000b00, 0xff800f10, "vqdmulh%c.s%20-21S6\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000b10, 0xff800f10, "vpadd%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000800, 0xff800f10, "vsub%c.i%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000810, 0xff800f10, "vceq%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000900, 0xff800f10, "vmls%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf3000b00, 0xff800f10, "vqrdmulh%c.s%20-21S6\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000000, 0xfe800f10, "vhadd%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000010, 0xfe800f10, "vqadd%c.%24?us%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000100, 0xfe800f10, "vrhadd%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000200, 0xfe800f10, "vhsub%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000210, 0xfe800f10, "vqsub%c.%24?us%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000300, 0xfe800f10, "vcgt%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000310, 0xfe800f10, "vcge%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000400, 0xfe800f10, "vshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, - {FPU_NEON_EXT_V1, 0xf2000410, 0xfe800f10, "vqshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, - {FPU_NEON_EXT_V1, 0xf2000500, 0xfe800f10, "vrshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, - {FPU_NEON_EXT_V1, 0xf2000510, 0xfe800f10, "vqrshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, - {FPU_NEON_EXT_V1, 0xf2000600, 0xfe800f10, "vmax%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000610, 0xfe800f10, "vmin%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000700, 0xfe800f10, "vabd%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000710, 0xfe800f10, "vaba%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000910, 0xfe800f10, "vmul%c.%24?pi%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000a00, 0xfe800f10, "vpmax%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - {FPU_NEON_EXT_V1, 0xf2000a10, 0xfe800f10, "vpmin%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, - - /* One register and an immediate value */ - {FPU_NEON_EXT_V1, 0xf2800e10, 0xfeb80fb0, "vmov%c.i8\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800e30, 0xfeb80fb0, "vmov%c.i64\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800f10, 0xfeb80fb0, "vmov%c.f32\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800810, 0xfeb80db0, "vmov%c.i16\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800830, 0xfeb80db0, "vmvn%c.i16\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800910, 0xfeb80db0, "vorr%c.i16\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800930, 0xfeb80db0, "vbic%c.i16\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800c10, 0xfeb80eb0, "vmov%c.i32\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800c30, 0xfeb80eb0, "vmvn%c.i32\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800110, 0xfeb809b0, "vorr%c.i32\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800130, 0xfeb809b0, "vbic%c.i32\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800010, 0xfeb808b0, "vmov%c.i32\t%12-15,22R, %E"}, - {FPU_NEON_EXT_V1, 0xf2800030, 0xfeb808b0, "vmvn%c.i32\t%12-15,22R, %E"}, - - /* Two registers and a shift amount */ - {FPU_NEON_EXT_V1, 0xf2880810, 0xffb80fd0, "vshrn%c.i16\t%12-15,22D, %0-3,5Q, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880850, 0xffb80fd0, "vrshrn%c.i16\t%12-15,22D, %0-3,5Q, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880810, 0xfeb80fd0, "vqshrun%c.s16\t%12-15,22D, %0-3,5Q, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880850, 0xfeb80fd0, "vqrshrun%c.s16\t%12-15,22D, %0-3,5Q, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880910, 0xfeb80fd0, "vqshrn%c.%24?us16\t%12-15,22D, %0-3,5Q, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880950, 0xfeb80fd0, "vqrshrn%c.%24?us16\t%12-15,22D, %0-3,5Q, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880a10, 0xfeb80fd0, "vshll%c.%24?us8\t%12-15,22D, %0-3,5Q, #%16-18d"}, - {FPU_NEON_EXT_V1, 0xf2900810, 0xffb00fd0, "vshrn%c.i32\t%12-15,22D, %0-3,5Q, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2900850, 0xffb00fd0, "vrshrn%c.i32\t%12-15,22D, %0-3,5Q, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2880510, 0xffb80f90, "vshl%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18d"}, - {FPU_NEON_EXT_V1, 0xf3880410, 0xffb80f90, "vsri%c.8\t%12-15,22R, %0-3,5R, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf3880510, 0xffb80f90, "vsli%c.8\t%12-15,22R, %0-3,5R, #%16-18d"}, - {FPU_NEON_EXT_V1, 0xf3880610, 0xffb80f90, "vqshlu%c.s8\t%12-15,22R, %0-3,5R, #%16-18d"}, - {FPU_NEON_EXT_V1, 0xf2900810, 0xfeb00fd0, "vqshrun%c.s32\t%12-15,22D, %0-3,5Q, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2900850, 0xfeb00fd0, "vqrshrun%c.s32\t%12-15,22D, %0-3,5Q, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2900910, 0xfeb00fd0, "vqshrn%c.%24?us32\t%12-15,22D, %0-3,5Q, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2900950, 0xfeb00fd0, "vqrshrn%c.%24?us32\t%12-15,22D, %0-3,5Q, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2900a10, 0xfeb00fd0, "vshll%c.%24?us16\t%12-15,22D, %0-3,5Q, #%16-19d"}, - {FPU_NEON_EXT_V1, 0xf2880010, 0xfeb80f90, "vshr%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880110, 0xfeb80f90, "vsra%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880210, 0xfeb80f90, "vrshr%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880310, 0xfeb80f90, "vrsra%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, - {FPU_NEON_EXT_V1, 0xf2880710, 0xfeb80f90, "vqshl%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18d"}, - {FPU_NEON_EXT_V1, 0xf2a00810, 0xffa00fd0, "vshrn%c.i64\t%12-15,22D, %0-3,5Q, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2a00850, 0xffa00fd0, "vrshrn%c.i64\t%12-15,22D, %0-3,5Q, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2900510, 0xffb00f90, "vshl%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19d"}, - {FPU_NEON_EXT_V1, 0xf3900410, 0xffb00f90, "vsri%c.16\t%12-15,22R, %0-3,5R, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf3900510, 0xffb00f90, "vsli%c.16\t%12-15,22R, %0-3,5R, #%16-19d"}, - {FPU_NEON_EXT_V1, 0xf3900610, 0xffb00f90, "vqshlu%c.s16\t%12-15,22R, %0-3,5R, #%16-19d"}, - {FPU_NEON_EXT_V1, 0xf2a00a10, 0xfea00fd0, "vshll%c.%24?us32\t%12-15,22D, %0-3,5Q, #%16-20d"}, - {FPU_NEON_EXT_V1, 0xf2900010, 0xfeb00f90, "vshr%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2900110, 0xfeb00f90, "vsra%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2900210, 0xfeb00f90, "vrshr%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2900310, 0xfeb00f90, "vrsra%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, - {FPU_NEON_EXT_V1, 0xf2900710, 0xfeb00f90, "vqshl%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19d"}, - {FPU_NEON_EXT_V1, 0xf2800810, 0xfec00fd0, "vqshrun%c.s64\t%12-15,22D, %0-3,5Q, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2800850, 0xfec00fd0, "vqrshrun%c.s64\t%12-15,22D, %0-3,5Q, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2800910, 0xfec00fd0, "vqshrn%c.%24?us64\t%12-15,22D, %0-3,5Q, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2800950, 0xfec00fd0, "vqrshrn%c.%24?us64\t%12-15,22D, %0-3,5Q, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2a00510, 0xffa00f90, "vshl%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20d"}, - {FPU_NEON_EXT_V1, 0xf3a00410, 0xffa00f90, "vsri%c.32\t%12-15,22R, %0-3,5R, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf3a00510, 0xffa00f90, "vsli%c.32\t%12-15,22R, %0-3,5R, #%16-20d"}, - {FPU_NEON_EXT_V1, 0xf3a00610, 0xffa00f90, "vqshlu%c.s32\t%12-15,22R, %0-3,5R, #%16-20d"}, - {FPU_NEON_EXT_V1, 0xf2a00010, 0xfea00f90, "vshr%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2a00110, 0xfea00f90, "vsra%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2a00210, 0xfea00f90, "vrshr%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2a00310, 0xfea00f90, "vrsra%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, - {FPU_NEON_EXT_V1, 0xf2a00710, 0xfea00f90, "vqshl%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20d"}, - {FPU_NEON_EXT_V1, 0xf2800590, 0xff800f90, "vshl%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21d"}, - {FPU_NEON_EXT_V1, 0xf3800490, 0xff800f90, "vsri%c.64\t%12-15,22R, %0-3,5R, #%16-21e"}, - {FPU_NEON_EXT_V1, 0xf3800590, 0xff800f90, "vsli%c.64\t%12-15,22R, %0-3,5R, #%16-21d"}, - {FPU_NEON_EXT_V1, 0xf3800690, 0xff800f90, "vqshlu%c.s64\t%12-15,22R, %0-3,5R, #%16-21d"}, - {FPU_NEON_EXT_V1, 0xf2800090, 0xfe800f90, "vshr%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, - {FPU_NEON_EXT_V1, 0xf2800190, 0xfe800f90, "vsra%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, - {FPU_NEON_EXT_V1, 0xf2800290, 0xfe800f90, "vrshr%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, - {FPU_NEON_EXT_V1, 0xf2800390, 0xfe800f90, "vrsra%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, - {FPU_NEON_EXT_V1, 0xf2800790, 0xfe800f90, "vqshl%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21d"}, - {FPU_NEON_EXT_V1, 0xf2a00e10, 0xfea00e90, "vcvt%c.%24,8?usff32.%24,8?ffus32\t%12-15,22R, %0-3,5R, #%16-20e"}, - - /* Three registers of different lengths */ - {FPU_NEON_EXT_V1, 0xf2800e00, 0xfea00f50, "vmull%c.p%20S0\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800400, 0xff800f50, "vaddhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, - {FPU_NEON_EXT_V1, 0xf2800600, 0xff800f50, "vsubhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, - {FPU_NEON_EXT_V1, 0xf2800900, 0xff800f50, "vqdmlal%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800b00, 0xff800f50, "vqdmlsl%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800d00, 0xff800f50, "vqdmull%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf3800400, 0xff800f50, "vraddhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, - {FPU_NEON_EXT_V1, 0xf3800600, 0xff800f50, "vrsubhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, - {FPU_NEON_EXT_V1, 0xf2800000, 0xfe800f50, "vaddl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800100, 0xfe800f50, "vaddw%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7Q, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800200, 0xfe800f50, "vsubl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800300, 0xfe800f50, "vsubw%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7Q, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800500, 0xfe800f50, "vabal%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800700, 0xfe800f50, "vabdl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800800, 0xfe800f50, "vmlal%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800a00, 0xfe800f50, "vmlsl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - {FPU_NEON_EXT_V1, 0xf2800c00, 0xfe800f50, "vmull%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, - - /* Two registers and a scalar */ - {FPU_NEON_EXT_V1, 0xf2800040, 0xff800f50, "vmla%c.i%20-21S6\t%12-15,22D, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800140, 0xff800f50, "vmla%c.f%20-21Sa\t%12-15,22D, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800340, 0xff800f50, "vqdmlal%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800440, 0xff800f50, "vmls%c.i%20-21S6\t%12-15,22D, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800540, 0xff800f50, "vmls%c.f%20-21S6\t%12-15,22D, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800740, 0xff800f50, "vqdmlsl%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800840, 0xff800f50, "vmul%c.i%20-21S6\t%12-15,22D, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800940, 0xff800f50, "vmul%c.f%20-21Sa\t%12-15,22D, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800b40, 0xff800f50, "vqdmull%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800c40, 0xff800f50, "vqdmulh%c.s%20-21S6\t%12-15,22D, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800d40, 0xff800f50, "vqrdmulh%c.s%20-21S6\t%12-15,22D, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf3800040, 0xff800f50, "vmla%c.i%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, - {FPU_NEON_EXT_V1, 0xf3800140, 0xff800f50, "vmla%c.f%20-21Sa\t%12-15,22Q, %16-19,7Q, %D"}, - {FPU_NEON_EXT_V1, 0xf3800440, 0xff800f50, "vmls%c.i%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, - {FPU_NEON_EXT_V1, 0xf3800540, 0xff800f50, "vmls%c.f%20-21Sa\t%12-15,22Q, %16-19,7Q, %D"}, - {FPU_NEON_EXT_V1, 0xf3800840, 0xff800f50, "vmul%c.i%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, - {FPU_NEON_EXT_V1, 0xf3800940, 0xff800f50, "vmul%c.f%20-21Sa\t%12-15,22Q, %16-19,7Q, %D"}, - {FPU_NEON_EXT_V1, 0xf3800c40, 0xff800f50, "vqdmulh%c.s%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, - {FPU_NEON_EXT_V1, 0xf3800d40, 0xff800f50, "vqrdmulh%c.s%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, - {FPU_NEON_EXT_V1, 0xf2800240, 0xfe800f50, "vmlal%c.%24?us%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800640, 0xfe800f50, "vmlsl%c.%24?us%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, - {FPU_NEON_EXT_V1, 0xf2800a40, 0xfe800f50, "vmull%c.%24?us%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, - - /* Element and structure load/store */ - {FPU_NEON_EXT_V1, 0xf4a00fc0, 0xffb00fc0, "vld4%c.32\t%C"}, - {FPU_NEON_EXT_V1, 0xf4a00c00, 0xffb00f00, "vld1%c.%6-7S2\t%C"}, - {FPU_NEON_EXT_V1, 0xf4a00d00, 0xffb00f00, "vld2%c.%6-7S2\t%C"}, - {FPU_NEON_EXT_V1, 0xf4a00e00, 0xffb00f00, "vld3%c.%6-7S2\t%C"}, - {FPU_NEON_EXT_V1, 0xf4a00f00, 0xffb00f00, "vld4%c.%6-7S2\t%C"}, - {FPU_NEON_EXT_V1, 0xf4000200, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, - {FPU_NEON_EXT_V1, 0xf4000300, 0xff900f00, "v%21?ls%21?dt2%c.%6-7S2\t%A"}, - {FPU_NEON_EXT_V1, 0xf4000400, 0xff900f00, "v%21?ls%21?dt3%c.%6-7S2\t%A"}, - {FPU_NEON_EXT_V1, 0xf4000500, 0xff900f00, "v%21?ls%21?dt3%c.%6-7S2\t%A"}, - {FPU_NEON_EXT_V1, 0xf4000600, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, - {FPU_NEON_EXT_V1, 0xf4000700, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, - {FPU_NEON_EXT_V1, 0xf4000800, 0xff900f00, "v%21?ls%21?dt2%c.%6-7S2\t%A"}, - {FPU_NEON_EXT_V1, 0xf4000900, 0xff900f00, "v%21?ls%21?dt2%c.%6-7S2\t%A"}, - {FPU_NEON_EXT_V1, 0xf4000a00, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, - {FPU_NEON_EXT_V1, 0xf4000000, 0xff900e00, "v%21?ls%21?dt4%c.%6-7S2\t%A"}, - {FPU_NEON_EXT_V1, 0xf4800000, 0xff900300, "v%21?ls%21?dt1%c.%10-11S2\t%B"}, - {FPU_NEON_EXT_V1, 0xf4800100, 0xff900300, "v%21?ls%21?dt2%c.%10-11S2\t%B"}, - {FPU_NEON_EXT_V1, 0xf4800200, 0xff900300, "v%21?ls%21?dt3%c.%10-11S2\t%B"}, - {FPU_NEON_EXT_V1, 0xf4800300, 0xff900300, "v%21?ls%21?dt4%c.%10-11S2\t%B"}, - - {0,0 ,0, 0} -}; - -/* Opcode tables: ARM, 16-bit Thumb, 32-bit Thumb. All three are partially - ordered: they must be searched linearly from the top to obtain a correct - match. */ - -/* print_insn_arm recognizes the following format control codes: - - %% % - - %a print address for ldr/str instruction - %s print address for ldr/str halfword/signextend instruction - %b print branch destination - %c print condition code (always bits 28-31) - %m print register mask for ldm/stm instruction - %o print operand2 (immediate or register + shift) - %p print 'p' iff bits 12-15 are 15 - %t print 't' iff bit 21 set and bit 24 clear - %B print arm BLX(1) destination - %C print the PSR sub type. - %U print barrier type. - %P print address for pli instruction. - - %r print as an ARM register - %d print the bitfield in decimal - %W print the bitfield plus one in decimal - %x print the bitfield in hex - %X print the bitfield as 1 hex digit without leading "0x" - - %'c print specified char iff bitfield is all ones - %`c print specified char iff bitfield is all zeroes - %?ab... select from array of values in big endian order - - %e print arm SMI operand (bits 0..7,8..19). - %E print the LSB and WIDTH fields of a BFI or BFC instruction. - %V print the 16-bit immediate field of a MOVT or MOVW instruction. */ - -static const struct opcode32 arm_opcodes[] = -{ - /* ARM instructions. */ - {ARM_EXT_V1, 0xe1a00000, 0xffffffff, "nop\t\t\t(mov r0,r0)"}, - {ARM_EXT_V4T | ARM_EXT_V5, 0x012FFF10, 0x0ffffff0, "bx%c\t%0-3r"}, - {ARM_EXT_V2, 0x00000090, 0x0fe000f0, "mul%20's%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V2, 0x00200090, 0x0fe000f0, "mla%20's%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V2S, 0x01000090, 0x0fb00ff0, "swp%22'b%c\t%12-15r, %0-3r, [%16-19r]"}, - {ARM_EXT_V3M, 0x00800090, 0x0fa000f0, "%22?sumull%20's%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V3M, 0x00a00090, 0x0fa000f0, "%22?sumlal%20's%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, - - /* IDIV instructions. */ - {ARM_EXT_DIV, 0x0710f010, 0x0ff0f0f0, "sdiv%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_DIV, 0x0730f010, 0x0ff0f0f0, "udiv%c\t%16-19r, %0-3r, %8-11r"}, - - /* V7 instructions. */ - {ARM_EXT_V7, 0xf450f000, 0xfd70f000, "pli\t%P"}, - {ARM_EXT_V7, 0x0320f0f0, 0x0ffffff0, "dbg%c\t#%0-3d"}, - {ARM_EXT_V7, 0xf57ff050, 0xfffffff0, "dmb\t%U"}, - {ARM_EXT_V7, 0xf57ff040, 0xfffffff0, "dsb\t%U"}, - {ARM_EXT_V7, 0xf57ff060, 0xfffffff0, "isb\t%U"}, - - /* ARM V6T2 instructions. */ - {ARM_EXT_V6T2, 0x07c0001f, 0x0fe0007f, "bfc%c\t%12-15r, %E"}, - {ARM_EXT_V6T2, 0x07c00010, 0x0fe00070, "bfi%c\t%12-15r, %0-3r, %E"}, - {ARM_EXT_V6T2, 0x00600090, 0x0ff000f0, "mls%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V6T2, 0x006000b0, 0x0f7000f0, "strht%c\t%12-15r, %s"}, - {ARM_EXT_V6T2, 0x00300090, 0x0f300090, "ldr%6's%5?hbt%c\t%12-15r, %s"}, - {ARM_EXT_V6T2, 0x03000000, 0x0ff00000, "movw%c\t%12-15r, %V"}, - {ARM_EXT_V6T2, 0x03400000, 0x0ff00000, "movt%c\t%12-15r, %V"}, - {ARM_EXT_V6T2, 0x06ff0f30, 0x0fff0ff0, "rbit%c\t%12-15r, %0-3r"}, - {ARM_EXT_V6T2, 0x07a00050, 0x0fa00070, "%22?usbfx%c\t%12-15r, %0-3r, #%7-11d, #%16-20W"}, - - /* ARM V6Z instructions. */ - {ARM_EXT_V6Z, 0x01600070, 0x0ff000f0, "smc%c\t%e"}, - - /* ARM V6K instructions. */ - {ARM_EXT_V6K, 0xf57ff01f, 0xffffffff, "clrex"}, - {ARM_EXT_V6K, 0x01d00f9f, 0x0ff00fff, "ldrexb%c\t%12-15r, [%16-19r]"}, - {ARM_EXT_V6K, 0x01b00f9f, 0x0ff00fff, "ldrexd%c\t%12-15r, [%16-19r]"}, - {ARM_EXT_V6K, 0x01f00f9f, 0x0ff00fff, "ldrexh%c\t%12-15r, [%16-19r]"}, - {ARM_EXT_V6K, 0x01c00f90, 0x0ff00ff0, "strexb%c\t%12-15r, %0-3r, [%16-19r]"}, - {ARM_EXT_V6K, 0x01a00f90, 0x0ff00ff0, "strexd%c\t%12-15r, %0-3r, [%16-19r]"}, - {ARM_EXT_V6K, 0x01e00f90, 0x0ff00ff0, "strexh%c\t%12-15r, %0-3r, [%16-19r]"}, - - /* ARM V6K NOP hints. */ - {ARM_EXT_V6K, 0x0320f001, 0x0fffffff, "yield%c"}, - {ARM_EXT_V6K, 0x0320f002, 0x0fffffff, "wfe%c"}, - {ARM_EXT_V6K, 0x0320f003, 0x0fffffff, "wfi%c"}, - {ARM_EXT_V6K, 0x0320f004, 0x0fffffff, "sev%c"}, - {ARM_EXT_V6K, 0x0320f000, 0x0fffff00, "nop%c\t{%0-7d}"}, - - /* ARM V6 instructions. */ - {ARM_EXT_V6, 0xf1080000, 0xfffffe3f, "cpsie\t%8'a%7'i%6'f"}, - {ARM_EXT_V6, 0xf10a0000, 0xfffffe20, "cpsie\t%8'a%7'i%6'f,#%0-4d"}, - {ARM_EXT_V6, 0xf10C0000, 0xfffffe3f, "cpsid\t%8'a%7'i%6'f"}, - {ARM_EXT_V6, 0xf10e0000, 0xfffffe20, "cpsid\t%8'a%7'i%6'f,#%0-4d"}, - {ARM_EXT_V6, 0xf1000000, 0xfff1fe20, "cps\t#%0-4d"}, - {ARM_EXT_V6, 0x06800010, 0x0ff00ff0, "pkhbt%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06800010, 0x0ff00070, "pkhbt%c\t%12-15r, %16-19r, %0-3r, lsl #%7-11d"}, - {ARM_EXT_V6, 0x06800050, 0x0ff00ff0, "pkhtb%c\t%12-15r, %16-19r, %0-3r, asr #32"}, - {ARM_EXT_V6, 0x06800050, 0x0ff00070, "pkhtb%c\t%12-15r, %16-19r, %0-3r, asr #%7-11d"}, - {ARM_EXT_V6, 0x01900f9f, 0x0ff00fff, "ldrex%c\tr%12-15d, [%16-19r]"}, - {ARM_EXT_V6, 0x06200f10, 0x0ff00ff0, "qadd16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06200f90, 0x0ff00ff0, "qadd8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06200f30, 0x0ff00ff0, "qaddsubx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06200f70, 0x0ff00ff0, "qsub16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06200ff0, 0x0ff00ff0, "qsub8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06200f50, 0x0ff00ff0, "qsubaddx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06100f10, 0x0ff00ff0, "sadd16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06100f90, 0x0ff00ff0, "sadd8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06100f30, 0x0ff00ff0, "saddaddx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06300f10, 0x0ff00ff0, "shadd16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06300f90, 0x0ff00ff0, "shadd8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06300f30, 0x0ff00ff0, "shaddsubx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06300f70, 0x0ff00ff0, "shsub16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06300ff0, 0x0ff00ff0, "shsub8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06300f50, 0x0ff00ff0, "shsubaddx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06100f70, 0x0ff00ff0, "ssub16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06100ff0, 0x0ff00ff0, "ssub8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06100f50, 0x0ff00ff0, "ssubaddx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06500f10, 0x0ff00ff0, "uadd16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06500f90, 0x0ff00ff0, "uadd8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06500f30, 0x0ff00ff0, "uaddsubx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06700f10, 0x0ff00ff0, "uhadd16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06700f90, 0x0ff00ff0, "uhadd8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06700f30, 0x0ff00ff0, "uhaddsubx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06700f70, 0x0ff00ff0, "uhsub16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06700ff0, 0x0ff00ff0, "uhsub8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06700f50, 0x0ff00ff0, "uhsubaddx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06600f10, 0x0ff00ff0, "uqadd16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06600f90, 0x0ff00ff0, "uqadd8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06600f30, 0x0ff00ff0, "uqaddsubx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06600f70, 0x0ff00ff0, "uqsub16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06600ff0, 0x0ff00ff0, "uqsub8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06600f50, 0x0ff00ff0, "uqsubaddx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06500f70, 0x0ff00ff0, "usub16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06500ff0, 0x0ff00ff0, "usub8%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06500f50, 0x0ff00ff0, "usubaddx%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06bf0f30, 0x0fff0ff0, "rev%c\t\%12-15r, %0-3r"}, - {ARM_EXT_V6, 0x06bf0fb0, 0x0fff0ff0, "rev16%c\t\%12-15r, %0-3r"}, - {ARM_EXT_V6, 0x06ff0fb0, 0x0fff0ff0, "revsh%c\t\%12-15r, %0-3r"}, - {ARM_EXT_V6, 0xf8100a00, 0xfe50ffff, "rfe%23?id%24?ba\t\%16-19r%21'!"}, - {ARM_EXT_V6, 0x06bf0070, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r"}, - {ARM_EXT_V6, 0x06bf0470, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06bf0870, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06bf0c70, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x068f0070, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r"}, - {ARM_EXT_V6, 0x068f0470, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x068f0870, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x068f0c70, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06af0070, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r"}, - {ARM_EXT_V6, 0x06af0470, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06af0870, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06af0c70, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06ff0070, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r"}, - {ARM_EXT_V6, 0x06ff0470, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06ff0870, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06ff0c70, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06cf0070, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r"}, - {ARM_EXT_V6, 0x06cf0470, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06cf0870, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06cf0c70, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06ef0070, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r"}, - {ARM_EXT_V6, 0x06ef0470, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06ef0870, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06ef0c70, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06b00070, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06b00470, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06b00870, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06b00c70, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06800070, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06800470, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06800870, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06800c70, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06a00070, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06a00470, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06a00870, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06a00c70, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06f00070, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06f00470, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06f00870, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06f00c70, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06c00070, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06c00470, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06c00870, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06c00c70, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r, ROR #24"}, - {ARM_EXT_V6, 0x06e00070, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0x06e00470, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r, ror #8"}, - {ARM_EXT_V6, 0x06e00870, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r, ror #16"}, - {ARM_EXT_V6, 0x06e00c70, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r, ror #24"}, - {ARM_EXT_V6, 0x06800fb0, 0x0ff00ff0, "sel%c\t%12-15r, %16-19r, %0-3r"}, - {ARM_EXT_V6, 0xf1010000, 0xfffffc00, "setend\t%9?ble"}, - {ARM_EXT_V6, 0x0700f010, 0x0ff0f0d0, "smuad%5'x%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V6, 0x0700f050, 0x0ff0f0d0, "smusd%5'x%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V6, 0x07000010, 0x0ff000d0, "smlad%5'x%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V6, 0x07400010, 0x0ff000d0, "smlald%5'x%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V6, 0x07000050, 0x0ff000d0, "smlsd%5'x%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V6, 0x07400050, 0x0ff000d0, "smlsld%5'x%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V6, 0x0750f010, 0x0ff0f0d0, "smmul%5'r%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V6, 0x07500010, 0x0ff000d0, "smmla%5'r%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V6, 0x075000d0, 0x0ff000d0, "smmls%5'r%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V6, 0xf84d0500, 0xfe5fffe0, "srs%23?id%24?ba\t%16-19r%21'!, #%0-4d"}, - {ARM_EXT_V6, 0x06a00010, 0x0fe00ff0, "ssat%c\t%12-15r, #%16-20W, %0-3r"}, - {ARM_EXT_V6, 0x06a00010, 0x0fe00070, "ssat%c\t%12-15r, #%16-20W, %0-3r, lsl #%7-11d"}, - {ARM_EXT_V6, 0x06a00050, 0x0fe00070, "ssat%c\t%12-15r, #%16-20W, %0-3r, asr #%7-11d"}, - {ARM_EXT_V6, 0x06a00f30, 0x0ff00ff0, "ssat16%c\t%12-15r, #%16-19W, %0-3r"}, - {ARM_EXT_V6, 0x01800f90, 0x0ff00ff0, "strex%c\t%12-15r, %0-3r, [%16-19r]"}, - {ARM_EXT_V6, 0x00400090, 0x0ff000f0, "umaal%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V6, 0x0780f010, 0x0ff0f0f0, "usad8%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V6, 0x07800010, 0x0ff000f0, "usada8%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V6, 0x06e00010, 0x0fe00ff0, "usat%c\t%12-15r, #%16-20d, %0-3r"}, - {ARM_EXT_V6, 0x06e00010, 0x0fe00070, "usat%c\t%12-15r, #%16-20d, %0-3r, lsl #%7-11d"}, - {ARM_EXT_V6, 0x06e00050, 0x0fe00070, "usat%c\t%12-15r, #%16-20d, %0-3r, asr #%7-11d"}, - {ARM_EXT_V6, 0x06e00f30, 0x0ff00ff0, "usat16%c\t%12-15r, #%16-19d, %0-3r"}, - - /* V5J instruction. */ - {ARM_EXT_V5J, 0x012fff20, 0x0ffffff0, "bxj%c\t%0-3r"}, - - /* V5 Instructions. */ - {ARM_EXT_V5, 0xe1200070, 0xfff000f0, "bkpt\t0x%16-19X%12-15X%8-11X%0-3X"}, - {ARM_EXT_V5, 0xfa000000, 0xfe000000, "blx\t%B"}, - {ARM_EXT_V5, 0x012fff30, 0x0ffffff0, "blx%c\t%0-3r"}, - {ARM_EXT_V5, 0x016f0f10, 0x0fff0ff0, "clz%c\t%12-15r, %0-3r"}, - - /* V5E "El Segundo" Instructions. */ - {ARM_EXT_V5E, 0x000000d0, 0x0e1000f0, "ldrd%c\t%12-15r, %s"}, - {ARM_EXT_V5E, 0x000000f0, 0x0e1000f0, "strd%c\t%12-15r, %s"}, - {ARM_EXT_V5E, 0xf450f000, 0xfc70f000, "pld\t%a"}, - {ARM_EXT_V5ExP, 0x01000080, 0x0ff000f0, "smlabb%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V5ExP, 0x010000a0, 0x0ff000f0, "smlatb%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V5ExP, 0x010000c0, 0x0ff000f0, "smlabt%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V5ExP, 0x010000e0, 0x0ff000f0, "smlatt%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - - {ARM_EXT_V5ExP, 0x01200080, 0x0ff000f0, "smlawb%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - {ARM_EXT_V5ExP, 0x012000c0, 0x0ff000f0, "smlawt%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, - - {ARM_EXT_V5ExP, 0x01400080, 0x0ff000f0, "smlalbb%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V5ExP, 0x014000a0, 0x0ff000f0, "smlaltb%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V5ExP, 0x014000c0, 0x0ff000f0, "smlalbt%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V5ExP, 0x014000e0, 0x0ff000f0, "smlaltt%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, - - {ARM_EXT_V5ExP, 0x01600080, 0x0ff0f0f0, "smulbb%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V5ExP, 0x016000a0, 0x0ff0f0f0, "smultb%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V5ExP, 0x016000c0, 0x0ff0f0f0, "smulbt%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V5ExP, 0x016000e0, 0x0ff0f0f0, "smultt%c\t%16-19r, %0-3r, %8-11r"}, - - {ARM_EXT_V5ExP, 0x012000a0, 0x0ff0f0f0, "smulwb%c\t%16-19r, %0-3r, %8-11r"}, - {ARM_EXT_V5ExP, 0x012000e0, 0x0ff0f0f0, "smulwt%c\t%16-19r, %0-3r, %8-11r"}, - - {ARM_EXT_V5ExP, 0x01000050, 0x0ff00ff0, "qadd%c\t%12-15r, %0-3r, %16-19r"}, - {ARM_EXT_V5ExP, 0x01400050, 0x0ff00ff0, "qdadd%c\t%12-15r, %0-3r, %16-19r"}, - {ARM_EXT_V5ExP, 0x01200050, 0x0ff00ff0, "qsub%c\t%12-15r, %0-3r, %16-19r"}, - {ARM_EXT_V5ExP, 0x01600050, 0x0ff00ff0, "qdsub%c\t%12-15r, %0-3r, %16-19r"}, - - /* ARM Instructions. */ - {ARM_EXT_V1, 0x00000090, 0x0e100090, "str%6's%5?hb%c\t%12-15r, %s"}, - {ARM_EXT_V1, 0x00100090, 0x0e100090, "ldr%6's%5?hb%c\t%12-15r, %s"}, - {ARM_EXT_V1, 0x00000000, 0x0de00000, "and%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V1, 0x00200000, 0x0de00000, "eor%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V1, 0x00400000, 0x0de00000, "sub%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V1, 0x00600000, 0x0de00000, "rsb%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V1, 0x00800000, 0x0de00000, "add%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V1, 0x00a00000, 0x0de00000, "adc%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V1, 0x00c00000, 0x0de00000, "sbc%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V1, 0x00e00000, 0x0de00000, "rsc%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V3, 0x0120f000, 0x0db0f000, "msr%c\t%22?SCPSR%C, %o"}, - {ARM_EXT_V3, 0x010f0000, 0x0fbf0fff, "mrs%c\t%12-15r, %22?SCPSR"}, - {ARM_EXT_V1, 0x01000000, 0x0de00000, "tst%p%c\t%16-19r, %o"}, - {ARM_EXT_V1, 0x01200000, 0x0de00000, "teq%p%c\t%16-19r, %o"}, - {ARM_EXT_V1, 0x01400000, 0x0de00000, "cmp%p%c\t%16-19r, %o"}, - {ARM_EXT_V1, 0x01600000, 0x0de00000, "cmn%p%c\t%16-19r, %o"}, - {ARM_EXT_V1, 0x01800000, 0x0de00000, "orr%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V1, 0x03a00000, 0x0fef0000, "mov%20's%c\t%12-15r, %o"}, - {ARM_EXT_V1, 0x01a00000, 0x0def0ff0, "mov%20's%c\t%12-15r, %0-3r"}, - {ARM_EXT_V1, 0x01a00000, 0x0def0060, "lsl%20's%c\t%12-15r, %q"}, - {ARM_EXT_V1, 0x01a00020, 0x0def0060, "lsr%20's%c\t%12-15r, %q"}, - {ARM_EXT_V1, 0x01a00040, 0x0def0060, "asr%20's%c\t%12-15r, %q"}, - {ARM_EXT_V1, 0x01a00060, 0x0def0ff0, "rrx%20's%c\t%12-15r, %0-3r"}, - {ARM_EXT_V1, 0x01a00060, 0x0def0060, "ror%20's%c\t%12-15r, %q"}, - {ARM_EXT_V1, 0x01c00000, 0x0de00000, "bic%20's%c\t%12-15r, %16-19r, %o"}, - {ARM_EXT_V1, 0x01e00000, 0x0de00000, "mvn%20's%c\t%12-15r, %o"}, - {ARM_EXT_V1, 0x052d0004, 0x0fff0fff, "push%c\t{%12-15r}\t\t; (str%c %12-15r, %a)"}, - {ARM_EXT_V1, 0x04000000, 0x0e100000, "str%22'b%t%c\t%12-15r, %a"}, - {ARM_EXT_V1, 0x06000000, 0x0e100ff0, "str%22'b%t%c\t%12-15r, %a"}, - {ARM_EXT_V1, 0x04000000, 0x0c100010, "str%22'b%t%c\t%12-15r, %a"}, - {ARM_EXT_V1, 0x06000010, 0x0e000010, "undefined"}, - {ARM_EXT_V1, 0x049d0004, 0x0fff0fff, "pop%c\t{%12-15r}\t\t; (ldr%c %12-15r, %a)"}, - {ARM_EXT_V1, 0x04100000, 0x0c100000, "ldr%22'b%t%c\t%12-15r, %a"}, - {ARM_EXT_V1, 0x092d0000, 0x0fff0000, "push%c\t%m"}, - {ARM_EXT_V1, 0x08800000, 0x0ff00000, "stm%c\t%16-19r%21'!, %m%22'^"}, - {ARM_EXT_V1, 0x08000000, 0x0e100000, "stm%23?id%24?ba%c\t%16-19r%21'!, %m%22'^"}, - {ARM_EXT_V1, 0x08bd0000, 0x0fff0000, "pop%c\t%m"}, - {ARM_EXT_V1, 0x08900000, 0x0f900000, "ldm%c\t%16-19r%21'!, %m%22'^"}, - {ARM_EXT_V1, 0x08100000, 0x0e100000, "ldm%23?id%24?ba%c\t%16-19r%21'!, %m%22'^"}, - {ARM_EXT_V1, 0x0a000000, 0x0e000000, "b%24'l%c\t%b"}, - {ARM_EXT_V1, 0x0f000000, 0x0f000000, "svc%c\t%0-23x"}, - - /* The rest. */ - {ARM_EXT_V1, 0x00000000, 0x00000000, "undefined instruction %0-31x"}, - {0, 0x00000000, 0x00000000, 0} -}; - -/* print_insn_thumb16 recognizes the following format control codes: - - %S print Thumb register (bits 3..5 as high number if bit 6 set) - %D print Thumb register (bits 0..2 as high number if bit 7 set) - %I print bitfield as a signed decimal - (top bit of range being the sign bit) - %N print Thumb register mask (with LR) - %O print Thumb register mask (with PC) - %M print Thumb register mask - %b print CZB's 6-bit unsigned branch destination - %s print Thumb right-shift immediate (6..10; 0 == 32). - %c print the condition code - %C print the condition code, or "s" if not conditional - %x print warning if conditional an not at end of IT block" - %X print "\t; unpredictable " if conditional - %I print IT instruction suffix and operands - %r print bitfield as an ARM register - %d print bitfield as a decimal - %H print (bitfield * 2) as a decimal - %W print (bitfield * 4) as a decimal - %a print (bitfield * 4) as a pc-rel offset + decoded symbol - %B print Thumb branch destination (signed displacement) - %c print bitfield as a condition code - %'c print specified char iff bit is one - %?ab print a if bit is one else print b. */ - -static const struct opcode16 thumb_opcodes[] = -{ - /* Thumb instructions. */ - - /* ARM V6K no-argument instructions. */ - {ARM_EXT_V6K, 0xbf00, 0xffff, "nop%c"}, - {ARM_EXT_V6K, 0xbf10, 0xffff, "yield%c"}, - {ARM_EXT_V6K, 0xbf20, 0xffff, "wfe%c"}, - {ARM_EXT_V6K, 0xbf30, 0xffff, "wfi%c"}, - {ARM_EXT_V6K, 0xbf40, 0xffff, "sev%c"}, - {ARM_EXT_V6K, 0xbf00, 0xff0f, "nop%c\t{%4-7d}"}, - - /* ARM V6T2 instructions. */ - {ARM_EXT_V6T2, 0xb900, 0xfd00, "cbnz\t%0-2r, %b%X"}, - {ARM_EXT_V6T2, 0xb100, 0xfd00, "cbz\t%0-2r, %b%X"}, - {ARM_EXT_V6T2, 0xbf00, 0xff00, "it%I%X"}, - - /* ARM V6. */ - {ARM_EXT_V6, 0xb660, 0xfff8, "cpsie\t%2'a%1'i%0'f%X"}, - {ARM_EXT_V6, 0xb670, 0xfff8, "cpsid\t%2'a%1'i%0'f%X"}, - {ARM_EXT_V6, 0x4600, 0xffc0, "mov%c\t%0-2r, %3-5r"}, - {ARM_EXT_V6, 0xba00, 0xffc0, "rev%c\t%0-2r, %3-5r"}, - {ARM_EXT_V6, 0xba40, 0xffc0, "rev16%c\t%0-2r, %3-5r"}, - {ARM_EXT_V6, 0xbac0, 0xffc0, "revsh%c\t%0-2r, %3-5r"}, - {ARM_EXT_V6, 0xb650, 0xfff7, "setend\t%3?ble%X"}, - {ARM_EXT_V6, 0xb200, 0xffc0, "sxth%c\t%0-2r, %3-5r"}, - {ARM_EXT_V6, 0xb240, 0xffc0, "sxtb%c\t%0-2r, %3-5r"}, - {ARM_EXT_V6, 0xb280, 0xffc0, "uxth%c\t%0-2r, %3-5r"}, - {ARM_EXT_V6, 0xb2c0, 0xffc0, "uxtb%c\t%0-2r, %3-5r"}, - - /* ARM V5 ISA extends Thumb. */ - {ARM_EXT_V5T, 0xbe00, 0xff00, "bkpt\t%0-7x"}, /* Is always unconditional. */ - /* This is BLX(2). BLX(1) is a 32-bit instruction. */ - {ARM_EXT_V5T, 0x4780, 0xff87, "blx%c\t%3-6r%x"}, /* note: 4 bit register number. */ - /* ARM V4T ISA (Thumb v1). */ - {ARM_EXT_V4T, 0x46C0, 0xFFFF, "nop%c\t\t\t(mov r8, r8)"}, - /* Format 4. */ - {ARM_EXT_V4T, 0x4000, 0xFFC0, "and%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4040, 0xFFC0, "eor%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4080, 0xFFC0, "lsl%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x40C0, 0xFFC0, "lsr%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4100, 0xFFC0, "asr%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4140, 0xFFC0, "adc%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4180, 0xFFC0, "sbc%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x41C0, 0xFFC0, "ror%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4200, 0xFFC0, "tst%c\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4240, 0xFFC0, "neg%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4280, 0xFFC0, "cmp%c\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x42C0, 0xFFC0, "cmn%c\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4300, 0xFFC0, "orr%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4340, 0xFFC0, "mul%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x4380, 0xFFC0, "bic%C\t%0-2r, %3-5r"}, - {ARM_EXT_V4T, 0x43C0, 0xFFC0, "mvn%C\t%0-2r, %3-5r"}, - /* format 13 */ - {ARM_EXT_V4T, 0xB000, 0xFF80, "add%c\tsp, #%0-6W"}, - {ARM_EXT_V4T, 0xB080, 0xFF80, "sub%c\tsp, #%0-6W"}, - /* format 5 */ - {ARM_EXT_V4T, 0x4700, 0xFF80, "bx%c\t%S%x"}, - {ARM_EXT_V4T, 0x4400, 0xFF00, "add%c\t%D, %S"}, - {ARM_EXT_V4T, 0x4500, 0xFF00, "cmp%c\t%D, %S"}, - {ARM_EXT_V4T, 0x4600, 0xFF00, "mov%c\t%D, %S"}, - /* format 14 */ - {ARM_EXT_V4T, 0xB400, 0xFE00, "push%c\t%N"}, - {ARM_EXT_V4T, 0xBC00, 0xFE00, "pop%c\t%O"}, - /* format 2 */ - {ARM_EXT_V4T, 0x1800, 0xFE00, "add%C\t%0-2r, %3-5r, %6-8r"}, - {ARM_EXT_V4T, 0x1A00, 0xFE00, "sub%C\t%0-2r, %3-5r, %6-8r"}, - {ARM_EXT_V4T, 0x1C00, 0xFE00, "add%C\t%0-2r, %3-5r, #%6-8d"}, - {ARM_EXT_V4T, 0x1E00, 0xFE00, "sub%C\t%0-2r, %3-5r, #%6-8d"}, - /* format 8 */ - {ARM_EXT_V4T, 0x5200, 0xFE00, "strh%c\t%0-2r, [%3-5r, %6-8r]"}, - {ARM_EXT_V4T, 0x5A00, 0xFE00, "ldrh%c\t%0-2r, [%3-5r, %6-8r]"}, - {ARM_EXT_V4T, 0x5600, 0xF600, "ldrs%11?hb%c\t%0-2r, [%3-5r, %6-8r]"}, - /* format 7 */ - {ARM_EXT_V4T, 0x5000, 0xFA00, "str%10'b%c\t%0-2r, [%3-5r, %6-8r]"}, - {ARM_EXT_V4T, 0x5800, 0xFA00, "ldr%10'b%c\t%0-2r, [%3-5r, %6-8r]"}, - /* format 1 */ - {ARM_EXT_V4T, 0x0000, 0xF800, "lsl%C\t%0-2r, %3-5r, #%6-10d"}, - {ARM_EXT_V4T, 0x0800, 0xF800, "lsr%C\t%0-2r, %3-5r, %s"}, - {ARM_EXT_V4T, 0x1000, 0xF800, "asr%C\t%0-2r, %3-5r, %s"}, - /* format 3 */ - {ARM_EXT_V4T, 0x2000, 0xF800, "mov%C\t%8-10r, #%0-7d"}, - {ARM_EXT_V4T, 0x2800, 0xF800, "cmp%c\t%8-10r, #%0-7d"}, - {ARM_EXT_V4T, 0x3000, 0xF800, "add%C\t%8-10r, #%0-7d"}, - {ARM_EXT_V4T, 0x3800, 0xF800, "sub%C\t%8-10r, #%0-7d"}, - /* format 6 */ - {ARM_EXT_V4T, 0x4800, 0xF800, "ldr%c\t%8-10r, [pc, #%0-7W]\t(%0-7a)"}, /* TODO: Disassemble PC relative "LDR rD,=" */ - /* format 9 */ - {ARM_EXT_V4T, 0x6000, 0xF800, "str%c\t%0-2r, [%3-5r, #%6-10W]"}, - {ARM_EXT_V4T, 0x6800, 0xF800, "ldr%c\t%0-2r, [%3-5r, #%6-10W]"}, - {ARM_EXT_V4T, 0x7000, 0xF800, "strb%c\t%0-2r, [%3-5r, #%6-10d]"}, - {ARM_EXT_V4T, 0x7800, 0xF800, "ldrb%c\t%0-2r, [%3-5r, #%6-10d]"}, - /* format 10 */ - {ARM_EXT_V4T, 0x8000, 0xF800, "strh%c\t%0-2r, [%3-5r, #%6-10H]"}, - {ARM_EXT_V4T, 0x8800, 0xF800, "ldrh%c\t%0-2r, [%3-5r, #%6-10H]"}, - /* format 11 */ - {ARM_EXT_V4T, 0x9000, 0xF800, "str%c\t%8-10r, [sp, #%0-7W]"}, - {ARM_EXT_V4T, 0x9800, 0xF800, "ldr%c\t%8-10r, [sp, #%0-7W]"}, - /* format 12 */ - {ARM_EXT_V4T, 0xA000, 0xF800, "add%c\t%8-10r, pc, #%0-7W\t(adr %8-10r, %0-7a)"}, - {ARM_EXT_V4T, 0xA800, 0xF800, "add%c\t%8-10r, sp, #%0-7W"}, - /* format 15 */ - {ARM_EXT_V4T, 0xC000, 0xF800, "stmia%c\t%8-10r!, %M"}, - {ARM_EXT_V4T, 0xC800, 0xF800, "ldmia%c\t%8-10r!, %M"}, - /* format 17 */ - {ARM_EXT_V4T, 0xDF00, 0xFF00, "svc%c\t%0-7d"}, - /* format 16 */ - {ARM_EXT_V4T, 0xDE00, 0xFE00, "undefined"}, - {ARM_EXT_V4T, 0xD000, 0xF000, "b%8-11c.n\t%0-7B%X"}, - /* format 18 */ - {ARM_EXT_V4T, 0xE000, 0xF800, "b%c.n\t%0-10B%x"}, - - /* The E800 .. FFFF range is unconditionally redirected to the - 32-bit table, because even in pre-V6T2 ISAs, BL and BLX(1) pairs - are processed via that table. Thus, we can never encounter a - bare "second half of BL/BLX(1)" instruction here. */ - {ARM_EXT_V1, 0x0000, 0x0000, "undefined"}, - {0, 0, 0, 0} -}; - -/* Thumb32 opcodes use the same table structure as the ARM opcodes. - We adopt the convention that hw1 is the high 16 bits of .value and - .mask, hw2 the low 16 bits. - - print_insn_thumb32 recognizes the following format control codes: - - %% % - - %I print a 12-bit immediate from hw1[10],hw2[14:12,7:0] - %M print a modified 12-bit immediate (same location) - %J print a 16-bit immediate from hw1[3:0,10],hw2[14:12,7:0] - %K print a 16-bit immediate from hw2[3:0],hw1[3:0],hw2[11:4] - %S print a possibly-shifted Rm - - %a print the address of a plain load/store - %w print the width and signedness of a core load/store - %m print register mask for ldm/stm - - %E print the lsb and width fields of a bfc/bfi instruction - %F print the lsb and width fields of a sbfx/ubfx instruction - %b print a conditional branch offset - %B print an unconditional branch offset - %s print the shift field of an SSAT instruction - %R print the rotation field of an SXT instruction - %U print barrier type. - %P print address for pli instruction. - %c print the condition code - %x print warning if conditional an not at end of IT block" - %X print "\t; unpredictable " if conditional - - %d print bitfield in decimal - %W print bitfield*4 in decimal - %r print bitfield as an ARM register - %c print bitfield as a condition code - - %'c print specified char iff bitfield is all ones - %`c print specified char iff bitfield is all zeroes - %?ab... select from array of values in big endian order - - With one exception at the bottom (done because BL and BLX(1) need - to come dead last), this table was machine-sorted first in - decreasing order of number of bits set in the mask, then in - increasing numeric order of mask, then in increasing numeric order - of opcode. This order is not the clearest for a human reader, but - is guaranteed never to catch a special-case bit pattern with a more - general mask, which is important, because this instruction encoding - makes heavy use of special-case bit patterns. */ -static const struct opcode32 thumb32_opcodes[] = -{ - /* V7 instructions. */ - {ARM_EXT_V7, 0xf910f000, 0xff70f000, "pli%c\t%a"}, - {ARM_EXT_V7, 0xf3af80f0, 0xfffffff0, "dbg%c\t#%0-3d"}, - {ARM_EXT_V7, 0xf3bf8f50, 0xfffffff0, "dmb%c\t%U"}, - {ARM_EXT_V7, 0xf3bf8f40, 0xfffffff0, "dsb%c\t%U"}, - {ARM_EXT_V7, 0xf3bf8f60, 0xfffffff0, "isb%c\t%U"}, - {ARM_EXT_DIV, 0xfb90f0f0, 0xfff0f0f0, "sdiv%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_DIV, 0xfbb0f0f0, 0xfff0f0f0, "udiv%c\t%8-11r, %16-19r, %0-3r"}, - - /* Instructions defined in the basic V6T2 set. */ - {ARM_EXT_V6T2, 0xf3af8000, 0xffffffff, "nop%c.w"}, - {ARM_EXT_V6T2, 0xf3af8001, 0xffffffff, "yield%c.w"}, - {ARM_EXT_V6T2, 0xf3af8002, 0xffffffff, "wfe%c.w"}, - {ARM_EXT_V6T2, 0xf3af8003, 0xffffffff, "wfi%c.w"}, - {ARM_EXT_V6T2, 0xf3af9004, 0xffffffff, "sev%c.w"}, - {ARM_EXT_V6T2, 0xf3af8000, 0xffffff00, "nop%c.w\t{%0-7d}"}, - - {ARM_EXT_V6T2, 0xf3bf8f2f, 0xffffffff, "clrex%c"}, - {ARM_EXT_V6T2, 0xf3af8400, 0xffffff1f, "cpsie.w\t%7'a%6'i%5'f%X"}, - {ARM_EXT_V6T2, 0xf3af8600, 0xffffff1f, "cpsid.w\t%7'a%6'i%5'f%X"}, - {ARM_EXT_V6T2, 0xf3c08f00, 0xfff0ffff, "bxj%c\t%16-19r%x"}, - {ARM_EXT_V6T2, 0xe810c000, 0xffd0ffff, "rfedb%c\t%16-19r%21'!"}, - {ARM_EXT_V6T2, 0xe990c000, 0xffd0ffff, "rfeia%c\t%16-19r%21'!"}, - {ARM_EXT_V6T2, 0xf3ef8000, 0xffeff000, "mrs%c\t%8-11r, %D"}, - {ARM_EXT_V6T2, 0xf3af8100, 0xffffffe0, "cps\t#%0-4d%X"}, - {ARM_EXT_V6T2, 0xe8d0f000, 0xfff0fff0, "tbb%c\t[%16-19r, %0-3r]%x"}, - {ARM_EXT_V6T2, 0xe8d0f010, 0xfff0fff0, "tbh%c\t[%16-19r, %0-3r, lsl #1]%x"}, - {ARM_EXT_V6T2, 0xf3af8500, 0xffffff00, "cpsie\t%7'a%6'i%5'f, #%0-4d%X"}, - {ARM_EXT_V6T2, 0xf3af8700, 0xffffff00, "cpsid\t%7'a%6'i%5'f, #%0-4d%X"}, - {ARM_EXT_V6T2, 0xf3de8f00, 0xffffff00, "subs%c\tpc, lr, #%0-7d"}, - {ARM_EXT_V6T2, 0xf3808000, 0xffe0f000, "msr%c\t%C, %16-19r"}, - {ARM_EXT_V6T2, 0xe8500f00, 0xfff00fff, "ldrex%c\t%12-15r, [%16-19r]"}, - {ARM_EXT_V6T2, 0xe8d00f4f, 0xfff00fef, "ldrex%4?hb%c\t%12-15r, [%16-19r]"}, - {ARM_EXT_V6T2, 0xe800c000, 0xffd0ffe0, "srsdb%c\t%16-19r%21'!, #%0-4d"}, - {ARM_EXT_V6T2, 0xe980c000, 0xffd0ffe0, "srsia%c\t%16-19r%21'!, #%0-4d"}, - {ARM_EXT_V6T2, 0xfa0ff080, 0xfffff0c0, "sxth%c.w\t%8-11r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa1ff080, 0xfffff0c0, "uxth%c.w\t%8-11r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa2ff080, 0xfffff0c0, "sxtb16%c\t%8-11r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa3ff080, 0xfffff0c0, "uxtb16%c\t%8-11r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa4ff080, 0xfffff0c0, "sxtb%c.w\t%8-11r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa5ff080, 0xfffff0c0, "uxtb%c.w\t%8-11r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xe8400000, 0xfff000ff, "strex%c\t%8-11r, %12-15r, [%16-19r]"}, - {ARM_EXT_V6T2, 0xe8d0007f, 0xfff000ff, "ldrexd%c\t%12-15r, %8-11r, [%16-19r]"}, - {ARM_EXT_V6T2, 0xfa80f000, 0xfff0f0f0, "sadd8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa80f010, 0xfff0f0f0, "qadd8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa80f020, 0xfff0f0f0, "shadd8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa80f040, 0xfff0f0f0, "uadd8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa80f050, 0xfff0f0f0, "uqadd8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa80f060, 0xfff0f0f0, "uhadd8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa80f080, 0xfff0f0f0, "qadd%c\t%8-11r, %0-3r, %16-19r"}, - {ARM_EXT_V6T2, 0xfa80f090, 0xfff0f0f0, "qdadd%c\t%8-11r, %0-3r, %16-19r"}, - {ARM_EXT_V6T2, 0xfa80f0a0, 0xfff0f0f0, "qsub%c\t%8-11r, %0-3r, %16-19r"}, - {ARM_EXT_V6T2, 0xfa80f0b0, 0xfff0f0f0, "qdsub%c\t%8-11r, %0-3r, %16-19r"}, - {ARM_EXT_V6T2, 0xfa90f000, 0xfff0f0f0, "sadd16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa90f010, 0xfff0f0f0, "qadd16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa90f020, 0xfff0f0f0, "shadd16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa90f040, 0xfff0f0f0, "uadd16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa90f050, 0xfff0f0f0, "uqadd16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa90f060, 0xfff0f0f0, "uhadd16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa90f080, 0xfff0f0f0, "rev%c.w\t%8-11r, %16-19r"}, - {ARM_EXT_V6T2, 0xfa90f090, 0xfff0f0f0, "rev16%c.w\t%8-11r, %16-19r"}, - {ARM_EXT_V6T2, 0xfa90f0a0, 0xfff0f0f0, "rbit%c\t%8-11r, %16-19r"}, - {ARM_EXT_V6T2, 0xfa90f0b0, 0xfff0f0f0, "revsh%c.w\t%8-11r, %16-19r"}, - {ARM_EXT_V6T2, 0xfaa0f000, 0xfff0f0f0, "saddsubx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfaa0f010, 0xfff0f0f0, "qaddsubx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfaa0f020, 0xfff0f0f0, "shaddsubx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfaa0f040, 0xfff0f0f0, "uaddsubx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfaa0f050, 0xfff0f0f0, "uqaddsubx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfaa0f060, 0xfff0f0f0, "uhaddsubx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfaa0f080, 0xfff0f0f0, "sel%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfab0f080, 0xfff0f0f0, "clz%c\t%8-11r, %16-19r"}, - {ARM_EXT_V6T2, 0xfac0f000, 0xfff0f0f0, "ssub8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfac0f010, 0xfff0f0f0, "qsub8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfac0f020, 0xfff0f0f0, "shsub8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfac0f040, 0xfff0f0f0, "usub8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfac0f050, 0xfff0f0f0, "uqsub8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfac0f060, 0xfff0f0f0, "uhsub8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfad0f000, 0xfff0f0f0, "ssub16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfad0f010, 0xfff0f0f0, "qsub16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfad0f020, 0xfff0f0f0, "shsub16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfad0f040, 0xfff0f0f0, "usub16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfad0f050, 0xfff0f0f0, "uqsub16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfad0f060, 0xfff0f0f0, "uhsub16%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfae0f000, 0xfff0f0f0, "ssubaddx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfae0f010, 0xfff0f0f0, "qsubaddx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfae0f020, 0xfff0f0f0, "shsubaddx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfae0f040, 0xfff0f0f0, "usubaddx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfae0f050, 0xfff0f0f0, "uqsubaddx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfae0f060, 0xfff0f0f0, "uhsubaddx%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfb00f000, 0xfff0f0f0, "mul%c.w\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfb70f000, 0xfff0f0f0, "usad8%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa00f000, 0xffe0f0f0, "lsl%20's%c.w\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa20f000, 0xffe0f0f0, "lsr%20's%c.w\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa40f000, 0xffe0f0f0, "asr%20's%c.w\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa60f000, 0xffe0f0f0, "ror%20's%c.w\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xe8c00f40, 0xfff00fe0, "strex%4?hb%c\t%0-3r, %12-15r, [%16-19r]"}, - {ARM_EXT_V6T2, 0xf3200000, 0xfff0f0e0, "ssat16%c\t%8-11r, #%0-4d, %16-19r"}, - {ARM_EXT_V6T2, 0xf3a00000, 0xfff0f0e0, "usat16%c\t%8-11r, #%0-4d, %16-19r"}, - {ARM_EXT_V6T2, 0xfb20f000, 0xfff0f0e0, "smuad%4'x%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfb30f000, 0xfff0f0e0, "smulw%4?tb%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfb40f000, 0xfff0f0e0, "smusd%4'x%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfb50f000, 0xfff0f0e0, "smmul%4'r%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfa00f080, 0xfff0f0c0, "sxtah%c\t%8-11r, %16-19r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa10f080, 0xfff0f0c0, "uxtah%c\t%8-11r, %16-19r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa20f080, 0xfff0f0c0, "sxtab16%c\t%8-11r, %16-19r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa30f080, 0xfff0f0c0, "uxtab16%c\t%8-11r, %16-19r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa40f080, 0xfff0f0c0, "sxtab%c\t%8-11r, %16-19r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfa50f080, 0xfff0f0c0, "uxtab%c\t%8-11r, %16-19r, %0-3r%R"}, - {ARM_EXT_V6T2, 0xfb10f000, 0xfff0f0c0, "smul%5?tb%4?tb%c\t%8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xf36f0000, 0xffff8020, "bfc%c\t%8-11r, %E"}, - {ARM_EXT_V6T2, 0xea100f00, 0xfff08f00, "tst%c.w\t%16-19r, %S"}, - {ARM_EXT_V6T2, 0xea900f00, 0xfff08f00, "teq%c\t%16-19r, %S"}, - {ARM_EXT_V6T2, 0xeb100f00, 0xfff08f00, "cmn%c.w\t%16-19r, %S"}, - {ARM_EXT_V6T2, 0xebb00f00, 0xfff08f00, "cmp%c.w\t%16-19r, %S"}, - {ARM_EXT_V6T2, 0xf0100f00, 0xfbf08f00, "tst%c.w\t%16-19r, %M"}, - {ARM_EXT_V6T2, 0xf0900f00, 0xfbf08f00, "teq%c\t%16-19r, %M"}, - {ARM_EXT_V6T2, 0xf1100f00, 0xfbf08f00, "cmn%c.w\t%16-19r, %M"}, - {ARM_EXT_V6T2, 0xf1b00f00, 0xfbf08f00, "cmp%c.w\t%16-19r, %M"}, - {ARM_EXT_V6T2, 0xea4f0000, 0xffef8000, "mov%20's%c.w\t%8-11r, %S"}, - {ARM_EXT_V6T2, 0xea6f0000, 0xffef8000, "mvn%20's%c.w\t%8-11r, %S"}, - {ARM_EXT_V6T2, 0xe8c00070, 0xfff000f0, "strexd%c\t%0-3r, %12-15r, %8-11r, [%16-19r]"}, - {ARM_EXT_V6T2, 0xfb000000, 0xfff000f0, "mla%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, - {ARM_EXT_V6T2, 0xfb000010, 0xfff000f0, "mls%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, - {ARM_EXT_V6T2, 0xfb700000, 0xfff000f0, "usada8%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, - {ARM_EXT_V6T2, 0xfb800000, 0xfff000f0, "smull%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfba00000, 0xfff000f0, "umull%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfbc00000, 0xfff000f0, "smlal%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfbe00000, 0xfff000f0, "umlal%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfbe00060, 0xfff000f0, "umaal%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xe8500f00, 0xfff00f00, "ldrex%c\t%12-15r, [%16-19r, #%0-7W]"}, - {ARM_EXT_V6T2, 0xf7f08000, 0xfff0f000, "smc%c\t%K"}, - {ARM_EXT_V6T2, 0xf04f0000, 0xfbef8000, "mov%20's%c.w\t%8-11r, %M"}, - {ARM_EXT_V6T2, 0xf06f0000, 0xfbef8000, "mvn%20's%c.w\t%8-11r, %M"}, - {ARM_EXT_V6T2, 0xf810f000, 0xff70f000, "pld%c\t%a"}, - {ARM_EXT_V6T2, 0xfb200000, 0xfff000e0, "smlad%4'x%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, - {ARM_EXT_V6T2, 0xfb300000, 0xfff000e0, "smlaw%4?tb%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, - {ARM_EXT_V6T2, 0xfb400000, 0xfff000e0, "smlsd%4'x%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, - {ARM_EXT_V6T2, 0xfb500000, 0xfff000e0, "smmla%4'r%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, - {ARM_EXT_V6T2, 0xfb600000, 0xfff000e0, "smmls%4'r%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, - {ARM_EXT_V6T2, 0xfbc000c0, 0xfff000e0, "smlald%4'x%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xfbd000c0, 0xfff000e0, "smlsld%4'x%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xeac00000, 0xfff08030, "pkhbt%c\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xeac00020, 0xfff08030, "pkhtb%c\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xf3400000, 0xfff08020, "sbfx%c\t%8-11r, %16-19r, %F"}, - {ARM_EXT_V6T2, 0xf3c00000, 0xfff08020, "ubfx%c\t%8-11r, %16-19r, %F"}, - {ARM_EXT_V6T2, 0xf8000e00, 0xff900f00, "str%wt%c\t%12-15r, %a"}, - {ARM_EXT_V6T2, 0xfb100000, 0xfff000c0, "smla%5?tb%4?tb%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, - {ARM_EXT_V6T2, 0xfbc00080, 0xfff000c0, "smlal%5?tb%4?tb%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, - {ARM_EXT_V6T2, 0xf3600000, 0xfff08020, "bfi%c\t%8-11r, %16-19r, %E"}, - {ARM_EXT_V6T2, 0xf8100e00, 0xfe900f00, "ldr%wt%c\t%12-15r, %a"}, - {ARM_EXT_V6T2, 0xf3000000, 0xffd08020, "ssat%c\t%8-11r, #%0-4d, %16-19r%s"}, - {ARM_EXT_V6T2, 0xf3800000, 0xffd08020, "usat%c\t%8-11r, #%0-4d, %16-19r%s"}, - {ARM_EXT_V6T2, 0xf2000000, 0xfbf08000, "addw%c\t%8-11r, %16-19r, %I"}, - {ARM_EXT_V6T2, 0xf2400000, 0xfbf08000, "movw%c\t%8-11r, %J"}, - {ARM_EXT_V6T2, 0xf2a00000, 0xfbf08000, "subw%c\t%8-11r, %16-19r, %I"}, - {ARM_EXT_V6T2, 0xf2c00000, 0xfbf08000, "movt%c\t%8-11r, %J"}, - {ARM_EXT_V6T2, 0xea000000, 0xffe08000, "and%20's%c.w\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xea200000, 0xffe08000, "bic%20's%c.w\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xea400000, 0xffe08000, "orr%20's%c.w\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xea600000, 0xffe08000, "orn%20's%c\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xea800000, 0xffe08000, "eor%20's%c.w\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xeb000000, 0xffe08000, "add%20's%c.w\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xeb400000, 0xffe08000, "adc%20's%c.w\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xeb600000, 0xffe08000, "sbc%20's%c.w\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xeba00000, 0xffe08000, "sub%20's%c.w\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xebc00000, 0xffe08000, "rsb%20's%c\t%8-11r, %16-19r, %S"}, - {ARM_EXT_V6T2, 0xe8400000, 0xfff00000, "strex%c\t%8-11r, %12-15r, [%16-19r, #%0-7W]"}, - {ARM_EXT_V6T2, 0xf0000000, 0xfbe08000, "and%20's%c.w\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xf0200000, 0xfbe08000, "bic%20's%c.w\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xf0400000, 0xfbe08000, "orr%20's%c.w\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xf0600000, 0xfbe08000, "orn%20's%c\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xf0800000, 0xfbe08000, "eor%20's%c.w\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xf1000000, 0xfbe08000, "add%20's%c.w\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xf1400000, 0xfbe08000, "adc%20's%c.w\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xf1600000, 0xfbe08000, "sbc%20's%c.w\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xf1a00000, 0xfbe08000, "sub%20's%c.w\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xf1c00000, 0xfbe08000, "rsb%20's%c\t%8-11r, %16-19r, %M"}, - {ARM_EXT_V6T2, 0xe8800000, 0xffd00000, "stmia%c.w\t%16-19r%21'!, %m"}, - {ARM_EXT_V6T2, 0xe8900000, 0xffd00000, "ldmia%c.w\t%16-19r%21'!, %m"}, - {ARM_EXT_V6T2, 0xe9000000, 0xffd00000, "stmdb%c\t%16-19r%21'!, %m"}, - {ARM_EXT_V6T2, 0xe9100000, 0xffd00000, "ldmdb%c\t%16-19r%21'!, %m"}, - {ARM_EXT_V6T2, 0xe9c00000, 0xffd000ff, "strd%c\t%12-15r, %8-11r, [%16-19r]"}, - {ARM_EXT_V6T2, 0xe9d00000, 0xffd000ff, "ldrd%c\t%12-15r, %8-11r, [%16-19r]"}, - {ARM_EXT_V6T2, 0xe9400000, 0xff500000, "strd%c\t%12-15r, %8-11r, [%16-19r, #%23`-%0-7W]%21'!"}, - {ARM_EXT_V6T2, 0xe9500000, 0xff500000, "ldrd%c\t%12-15r, %8-11r, [%16-19r, #%23`-%0-7W]%21'!"}, - {ARM_EXT_V6T2, 0xe8600000, 0xff700000, "strd%c\t%12-15r, %8-11r, [%16-19r], #%23`-%0-7W"}, - {ARM_EXT_V6T2, 0xe8700000, 0xff700000, "ldrd%c\t%12-15r, %8-11r, [%16-19r], #%23`-%0-7W"}, - {ARM_EXT_V6T2, 0xf8000000, 0xff100000, "str%w%c.w\t%12-15r, %a"}, - {ARM_EXT_V6T2, 0xf8100000, 0xfe100000, "ldr%w%c.w\t%12-15r, %a"}, - - /* Filter out Bcc with cond=E or F, which are used for other instructions. */ - {ARM_EXT_V6T2, 0xf3c08000, 0xfbc0d000, "undefined (bcc, cond=0xF)"}, - {ARM_EXT_V6T2, 0xf3808000, 0xfbc0d000, "undefined (bcc, cond=0xE)"}, - {ARM_EXT_V6T2, 0xf0008000, 0xf800d000, "b%22-25c.w\t%b%X"}, - {ARM_EXT_V6T2, 0xf0009000, 0xf800d000, "b%c.w\t%B%x"}, - - /* These have been 32-bit since the invention of Thumb. */ - {ARM_EXT_V4T, 0xf000c000, 0xf800d000, "blx%c\t%B%x"}, - {ARM_EXT_V4T, 0xf000d000, 0xf800d000, "bl%c\t%B%x"}, - - /* Fallback. */ - {ARM_EXT_V1, 0x00000000, 0x00000000, "undefined"}, - {0, 0, 0, 0} -}; - -static const char *const arm_conditional[] = -{"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", - "hi", "ls", "ge", "lt", "gt", "le", "al", "", ""}; - -static const char *const arm_fp_const[] = -{"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"}; - -static const char *const arm_shift[] = -{"lsl", "lsr", "asr", "ror"}; - -typedef struct -{ - const char *name; - const char *description; - const char *reg_names[16]; -} -arm_regname; - -static const arm_regname regnames[] = -{ - { "raw" , "Select raw register names", - { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}}, - { "gcc", "Select register names used by GCC", - { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc" }}, - { "std", "Select register names used in ARM's ISA documentation", - { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" }}, - { "apcs", "Select register names used in the APCS", - { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "sl", "fp", "ip", "sp", "lr", "pc" }}, - { "atpcs", "Select register names used in the ATPCS", - { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "IP", "SP", "LR", "PC" }}, - { "special-atpcs", "Select special register names used in the ATPCS", - { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }}, -}; - -static const char *const iwmmxt_wwnames[] = -{"b", "h", "w", "d"}; - -static const char *const iwmmxt_wwssnames[] = -{"b", "bus", "bc", "bss", - "h", "hus", "hc", "hss", - "w", "wus", "wc", "wss", - "d", "dus", "dc", "dss" -}; - -static const char *const iwmmxt_regnames[] = -{ "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7", - "wr8", "wr9", "wr10", "wr11", "wr12", "wr13", "wr14", "wr15" -}; - -static const char *const iwmmxt_cregnames[] = -{ "wcid", "wcon", "wcssf", "wcasf", "reserved", "reserved", "reserved", "reserved", - "wcgr0", "wcgr1", "wcgr2", "wcgr3", "reserved", "reserved", "reserved", "reserved" -}; - -/* Default to GCC register name set. */ -static unsigned int regname_selected = 1; - -#define arm_regnames regnames[regname_selected].reg_names - -static bfd_boolean force_thumb = false; - -/* Current IT instruction state. This contains the same state as the IT - bits in the CPSR. */ -static unsigned int ifthen_state; -/* IT state for the next instruction. */ -static unsigned int ifthen_next_state; -/* The address of the insn for which the IT state is valid. */ -static bfd_vma ifthen_address; -#define IFTHEN_COND ((ifthen_state >> 4) & 0xf) - -/* Cached mapping symbol state. */ -enum map_type { - MAP_ARM, - MAP_THUMB, - MAP_DATA -}; - -/* Decode a bitfield of the form matching regexp (N(-N)?,)*N(-N)?. - Returns pointer to following character of the format string and - fills in *VALUEP and *WIDTHP with the extracted value and number of - bits extracted. WIDTHP can be NULL. */ - -static const char * -arm_decode_bitfield (const char *ptr, unsigned long insn, - unsigned long *valuep, int *widthp) -{ - unsigned long value = 0; - int width = 0; - - do - { - int start, end; - int bits; - - for (start = 0; *ptr >= '0' && *ptr <= '9'; ptr++) - start = start * 10 + *ptr - '0'; - if (*ptr == '-') - for (end = 0, ptr++; *ptr >= '0' && *ptr <= '9'; ptr++) - end = end * 10 + *ptr - '0'; - else - end = start; - bits = end - start; - if (bits < 0) - abort (); - value |= ((insn >> start) & ((2ul << bits) - 1)) << width; - width += bits + 1; - } - while (*ptr++ == ','); - *valuep = value; - if (widthp) - *widthp = width; - return ptr - 1; -} - -static void -arm_decode_shift (long given, fprintf_function func, void *stream, - int print_shift) -{ - func (stream, "%s", arm_regnames[given & 0xf]); - - if ((given & 0xff0) != 0) - { - if ((given & 0x10) == 0) - { - int amount = (given & 0xf80) >> 7; - int shift = (given & 0x60) >> 5; - - if (amount == 0) - { - if (shift == 3) - { - func (stream, ", rrx"); - return; - } - - amount = 32; - } - - if (print_shift) - func (stream, ", %s #%d", arm_shift[shift], amount); - else - func (stream, ", #%d", amount); - } - else if (print_shift) - func (stream, ", %s %s", arm_shift[(given & 0x60) >> 5], - arm_regnames[(given & 0xf00) >> 8]); - else - func (stream, ", %s", arm_regnames[(given & 0xf00) >> 8]); - } -} - -/* Print one coprocessor instruction on INFO->STREAM. - Return true if the instruction matched, false if this is not a - recognised coprocessor instruction. */ - -static bfd_boolean -print_insn_coprocessor (bfd_vma pc, struct disassemble_info *info, long given, - bfd_boolean thumb) -{ - const struct opcode32 *insn; - void *stream = info->stream; - fprintf_function func = info->fprintf_func; - unsigned long mask; - unsigned long value; - int cond; - - for (insn = coprocessor_opcodes; insn->assembler; insn++) - { - if (insn->value == FIRST_IWMMXT_INSN - && info->mach != bfd_mach_arm_XScale - && info->mach != bfd_mach_arm_iWMMXt - && info->mach != bfd_mach_arm_iWMMXt2) - insn = insn + IWMMXT_INSN_COUNT; - - mask = insn->mask; - value = insn->value; - if (thumb) - { - /* The high 4 bits are 0xe for Arm conditional instructions, and - 0xe for arm unconditional instructions. The rest of the - encoding is the same. */ - mask |= 0xf0000000; - value |= 0xe0000000; - if (ifthen_state) - cond = IFTHEN_COND; - else - cond = 16; - } - else - { - /* Only match unconditional instructions against unconditional - patterns. */ - if ((given & 0xf0000000) == 0xf0000000) - { - mask |= 0xf0000000; - cond = 16; - } - else - { - cond = (given >> 28) & 0xf; - if (cond == 0xe) - cond = 16; - } - } - if ((given & mask) == value) - { - const char *c; - - for (c = insn->assembler; *c; c++) - { - if (*c == '%') - { - switch (*++c) - { - case '%': - func (stream, "%%"); - break; - - case 'A': - func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]); - - if ((given & (1 << 24)) != 0) - { - int offset = given & 0xff; - - if (offset) - func (stream, ", #%s%d]%s", - ((given & 0x00800000) == 0 ? "-" : ""), - offset * 4, - ((given & 0x00200000) != 0 ? "!" : "")); - else - func (stream, "]"); - } - else - { - int offset = given & 0xff; - - func (stream, "]"); - - if (given & (1 << 21)) - { - if (offset) - func (stream, ", #%s%d", - ((given & 0x00800000) == 0 ? "-" : ""), - offset * 4); - } - else - func (stream, ", {%d}", offset); - } - break; - - case 'B': - { - int regno = ((given >> 12) & 0xf) | ((given >> (22 - 4)) & 0x10); - int offset = (given >> 1) & 0x3f; - - if (offset == 1) - func (stream, "{d%d}", regno); - else if (regno + offset > 32) - func (stream, "{d%d-}", regno, regno + offset - 1); - else - func (stream, "{d%d-d%d}", regno, regno + offset - 1); - } - break; - - case 'C': - { - int rn = (given >> 16) & 0xf; - int offset = (given & 0xff) * 4; - int add = (given >> 23) & 1; - - func (stream, "[%s", arm_regnames[rn]); - - if (offset) - { - if (!add) - offset = -offset; - func (stream, ", #%d", offset); - } - func (stream, "]"); - if (rn == 15) - { - func (stream, "\t; "); - /* FIXME: Unsure if info->bytes_per_chunk is the - right thing to use here. */ - info->print_address_func (offset + pc - + info->bytes_per_chunk * 2, info); - } - } - break; - - case 'c': - func (stream, "%s", arm_conditional[cond]); - break; - - case 'I': - /* Print a Cirrus/DSP shift immediate. */ - /* Immediates are 7bit signed ints with bits 0..3 in - bits 0..3 of opcode and bits 4..6 in bits 5..7 - of opcode. */ - { - int imm; - - imm = (given & 0xf) | ((given & 0xe0) >> 1); - - /* Is ``imm'' a negative number? */ - if (imm & 0x40) - imm |= (~0u << 7); - - func (stream, "%d", imm); - } - - break; - - case 'F': - switch (given & 0x00408000) - { - case 0: - func (stream, "4"); - break; - case 0x8000: - func (stream, "1"); - break; - case 0x00400000: - func (stream, "2"); - break; - default: - func (stream, "3"); - } - break; - - case 'P': - switch (given & 0x00080080) - { - case 0: - func (stream, "s"); - break; - case 0x80: - func (stream, "d"); - break; - case 0x00080000: - func (stream, "e"); - break; - default: - func (stream, ""); - break; - } - break; - case 'Q': - switch (given & 0x00408000) - { - case 0: - func (stream, "s"); - break; - case 0x8000: - func (stream, "d"); - break; - case 0x00400000: - func (stream, "e"); - break; - default: - func (stream, "p"); - break; - } - break; - case 'R': - switch (given & 0x60) - { - case 0: - break; - case 0x20: - func (stream, "p"); - break; - case 0x40: - func (stream, "m"); - break; - default: - func (stream, "z"); - break; - } - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - int width; - unsigned long value; - - c = arm_decode_bitfield (c, given, &value, &width); - - switch (*c) - { - case 'r': - func (stream, "%s", arm_regnames[value]); - break; - case 'D': - func (stream, "d%ld", value); - break; - case 'Q': - if (value & 1) - func (stream, "", value >> 1); - else - func (stream, "q%ld", value >> 1); - break; - case 'd': - func (stream, "%ld", value); - break; - case 'k': - { - int from = (given & (1 << 7)) ? 32 : 16; - func (stream, "%ld", from - value); - } - break; - - case 'f': - if (value > 7) - func (stream, "#%s", arm_fp_const[value & 7]); - else - func (stream, "f%ld", value); - break; - - case 'w': - if (width == 2) - func (stream, "%s", iwmmxt_wwnames[value]); - else - func (stream, "%s", iwmmxt_wwssnames[value]); - break; - - case 'g': - func (stream, "%s", iwmmxt_regnames[value]); - break; - case 'G': - func (stream, "%s", iwmmxt_cregnames[value]); - break; - - case 'x': - func (stream, "0x%lx", value); - break; - - case '`': - c++; - if (value == 0) - func (stream, "%c", *c); - break; - case '\'': - c++; - if (value == ((1ul << width) - 1)) - func (stream, "%c", *c); - break; - case '?': - func (stream, "%c", c[(1 << width) - (int)value]); - c += 1 << width; - break; - default: - abort (); - } - break; - - case 'y': - case 'z': - { - int single = *c++ == 'y'; - int regno; - - switch (*c) - { - case '4': /* Sm pair */ - func (stream, "{"); - /* Fall through. */ - case '0': /* Sm, Dm */ - regno = given & 0x0000000f; - if (single) - { - regno <<= 1; - regno += (given >> 5) & 1; - } - else - regno += ((given >> 5) & 1) << 4; - break; - - case '1': /* Sd, Dd */ - regno = (given >> 12) & 0x0000000f; - if (single) - { - regno <<= 1; - regno += (given >> 22) & 1; - } - else - regno += ((given >> 22) & 1) << 4; - break; - - case '2': /* Sn, Dn */ - regno = (given >> 16) & 0x0000000f; - if (single) - { - regno <<= 1; - regno += (given >> 7) & 1; - } - else - regno += ((given >> 7) & 1) << 4; - break; - - case '3': /* List */ - func (stream, "{"); - regno = (given >> 12) & 0x0000000f; - if (single) - { - regno <<= 1; - regno += (given >> 22) & 1; - } - else - regno += ((given >> 22) & 1) << 4; - break; - - default: - abort (); - } - - func (stream, "%c%d", single ? 's' : 'd', regno); - - if (*c == '3') - { - int count = given & 0xff; - - if (single == 0) - count >>= 1; - - if (--count) - { - func (stream, "-%c%d", - single ? 's' : 'd', - regno + count); - } - - func (stream, "}"); - } - else if (*c == '4') - func (stream, ", %c%d}", single ? 's' : 'd', - regno + 1); - } - break; - - case 'L': - switch (given & 0x00400100) - { - case 0x00000000: func (stream, "b"); break; - case 0x00400000: func (stream, "h"); break; - case 0x00000100: func (stream, "w"); break; - case 0x00400100: func (stream, "d"); break; - default: - break; - } - break; - - case 'Z': - { - int value; - /* given (20, 23) | given (0, 3) */ - value = ((given >> 16) & 0xf0) | (given & 0xf); - func (stream, "%d", value); - } - break; - - case 'l': - /* This is like the 'A' operator, except that if - the width field "M" is zero, then the offset is - *not* multiplied by four. */ - { - int offset = given & 0xff; - int multiplier = (given & 0x00000100) ? 4 : 1; - - func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]); - - if (offset) - { - if ((given & 0x01000000) != 0) - func (stream, ", #%s%d]%s", - ((given & 0x00800000) == 0 ? "-" : ""), - offset * multiplier, - ((given & 0x00200000) != 0 ? "!" : "")); - else - func (stream, "], #%s%d", - ((given & 0x00800000) == 0 ? "-" : ""), - offset * multiplier); - } - else - func (stream, "]"); - } - break; - - case 'r': - { - int imm4 = (given >> 4) & 0xf; - int puw_bits = ((given >> 22) & 6) | ((given >> 21) & 1); - int ubit = (given >> 23) & 1; - const char *rm = arm_regnames [given & 0xf]; - const char *rn = arm_regnames [(given >> 16) & 0xf]; - - switch (puw_bits) - { - case 1: - /* fall through */ - case 3: - func (stream, "[%s], %c%s", rn, ubit ? '+' : '-', rm); - if (imm4) - func (stream, ", lsl #%d", imm4); - break; - - case 4: - /* fall through */ - case 5: - /* fall through */ - case 6: - /* fall through */ - case 7: - func (stream, "[%s, %c%s", rn, ubit ? '+' : '-', rm); - if (imm4 > 0) - func (stream, ", lsl #%d", imm4); - func (stream, "]"); - if (puw_bits == 5 || puw_bits == 7) - func (stream, "!"); - break; - - default: - func (stream, "INVALID"); - } - } - break; - - case 'i': - { - long imm5; - imm5 = ((given & 0x100) >> 4) | (given & 0xf); - func (stream, "%ld", (imm5 == 0) ? 32 : imm5); - } - break; - - default: - abort (); - } - } - } - else - func (stream, "%c", *c); - } - return true; - } - } - return false; -} - -static void -print_arm_address (bfd_vma pc, struct disassemble_info *info, long given) -{ - void *stream = info->stream; - fprintf_function func = info->fprintf_func; - - if (((given & 0x000f0000) == 0x000f0000) - && ((given & 0x02000000) == 0)) - { - int offset = given & 0xfff; - - func (stream, "[pc"); - - if (given & 0x01000000) - { - if ((given & 0x00800000) == 0) - offset = - offset; - - /* Pre-indexed. */ - func (stream, ", #%d]", offset); - - offset += pc + 8; - - /* Cope with the possibility of write-back - being used. Probably a very dangerous thing - for the programmer to do, but who are we to - argue ? */ - if (given & 0x00200000) - func (stream, "!"); - } - else - { - /* Post indexed. */ - func (stream, "], #%d", offset); - - /* ie ignore the offset. */ - offset = pc + 8; - } - - func (stream, "\t; "); - info->print_address_func (offset, info); - } - else - { - func (stream, "[%s", - arm_regnames[(given >> 16) & 0xf]); - if ((given & 0x01000000) != 0) - { - if ((given & 0x02000000) == 0) - { - int offset = given & 0xfff; - if (offset) - func (stream, ", #%s%d", - (((given & 0x00800000) == 0) - ? "-" : ""), offset); - } - else - { - func (stream, ", %s", - (((given & 0x00800000) == 0) - ? "-" : "")); - arm_decode_shift (given, func, stream, 1); - } - - func (stream, "]%s", - ((given & 0x00200000) != 0) ? "!" : ""); - } - else - { - if ((given & 0x02000000) == 0) - { - int offset = given & 0xfff; - if (offset) - func (stream, "], #%s%d", - (((given & 0x00800000) == 0) - ? "-" : ""), offset); - else - func (stream, "]"); - } - else - { - func (stream, "], %s", - (((given & 0x00800000) == 0) - ? "-" : "")); - arm_decode_shift (given, func, stream, 1); - } - } - } -} - -/* Print one neon instruction on INFO->STREAM. - Return true if the instruction matched, false if this is not a - recognised neon instruction. */ - -static bfd_boolean -print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb) -{ - const struct opcode32 *insn; - void *stream = info->stream; - fprintf_function func = info->fprintf_func; - - if (thumb) - { - if ((given & 0xef000000) == 0xef000000) - { - /* move bit 28 to bit 24 to translate Thumb2 to ARM encoding. */ - unsigned long bit28 = given & (1 << 28); - - given &= 0x00ffffff; - if (bit28) - given |= 0xf3000000; - else - given |= 0xf2000000; - } - else if ((given & 0xff000000) == 0xf9000000) - given ^= 0xf9000000 ^ 0xf4000000; - else - return false; - } - - for (insn = neon_opcodes; insn->assembler; insn++) - { - if ((given & insn->mask) == insn->value) - { - const char *c; - - for (c = insn->assembler; *c; c++) - { - if (*c == '%') - { - switch (*++c) - { - case '%': - func (stream, "%%"); - break; - - case 'c': - if (thumb && ifthen_state) - func (stream, "%s", arm_conditional[IFTHEN_COND]); - break; - - case 'A': - { - static const unsigned char enc[16] = - { - 0x4, 0x14, /* st4 0,1 */ - 0x4, /* st1 2 */ - 0x4, /* st2 3 */ - 0x3, /* st3 4 */ - 0x13, /* st3 5 */ - 0x3, /* st1 6 */ - 0x1, /* st1 7 */ - 0x2, /* st2 8 */ - 0x12, /* st2 9 */ - 0x2, /* st1 10 */ - 0, 0, 0, 0, 0 - }; - int rd = ((given >> 12) & 0xf) | (((given >> 22) & 1) << 4); - int rn = ((given >> 16) & 0xf); - int rm = ((given >> 0) & 0xf); - int align = ((given >> 4) & 0x3); - int type = ((given >> 8) & 0xf); - int n = enc[type] & 0xf; - int stride = (enc[type] >> 4) + 1; - int ix; - - func (stream, "{"); - if (stride > 1) - for (ix = 0; ix != n; ix++) - func (stream, "%sd%d", ix ? "," : "", rd + ix * stride); - else if (n == 1) - func (stream, "d%d", rd); - else - func (stream, "d%d-d%d", rd, rd + n - 1); - func (stream, "}, [%s", arm_regnames[rn]); - if (align) - func (stream, ", :%d", 32 << align); - func (stream, "]"); - if (rm == 0xd) - func (stream, "!"); - else if (rm != 0xf) - func (stream, ", %s", arm_regnames[rm]); - } - break; - - case 'B': - { - int rd = ((given >> 12) & 0xf) | (((given >> 22) & 1) << 4); - int rn = ((given >> 16) & 0xf); - int rm = ((given >> 0) & 0xf); - int idx_align = ((given >> 4) & 0xf); - int align = 0; - int size = ((given >> 10) & 0x3); - int idx = idx_align >> (size + 1); - int length = ((given >> 8) & 3) + 1; - int stride = 1; - int i; - - if (length > 1 && size > 0) - stride = (idx_align & (1 << size)) ? 2 : 1; - - switch (length) - { - case 1: - { - int amask = (1 << size) - 1; - if ((idx_align & (1 << size)) != 0) - return false; - if (size > 0) - { - if ((idx_align & amask) == amask) - align = 8 << size; - else if ((idx_align & amask) != 0) - return false; - } - } - break; - - case 2: - if (size == 2 && (idx_align & 2) != 0) - return false; - align = (idx_align & 1) ? 16 << size : 0; - break; - - case 3: - if ((size == 2 && (idx_align & 3) != 0) - || (idx_align & 1) != 0) - return false; - break; - - case 4: - if (size == 2) - { - if ((idx_align & 3) == 3) - return false; - align = (idx_align & 3) * 64; - } - else - align = (idx_align & 1) ? 32 << size : 0; - break; - - default: - abort (); - } - - func (stream, "{"); - for (i = 0; i < length; i++) - func (stream, "%sd%d[%d]", (i == 0) ? "" : ",", - rd + i * stride, idx); - func (stream, "}, [%s", arm_regnames[rn]); - if (align) - func (stream, ", :%d", align); - func (stream, "]"); - if (rm == 0xd) - func (stream, "!"); - else if (rm != 0xf) - func (stream, ", %s", arm_regnames[rm]); - } - break; - - case 'C': - { - int rd = ((given >> 12) & 0xf) | (((given >> 22) & 1) << 4); - int rn = ((given >> 16) & 0xf); - int rm = ((given >> 0) & 0xf); - int align = ((given >> 4) & 0x1); - int size = ((given >> 6) & 0x3); - int type = ((given >> 8) & 0x3); - int n = type + 1; - int stride = ((given >> 5) & 0x1); - int ix; - - if (stride && (n == 1)) - n++; - else - stride++; - - func (stream, "{"); - if (stride > 1) - for (ix = 0; ix != n; ix++) - func (stream, "%sd%d[]", ix ? "," : "", rd + ix * stride); - else if (n == 1) - func (stream, "d%d[]", rd); - else - func (stream, "d%d[]-d%d[]", rd, rd + n - 1); - func (stream, "}, [%s", arm_regnames[rn]); - if (align) - { - int align = (8 * (type + 1)) << size; - if (type == 3) - align = (size > 1) ? align >> 1 : align; - if (type == 2 || (type == 0 && !size)) - func (stream, ", :", align); - else - func (stream, ", :%d", align); - } - func (stream, "]"); - if (rm == 0xd) - func (stream, "!"); - else if (rm != 0xf) - func (stream, ", %s", arm_regnames[rm]); - } - break; - - case 'D': - { - int raw_reg = (given & 0xf) | ((given >> 1) & 0x10); - int size = (given >> 20) & 3; - int reg = raw_reg & ((4 << size) - 1); - int ix = raw_reg >> size >> 2; - - func (stream, "d%d[%d]", reg, ix); - } - break; - - case 'E': - /* Neon encoded constant for mov, mvn, vorr, vbic */ - { - int bits = 0; - int cmode = (given >> 8) & 0xf; - int op = (given >> 5) & 0x1; - unsigned long value = 0, hival = 0; - unsigned shift; - int size = 0; - int isfloat = 0; - - bits |= ((given >> 24) & 1) << 7; - bits |= ((given >> 16) & 7) << 4; - bits |= ((given >> 0) & 15) << 0; - - if (cmode < 8) - { - shift = (cmode >> 1) & 3; - value = (unsigned long)bits << (8 * shift); - size = 32; - } - else if (cmode < 12) - { - shift = (cmode >> 1) & 1; - value = (unsigned long)bits << (8 * shift); - size = 16; - } - else if (cmode < 14) - { - shift = (cmode & 1) + 1; - value = (unsigned long)bits << (8 * shift); - value |= (1ul << (8 * shift)) - 1; - size = 32; - } - else if (cmode == 14) - { - if (op) - { - /* bit replication into bytes */ - int ix; - unsigned long mask; - - value = 0; - hival = 0; - for (ix = 7; ix >= 0; ix--) - { - mask = ((bits >> ix) & 1) ? 0xff : 0; - if (ix <= 3) - value = (value << 8) | mask; - else - hival = (hival << 8) | mask; - } - size = 64; - } - else - { - /* byte replication */ - value = (unsigned long)bits; - size = 8; - } - } - else if (!op) - { - /* floating point encoding */ - int tmp; - - value = (unsigned long)(bits & 0x7f) << 19; - value |= (unsigned long)(bits & 0x80) << 24; - tmp = bits & 0x40 ? 0x3c : 0x40; - value |= (unsigned long)tmp << 24; - size = 32; - isfloat = 1; - } - else - { - func (stream, "", - bits, cmode, op); - break; - } - switch (size) - { - case 8: - func (stream, "#%ld\t; 0x%.2lx", value, value); - break; - - case 16: - func (stream, "#%ld\t; 0x%.4lx", value, value); - break; - - case 32: - if (isfloat) - { - unsigned char valbytes[4]; - double fvalue; - - /* Do this a byte at a time so we don't have to - worry about the host's endianness. */ - valbytes[0] = value & 0xff; - valbytes[1] = (value >> 8) & 0xff; - valbytes[2] = (value >> 16) & 0xff; - valbytes[3] = (value >> 24) & 0xff; - - floatformat_to_double (valbytes, &fvalue); - - func (stream, "#%.7g\t; 0x%.8lx", fvalue, - value); - } - else - func (stream, "#%ld\t; 0x%.8lx", - (long) ((value & 0x80000000) - ? value | ~0xffffffffl : value), value); - break; - - case 64: - func (stream, "#0x%.8lx%.8lx", hival, value); - break; - - default: - abort (); - } - } - break; - - case 'F': - { - int regno = ((given >> 16) & 0xf) | ((given >> (7 - 4)) & 0x10); - int num = (given >> 8) & 0x3; - - if (!num) - func (stream, "{d%d}", regno); - else if (num + regno >= 32) - func (stream, "{d%d-= '0' && *c <= '9') - limit = *c - '0'; - else if (*c >= 'a' && *c <= 'f') - limit = *c - 'a' + 10; - else - abort (); - low = limit >> 2; - high = limit & 3; - - if (value < low || value > high) - func (stream, "", base << value); - else - func (stream, "%d", base << value); - } - break; - case 'R': - if (given & (1 << 6)) - goto Q; - /* FALLTHROUGH */ - case 'D': - func (stream, "d%ld", value); - break; - case 'Q': - Q: - if (value & 1) - func (stream, "", value >> 1); - else - func (stream, "q%ld", value >> 1); - break; - - case '`': - c++; - if (value == 0) - func (stream, "%c", *c); - break; - case '\'': - c++; - if (value == ((1ul << width) - 1)) - func (stream, "%c", *c); - break; - case '?': - func (stream, "%c", c[(1 << width) - (int)value]); - c += 1 << width; - break; - default: - abort (); - } - break; - - default: - abort (); - } - } - } - else - func (stream, "%c", *c); - } - return true; - } - } - return false; -} - -/* Print one ARM instruction from PC on INFO->STREAM. */ - -static void -print_insn_arm_internal (bfd_vma pc, struct disassemble_info *info, long given) -{ - const struct opcode32 *insn; - void *stream = info->stream; - fprintf_function func = info->fprintf_func; - - if (print_insn_coprocessor (pc, info, given, false)) - return; - - if (print_insn_neon (info, given, false)) - return; - - for (insn = arm_opcodes; insn->assembler; insn++) - { - if (insn->value == FIRST_IWMMXT_INSN - && info->mach != bfd_mach_arm_XScale - && info->mach != bfd_mach_arm_iWMMXt) - insn = insn + IWMMXT_INSN_COUNT; - - if ((given & insn->mask) == insn->value - /* Special case: an instruction with all bits set in the condition field - (0xFnnn_nnnn) is only matched if all those bits are set in insn->mask, - or by the catchall at the end of the table. */ - && ((given & 0xF0000000) != 0xF0000000 - || (insn->mask & 0xF0000000) == 0xF0000000 - || (insn->mask == 0 && insn->value == 0))) - { - const char *c; - - for (c = insn->assembler; *c; c++) - { - if (*c == '%') - { - switch (*++c) - { - case '%': - func (stream, "%%"); - break; - - case 'a': - print_arm_address (pc, info, given); - break; - - case 'P': - /* Set P address bit and use normal address - printing routine. */ - print_arm_address (pc, info, given | (1 << 24)); - break; - - case 's': - if ((given & 0x004f0000) == 0x004f0000) - { - /* PC relative with immediate offset. */ - int offset = ((given & 0xf00) >> 4) | (given & 0xf); - - if ((given & 0x00800000) == 0) - offset = -offset; - - func (stream, "[pc, #%d]\t; ", offset); - info->print_address_func (offset + pc + 8, info); - } - else - { - func (stream, "[%s", - arm_regnames[(given >> 16) & 0xf]); - if ((given & 0x01000000) != 0) - { - /* Pre-indexed. */ - if ((given & 0x00400000) == 0x00400000) - { - /* Immediate. */ - int offset = ((given & 0xf00) >> 4) | (given & 0xf); - if (offset) - func (stream, ", #%s%d", - (((given & 0x00800000) == 0) - ? "-" : ""), offset); - } - else - { - /* Register. */ - func (stream, ", %s%s", - (((given & 0x00800000) == 0) - ? "-" : ""), - arm_regnames[given & 0xf]); - } - - func (stream, "]%s", - ((given & 0x00200000) != 0) ? "!" : ""); - } - else - { - /* Post-indexed. */ - if ((given & 0x00400000) == 0x00400000) - { - /* Immediate. */ - int offset = ((given & 0xf00) >> 4) | (given & 0xf); - if (offset) - func (stream, "], #%s%d", - (((given & 0x00800000) == 0) - ? "-" : ""), offset); - else - func (stream, "]"); - } - else - { - /* Register. */ - func (stream, "], %s%s", - (((given & 0x00800000) == 0) - ? "-" : ""), - arm_regnames[given & 0xf]); - } - } - } - break; - - case 'b': - { - int disp = (((given & 0xffffff) ^ 0x800000) - 0x800000); - info->print_address_func (disp*4 + pc + 8, info); - } - break; - - case 'c': - if (((given >> 28) & 0xf) != 0xe) - func (stream, "%s", - arm_conditional [(given >> 28) & 0xf]); - break; - - case 'm': - { - int started = 0; - int reg; - - func (stream, "{"); - for (reg = 0; reg < 16; reg++) - if ((given & (1 << reg)) != 0) - { - if (started) - func (stream, ", "); - started = 1; - func (stream, "%s", arm_regnames[reg]); - } - func (stream, "}"); - } - break; - - case 'q': - arm_decode_shift (given, func, stream, 0); - break; - - case 'o': - if ((given & 0x02000000) != 0) - { - int rotate = (given & 0xf00) >> 7; - int immed = (given & 0xff); - immed = (((immed << (32 - rotate)) - | (immed >> rotate)) & 0xffffffff); - func (stream, "#%d\t; 0x%x", immed, immed); - } - else - arm_decode_shift (given, func, stream, 1); - break; - - case 'p': - if ((given & 0x0000f000) == 0x0000f000) - func (stream, "p"); - break; - - case 't': - if ((given & 0x01200000) == 0x00200000) - func (stream, "t"); - break; - - case 'A': - func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]); - - if ((given & (1 << 24)) != 0) - { - int offset = given & 0xff; - - if (offset) - func (stream, ", #%s%d]%s", - ((given & 0x00800000) == 0 ? "-" : ""), - offset * 4, - ((given & 0x00200000) != 0 ? "!" : "")); - else - func (stream, "]"); - } - else - { - int offset = given & 0xff; - - func (stream, "]"); - - if (given & (1 << 21)) - { - if (offset) - func (stream, ", #%s%d", - ((given & 0x00800000) == 0 ? "-" : ""), - offset * 4); - } - else - func (stream, ", {%d}", offset); - } - break; - - case 'B': - /* Print ARM V5 BLX(1) address: pc+25 bits. */ - { - bfd_vma address; - bfd_vma offset = 0; - - if (given & 0x00800000) - /* Is signed, hi bits should be ones. */ - offset = (-1) ^ 0x00ffffff; - - /* Offset is (SignExtend(offset field)<<2). */ - offset += given & 0x00ffffff; - offset <<= 2; - address = offset + pc + 8; - - if (given & 0x01000000) - /* H bit allows addressing to 2-byte boundaries. */ - address += 2; - - info->print_address_func (address, info); - } - break; - - case 'C': - func (stream, "_"); - if (given & 0x80000) - func (stream, "f"); - if (given & 0x40000) - func (stream, "s"); - if (given & 0x20000) - func (stream, "x"); - if (given & 0x10000) - func (stream, "c"); - break; - - case 'U': - switch (given & 0xf) - { - case 0xf: func(stream, "sy"); break; - case 0x7: func(stream, "un"); break; - case 0xe: func(stream, "st"); break; - case 0x6: func(stream, "unst"); break; - default: - func(stream, "#%d", (int)given & 0xf); - break; - } - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - int width; - unsigned long value; - - c = arm_decode_bitfield (c, given, &value, &width); - - switch (*c) - { - case 'r': - func (stream, "%s", arm_regnames[value]); - break; - case 'd': - func (stream, "%ld", value); - break; - case 'b': - func (stream, "%ld", value * 8); - break; - case 'W': - func (stream, "%ld", value + 1); - break; - case 'x': - func (stream, "0x%08lx", value); - - /* Some SWI instructions have special - meanings. */ - if ((given & 0x0fffffff) == 0x0FF00000) - func (stream, "\t; IMB"); - else if ((given & 0x0fffffff) == 0x0FF00001) - func (stream, "\t; IMBRange"); - break; - case 'X': - func (stream, "%01lx", value & 0xf); - break; - case '`': - c++; - if (value == 0) - func (stream, "%c", *c); - break; - case '\'': - c++; - if (value == ((1ul << width) - 1)) - func (stream, "%c", *c); - break; - case '?': - func (stream, "%c", c[(1 << width) - (int)value]); - c += 1 << width; - break; - default: - abort (); - } - break; - - case 'e': - { - int imm; - - imm = (given & 0xf) | ((given & 0xfff00) >> 4); - func (stream, "%d", imm); - } - break; - - case 'E': - /* LSB and WIDTH fields of BFI or BFC. The machine- - language instruction encodes LSB and MSB. */ - { - long msb = (given & 0x001f0000) >> 16; - long lsb = (given & 0x00000f80) >> 7; - - long width = msb - lsb + 1; - if (width > 0) - func (stream, "#%lu, #%lu", lsb, width); - else - func (stream, "(invalid: %lu:%lu)", lsb, msb); - } - break; - - case 'V': - /* 16-bit unsigned immediate from a MOVT or MOVW - instruction, encoded in bits 0:11 and 15:19. */ - { - long hi = (given & 0x000f0000) >> 4; - long lo = (given & 0x00000fff); - long imm16 = hi | lo; - func (stream, "#%lu\t; 0x%lx", imm16, imm16); - } - break; - - default: - abort (); - } - } - } - else - func (stream, "%c", *c); - } - return; - } - } - abort (); -} - -/* Print one 16-bit Thumb instruction from PC on INFO->STREAM. */ - -static void -print_insn_thumb16 (bfd_vma pc, struct disassemble_info *info, long given) -{ - const struct opcode16 *insn; - void *stream = info->stream; - fprintf_function func = info->fprintf_func; - - for (insn = thumb_opcodes; insn->assembler; insn++) - if ((given & insn->mask) == insn->value) - { - const char *c = insn->assembler; - for (; *c; c++) - { - int domaskpc = 0; - int domasklr = 0; - - if (*c != '%') - { - func (stream, "%c", *c); - continue; - } - - switch (*++c) - { - case '%': - func (stream, "%%"); - break; - - case 'c': - if (ifthen_state) - func (stream, "%s", arm_conditional[IFTHEN_COND]); - break; - - case 'C': - if (ifthen_state) - func (stream, "%s", arm_conditional[IFTHEN_COND]); - else - func (stream, "s"); - break; - - case 'I': - { - unsigned int tmp; - - ifthen_next_state = given & 0xff; - for (tmp = given << 1; tmp & 0xf; tmp <<= 1) - func (stream, ((given ^ tmp) & 0x10) ? "e" : "t"); - func (stream, "\t%s", arm_conditional[(given >> 4) & 0xf]); - } - break; - - case 'x': - if (ifthen_next_state) - func (stream, "\t; unpredictable branch in IT block\n"); - break; - - case 'X': - if (ifthen_state) - func (stream, "\t; unpredictable ", - arm_conditional[IFTHEN_COND]); - break; - - case 'S': - { - long reg; - - reg = (given >> 3) & 0x7; - if (given & (1 << 6)) - reg += 8; - - func (stream, "%s", arm_regnames[reg]); - } - break; - - case 'D': - { - long reg; - - reg = given & 0x7; - if (given & (1 << 7)) - reg += 8; - - func (stream, "%s", arm_regnames[reg]); - } - break; - - case 'N': - if (given & (1 << 8)) - domasklr = 1; - /* Fall through. */ - case 'O': - if (*c == 'O' && (given & (1 << 8))) - domaskpc = 1; - /* Fall through. */ - case 'M': - { - int started = 0; - int reg; - - func (stream, "{"); - - /* It would be nice if we could spot - ranges, and generate the rS-rE format: */ - for (reg = 0; (reg < 8); reg++) - if ((given & (1 << reg)) != 0) - { - if (started) - func (stream, ", "); - started = 1; - func (stream, "%s", arm_regnames[reg]); - } - - if (domasklr) - { - if (started) - func (stream, ", "); - started = 1; - func (stream, "%s", arm_regnames[14] /* "lr" */); - } - - if (domaskpc) - { - if (started) - func (stream, ", "); - func (stream, "%s", arm_regnames[15] /* "pc" */); - } - - func (stream, "}"); - } - break; - - case 'b': - /* Print ARM V6T2 CZB address: pc+4+6 bits. */ - { - bfd_vma address = (pc + 4 - + ((given & 0x00f8) >> 2) - + ((given & 0x0200) >> 3)); - info->print_address_func (address, info); - } - break; - - case 's': - /* Right shift immediate -- bits 6..10; 1-31 print - as themselves, 0 prints as 32. */ - { - long imm = (given & 0x07c0) >> 6; - if (imm == 0) - imm = 32; - func (stream, "#%ld", imm); - } - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - int bitstart = *c++ - '0'; - int bitend = 0; - - while (*c >= '0' && *c <= '9') - bitstart = (bitstart * 10) + *c++ - '0'; - - switch (*c) - { - case '-': - { - long reg; - - c++; - while (*c >= '0' && *c <= '9') - bitend = (bitend * 10) + *c++ - '0'; - if (!bitend) - abort (); - reg = given >> bitstart; - reg &= (2 << (bitend - bitstart)) - 1; - switch (*c) - { - case 'r': - func (stream, "%s", arm_regnames[reg]); - break; - - case 'd': - func (stream, "%ld", reg); - break; - - case 'H': - func (stream, "%ld", reg << 1); - break; - - case 'W': - func (stream, "%ld", reg << 2); - break; - - case 'a': - /* PC-relative address -- the bottom two - bits of the address are dropped - before the calculation. */ - info->print_address_func - (((pc + 4) & ~3) + (reg << 2), info); - break; - - case 'x': - func (stream, "0x%04lx", reg); - break; - - case 'B': - reg = ((reg ^ (1 << bitend)) - (1 << bitend)); - info->print_address_func (reg * 2 + pc + 4, info); - break; - - case 'c': - func (stream, "%s", arm_conditional [reg]); - break; - - default: - abort (); - } - } - break; - - case '\'': - c++; - if ((given & (1 << bitstart)) != 0) - func (stream, "%c", *c); - break; - - case '?': - ++c; - if ((given & (1 << bitstart)) != 0) - func (stream, "%c", *c++); - else - func (stream, "%c", *++c); - break; - - default: - abort (); - } - } - break; - - default: - abort (); - } - } - return; - } - - /* No match. */ - abort (); -} - -/* Return the name of an V7M special register. */ -static const char * -psr_name (int regno) -{ - switch (regno) - { - case 0: return "APSR"; - case 1: return "IAPSR"; - case 2: return "EAPSR"; - case 3: return "PSR"; - case 5: return "IPSR"; - case 6: return "EPSR"; - case 7: return "IEPSR"; - case 8: return "MSP"; - case 9: return "PSP"; - case 16: return "PRIMASK"; - case 17: return "BASEPRI"; - case 18: return "BASEPRI_MASK"; - case 19: return "FAULTMASK"; - case 20: return "CONTROL"; - default: return ""; - } -} - -/* Print one 32-bit Thumb instruction from PC on INFO->STREAM. */ - -static void -print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given) -{ - const struct opcode32 *insn; - void *stream = info->stream; - fprintf_function func = info->fprintf_func; - - if (print_insn_coprocessor (pc, info, given, true)) - return; - - if (print_insn_neon (info, given, true)) - return; - - for (insn = thumb32_opcodes; insn->assembler; insn++) - if ((given & insn->mask) == insn->value) - { - const char *c = insn->assembler; - for (; *c; c++) - { - if (*c != '%') - { - func (stream, "%c", *c); - continue; - } - - switch (*++c) - { - case '%': - func (stream, "%%"); - break; - - case 'c': - if (ifthen_state) - func (stream, "%s", arm_conditional[IFTHEN_COND]); - break; - - case 'x': - if (ifthen_next_state) - func (stream, "\t; unpredictable branch in IT block\n"); - break; - - case 'X': - if (ifthen_state) - func (stream, "\t; unpredictable ", - arm_conditional[IFTHEN_COND]); - break; - - case 'I': - { - unsigned int imm12 = 0; - imm12 |= (given & 0x000000ffu); - imm12 |= (given & 0x00007000u) >> 4; - imm12 |= (given & 0x04000000u) >> 15; - func (stream, "#%u\t; 0x%x", imm12, imm12); - } - break; - - case 'M': - { - unsigned int bits = 0, imm, imm8, mod; - bits |= (given & 0x000000ffu); - bits |= (given & 0x00007000u) >> 4; - bits |= (given & 0x04000000u) >> 15; - imm8 = (bits & 0x0ff); - mod = (bits & 0xf00) >> 8; - switch (mod) - { - case 0: imm = imm8; break; - case 1: imm = ((imm8<<16) | imm8); break; - case 2: imm = ((imm8<<24) | (imm8 << 8)); break; - case 3: imm = ((imm8<<24) | (imm8 << 16) | (imm8 << 8) | imm8); break; - default: - mod = (bits & 0xf80) >> 7; - imm8 = (bits & 0x07f) | 0x80; - imm = (((imm8 << (32 - mod)) | (imm8 >> mod)) & 0xffffffff); - } - func (stream, "#%u\t; 0x%x", imm, imm); - } - break; - - case 'J': - { - unsigned int imm = 0; - imm |= (given & 0x000000ffu); - imm |= (given & 0x00007000u) >> 4; - imm |= (given & 0x04000000u) >> 15; - imm |= (given & 0x000f0000u) >> 4; - func (stream, "#%u\t; 0x%x", imm, imm); - } - break; - - case 'K': - { - unsigned int imm = 0; - imm |= (given & 0x000f0000u) >> 16; - imm |= (given & 0x00000ff0u) >> 0; - imm |= (given & 0x0000000fu) << 12; - func (stream, "#%u\t; 0x%x", imm, imm); - } - break; - - case 'S': - { - unsigned int reg = (given & 0x0000000fu); - unsigned int stp = (given & 0x00000030u) >> 4; - unsigned int imm = 0; - imm |= (given & 0x000000c0u) >> 6; - imm |= (given & 0x00007000u) >> 10; - - func (stream, "%s", arm_regnames[reg]); - switch (stp) - { - case 0: - if (imm > 0) - func (stream, ", lsl #%u", imm); - break; - - case 1: - if (imm == 0) - imm = 32; - func (stream, ", lsr #%u", imm); - break; - - case 2: - if (imm == 0) - imm = 32; - func (stream, ", asr #%u", imm); - break; - - case 3: - if (imm == 0) - func (stream, ", rrx"); - else - func (stream, ", ror #%u", imm); - } - } - break; - - case 'a': - { - unsigned int Rn = (given & 0x000f0000) >> 16; - unsigned int U = (given & 0x00800000) >> 23; - unsigned int op = (given & 0x00000f00) >> 8; - unsigned int i12 = (given & 0x00000fff); - unsigned int i8 = (given & 0x000000ff); - bfd_boolean writeback = false, postind = false; - int offset = 0; - - func (stream, "[%s", arm_regnames[Rn]); - if (U) /* 12-bit positive immediate offset */ - offset = i12; - else if (Rn == 15) /* 12-bit negative immediate offset */ - offset = -(int)i12; - else if (op == 0x0) /* shifted register offset */ - { - unsigned int Rm = (i8 & 0x0f); - unsigned int sh = (i8 & 0x30) >> 4; - func (stream, ", %s", arm_regnames[Rm]); - if (sh) - func (stream, ", lsl #%u", sh); - func (stream, "]"); - break; - } - else switch (op) - { - case 0xE: /* 8-bit positive immediate offset */ - offset = i8; - break; - - case 0xC: /* 8-bit negative immediate offset */ - offset = -i8; - break; - - case 0xF: /* 8-bit + preindex with wb */ - offset = i8; - writeback = true; - break; - - case 0xD: /* 8-bit - preindex with wb */ - offset = -i8; - writeback = true; - break; - - case 0xB: /* 8-bit + postindex */ - offset = i8; - postind = true; - break; - - case 0x9: /* 8-bit - postindex */ - offset = -i8; - postind = true; - break; - - default: - func (stream, ", ]"); - goto skip; - } - - if (postind) - func (stream, "], #%d", offset); - else - { - if (offset) - func (stream, ", #%d", offset); - func (stream, writeback ? "]!" : "]"); - } - - if (Rn == 15) - { - func (stream, "\t; "); - info->print_address_func (((pc + 4) & ~3) + offset, info); - } - } - skip: - break; - - case 'A': - { - unsigned int P = (given & 0x01000000) >> 24; - unsigned int U = (given & 0x00800000) >> 23; - unsigned int W = (given & 0x00400000) >> 21; - unsigned int Rn = (given & 0x000f0000) >> 16; - unsigned int off = (given & 0x000000ff); - - func (stream, "[%s", arm_regnames[Rn]); - if (P) - { - if (off || !U) - func (stream, ", #%c%u", U ? '+' : '-', off * 4); - func (stream, "]"); - if (W) - func (stream, "!"); - } - else - { - func (stream, "], "); - if (W) - func (stream, "#%c%u", U ? '+' : '-', off * 4); - else - func (stream, "{%u}", off); - } - } - break; - - case 'w': - { - unsigned int Sbit = (given & 0x01000000) >> 24; - unsigned int type = (given & 0x00600000) >> 21; - switch (type) - { - case 0: func (stream, Sbit ? "sb" : "b"); break; - case 1: func (stream, Sbit ? "sh" : "h"); break; - case 2: - if (Sbit) - func (stream, "??"); - break; - case 3: - func (stream, "??"); - break; - } - } - break; - - case 'm': - { - int started = 0; - int reg; - - func (stream, "{"); - for (reg = 0; reg < 16; reg++) - if ((given & (1 << reg)) != 0) - { - if (started) - func (stream, ", "); - started = 1; - func (stream, "%s", arm_regnames[reg]); - } - func (stream, "}"); - } - break; - - case 'E': - { - unsigned int msb = (given & 0x0000001f); - unsigned int lsb = 0; - lsb |= (given & 0x000000c0u) >> 6; - lsb |= (given & 0x00007000u) >> 10; - func (stream, "#%u, #%u", lsb, msb - lsb + 1); - } - break; - - case 'F': - { - unsigned int width = (given & 0x0000001f) + 1; - unsigned int lsb = 0; - lsb |= (given & 0x000000c0u) >> 6; - lsb |= (given & 0x00007000u) >> 10; - func (stream, "#%u, #%u", lsb, width); - } - break; - - case 'b': - { - unsigned int S = (given & 0x04000000u) >> 26; - unsigned int J1 = (given & 0x00002000u) >> 13; - unsigned int J2 = (given & 0x00000800u) >> 11; - int offset = 0; - - offset |= !S << 20; - offset |= J2 << 19; - offset |= J1 << 18; - offset |= (given & 0x003f0000) >> 4; - offset |= (given & 0x000007ff) << 1; - offset -= (1 << 20); - - info->print_address_func (pc + 4 + offset, info); - } - break; - - case 'B': - { - unsigned int S = (given & 0x04000000u) >> 26; - unsigned int I1 = (given & 0x00002000u) >> 13; - unsigned int I2 = (given & 0x00000800u) >> 11; - int offset = 0; - - offset |= !S << 24; - offset |= !(I1 ^ S) << 23; - offset |= !(I2 ^ S) << 22; - offset |= (given & 0x03ff0000u) >> 4; - offset |= (given & 0x000007ffu) << 1; - offset -= (1 << 24); - offset += pc + 4; - - /* BLX target addresses are always word aligned. */ - if ((given & 0x00001000u) == 0) - offset &= ~2u; - - info->print_address_func (offset, info); - } - break; - - case 's': - { - unsigned int shift = 0; - shift |= (given & 0x000000c0u) >> 6; - shift |= (given & 0x00007000u) >> 10; - if (given & 0x00200000u) - func (stream, ", asr #%u", shift); - else if (shift) - func (stream, ", lsl #%u", shift); - /* else print nothing - lsl #0 */ - } - break; - - case 'R': - { - unsigned int rot = (given & 0x00000030) >> 4; - if (rot) - func (stream, ", ror #%u", rot * 8); - } - break; - - case 'U': - switch (given & 0xf) - { - case 0xf: func(stream, "sy"); break; - case 0x7: func(stream, "un"); break; - case 0xe: func(stream, "st"); break; - case 0x6: func(stream, "unst"); break; - default: - func(stream, "#%d", (int)given & 0xf); - break; - } - break; - - case 'C': - if ((given & 0xff) == 0) - { - func (stream, "%cPSR_", (given & 0x100000) ? 'S' : 'C'); - if (given & 0x800) - func (stream, "f"); - if (given & 0x400) - func (stream, "s"); - if (given & 0x200) - func (stream, "x"); - if (given & 0x100) - func (stream, "c"); - } - else - { - func (stream, "%s", psr_name (given & 0xff)); - } - break; - - case 'D': - if ((given & 0xff) == 0) - func (stream, "%cPSR", (given & 0x100000) ? 'S' : 'C'); - else - func (stream, "%s", psr_name (given & 0xff)); - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - int width; - unsigned long val; - - c = arm_decode_bitfield (c, given, &val, &width); - - switch (*c) - { - case 'd': func (stream, "%lu", val); break; - case 'W': func (stream, "%lu", val * 4); break; - case 'r': func (stream, "%s", arm_regnames[val]); break; - - case 'c': - func (stream, "%s", arm_conditional[val]); - break; - - case '\'': - c++; - if (val == ((1ul << width) - 1)) - func (stream, "%c", *c); - break; - - case '`': - c++; - if (val == 0) - func (stream, "%c", *c); - break; - - case '?': - func (stream, "%c", c[(1 << width) - (int)val]); - c += 1 << width; - break; - - default: - abort (); - } - } - break; - - default: - abort (); - } - } - return; - } - - /* No match. */ - abort (); -} - -/* Print data bytes on INFO->STREAM. */ - -static void -print_insn_data (bfd_vma pc ATTRIBUTE_UNUSED, struct disassemble_info *info, - long given) -{ - switch (info->bytes_per_chunk) - { - case 1: - info->fprintf_func (info->stream, ".byte\t0x%02lx", given); - break; - case 2: - info->fprintf_func (info->stream, ".short\t0x%04lx", given); - break; - case 4: - info->fprintf_func (info->stream, ".word\t0x%08lx", given); - break; - default: - abort (); - } -} - -/* Search back through the insn stream to determine if this instruction is - conditionally executed. */ -static void -find_ifthen_state (bfd_vma pc, struct disassemble_info *info, - bfd_boolean little) -{ - unsigned char b[2]; - unsigned int insn; - int status; - /* COUNT is twice the number of instructions seen. It will be odd if we - just crossed an instruction boundary. */ - int count; - int it_count; - unsigned int seen_it; - bfd_vma addr; - - ifthen_address = pc; - ifthen_state = 0; - - addr = pc; - count = 1; - it_count = 0; - seen_it = 0; - /* Scan backwards looking for IT instructions, keeping track of where - instruction boundaries are. We don't know if something is actually an - IT instruction until we find a definite instruction boundary. */ - for (;;) - { - if (addr == 0 || info->symbol_at_address_func(addr, info)) - { - /* A symbol must be on an instruction boundary, and will not - be within an IT block. */ - if (seen_it && (count & 1)) - break; - - return; - } - addr -= 2; - status = arm_read_memory (addr, (bfd_byte *)b, 2, info); - if (status) - return; - - if (little) - insn = (b[0]) | (b[1] << 8); - else - insn = (b[1]) | (b[0] << 8); - if (seen_it) - { - if ((insn & 0xf800) < 0xe800) - { - /* Addr + 2 is an instruction boundary. See if this matches - the expected boundary based on the position of the last - IT candidate. */ - if (count & 1) - break; - seen_it = 0; - } - } - if ((insn & 0xff00) == 0xbf00 && (insn & 0xf) != 0) - { - /* This could be an IT instruction. */ - seen_it = insn; - it_count = count >> 1; - } - if ((insn & 0xf800) >= 0xe800) - count++; - else - count = (count + 2) | 1; - /* IT blocks contain at most 4 instructions. */ - if (count >= 8 && !seen_it) - return; - } - /* We found an IT instruction. */ - ifthen_state = (seen_it & 0xe0) | ((seen_it << it_count) & 0x1f); - if ((ifthen_state & 0xf) == 0) - ifthen_state = 0; -} - -/* NOTE: There are no checks in these routines that - the relevant number of data bytes exist. */ - -int -print_insn_arm (bfd_vma pc, struct disassemble_info *info) -{ - unsigned char b[4]; - long given; - int status; - int is_thumb = false; - int is_data = false; - unsigned int size = 4; - void (*printer) (bfd_vma, struct disassemble_info *, long); - int little; - - little = (info->endian == BFD_ENDIAN_LITTLE); - is_thumb |= (pc & 1); - pc &= ~(bfd_vma)1; - - if (force_thumb) - is_thumb = true; - - info->bytes_per_line = 4; - - if (is_data) - { - int i; - - /* size was already set above. */ - info->bytes_per_chunk = size; - printer = print_insn_data; - - status = arm_read_memory (pc, (bfd_byte *)b, size, info); - given = 0; - if (little) - for (i = size - 1; i >= 0; i--) - given = b[i] | (given << 8); - else - for (i = 0; i < (int) size; i++) - given = b[i] | (given << 8); - } - else if (!is_thumb) - { - /* In ARM mode endianness is a straightforward issue: the instruction - is four bytes long and is either ordered 0123 or 3210. */ - printer = print_insn_arm_internal; - info->bytes_per_chunk = 4; - size = 4; - - status = arm_read_memory (pc, (bfd_byte *)b, 4, info); - if (little) - given = (b[0]) | (b[1] << 8) | (b[2] << 16) | ((unsigned)b[3] << 24); - else - given = (b[3]) | (b[2] << 8) | (b[1] << 16) | ((unsigned)b[0] << 24); - } - else - { - /* In Thumb mode we have the additional wrinkle of two - instruction lengths. Fortunately, the bits that determine - the length of the current instruction are always to be found - in the first two bytes. */ - printer = print_insn_thumb16; - info->bytes_per_chunk = 2; - size = 2; - - status = arm_read_memory (pc, (bfd_byte *)b, 2, info); - if (little) - given = (b[0]) | (b[1] << 8); - else - given = (b[1]) | (b[0] << 8); - - if (!status) - { - /* These bit patterns signal a four-byte Thumb - instruction. */ - if ((given & 0xF800) == 0xF800 - || (given & 0xF800) == 0xF000 - || (given & 0xF800) == 0xE800) - { - status = arm_read_memory (pc + 2, (bfd_byte *)b, 2, info); - if (little) - given = (b[0]) | (b[1] << 8) | (given << 16); - else - given = (b[1]) | (b[0] << 8) | (given << 16); - - printer = print_insn_thumb32; - size = 4; - } - } - - if (ifthen_address != pc) - find_ifthen_state(pc, info, little); - - if (ifthen_state) - { - if ((ifthen_state & 0xf) == 0x8) - ifthen_next_state = 0; - else - ifthen_next_state = (ifthen_state & 0xe0) - | ((ifthen_state & 0xf) << 1); - } - } - - if (status) - { - info->memory_error_func (status, pc, info); - return -1; - } - if (info->flags & INSN_HAS_RELOC) - /* If the instruction has a reloc associated with it, then - the offset field in the instruction will actually be the - addend for the reloc. (We are using REL type relocs). - In such cases, we can ignore the pc when computing - addresses, since the addend is not currently pc-relative. */ - pc = 0; - - /* We include the hexdump of the instruction. The format here - matches that used by objdump and the ARM ARM (in particular, - 32 bit Thumb instructions are displayed as pairs of halfwords, - not as a single word.) */ - if (is_thumb) - { - if (size == 2) - { - info->fprintf_func(info->stream, "%04lx ", - ((unsigned long)given) & 0xffff); - } - else - { - info->fprintf_func(info->stream, "%04lx %04lx ", - (((unsigned long)given) >> 16) & 0xffff, - ((unsigned long)given) & 0xffff); - } - } - else - { - info->fprintf_func(info->stream, "%08lx ", - ((unsigned long)given) & 0xffffffff); - } - - printer (pc, info, given); - - if (is_thumb) - { - ifthen_state = ifthen_next_state; - ifthen_address += size; - } - return size; -} diff --git a/disas/meson.build b/disas/meson.build index e3e1b67923..a6402e7e1c 100644 --- a/disas/meson.build +++ b/disas/meson.build @@ -4,7 +4,6 @@ subdir('libvixl') common_ss.add(when: 'CONFIG_ALPHA_DIS', if_true: files('alpha.c')) common_ss.add(when: 'CONFIG_ARM_A64_DIS', if_true: files('arm-a64.cc')) common_ss.add_all(when: 'CONFIG_ARM_A64_DIS', if_true: libvixl_ss) -common_ss.add(when: 'CONFIG_ARM_DIS', if_true: files('arm.c')) common_ss.add(when: 'CONFIG_CRIS_DIS', if_true: files('cris.c')) common_ss.add(when: 'CONFIG_HEXAGON_DIS', if_true: files('hexagon.c')) common_ss.add(when: 'CONFIG_HPPA_DIS', if_true: files('hppa.c')) diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h index aebd23dc20..e857f0ae8b 100644 --- a/include/disas/dis-asm.h +++ b/include/disas/dis-asm.h @@ -429,7 +429,6 @@ int print_insn_h8500 (bfd_vma, disassemble_info*); int print_insn_arm_a64 (bfd_vma, disassemble_info*); int print_insn_alpha (bfd_vma, disassemble_info*); disassembler_ftype arc_get_disassembler (int, int); -int print_insn_arm (bfd_vma, disassemble_info*); int print_insn_sparc (bfd_vma, disassemble_info*); int print_insn_big_a29k (bfd_vma, disassemble_info*); int print_insn_little_a29k (bfd_vma, disassemble_info*); diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 01176b2569..16fb5f9c12 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -775,12 +775,6 @@ static bool arm_cpu_virtio_is_big_endian(CPUState *cs) #endif -static int -print_insn_thumb1(bfd_vma pc, disassemble_info *info) -{ - return print_insn_arm(pc | 1, info); -} - static void arm_disas_set_info(CPUState *cpu, disassemble_info *info) { ARMCPU *ac = ARM_CPU(cpu); @@ -801,12 +795,10 @@ static void arm_disas_set_info(CPUState *cpu, disassemble_info *info) } else { int cap_mode; if (env->thumb) { - info->print_insn = print_insn_thumb1; info->cap_insn_unit = 2; info->cap_insn_split = 4; cap_mode = CS_MODE_THUMB; } else { - info->print_insn = print_insn_arm; info->cap_insn_unit = 4; info->cap_insn_split = 4; cap_mode = CS_MODE_ARM; From 457248a54c9d3dbc3c7f4dc8e184f07ca858640c Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 12 Apr 2022 18:58:36 +0200 Subject: [PATCH 176/935] disas: Remove old libopcode i386 disassembler Capstone should be superior to the old libopcode disassembler, so we can drop the old file nowadays. Signed-off-by: Thomas Huth Reviewed-by: Richard Henderson Message-Id: <20220412165836.355850-4-thuth@redhat.com> Signed-off-by: Thomas Huth --- MAINTAINERS | 2 - disas.c | 2 - disas/i386.c | 6771 --------------------------------------- disas/meson.build | 1 - include/disas/dis-asm.h | 1 - target/i386/cpu.c | 1 - 6 files changed, 6778 deletions(-) delete mode 100644 disas/i386.c diff --git a/MAINTAINERS b/MAINTAINERS index 7f3788b694..85d593a41f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -334,7 +334,6 @@ F: target/i386/tcg/ F: tests/tcg/i386/ F: tests/tcg/x86_64/ F: hw/i386/ -F: disas/i386.c F: docs/system/cpu-models-x86* T: git https://gitlab.com/ehabkost/qemu.git x86-next @@ -3275,7 +3274,6 @@ i386 TCG target M: Richard Henderson S: Maintained F: tcg/i386/ -F: disas/i386.c LoongArch64 TCG target M: WANG Xuerui diff --git a/disas.c b/disas.c index 4e443b4d49..b6f4dc73b2 100644 --- a/disas.c +++ b/disas.c @@ -153,14 +153,12 @@ static void initialize_debug_host(CPUDebug *s) s->info.print_insn = print_insn_tci; #elif defined(__i386__) s->info.mach = bfd_mach_i386_i386; - s->info.print_insn = print_insn_i386; s->info.cap_arch = CS_ARCH_X86; s->info.cap_mode = CS_MODE_32; s->info.cap_insn_unit = 1; s->info.cap_insn_split = 8; #elif defined(__x86_64__) s->info.mach = bfd_mach_x86_64; - s->info.print_insn = print_insn_i386; s->info.cap_arch = CS_ARCH_X86; s->info.cap_mode = CS_MODE_64; s->info.cap_insn_unit = 1; diff --git a/disas/i386.c b/disas/i386.c deleted file mode 100644 index 06c835236e..0000000000 --- a/disas/i386.c +++ /dev/null @@ -1,6771 +0,0 @@ -/* opcodes/i386-dis.c r1.126 */ -/* Print i386 instructions for GDB, the GNU debugger. - Copyright 1988, 1989, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . */ - -/* 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) - July 1988 - modified by John Hassey (hassey@dg-rtp.dg.com) - x86-64 support added by Jan Hubicka (jh@suse.cz) - VIA PadLock support by Michal Ludvig (mludvig@suse.cz). */ - -/* The main tables describing the instructions is essentially a copy - of the "Opcode Map" chapter (Appendix A) of the Intel 80386 - Programmers Manual. Usually, there is a capital letter, followed - by a small letter. The capital letter tell the addressing mode, - and the small letter tells about the operand size. Refer to - the Intel manual for details. */ - -#include "qemu/osdep.h" -#include "disas/dis-asm.h" -#include "qemu/cutils.h" - -/* include/opcode/i386.h r1.78 */ - -/* opcode/i386.h -- Intel 80386 opcode macros - Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 - Free Software Foundation, Inc. - - This file is part of GAS, the GNU Assembler, and GDB, the GNU Debugger. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . */ - -/* The SystemV/386 SVR3.2 assembler, and probably all AT&T derived - ix86 Unix assemblers, generate floating point instructions with - reversed source and destination registers in certain cases. - Unfortunately, gcc and possibly many other programs use this - reversed syntax, so we're stuck with it. - - eg. `fsub %st(3),%st' results in st = st - st(3) as expected, but - `fsub %st,%st(3)' results in st(3) = st - st(3), rather than - the expected st(3) = st(3) - st - - This happens with all the non-commutative arithmetic floating point - operations with two register operands, where the source register is - %st, and destination register is %st(i). - - The affected opcode map is dceX, dcfX, deeX, defX. */ - -#ifndef SYSV386_COMPAT -/* Set non-zero for broken, compatible instructions. Set to zero for - non-broken opcodes at your peril. gcc generates SystemV/386 - compatible instructions. */ -#define SYSV386_COMPAT 1 -#endif -#ifndef OLDGCC_COMPAT -/* Set non-zero to cater for old (<= 2.8.1) versions of gcc that could - generate nonsense fsubp, fsubrp, fdivp and fdivrp with operands - reversed. */ -#define OLDGCC_COMPAT SYSV386_COMPAT -#endif - -#define MOV_AX_DISP32 0xa0 -#define POP_SEG_SHORT 0x07 -#define JUMP_PC_RELATIVE 0xeb -#define INT_OPCODE 0xcd -#define INT3_OPCODE 0xcc -/* The opcode for the fwait instruction, which disassembler treats as a - prefix when it can. */ -#define FWAIT_OPCODE 0x9b -#define ADDR_PREFIX_OPCODE 0x67 -#define DATA_PREFIX_OPCODE 0x66 -#define LOCK_PREFIX_OPCODE 0xf0 -#define CS_PREFIX_OPCODE 0x2e -#define DS_PREFIX_OPCODE 0x3e -#define ES_PREFIX_OPCODE 0x26 -#define FS_PREFIX_OPCODE 0x64 -#define GS_PREFIX_OPCODE 0x65 -#define SS_PREFIX_OPCODE 0x36 -#define REPNE_PREFIX_OPCODE 0xf2 -#define REPE_PREFIX_OPCODE 0xf3 - -#define TWO_BYTE_OPCODE_ESCAPE 0x0f -#define NOP_OPCODE (char) 0x90 - -/* register numbers */ -#define EBP_REG_NUM 5 -#define ESP_REG_NUM 4 - -/* modrm_byte.regmem for twobyte escape */ -#define ESCAPE_TO_TWO_BYTE_ADDRESSING ESP_REG_NUM -/* index_base_byte.index for no index register addressing */ -#define NO_INDEX_REGISTER ESP_REG_NUM -/* index_base_byte.base for no base register addressing */ -#define NO_BASE_REGISTER EBP_REG_NUM -#define NO_BASE_REGISTER_16 6 - -/* modrm.mode = REGMEM_FIELD_HAS_REG when a register is in there */ -#define REGMEM_FIELD_HAS_REG 0x3/* always = 0x3 */ -#define REGMEM_FIELD_HAS_MEM (~REGMEM_FIELD_HAS_REG) - -/* x86-64 extension prefix. */ -#define REX_OPCODE 0x40 - -/* Indicates 64 bit operand size. */ -#define REX_W 8 -/* High extension to reg field of modrm byte. */ -#define REX_R 4 -/* High extension to SIB index field. */ -#define REX_X 2 -/* High extension to base field of modrm or SIB, or reg field of opcode. */ -#define REX_B 1 - -/* max operands per insn */ -#define MAX_OPERANDS 4 - -/* max immediates per insn (lcall, ljmp, insertq, extrq) */ -#define MAX_IMMEDIATE_OPERANDS 2 - -/* max memory refs per insn (string ops) */ -#define MAX_MEMORY_OPERANDS 2 - -/* max size of insn mnemonics. */ -#define MAX_MNEM_SIZE 16 - -/* max size of register name in insn mnemonics. */ -#define MAX_REG_NAME_SIZE 8 - -/* opcodes/i386-dis.c r1.126 */ - -static int fetch_data2(struct disassemble_info *, bfd_byte *); -static int fetch_data(struct disassemble_info *, bfd_byte *); -static void ckprefix (void); -static const char *prefix_name (int, int); -static int print_insn (bfd_vma, disassemble_info *); -static void dofloat (int); -static void OP_ST (int, int); -static void OP_STi (int, int); -static int putop (const char *, int); -static void oappend (const char *); -static void append_seg (void); -static void OP_indirE (int, int); -static void print_operand_value (char *buf, size_t bufsize, int hex, bfd_vma disp); -static void print_displacement (char *, bfd_vma); -static void OP_E (int, int); -static void OP_G (int, int); -static void OP_vvvv (int, int); -static bfd_vma get64 (void); -static bfd_signed_vma get32 (void); -static bfd_signed_vma get32s (void); -static int get16 (void); -static void set_op (bfd_vma, int); -static void OP_REG (int, int); -static void OP_IMREG (int, int); -static void OP_I (int, int); -static void OP_I64 (int, int); -static void OP_sI (int, int); -static void OP_J (int, int); -static void OP_SEG (int, int); -static void OP_DIR (int, int); -static void OP_OFF (int, int); -static void OP_OFF64 (int, int); -static void ptr_reg (int, int); -static void OP_ESreg (int, int); -static void OP_DSreg (int, int); -static void OP_C (int, int); -static void OP_D (int, int); -static void OP_T (int, int); -static void OP_R (int, int); -static void OP_MMX (int, int); -static void OP_XMM (int, int); -static void OP_EM (int, int); -static void OP_EX (int, int); -static void OP_EMC (int,int); -static void OP_MXC (int,int); -static void OP_MS (int, int); -static void OP_XS (int, int); -static void OP_M (int, int); -static void OP_VMX (int, int); -static void OP_0fae (int, int); -static void OP_0f07 (int, int); -static void NOP_Fixup1 (int, int); -static void NOP_Fixup2 (int, int); -static void OP_3DNowSuffix (int, int); -static void OP_SIMD_Suffix (int, int); -static void SIMD_Fixup (int, int); -static void PNI_Fixup (int, int); -static void SVME_Fixup (int, int); -static void INVLPG_Fixup (int, int); -static void BadOp (void); -static void VMX_Fixup (int, int); -static void REP_Fixup (int, int); -static void CMPXCHG8B_Fixup (int, int); -static void XMM_Fixup (int, int); -static void CRC32_Fixup (int, int); - -struct dis_private { - /* Points to first byte not fetched. */ - bfd_byte *max_fetched; - bfd_byte the_buffer[MAX_MNEM_SIZE]; - bfd_vma insn_start; - int orig_sizeflag; - sigjmp_buf bailout; -}; - -enum address_mode -{ - mode_16bit, - mode_32bit, - mode_64bit -}; - -static enum address_mode address_mode; - -/* Flags for the prefixes for the current instruction. See below. */ -static int prefixes; - -/* REX prefix the current instruction. See below. */ -static int rex; -/* Bits of REX we've already used. */ -static int rex_used; -/* Mark parts used in the REX prefix. When we are testing for - empty prefix (for 8bit register REX extension), just mask it - out. Otherwise test for REX bit is excuse for existence of REX - only in case value is nonzero. */ -#define USED_REX(value) \ - { \ - if (value) \ - { \ - if ((rex & value)) \ - rex_used |= (value) | REX_OPCODE; \ - } \ - else \ - rex_used |= REX_OPCODE; \ - } - -/* Flags for prefixes which we somehow handled when printing the - current instruction. */ -static int used_prefixes; - -/* The VEX.vvvv register, unencoded. */ -static int vex_reg; - -/* Flags stored in PREFIXES. */ -#define PREFIX_REPZ 1 -#define PREFIX_REPNZ 2 -#define PREFIX_LOCK 4 -#define PREFIX_CS 8 -#define PREFIX_SS 0x10 -#define PREFIX_DS 0x20 -#define PREFIX_ES 0x40 -#define PREFIX_FS 0x80 -#define PREFIX_GS 0x100 -#define PREFIX_DATA 0x200 -#define PREFIX_ADDR 0x400 -#define PREFIX_FWAIT 0x800 - -#define PREFIX_VEX_0F 0x1000 -#define PREFIX_VEX_0F38 0x2000 -#define PREFIX_VEX_0F3A 0x4000 - -/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) - to ADDR (exclusive) are valid. Returns 1 for success, longjmps - on error. */ -static int -fetch_data2(struct disassemble_info *info, bfd_byte *addr) -{ - int status; - struct dis_private *priv = (struct dis_private *) info->private_data; - bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); - - if (addr <= priv->the_buffer + MAX_MNEM_SIZE) - status = (*info->read_memory_func) (start, - priv->max_fetched, - addr - priv->max_fetched, - info); - else - status = -1; - if (status != 0) - { - /* If we did manage to read at least one byte, then - print_insn_i386 will do something sensible. Otherwise, print - an error. We do that here because this is where we know - STATUS. */ - if (priv->max_fetched == priv->the_buffer) - (*info->memory_error_func) (status, start, info); - siglongjmp(priv->bailout, 1); - } - else - priv->max_fetched = addr; - return 1; -} - -static int -fetch_data(struct disassemble_info *info, bfd_byte *addr) -{ - if (addr <= ((struct dis_private *) (info->private_data))->max_fetched) { - return 1; - } else { - return fetch_data2(info, addr); - } -} - - -#define XX { NULL, 0 } - -#define Bv { OP_vvvv, v_mode } -#define Eb { OP_E, b_mode } -#define Ev { OP_E, v_mode } -#define Ed { OP_E, d_mode } -#define Edq { OP_E, dq_mode } -#define Edqw { OP_E, dqw_mode } -#define Edqb { OP_E, dqb_mode } -#define Edqd { OP_E, dqd_mode } -#define indirEv { OP_indirE, stack_v_mode } -#define indirEp { OP_indirE, f_mode } -#define stackEv { OP_E, stack_v_mode } -#define Em { OP_E, m_mode } -#define Ew { OP_E, w_mode } -#define M { OP_M, 0 } /* lea, lgdt, etc. */ -#define Ma { OP_M, v_mode } -#define Mp { OP_M, f_mode } /* 32 or 48 bit memory operand for LDS, LES etc */ -#define Mq { OP_M, q_mode } -#define Gb { OP_G, b_mode } -#define Gv { OP_G, v_mode } -#define Gd { OP_G, d_mode } -#define Gdq { OP_G, dq_mode } -#define Gm { OP_G, m_mode } -#define Gw { OP_G, w_mode } -#define Rd { OP_R, d_mode } -#define Rm { OP_R, m_mode } -#define Ib { OP_I, b_mode } -#define sIb { OP_sI, b_mode } /* sign extended byte */ -#define Iv { OP_I, v_mode } -#define Iq { OP_I, q_mode } -#define Iv64 { OP_I64, v_mode } -#define Iw { OP_I, w_mode } -#define I1 { OP_I, const_1_mode } -#define Jb { OP_J, b_mode } -#define Jv { OP_J, v_mode } -#define Cm { OP_C, m_mode } -#define Dm { OP_D, m_mode } -#define Td { OP_T, d_mode } - -#define RMeAX { OP_REG, eAX_reg } -#define RMeBX { OP_REG, eBX_reg } -#define RMeCX { OP_REG, eCX_reg } -#define RMeDX { OP_REG, eDX_reg } -#define RMeSP { OP_REG, eSP_reg } -#define RMeBP { OP_REG, eBP_reg } -#define RMeSI { OP_REG, eSI_reg } -#define RMeDI { OP_REG, eDI_reg } -#define RMrAX { OP_REG, rAX_reg } -#define RMrBX { OP_REG, rBX_reg } -#define RMrCX { OP_REG, rCX_reg } -#define RMrDX { OP_REG, rDX_reg } -#define RMrSP { OP_REG, rSP_reg } -#define RMrBP { OP_REG, rBP_reg } -#define RMrSI { OP_REG, rSI_reg } -#define RMrDI { OP_REG, rDI_reg } -#define RMAL { OP_REG, al_reg } -#define RMAL { OP_REG, al_reg } -#define RMCL { OP_REG, cl_reg } -#define RMDL { OP_REG, dl_reg } -#define RMBL { OP_REG, bl_reg } -#define RMAH { OP_REG, ah_reg } -#define RMCH { OP_REG, ch_reg } -#define RMDH { OP_REG, dh_reg } -#define RMBH { OP_REG, bh_reg } -#define RMAX { OP_REG, ax_reg } -#define RMDX { OP_REG, dx_reg } - -#define eAX { OP_IMREG, eAX_reg } -#define eBX { OP_IMREG, eBX_reg } -#define eCX { OP_IMREG, eCX_reg } -#define eDX { OP_IMREG, eDX_reg } -#define eSP { OP_IMREG, eSP_reg } -#define eBP { OP_IMREG, eBP_reg } -#define eSI { OP_IMREG, eSI_reg } -#define eDI { OP_IMREG, eDI_reg } -#define AL { OP_IMREG, al_reg } -#define CL { OP_IMREG, cl_reg } -#define DL { OP_IMREG, dl_reg } -#define BL { OP_IMREG, bl_reg } -#define AH { OP_IMREG, ah_reg } -#define CH { OP_IMREG, ch_reg } -#define DH { OP_IMREG, dh_reg } -#define BH { OP_IMREG, bh_reg } -#define AX { OP_IMREG, ax_reg } -#define DX { OP_IMREG, dx_reg } -#define zAX { OP_IMREG, z_mode_ax_reg } -#define indirDX { OP_IMREG, indir_dx_reg } - -#define Sw { OP_SEG, w_mode } -#define Sv { OP_SEG, v_mode } -#define Ap { OP_DIR, 0 } -#define Ob { OP_OFF64, b_mode } -#define Ov { OP_OFF64, v_mode } -#define Xb { OP_DSreg, eSI_reg } -#define Xv { OP_DSreg, eSI_reg } -#define Xz { OP_DSreg, eSI_reg } -#define Yb { OP_ESreg, eDI_reg } -#define Yv { OP_ESreg, eDI_reg } -#define DSBX { OP_DSreg, eBX_reg } - -#define es { OP_REG, es_reg } -#define ss { OP_REG, ss_reg } -#define cs { OP_REG, cs_reg } -#define ds { OP_REG, ds_reg } -#define fs { OP_REG, fs_reg } -#define gs { OP_REG, gs_reg } - -#define MX { OP_MMX, 0 } -#define XM { OP_XMM, 0 } -#define EM { OP_EM, v_mode } -#define EMd { OP_EM, d_mode } -#define EMq { OP_EM, q_mode } -#define EXd { OP_EX, d_mode } -#define EXq { OP_EX, q_mode } -#define EXx { OP_EX, x_mode } -#define MS { OP_MS, v_mode } -#define XS { OP_XS, v_mode } -#define EMC { OP_EMC, v_mode } -#define MXC { OP_MXC, 0 } -#define VM { OP_VMX, q_mode } -#define OPSUF { OP_3DNowSuffix, 0 } -#define OPSIMD { OP_SIMD_Suffix, 0 } -#define XMM0 { XMM_Fixup, 0 } - -/* Used handle "rep" prefix for string instructions. */ -#define Xbr { REP_Fixup, eSI_reg } -#define Xvr { REP_Fixup, eSI_reg } -#define Ybr { REP_Fixup, eDI_reg } -#define Yvr { REP_Fixup, eDI_reg } -#define Yzr { REP_Fixup, eDI_reg } -#define indirDXr { REP_Fixup, indir_dx_reg } -#define ALr { REP_Fixup, al_reg } -#define eAXr { REP_Fixup, eAX_reg } - -#define cond_jump_flag { NULL, cond_jump_mode } -#define loop_jcxz_flag { NULL, loop_jcxz_mode } - -/* bits in sizeflag */ -#define SUFFIX_ALWAYS 4 -#define AFLAG 2 -#define DFLAG 1 - -#define b_mode 1 /* byte operand */ -#define v_mode 2 /* operand size depends on prefixes */ -#define w_mode 3 /* word operand */ -#define d_mode 4 /* double word operand */ -#define q_mode 5 /* quad word operand */ -#define t_mode 6 /* ten-byte operand */ -#define x_mode 7 /* 16-byte XMM operand */ -#define m_mode 8 /* d_mode in 32bit, q_mode in 64bit mode. */ -#define cond_jump_mode 9 -#define loop_jcxz_mode 10 -#define dq_mode 11 /* operand size depends on REX prefixes. */ -#define dqw_mode 12 /* registers like dq_mode, memory like w_mode. */ -#define f_mode 13 /* 4- or 6-byte pointer operand */ -#define const_1_mode 14 -#define stack_v_mode 15 /* v_mode for stack-related opcodes. */ -#define z_mode 16 /* non-quad operand size depends on prefixes */ -#define o_mode 17 /* 16-byte operand */ -#define dqb_mode 18 /* registers like dq_mode, memory like b_mode. */ -#define dqd_mode 19 /* registers like dq_mode, memory like d_mode. */ - -#define es_reg 100 -#define cs_reg 101 -#define ss_reg 102 -#define ds_reg 103 -#define fs_reg 104 -#define gs_reg 105 - -#define eAX_reg 108 -#define eCX_reg 109 -#define eDX_reg 110 -#define eBX_reg 111 -#define eSP_reg 112 -#define eBP_reg 113 -#define eSI_reg 114 -#define eDI_reg 115 - -#define al_reg 116 -#define cl_reg 117 -#define dl_reg 118 -#define bl_reg 119 -#define ah_reg 120 -#define ch_reg 121 -#define dh_reg 122 -#define bh_reg 123 - -#define ax_reg 124 -#define cx_reg 125 -#define dx_reg 126 -#define bx_reg 127 -#define sp_reg 128 -#define bp_reg 129 -#define si_reg 130 -#define di_reg 131 - -#define rAX_reg 132 -#define rCX_reg 133 -#define rDX_reg 134 -#define rBX_reg 135 -#define rSP_reg 136 -#define rBP_reg 137 -#define rSI_reg 138 -#define rDI_reg 139 - -#define z_mode_ax_reg 149 -#define indir_dx_reg 150 - -#define FLOATCODE 1 -#define USE_GROUPS 2 -#define USE_PREFIX_USER_TABLE 3 -#define X86_64_SPECIAL 4 -#define IS_3BYTE_OPCODE 5 - -#define FLOAT NULL, { { NULL, FLOATCODE } } - -#define GRP1a NULL, { { NULL, USE_GROUPS }, { NULL, 0 } } -#define GRP1b NULL, { { NULL, USE_GROUPS }, { NULL, 1 } } -#define GRP1S NULL, { { NULL, USE_GROUPS }, { NULL, 2 } } -#define GRP1Ss NULL, { { NULL, USE_GROUPS }, { NULL, 3 } } -#define GRP2b NULL, { { NULL, USE_GROUPS }, { NULL, 4 } } -#define GRP2S NULL, { { NULL, USE_GROUPS }, { NULL, 5 } } -#define GRP2b_one NULL, { { NULL, USE_GROUPS }, { NULL, 6 } } -#define GRP2S_one NULL, { { NULL, USE_GROUPS }, { NULL, 7 } } -#define GRP2b_cl NULL, { { NULL, USE_GROUPS }, { NULL, 8 } } -#define GRP2S_cl NULL, { { NULL, USE_GROUPS }, { NULL, 9 } } -#define GRP3b NULL, { { NULL, USE_GROUPS }, { NULL, 10 } } -#define GRP3S NULL, { { NULL, USE_GROUPS }, { NULL, 11 } } -#define GRP4 NULL, { { NULL, USE_GROUPS }, { NULL, 12 } } -#define GRP5 NULL, { { NULL, USE_GROUPS }, { NULL, 13 } } -#define GRP6 NULL, { { NULL, USE_GROUPS }, { NULL, 14 } } -#define GRP7 NULL, { { NULL, USE_GROUPS }, { NULL, 15 } } -#define GRP8 NULL, { { NULL, USE_GROUPS }, { NULL, 16 } } -#define GRP9 NULL, { { NULL, USE_GROUPS }, { NULL, 17 } } -#define GRP11_C6 NULL, { { NULL, USE_GROUPS }, { NULL, 18 } } -#define GRP11_C7 NULL, { { NULL, USE_GROUPS }, { NULL, 19 } } -#define GRP12 NULL, { { NULL, USE_GROUPS }, { NULL, 20 } } -#define GRP13 NULL, { { NULL, USE_GROUPS }, { NULL, 21 } } -#define GRP14 NULL, { { NULL, USE_GROUPS }, { NULL, 22 } } -#define GRP15 NULL, { { NULL, USE_GROUPS }, { NULL, 23 } } -#define GRP16 NULL, { { NULL, USE_GROUPS }, { NULL, 24 } } -#define GRPAMD NULL, { { NULL, USE_GROUPS }, { NULL, 25 } } -#define GRPPADLCK1 NULL, { { NULL, USE_GROUPS }, { NULL, 26 } } -#define GRPPADLCK2 NULL, { { NULL, USE_GROUPS }, { NULL, 27 } } - -#define PREGRP0 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 0 } } -#define PREGRP1 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 1 } } -#define PREGRP2 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 2 } } -#define PREGRP3 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 3 } } -#define PREGRP4 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 4 } } -#define PREGRP5 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 5 } } -#define PREGRP6 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 6 } } -#define PREGRP7 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 7 } } -#define PREGRP8 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 8 } } -#define PREGRP9 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 9 } } -#define PREGRP10 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 10 } } -#define PREGRP11 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 11 } } -#define PREGRP12 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 12 } } -#define PREGRP13 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 13 } } -#define PREGRP14 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 14 } } -#define PREGRP15 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 15 } } -#define PREGRP16 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 16 } } -#define PREGRP17 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 17 } } -#define PREGRP18 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 18 } } -#define PREGRP19 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 19 } } -#define PREGRP20 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 20 } } -#define PREGRP21 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 21 } } -#define PREGRP22 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 22 } } -#define PREGRP23 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 23 } } -#define PREGRP24 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 24 } } -#define PREGRP25 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 25 } } -#define PREGRP26 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 26 } } -#define PREGRP27 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 27 } } -#define PREGRP28 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 28 } } -#define PREGRP29 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 29 } } -#define PREGRP30 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 30 } } -#define PREGRP31 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 31 } } -#define PREGRP32 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 32 } } -#define PREGRP33 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 33 } } -#define PREGRP34 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 34 } } -#define PREGRP35 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 35 } } -#define PREGRP36 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 36 } } -#define PREGRP37 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 37 } } -#define PREGRP38 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 38 } } -#define PREGRP39 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 39 } } -#define PREGRP40 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 40 } } -#define PREGRP41 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 41 } } -#define PREGRP42 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 42 } } -#define PREGRP43 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 43 } } -#define PREGRP44 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 44 } } -#define PREGRP45 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 45 } } -#define PREGRP46 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 46 } } -#define PREGRP47 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 47 } } -#define PREGRP48 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 48 } } -#define PREGRP49 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 49 } } -#define PREGRP50 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 50 } } -#define PREGRP51 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 51 } } -#define PREGRP52 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 52 } } -#define PREGRP53 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 53 } } -#define PREGRP54 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 54 } } -#define PREGRP55 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 55 } } -#define PREGRP56 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 56 } } -#define PREGRP57 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 57 } } -#define PREGRP58 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 58 } } -#define PREGRP59 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 59 } } -#define PREGRP60 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 60 } } -#define PREGRP61 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 61 } } -#define PREGRP62 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 62 } } -#define PREGRP63 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 63 } } -#define PREGRP64 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 64 } } -#define PREGRP65 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 65 } } -#define PREGRP66 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 66 } } -#define PREGRP67 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 67 } } -#define PREGRP68 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 68 } } -#define PREGRP69 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 69 } } -#define PREGRP70 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 70 } } -#define PREGRP71 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 71 } } -#define PREGRP72 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 72 } } -#define PREGRP73 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 73 } } -#define PREGRP74 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 74 } } -#define PREGRP75 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 75 } } -#define PREGRP76 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 76 } } -#define PREGRP77 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 77 } } -#define PREGRP78 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 78 } } -#define PREGRP79 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 79 } } -#define PREGRP80 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 80 } } -#define PREGRP81 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 81 } } -#define PREGRP82 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 82 } } -#define PREGRP83 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 83 } } -#define PREGRP84 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 84 } } -#define PREGRP85 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 85 } } -#define PREGRP86 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 86 } } -#define PREGRP87 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 87 } } -#define PREGRP88 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 88 } } -#define PREGRP89 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 89 } } -#define PREGRP90 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 90 } } -#define PREGRP91 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 91 } } -#define PREGRP92 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 92 } } -#define PREGRP93 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 93 } } -#define PREGRP94 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 94 } } -#define PREGRP95 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 95 } } -#define PREGRP96 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 96 } } -#define PREGRP97 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 97 } } -#define PREGRP98 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 98 } } -#define PREGRP99 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 99 } } -#define PREGRP100 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 100 } } -#define PREGRP101 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 101 } } -#define PREGRP102 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 102 } } -#define PREGRP103 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 103 } } -#define PREGRP104 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 104 } } -#define PREGRP105 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 105 } } -#define PREGRP106 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 106 } } -#define PREGRP107 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 107 } } -#define PREGRP108 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 108 } } -#define PREGRP109 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 109 } } - -#define X86_64_0 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 0 } } -#define X86_64_1 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 1 } } -#define X86_64_2 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 2 } } -#define X86_64_3 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 3 } } - -#define THREE_BYTE_0 NULL, { { NULL, IS_3BYTE_OPCODE }, { NULL, 0 } } -#define THREE_BYTE_1 NULL, { { NULL, IS_3BYTE_OPCODE }, { NULL, 1 } } - -typedef void (*op_rtn) (int bytemode, int sizeflag); - -struct dis386 { - const char *name; - struct - { - op_rtn rtn; - int bytemode; - } op[MAX_OPERANDS]; -}; - -/* Upper case letters in the instruction names here are macros. - 'A' => print 'b' if no register operands or suffix_always is true - 'B' => print 'b' if suffix_always is true - 'C' => print 's' or 'l' ('w' or 'd' in Intel mode) depending on operand - . size prefix - 'D' => print 'w' if no register operands or 'w', 'l' or 'q', if - . suffix_always is true - 'E' => print 'e' if 32-bit form of jcxz - 'F' => print 'w' or 'l' depending on address size prefix (loop insns) - 'G' => print 'w' or 'l' depending on operand size prefix (i/o insns) - 'H' => print ",pt" or ",pn" branch hint - 'I' => honor following macro letter even in Intel mode (implemented only - . for some of the macro letters) - 'J' => print 'l' - 'K' => print 'd' or 'q' if rex prefix is present. - 'L' => print 'l' if suffix_always is true - 'N' => print 'n' if instruction has no wait "prefix" - 'O' => print 'd' or 'o' (or 'q' in Intel mode) - 'P' => print 'w', 'l' or 'q' if instruction has an operand size prefix, - . or suffix_always is true. print 'q' if rex prefix is present. - 'Q' => print 'w', 'l' or 'q' if no register operands or suffix_always - . is true - 'R' => print 'w', 'l' or 'q' ('d' for 'l' and 'e' in Intel mode) - 'S' => print 'w', 'l' or 'q' if suffix_always is true - 'T' => print 'q' in 64bit mode and behave as 'P' otherwise - 'U' => print 'q' in 64bit mode and behave as 'Q' otherwise - 'V' => print 'q' in 64bit mode and behave as 'S' otherwise - 'W' => print 'b', 'w' or 'l' ('d' in Intel mode) - 'X' => print 's', 'd' depending on data16 prefix (for XMM) - 'Y' => 'q' if instruction has an REX 64bit overwrite prefix - 'Z' => print 'q' in 64bit mode and behave as 'L' otherwise - - Many of the above letters print nothing in Intel mode. See "putop" - for the details. - - Braces '{' and '}', and vertical bars '|', indicate alternative - mnemonic strings for AT&T, Intel, X86_64 AT&T, and X86_64 Intel - modes. In cases where there are only two alternatives, the X86_64 - instruction is reserved, and "(bad)" is printed. -*/ - -static const struct dis386 dis386[] = { - /* 00 */ - { "addB", { Eb, Gb } }, - { "addS", { Ev, Gv } }, - { "addB", { Gb, Eb } }, - { "addS", { Gv, Ev } }, - { "addB", { AL, Ib } }, - { "addS", { eAX, Iv } }, - { "push{T|}", { es } }, - { "pop{T|}", { es } }, - /* 08 */ - { "orB", { Eb, Gb } }, - { "orS", { Ev, Gv } }, - { "orB", { Gb, Eb } }, - { "orS", { Gv, Ev } }, - { "orB", { AL, Ib } }, - { "orS", { eAX, Iv } }, - { "push{T|}", { cs } }, - { "(bad)", { XX } }, /* 0x0f extended opcode escape */ - /* 10 */ - { "adcB", { Eb, Gb } }, - { "adcS", { Ev, Gv } }, - { "adcB", { Gb, Eb } }, - { "adcS", { Gv, Ev } }, - { "adcB", { AL, Ib } }, - { "adcS", { eAX, Iv } }, - { "push{T|}", { ss } }, - { "pop{T|}", { ss } }, - /* 18 */ - { "sbbB", { Eb, Gb } }, - { "sbbS", { Ev, Gv } }, - { "sbbB", { Gb, Eb } }, - { "sbbS", { Gv, Ev } }, - { "sbbB", { AL, Ib } }, - { "sbbS", { eAX, Iv } }, - { "push{T|}", { ds } }, - { "pop{T|}", { ds } }, - /* 20 */ - { "andB", { Eb, Gb } }, - { "andS", { Ev, Gv } }, - { "andB", { Gb, Eb } }, - { "andS", { Gv, Ev } }, - { "andB", { AL, Ib } }, - { "andS", { eAX, Iv } }, - { "(bad)", { XX } }, /* SEG ES prefix */ - { "daa{|}", { XX } }, - /* 28 */ - { "subB", { Eb, Gb } }, - { "subS", { Ev, Gv } }, - { "subB", { Gb, Eb } }, - { "subS", { Gv, Ev } }, - { "subB", { AL, Ib } }, - { "subS", { eAX, Iv } }, - { "(bad)", { XX } }, /* SEG CS prefix */ - { "das{|}", { XX } }, - /* 30 */ - { "xorB", { Eb, Gb } }, - { "xorS", { Ev, Gv } }, - { "xorB", { Gb, Eb } }, - { "xorS", { Gv, Ev } }, - { "xorB", { AL, Ib } }, - { "xorS", { eAX, Iv } }, - { "(bad)", { XX } }, /* SEG SS prefix */ - { "aaa{|}", { XX } }, - /* 38 */ - { "cmpB", { Eb, Gb } }, - { "cmpS", { Ev, Gv } }, - { "cmpB", { Gb, Eb } }, - { "cmpS", { Gv, Ev } }, - { "cmpB", { AL, Ib } }, - { "cmpS", { eAX, Iv } }, - { "(bad)", { XX } }, /* SEG DS prefix */ - { "aas{|}", { XX } }, - /* 40 */ - { "inc{S|}", { RMeAX } }, - { "inc{S|}", { RMeCX } }, - { "inc{S|}", { RMeDX } }, - { "inc{S|}", { RMeBX } }, - { "inc{S|}", { RMeSP } }, - { "inc{S|}", { RMeBP } }, - { "inc{S|}", { RMeSI } }, - { "inc{S|}", { RMeDI } }, - /* 48 */ - { "dec{S|}", { RMeAX } }, - { "dec{S|}", { RMeCX } }, - { "dec{S|}", { RMeDX } }, - { "dec{S|}", { RMeBX } }, - { "dec{S|}", { RMeSP } }, - { "dec{S|}", { RMeBP } }, - { "dec{S|}", { RMeSI } }, - { "dec{S|}", { RMeDI } }, - /* 50 */ - { "pushV", { RMrAX } }, - { "pushV", { RMrCX } }, - { "pushV", { RMrDX } }, - { "pushV", { RMrBX } }, - { "pushV", { RMrSP } }, - { "pushV", { RMrBP } }, - { "pushV", { RMrSI } }, - { "pushV", { RMrDI } }, - /* 58 */ - { "popV", { RMrAX } }, - { "popV", { RMrCX } }, - { "popV", { RMrDX } }, - { "popV", { RMrBX } }, - { "popV", { RMrSP } }, - { "popV", { RMrBP } }, - { "popV", { RMrSI } }, - { "popV", { RMrDI } }, - /* 60 */ - { X86_64_0 }, - { X86_64_1 }, - { X86_64_2 }, - { X86_64_3 }, - { "(bad)", { XX } }, /* seg fs */ - { "(bad)", { XX } }, /* seg gs */ - { "(bad)", { XX } }, /* op size prefix */ - { "(bad)", { XX } }, /* adr size prefix */ - /* 68 */ - { "pushT", { Iq } }, - { "imulS", { Gv, Ev, Iv } }, - { "pushT", { sIb } }, - { "imulS", { Gv, Ev, sIb } }, - { "ins{b||b|}", { Ybr, indirDX } }, - { "ins{R||G|}", { Yzr, indirDX } }, - { "outs{b||b|}", { indirDXr, Xb } }, - { "outs{R||G|}", { indirDXr, Xz } }, - /* 70 */ - { "joH", { Jb, XX, cond_jump_flag } }, - { "jnoH", { Jb, XX, cond_jump_flag } }, - { "jbH", { Jb, XX, cond_jump_flag } }, - { "jaeH", { Jb, XX, cond_jump_flag } }, - { "jeH", { Jb, XX, cond_jump_flag } }, - { "jneH", { Jb, XX, cond_jump_flag } }, - { "jbeH", { Jb, XX, cond_jump_flag } }, - { "jaH", { Jb, XX, cond_jump_flag } }, - /* 78 */ - { "jsH", { Jb, XX, cond_jump_flag } }, - { "jnsH", { Jb, XX, cond_jump_flag } }, - { "jpH", { Jb, XX, cond_jump_flag } }, - { "jnpH", { Jb, XX, cond_jump_flag } }, - { "jlH", { Jb, XX, cond_jump_flag } }, - { "jgeH", { Jb, XX, cond_jump_flag } }, - { "jleH", { Jb, XX, cond_jump_flag } }, - { "jgH", { Jb, XX, cond_jump_flag } }, - /* 80 */ - { GRP1b }, - { GRP1S }, - { "(bad)", { XX } }, - { GRP1Ss }, - { "testB", { Eb, Gb } }, - { "testS", { Ev, Gv } }, - { "xchgB", { Eb, Gb } }, - { "xchgS", { Ev, Gv } }, - /* 88 */ - { "movB", { Eb, Gb } }, - { "movS", { Ev, Gv } }, - { "movB", { Gb, Eb } }, - { "movS", { Gv, Ev } }, - { "movD", { Sv, Sw } }, - { "leaS", { Gv, M } }, - { "movD", { Sw, Sv } }, - { GRP1a }, - /* 90 */ - { PREGRP38 }, - { "xchgS", { RMeCX, eAX } }, - { "xchgS", { RMeDX, eAX } }, - { "xchgS", { RMeBX, eAX } }, - { "xchgS", { RMeSP, eAX } }, - { "xchgS", { RMeBP, eAX } }, - { "xchgS", { RMeSI, eAX } }, - { "xchgS", { RMeDI, eAX } }, - /* 98 */ - { "cW{t||t|}R", { XX } }, - { "cR{t||t|}O", { XX } }, - { "Jcall{T|}", { Ap } }, - { "(bad)", { XX } }, /* fwait */ - { "pushfT", { XX } }, - { "popfT", { XX } }, - { "sahf{|}", { XX } }, - { "lahf{|}", { XX } }, - /* a0 */ - { "movB", { AL, Ob } }, - { "movS", { eAX, Ov } }, - { "movB", { Ob, AL } }, - { "movS", { Ov, eAX } }, - { "movs{b||b|}", { Ybr, Xb } }, - { "movs{R||R|}", { Yvr, Xv } }, - { "cmps{b||b|}", { Xb, Yb } }, - { "cmps{R||R|}", { Xv, Yv } }, - /* a8 */ - { "testB", { AL, Ib } }, - { "testS", { eAX, Iv } }, - { "stosB", { Ybr, AL } }, - { "stosS", { Yvr, eAX } }, - { "lodsB", { ALr, Xb } }, - { "lodsS", { eAXr, Xv } }, - { "scasB", { AL, Yb } }, - { "scasS", { eAX, Yv } }, - /* b0 */ - { "movB", { RMAL, Ib } }, - { "movB", { RMCL, Ib } }, - { "movB", { RMDL, Ib } }, - { "movB", { RMBL, Ib } }, - { "movB", { RMAH, Ib } }, - { "movB", { RMCH, Ib } }, - { "movB", { RMDH, Ib } }, - { "movB", { RMBH, Ib } }, - /* b8 */ - { "movS", { RMeAX, Iv64 } }, - { "movS", { RMeCX, Iv64 } }, - { "movS", { RMeDX, Iv64 } }, - { "movS", { RMeBX, Iv64 } }, - { "movS", { RMeSP, Iv64 } }, - { "movS", { RMeBP, Iv64 } }, - { "movS", { RMeSI, Iv64 } }, - { "movS", { RMeDI, Iv64 } }, - /* c0 */ - { GRP2b }, - { GRP2S }, - { "retT", { Iw } }, - { "retT", { XX } }, - { "les{S|}", { Gv, Mp } }, - { "ldsS", { Gv, Mp } }, - { GRP11_C6 }, - { GRP11_C7 }, - /* c8 */ - { "enterT", { Iw, Ib } }, - { "leaveT", { XX } }, - { "lretP", { Iw } }, - { "lretP", { XX } }, - { "int3", { XX } }, - { "int", { Ib } }, - { "into{|}", { XX } }, - { "iretP", { XX } }, - /* d0 */ - { GRP2b_one }, - { GRP2S_one }, - { GRP2b_cl }, - { GRP2S_cl }, - { "aam{|}", { sIb } }, - { "aad{|}", { sIb } }, - { "(bad)", { XX } }, - { "xlat", { DSBX } }, - /* d8 */ - { FLOAT }, - { FLOAT }, - { FLOAT }, - { FLOAT }, - { FLOAT }, - { FLOAT }, - { FLOAT }, - { FLOAT }, - /* e0 */ - { "loopneFH", { Jb, XX, loop_jcxz_flag } }, - { "loopeFH", { Jb, XX, loop_jcxz_flag } }, - { "loopFH", { Jb, XX, loop_jcxz_flag } }, - { "jEcxzH", { Jb, XX, loop_jcxz_flag } }, - { "inB", { AL, Ib } }, - { "inG", { zAX, Ib } }, - { "outB", { Ib, AL } }, - { "outG", { Ib, zAX } }, - /* e8 */ - { "callT", { Jv } }, - { "jmpT", { Jv } }, - { "Jjmp{T|}", { Ap } }, - { "jmp", { Jb } }, - { "inB", { AL, indirDX } }, - { "inG", { zAX, indirDX } }, - { "outB", { indirDX, AL } }, - { "outG", { indirDX, zAX } }, - /* f0 */ - { "(bad)", { XX } }, /* lock prefix */ - { "icebp", { XX } }, - { "(bad)", { XX } }, /* repne */ - { "(bad)", { XX } }, /* repz */ - { "hlt", { XX } }, - { "cmc", { XX } }, - { GRP3b }, - { GRP3S }, - /* f8 */ - { "clc", { XX } }, - { "stc", { XX } }, - { "cli", { XX } }, - { "sti", { XX } }, - { "cld", { XX } }, - { "std", { XX } }, - { GRP4 }, - { GRP5 }, -}; - -static const struct dis386 dis386_twobyte[] = { - /* 00 */ - { GRP6 }, - { GRP7 }, - { "larS", { Gv, Ew } }, - { "lslS", { Gv, Ew } }, - { "(bad)", { XX } }, - { "syscall", { XX } }, - { "clts", { XX } }, - { "sysretP", { XX } }, - /* 08 */ - { "invd", { XX } }, - { "wbinvd", { XX } }, - { "(bad)", { XX } }, - { "ud2a", { XX } }, - { "(bad)", { XX } }, - { GRPAMD }, - { "femms", { XX } }, - { "", { MX, EM, OPSUF } }, /* See OP_3DNowSuffix. */ - /* 10 */ - { PREGRP8 }, - { PREGRP9 }, - { PREGRP30 }, - { "movlpX", { EXq, XM, { SIMD_Fixup, 'h' } } }, - { "unpcklpX", { XM, EXq } }, - { "unpckhpX", { XM, EXq } }, - { PREGRP31 }, - { "movhpX", { EXq, XM, { SIMD_Fixup, 'l' } } }, - /* 18 */ - { GRP16 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "nopQ", { Ev } }, - /* 20 */ - { "movZ", { Rm, Cm } }, - { "movZ", { Rm, Dm } }, - { "movZ", { Cm, Rm } }, - { "movZ", { Dm, Rm } }, - { "movL", { Rd, Td } }, - { "(bad)", { XX } }, - { "movL", { Td, Rd } }, - { "(bad)", { XX } }, - /* 28 */ - { "movapX", { XM, EXx } }, - { "movapX", { EXx, XM } }, - { PREGRP2 }, - { PREGRP33 }, - { PREGRP4 }, - { PREGRP3 }, - { PREGRP93 }, - { PREGRP94 }, - /* 30 */ - { "wrmsr", { XX } }, - { "rdtsc", { XX } }, - { "rdmsr", { XX } }, - { "rdpmc", { XX } }, - { "sysenter", { XX } }, - { "sysexit", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 38 */ - { THREE_BYTE_0 }, - { "(bad)", { XX } }, - { THREE_BYTE_1 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 40 */ - { "cmovo", { Gv, Ev } }, - { "cmovno", { Gv, Ev } }, - { "cmovb", { Gv, Ev } }, - { "cmovae", { Gv, Ev } }, - { "cmove", { Gv, Ev } }, - { "cmovne", { Gv, Ev } }, - { "cmovbe", { Gv, Ev } }, - { "cmova", { Gv, Ev } }, - /* 48 */ - { "cmovs", { Gv, Ev } }, - { "cmovns", { Gv, Ev } }, - { "cmovp", { Gv, Ev } }, - { "cmovnp", { Gv, Ev } }, - { "cmovl", { Gv, Ev } }, - { "cmovge", { Gv, Ev } }, - { "cmovle", { Gv, Ev } }, - { "cmovg", { Gv, Ev } }, - /* 50 */ - { "movmskpX", { Gdq, XS } }, - { PREGRP13 }, - { PREGRP12 }, - { PREGRP11 }, - { "andpX", { XM, EXx } }, - { "andnpX", { XM, EXx } }, - { "orpX", { XM, EXx } }, - { "xorpX", { XM, EXx } }, - /* 58 */ - { PREGRP0 }, - { PREGRP10 }, - { PREGRP17 }, - { PREGRP16 }, - { PREGRP14 }, - { PREGRP7 }, - { PREGRP5 }, - { PREGRP6 }, - /* 60 */ - { PREGRP95 }, - { PREGRP96 }, - { PREGRP97 }, - { "packsswb", { MX, EM } }, - { "pcmpgtb", { MX, EM } }, - { "pcmpgtw", { MX, EM } }, - { "pcmpgtd", { MX, EM } }, - { "packuswb", { MX, EM } }, - /* 68 */ - { "punpckhbw", { MX, EM } }, - { "punpckhwd", { MX, EM } }, - { "punpckhdq", { MX, EM } }, - { "packssdw", { MX, EM } }, - { PREGRP26 }, - { PREGRP24 }, - { "movd", { MX, Edq } }, - { PREGRP19 }, - /* 70 */ - { PREGRP22 }, - { GRP12 }, - { GRP13 }, - { GRP14 }, - { "pcmpeqb", { MX, EM } }, - { "pcmpeqw", { MX, EM } }, - { "pcmpeqd", { MX, EM } }, - { "emms", { XX } }, - /* 78 */ - { PREGRP34 }, - { PREGRP35 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { PREGRP28 }, - { PREGRP29 }, - { PREGRP23 }, - { PREGRP20 }, - /* 80 */ - { "joH", { Jv, XX, cond_jump_flag } }, - { "jnoH", { Jv, XX, cond_jump_flag } }, - { "jbH", { Jv, XX, cond_jump_flag } }, - { "jaeH", { Jv, XX, cond_jump_flag } }, - { "jeH", { Jv, XX, cond_jump_flag } }, - { "jneH", { Jv, XX, cond_jump_flag } }, - { "jbeH", { Jv, XX, cond_jump_flag } }, - { "jaH", { Jv, XX, cond_jump_flag } }, - /* 88 */ - { "jsH", { Jv, XX, cond_jump_flag } }, - { "jnsH", { Jv, XX, cond_jump_flag } }, - { "jpH", { Jv, XX, cond_jump_flag } }, - { "jnpH", { Jv, XX, cond_jump_flag } }, - { "jlH", { Jv, XX, cond_jump_flag } }, - { "jgeH", { Jv, XX, cond_jump_flag } }, - { "jleH", { Jv, XX, cond_jump_flag } }, - { "jgH", { Jv, XX, cond_jump_flag } }, - /* 90 */ - { "seto", { Eb } }, - { "setno", { Eb } }, - { "setb", { Eb } }, - { "setae", { Eb } }, - { "sete", { Eb } }, - { "setne", { Eb } }, - { "setbe", { Eb } }, - { "seta", { Eb } }, - /* 98 */ - { "sets", { Eb } }, - { "setns", { Eb } }, - { "setp", { Eb } }, - { "setnp", { Eb } }, - { "setl", { Eb } }, - { "setge", { Eb } }, - { "setle", { Eb } }, - { "setg", { Eb } }, - /* a0 */ - { "pushT", { fs } }, - { "popT", { fs } }, - { "cpuid", { XX } }, - { "btS", { Ev, Gv } }, - { "shldS", { Ev, Gv, Ib } }, - { "shldS", { Ev, Gv, CL } }, - { GRPPADLCK2 }, - { GRPPADLCK1 }, - /* a8 */ - { "pushT", { gs } }, - { "popT", { gs } }, - { "rsm", { XX } }, - { "btsS", { Ev, Gv } }, - { "shrdS", { Ev, Gv, Ib } }, - { "shrdS", { Ev, Gv, CL } }, - { GRP15 }, - { "imulS", { Gv, Ev } }, - /* b0 */ - { "cmpxchgB", { Eb, Gb } }, - { "cmpxchgS", { Ev, Gv } }, - { "lssS", { Gv, Mp } }, - { "btrS", { Ev, Gv } }, - { "lfsS", { Gv, Mp } }, - { "lgsS", { Gv, Mp } }, - { "movz{bR|x|bR|x}", { Gv, Eb } }, - { "movz{wR|x|wR|x}", { Gv, Ew } }, /* yes, there really is movzww ! */ - /* b8 */ - { PREGRP37 }, - { "ud2b", { XX } }, - { GRP8 }, - { "btcS", { Ev, Gv } }, - { PREGRP107 }, - { PREGRP36 }, - { "movs{bR|x|bR|x}", { Gv, Eb } }, - { "movs{wR|x|wR|x}", { Gv, Ew } }, /* yes, there really is movsww ! */ - /* c0 */ - { "xaddB", { Eb, Gb } }, - { "xaddS", { Ev, Gv } }, - { PREGRP1 }, - { "movntiS", { Ev, Gv } }, - { "pinsrw", { MX, Edqw, Ib } }, - { "pextrw", { Gdq, MS, Ib } }, - { "shufpX", { XM, EXx, Ib } }, - { GRP9 }, - /* c8 */ - { "bswap", { RMeAX } }, - { "bswap", { RMeCX } }, - { "bswap", { RMeDX } }, - { "bswap", { RMeBX } }, - { "bswap", { RMeSP } }, - { "bswap", { RMeBP } }, - { "bswap", { RMeSI } }, - { "bswap", { RMeDI } }, - /* d0 */ - { PREGRP27 }, - { "psrlw", { MX, EM } }, - { "psrld", { MX, EM } }, - { "psrlq", { MX, EM } }, - { "paddq", { MX, EM } }, - { "pmullw", { MX, EM } }, - { PREGRP21 }, - { "pmovmskb", { Gdq, MS } }, - /* d8 */ - { "psubusb", { MX, EM } }, - { "psubusw", { MX, EM } }, - { "pminub", { MX, EM } }, - { "pand", { MX, EM } }, - { "paddusb", { MX, EM } }, - { "paddusw", { MX, EM } }, - { "pmaxub", { MX, EM } }, - { "pandn", { MX, EM } }, - /* e0 */ - { "pavgb", { MX, EM } }, - { "psraw", { MX, EM } }, - { "psrad", { MX, EM } }, - { "pavgw", { MX, EM } }, - { "pmulhuw", { MX, EM } }, - { "pmulhw", { MX, EM } }, - { PREGRP15 }, - { PREGRP25 }, - /* e8 */ - { "psubsb", { MX, EM } }, - { "psubsw", { MX, EM } }, - { "pminsw", { MX, EM } }, - { "por", { MX, EM } }, - { "paddsb", { MX, EM } }, - { "paddsw", { MX, EM } }, - { "pmaxsw", { MX, EM } }, - { "pxor", { MX, EM } }, - /* f0 */ - { PREGRP32 }, - { "psllw", { MX, EM } }, - { "pslld", { MX, EM } }, - { "psllq", { MX, EM } }, - { "pmuludq", { MX, EM } }, - { "pmaddwd", { MX, EM } }, - { "psadbw", { MX, EM } }, - { PREGRP18 }, - /* f8 */ - { "psubb", { MX, EM } }, - { "psubw", { MX, EM } }, - { "psubd", { MX, EM } }, - { "psubq", { MX, EM } }, - { "paddb", { MX, EM } }, - { "paddw", { MX, EM } }, - { "paddd", { MX, EM } }, - { "(bad)", { XX } }, -}; - -static const unsigned char onebyte_has_modrm[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 00 */ - /* 10 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 10 */ - /* 20 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 20 */ - /* 30 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 30 */ - /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40 */ - /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */ - /* 60 */ 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0, /* 60 */ - /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */ - /* 80 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 80 */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* a0 */ - /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* b0 */ - /* c0 */ 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* c0 */ - /* d0 */ 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* d0 */ - /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* e0 */ - /* f0 */ 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1 /* f0 */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -static const unsigned char twobyte_has_modrm[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1, /* 0f */ - /* 10 */ 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1, /* 1f */ - /* 20 */ 1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1, /* 2f */ - /* 30 */ 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, /* 3f */ - /* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */ - /* 50 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 5f */ - /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6f */ - /* 70 */ 1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9f */ - /* a0 */ 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, /* af */ - /* b0 */ 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1, /* bf */ - /* c0 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* df */ - /* e0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* ef */ - /* f0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -static const unsigned char twobyte_uses_DATA_prefix[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ - /* 10 */ 1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0, /* 1f */ - /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, /* 2f */ - /* 30 */ 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, /* 3f */ - /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ - /* 50 */ 0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* 5f */ - /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1, /* 6f */ - /* 70 */ 1,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ - /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ - /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */ - /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */ - /* f0 */ 1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -static const unsigned char twobyte_uses_REPNZ_prefix[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ - /* 10 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ - /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, /* 2f */ - /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ - /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ - /* 50 */ 0,1,0,0,0,0,0,0,1,1,1,0,1,1,1,1, /* 5f */ - /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ - /* 70 */ 1,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ - /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ - /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */ - /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */ - /* f0 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -static const unsigned char twobyte_uses_REPZ_prefix[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ - /* 10 */ 1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0, /* 1f */ - /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, /* 2f */ - /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ - /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ - /* 50 */ 0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* 5f */ - /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, /* 6f */ - /* 70 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ - /* b0 */ 0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0, /* bf */ - /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */ - /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */ - /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -/* This is used to determine if opcode 0f 38 XX uses DATA prefix. */ -static const unsigned char threebyte_0x38_uses_DATA_prefix[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, /* 0f */ - /* 10 */ 1,0,0,0,1,1,0,1,0,0,0,0,1,1,1,0, /* 1f */ - /* 20 */ 1,1,1,1,1,1,0,0,1,1,1,1,0,0,0,0, /* 2f */ - /* 30 */ 1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, /* 3f */ - /* 40 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ - /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ - /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ - /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ - /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ - /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1, /* df */ - /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ - /* f0 */ 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -/* This is used to determine if opcode 0f 38 XX uses REPNZ prefix. */ -static const unsigned char threebyte_0x38_uses_REPNZ_prefix[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ - /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ - /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ - /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ - /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ - /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ - /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ - /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ - /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ - /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ - /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ - /* f0 */ 1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0, /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -/* This is used to determine if opcode 0f 38 XX uses REPZ prefix. */ -static const unsigned char threebyte_0x38_uses_REPZ_prefix[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ - /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ - /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ - /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ - /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ - /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ - /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ - /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ - /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ - /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ - /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ - /* f0 */ 0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0, /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -/* This is used to determine if opcode 0f 3a XX uses DATA prefix. */ -static const unsigned char threebyte_0x3a_uses_DATA_prefix[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1, /* 0f */ - /* 10 */ 0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* 1f */ - /* 20 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ - /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ - /* 40 */ 1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ - /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ - /* 60 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ - /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ - /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ - /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, /* df */ - /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ - /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -/* This is used to determine if opcode 0f 3a XX uses REPNZ prefix. */ -static const unsigned char threebyte_0x3a_uses_REPNZ_prefix[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ - /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ - /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ - /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ - /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ - /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ - /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ - /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ - /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ - /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ - /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ - /* f0 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -/* This is used to determine if opcode 0f 3a XX uses REPZ prefix. */ -static const unsigned char threebyte_0x3a_uses_REPZ_prefix[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ------------------------------- */ - /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ - /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ - /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */ - /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ - /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ - /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ - /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ - /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ - /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ - /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ - /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ - /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ - /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ - /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ - /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */ - /* ------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -static char obuf[100]; -static char *obufp; -static char scratchbuf[100]; -static unsigned char *start_codep; -static unsigned char *insn_codep; -static unsigned char *codep; -static disassemble_info *the_info; -static struct - { - int mod; - int reg; - int rm; - } -modrm; -static unsigned char need_modrm; - -/* If we are accessing mod/rm/reg without need_modrm set, then the - values are stale. Hitting this abort likely indicates that you - need to update onebyte_has_modrm or twobyte_has_modrm. */ -#define MODRM_CHECK if (!need_modrm) abort () - -static const char * const *names64; -static const char * const *names32; -static const char * const *names16; -static const char * const *names8; -static const char * const *names8rex; -static const char * const *names_seg; -static const char * const *index16; - -static const char * const intel_names64[] = { - "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" -}; -static const char * const intel_names32[] = { - "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", - "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" -}; -static const char * const intel_names16[] = { - "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", - "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" -}; -static const char * const intel_names8[] = { - "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", -}; -static const char * const intel_names8rex[] = { - "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", - "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" -}; -static const char * const intel_names_seg[] = { - "es", "cs", "ss", "ds", "fs", "gs", "?", "?", -}; -static const char * const intel_index16[] = { - "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx" -}; - -static const char * const att_names64[] = { - "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi", - "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" -}; -static const char * const att_names32[] = { - "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi", - "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d" -}; -static const char * const att_names16[] = { - "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di", - "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w" -}; -static const char * const att_names8[] = { - "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh", -}; -static const char * const att_names8rex[] = { - "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil", - "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b" -}; -static const char * const att_names_seg[] = { - "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "%?", "%?", -}; -static const char * const att_index16[] = { - "%bx,%si", "%bx,%di", "%bp,%si", "%bp,%di", "%si", "%di", "%bp", "%bx" -}; - -static const struct dis386 grps[][8] = { - /* GRP1a */ - { - { "popU", { stackEv } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* GRP1b */ - { - { "addA", { Eb, Ib } }, - { "orA", { Eb, Ib } }, - { "adcA", { Eb, Ib } }, - { "sbbA", { Eb, Ib } }, - { "andA", { Eb, Ib } }, - { "subA", { Eb, Ib } }, - { "xorA", { Eb, Ib } }, - { "cmpA", { Eb, Ib } }, - }, - /* GRP1S */ - { - { "addQ", { Ev, Iv } }, - { "orQ", { Ev, Iv } }, - { "adcQ", { Ev, Iv } }, - { "sbbQ", { Ev, Iv } }, - { "andQ", { Ev, Iv } }, - { "subQ", { Ev, Iv } }, - { "xorQ", { Ev, Iv } }, - { "cmpQ", { Ev, Iv } }, - }, - /* GRP1Ss */ - { - { "addQ", { Ev, sIb } }, - { "orQ", { Ev, sIb } }, - { "adcQ", { Ev, sIb } }, - { "sbbQ", { Ev, sIb } }, - { "andQ", { Ev, sIb } }, - { "subQ", { Ev, sIb } }, - { "xorQ", { Ev, sIb } }, - { "cmpQ", { Ev, sIb } }, - }, - /* GRP2b */ - { - { "rolA", { Eb, Ib } }, - { "rorA", { Eb, Ib } }, - { "rclA", { Eb, Ib } }, - { "rcrA", { Eb, Ib } }, - { "shlA", { Eb, Ib } }, - { "shrA", { Eb, Ib } }, - { "(bad)", { XX } }, - { "sarA", { Eb, Ib } }, - }, - /* GRP2S */ - { - { "rolQ", { Ev, Ib } }, - { "rorQ", { Ev, Ib } }, - { "rclQ", { Ev, Ib } }, - { "rcrQ", { Ev, Ib } }, - { "shlQ", { Ev, Ib } }, - { "shrQ", { Ev, Ib } }, - { "(bad)", { XX } }, - { "sarQ", { Ev, Ib } }, - }, - /* GRP2b_one */ - { - { "rolA", { Eb, I1 } }, - { "rorA", { Eb, I1 } }, - { "rclA", { Eb, I1 } }, - { "rcrA", { Eb, I1 } }, - { "shlA", { Eb, I1 } }, - { "shrA", { Eb, I1 } }, - { "(bad)", { XX } }, - { "sarA", { Eb, I1 } }, - }, - /* GRP2S_one */ - { - { "rolQ", { Ev, I1 } }, - { "rorQ", { Ev, I1 } }, - { "rclQ", { Ev, I1 } }, - { "rcrQ", { Ev, I1 } }, - { "shlQ", { Ev, I1 } }, - { "shrQ", { Ev, I1 } }, - { "(bad)", { XX } }, - { "sarQ", { Ev, I1 } }, - }, - /* GRP2b_cl */ - { - { "rolA", { Eb, CL } }, - { "rorA", { Eb, CL } }, - { "rclA", { Eb, CL } }, - { "rcrA", { Eb, CL } }, - { "shlA", { Eb, CL } }, - { "shrA", { Eb, CL } }, - { "(bad)", { XX } }, - { "sarA", { Eb, CL } }, - }, - /* GRP2S_cl */ - { - { "rolQ", { Ev, CL } }, - { "rorQ", { Ev, CL } }, - { "rclQ", { Ev, CL } }, - { "rcrQ", { Ev, CL } }, - { "shlQ", { Ev, CL } }, - { "shrQ", { Ev, CL } }, - { "(bad)", { XX } }, - { "sarQ", { Ev, CL } }, - }, - /* GRP3b */ - { - { "testA", { Eb, Ib } }, - { "(bad)", { Eb } }, - { "notA", { Eb } }, - { "negA", { Eb } }, - { "mulA", { Eb } }, /* Don't print the implicit %al register, */ - { "imulA", { Eb } }, /* to distinguish these opcodes from other */ - { "divA", { Eb } }, /* mul/imul opcodes. Do the same for div */ - { "idivA", { Eb } }, /* and idiv for consistency. */ - }, - /* GRP3S */ - { - { "testQ", { Ev, Iv } }, - { "(bad)", { XX } }, - { "notQ", { Ev } }, - { "negQ", { Ev } }, - { "mulQ", { Ev } }, /* Don't print the implicit register. */ - { "imulQ", { Ev } }, - { "divQ", { Ev } }, - { "idivQ", { Ev } }, - }, - /* GRP4 */ - { - { "incA", { Eb } }, - { "decA", { Eb } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* GRP5 */ - { - { "incQ", { Ev } }, - { "decQ", { Ev } }, - { "callT", { indirEv } }, - { "JcallT", { indirEp } }, - { "jmpT", { indirEv } }, - { "JjmpT", { indirEp } }, - { "pushU", { stackEv } }, - { "(bad)", { XX } }, - }, - /* GRP6 */ - { - { "sldtD", { Sv } }, - { "strD", { Sv } }, - { "lldt", { Ew } }, - { "ltr", { Ew } }, - { "verr", { Ew } }, - { "verw", { Ew } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* GRP7 */ - { - { "sgdt{Q|IQ||}", { { VMX_Fixup, 0 } } }, - { "sidt{Q|IQ||}", { { PNI_Fixup, 0 } } }, - { "lgdt{Q|Q||}", { M } }, - { "lidt{Q|Q||}", { { SVME_Fixup, 0 } } }, - { "smswD", { Sv } }, - { "(bad)", { XX } }, - { "lmsw", { Ew } }, - { "invlpg", { { INVLPG_Fixup, w_mode } } }, - }, - /* GRP8 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "btQ", { Ev, Ib } }, - { "btsQ", { Ev, Ib } }, - { "btrQ", { Ev, Ib } }, - { "btcQ", { Ev, Ib } }, - }, - /* GRP9 */ - { - { "(bad)", { XX } }, - { "cmpxchg8b", { { CMPXCHG8B_Fixup, q_mode } } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "", { VM } }, /* See OP_VMX. */ - { "vmptrst", { Mq } }, - }, - /* GRP11_C6 */ - { - { "movA", { Eb, Ib } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* GRP11_C7 */ - { - { "movQ", { Ev, Iv } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* GRP12 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "psrlw", { MS, Ib } }, - { "(bad)", { XX } }, - { "psraw", { MS, Ib } }, - { "(bad)", { XX } }, - { "psllw", { MS, Ib } }, - { "(bad)", { XX } }, - }, - /* GRP13 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "psrld", { MS, Ib } }, - { "(bad)", { XX } }, - { "psrad", { MS, Ib } }, - { "(bad)", { XX } }, - { "pslld", { MS, Ib } }, - { "(bad)", { XX } }, - }, - /* GRP14 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "psrlq", { MS, Ib } }, - { "psrldq", { MS, Ib } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "psllq", { MS, Ib } }, - { "pslldq", { MS, Ib } }, - }, - /* GRP15 */ - { - { "fxsave", { Ev } }, - { "fxrstor", { Ev } }, - { "ldmxcsr", { Ev } }, - { "stmxcsr", { Ev } }, - { "(bad)", { XX } }, - { "lfence", { { OP_0fae, 0 } } }, - { "mfence", { { OP_0fae, 0 } } }, - { "clflush", { { OP_0fae, 0 } } }, - }, - /* GRP16 */ - { - { "prefetchnta", { Ev } }, - { "prefetcht0", { Ev } }, - { "prefetcht1", { Ev } }, - { "prefetcht2", { Ev } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* GRPAMD */ - { - { "prefetch", { Eb } }, - { "prefetchw", { Eb } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* GRPPADLCK1 */ - { - { "xstore-rng", { { OP_0f07, 0 } } }, - { "xcrypt-ecb", { { OP_0f07, 0 } } }, - { "xcrypt-cbc", { { OP_0f07, 0 } } }, - { "xcrypt-ctr", { { OP_0f07, 0 } } }, - { "xcrypt-cfb", { { OP_0f07, 0 } } }, - { "xcrypt-ofb", { { OP_0f07, 0 } } }, - { "(bad)", { { OP_0f07, 0 } } }, - { "(bad)", { { OP_0f07, 0 } } }, - }, - /* GRPPADLCK2 */ - { - { "montmul", { { OP_0f07, 0 } } }, - { "xsha1", { { OP_0f07, 0 } } }, - { "xsha256", { { OP_0f07, 0 } } }, - { "(bad)", { { OP_0f07, 0 } } }, - { "(bad)", { { OP_0f07, 0 } } }, - { "(bad)", { { OP_0f07, 0 } } }, - { "(bad)", { { OP_0f07, 0 } } }, - { "(bad)", { { OP_0f07, 0 } } }, - } -}; - -static const struct dis386 prefix_user_table[][4] = { - /* PREGRP0 */ - { - { "addps", { XM, EXx } }, - { "addss", { XM, EXd } }, - { "addpd", { XM, EXx } }, - { "addsd", { XM, EXq } }, - }, - /* PREGRP1 */ - { - { "", { XM, EXx, OPSIMD } }, /* See OP_SIMD_SUFFIX. */ - { "", { XM, EXx, OPSIMD } }, - { "", { XM, EXx, OPSIMD } }, - { "", { XM, EXx, OPSIMD } }, - }, - /* PREGRP2 */ - { - { "cvtpi2ps", { XM, EMC } }, - { "cvtsi2ssY", { XM, Ev } }, - { "cvtpi2pd", { XM, EMC } }, - { "cvtsi2sdY", { XM, Ev } }, - }, - /* PREGRP3 */ - { - { "cvtps2pi", { MXC, EXx } }, - { "cvtss2siY", { Gv, EXx } }, - { "cvtpd2pi", { MXC, EXx } }, - { "cvtsd2siY", { Gv, EXx } }, - }, - /* PREGRP4 */ - { - { "cvttps2pi", { MXC, EXx } }, - { "cvttss2siY", { Gv, EXx } }, - { "cvttpd2pi", { MXC, EXx } }, - { "cvttsd2siY", { Gv, EXx } }, - }, - /* PREGRP5 */ - { - { "divps", { XM, EXx } }, - { "divss", { XM, EXx } }, - { "divpd", { XM, EXx } }, - { "divsd", { XM, EXx } }, - }, - /* PREGRP6 */ - { - { "maxps", { XM, EXx } }, - { "maxss", { XM, EXx } }, - { "maxpd", { XM, EXx } }, - { "maxsd", { XM, EXx } }, - }, - /* PREGRP7 */ - { - { "minps", { XM, EXx } }, - { "minss", { XM, EXx } }, - { "minpd", { XM, EXx } }, - { "minsd", { XM, EXx } }, - }, - /* PREGRP8 */ - { - { "movups", { XM, EXx } }, - { "movss", { XM, EXx } }, - { "movupd", { XM, EXx } }, - { "movsd", { XM, EXx } }, - }, - /* PREGRP9 */ - { - { "movups", { EXx, XM } }, - { "movss", { EXx, XM } }, - { "movupd", { EXx, XM } }, - { "movsd", { EXx, XM } }, - }, - /* PREGRP10 */ - { - { "mulps", { XM, EXx } }, - { "mulss", { XM, EXx } }, - { "mulpd", { XM, EXx } }, - { "mulsd", { XM, EXx } }, - }, - /* PREGRP11 */ - { - { "rcpps", { XM, EXx } }, - { "rcpss", { XM, EXx } }, - { "(bad)", { XM, EXx } }, - { "(bad)", { XM, EXx } }, - }, - /* PREGRP12 */ - { - { "rsqrtps",{ XM, EXx } }, - { "rsqrtss",{ XM, EXx } }, - { "(bad)", { XM, EXx } }, - { "(bad)", { XM, EXx } }, - }, - /* PREGRP13 */ - { - { "sqrtps", { XM, EXx } }, - { "sqrtss", { XM, EXx } }, - { "sqrtpd", { XM, EXx } }, - { "sqrtsd", { XM, EXx } }, - }, - /* PREGRP14 */ - { - { "subps", { XM, EXx } }, - { "subss", { XM, EXx } }, - { "subpd", { XM, EXx } }, - { "subsd", { XM, EXx } }, - }, - /* PREGRP15 */ - { - { "(bad)", { XM, EXx } }, - { "cvtdq2pd", { XM, EXq } }, - { "cvttpd2dq", { XM, EXx } }, - { "cvtpd2dq", { XM, EXx } }, - }, - /* PREGRP16 */ - { - { "cvtdq2ps", { XM, EXx } }, - { "cvttps2dq", { XM, EXx } }, - { "cvtps2dq", { XM, EXx } }, - { "(bad)", { XM, EXx } }, - }, - /* PREGRP17 */ - { - { "cvtps2pd", { XM, EXq } }, - { "cvtss2sd", { XM, EXx } }, - { "cvtpd2ps", { XM, EXx } }, - { "cvtsd2ss", { XM, EXx } }, - }, - /* PREGRP18 */ - { - { "maskmovq", { MX, MS } }, - { "(bad)", { XM, EXx } }, - { "maskmovdqu", { XM, XS } }, - { "(bad)", { XM, EXx } }, - }, - /* PREGRP19 */ - { - { "movq", { MX, EM } }, - { "movdqu", { XM, EXx } }, - { "movdqa", { XM, EXx } }, - { "(bad)", { XM, EXx } }, - }, - /* PREGRP20 */ - { - { "movq", { EM, MX } }, - { "movdqu", { EXx, XM } }, - { "movdqa", { EXx, XM } }, - { "(bad)", { EXx, XM } }, - }, - /* PREGRP21 */ - { - { "(bad)", { EXx, XM } }, - { "movq2dq",{ XM, MS } }, - { "movq", { EXx, XM } }, - { "movdq2q",{ MX, XS } }, - }, - /* PREGRP22 */ - { - { "pshufw", { MX, EM, Ib } }, - { "pshufhw",{ XM, EXx, Ib } }, - { "pshufd", { XM, EXx, Ib } }, - { "pshuflw",{ XM, EXx, Ib } }, - }, - /* PREGRP23 */ - { - { "movd", { Edq, MX } }, - { "movq", { XM, EXx } }, - { "movd", { Edq, XM } }, - { "(bad)", { Ed, XM } }, - }, - /* PREGRP24 */ - { - { "(bad)", { MX, EXx } }, - { "(bad)", { XM, EXx } }, - { "punpckhqdq", { XM, EXx } }, - { "(bad)", { XM, EXx } }, - }, - /* PREGRP25 */ - { - { "movntq", { EM, MX } }, - { "(bad)", { EM, XM } }, - { "movntdq",{ EM, XM } }, - { "(bad)", { EM, XM } }, - }, - /* PREGRP26 */ - { - { "(bad)", { MX, EXx } }, - { "(bad)", { XM, EXx } }, - { "punpcklqdq", { XM, EXx } }, - { "(bad)", { XM, EXx } }, - }, - /* PREGRP27 */ - { - { "(bad)", { MX, EXx } }, - { "(bad)", { XM, EXx } }, - { "addsubpd", { XM, EXx } }, - { "addsubps", { XM, EXx } }, - }, - /* PREGRP28 */ - { - { "(bad)", { MX, EXx } }, - { "(bad)", { XM, EXx } }, - { "haddpd", { XM, EXx } }, - { "haddps", { XM, EXx } }, - }, - /* PREGRP29 */ - { - { "(bad)", { MX, EXx } }, - { "(bad)", { XM, EXx } }, - { "hsubpd", { XM, EXx } }, - { "hsubps", { XM, EXx } }, - }, - /* PREGRP30 */ - { - { "movlpX", { XM, EXq, { SIMD_Fixup, 'h' } } }, /* really only 2 operands */ - { "movsldup", { XM, EXx } }, - { "movlpd", { XM, EXq } }, - { "movddup", { XM, EXq } }, - }, - /* PREGRP31 */ - { - { "movhpX", { XM, EXq, { SIMD_Fixup, 'l' } } }, - { "movshdup", { XM, EXx } }, - { "movhpd", { XM, EXq } }, - { "(bad)", { XM, EXq } }, - }, - /* PREGRP32 */ - { - { "(bad)", { XM, EXx } }, - { "(bad)", { XM, EXx } }, - { "(bad)", { XM, EXx } }, - { "lddqu", { XM, M } }, - }, - /* PREGRP33 */ - { - {"movntps", { Ev, XM } }, - {"movntss", { Ev, XM } }, - {"movntpd", { Ev, XM } }, - {"movntsd", { Ev, XM } }, - }, - - /* PREGRP34 */ - { - {"vmread", { Em, Gm } }, - {"(bad)", { XX } }, - {"extrq", { XS, Ib, Ib } }, - {"insertq", { XM, XS, Ib, Ib } }, - }, - - /* PREGRP35 */ - { - {"vmwrite", { Gm, Em } }, - {"(bad)", { XX } }, - {"extrq", { XM, XS } }, - {"insertq", { XM, XS } }, - }, - - /* PREGRP36 */ - { - { "bsrS", { Gv, Ev } }, - { "lzcntS", { Gv, Ev } }, - { "bsrS", { Gv, Ev } }, - { "(bad)", { XX } }, - }, - - /* PREGRP37 */ - { - { "(bad)", { XX } }, - { "popcntS", { Gv, Ev } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - - /* PREGRP38 */ - { - { "xchgS", { { NOP_Fixup1, eAX_reg }, { NOP_Fixup2, eAX_reg } } }, - { "pause", { XX } }, - { "xchgS", { { NOP_Fixup1, eAX_reg }, { NOP_Fixup2, eAX_reg } } }, - { "(bad)", { XX } }, - }, - - /* PREGRP39 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pblendvb", {XM, EXx, XMM0 } }, - { "(bad)", { XX } }, - }, - - /* PREGRP40 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "blendvps", {XM, EXx, XMM0 } }, - { "(bad)", { XX } }, - }, - - /* PREGRP41 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "blendvpd", { XM, EXx, XMM0 } }, - { "(bad)", { XX } }, - }, - - /* PREGRP42 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "ptest", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP43 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovsxbw", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP44 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovsxbd", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP45 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovsxbq", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP46 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovsxwd", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP47 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovsxwq", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP48 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovsxdq", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP49 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmuldq", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP50 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pcmpeqq", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP51 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "movntdqa", { XM, EM } }, - { "(bad)", { XX } }, - }, - - /* PREGRP52 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "packusdw", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP53 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovzxbw", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP54 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovzxbd", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP55 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovzxbq", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP56 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovzxwd", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP57 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovzxwq", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP58 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmovzxdq", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP59 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pminsb", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP60 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pminsd", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP61 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pminuw", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP62 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pminud", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP63 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmaxsb", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP64 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmaxsd", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP65 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmaxuw", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP66 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmaxud", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP67 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pmulld", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP68 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "phminposuw", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP69 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "roundps", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP70 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "roundpd", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP71 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "roundss", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP72 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "roundsd", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP73 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "blendps", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP74 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "blendpd", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP75 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pblendw", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP76 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pextrb", { Edqb, XM, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP77 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pextrw", { Edqw, XM, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP78 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pextrK", { Edq, XM, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP79 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "extractps", { Edqd, XM, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP80 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pinsrb", { XM, Edqb, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP81 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "insertps", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP82 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pinsrK", { XM, Edq, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP83 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "dpps", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP84 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "dppd", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP85 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "mpsadbw", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP86 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pcmpgtq", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP87 */ - { - { "movbe", { Gv, Ev } }, - { "(bad)", { XX } }, - { "movbe", { Gv, Ev } }, - { "crc32", { Gdq, { CRC32_Fixup, b_mode } } }, - }, - - /* PREGRP88 */ - { - { "movbe", { Ev, Gv } }, - { "(bad)", { XX } }, - { "movbe", { Ev, Gv } }, - { "crc32", { Gdq, { CRC32_Fixup, v_mode } } }, - }, - - /* PREGRP89 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pcmpestrm", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP90 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pcmpestri", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP91 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pcmpistrm", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP92 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pcmpistri", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP93 */ - { - { "ucomiss",{ XM, EXd } }, - { "(bad)", { XX } }, - { "ucomisd",{ XM, EXq } }, - { "(bad)", { XX } }, - }, - - /* PREGRP94 */ - { - { "comiss", { XM, EXd } }, - { "(bad)", { XX } }, - { "comisd", { XM, EXq } }, - { "(bad)", { XX } }, - }, - - /* PREGRP95 */ - { - { "punpcklbw",{ MX, EMd } }, - { "(bad)", { XX } }, - { "punpcklbw",{ MX, EMq } }, - { "(bad)", { XX } }, - }, - - /* PREGRP96 */ - { - { "punpcklwd",{ MX, EMd } }, - { "(bad)", { XX } }, - { "punpcklwd",{ MX, EMq } }, - { "(bad)", { XX } }, - }, - - /* PREGRP97 */ - { - { "punpckldq",{ MX, EMd } }, - { "(bad)", { XX } }, - { "punpckldq",{ MX, EMq } }, - { "(bad)", { XX } }, - }, - - /* PREGRP98 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pclmulqdq", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP99 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "aesimc", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP100 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "aesenc", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP101 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "aesenclast", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP102 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "aesdec", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP103 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "aesdeclast", { XM, EXx } }, - { "(bad)", { XX } }, - }, - - /* PREGRP104 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "aeskeygenassist", { XM, EXx, Ib } }, - { "(bad)", { XX } }, - }, - - /* PREGRP105 */ - { - { "andnS", { Gv, Bv, Ev } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - - /* PREGRP106 */ - { - { "bextrS", { Gv, Ev, Bv } }, - { "sarxS", { Gv, Ev, Bv } }, - { "shlxS", { Gv, Ev, Bv } }, - { "shrxS", { Gv, Ev, Bv } }, - }, - - /* PREGRP107 */ - { - { "bsfS", { Gv, Ev } }, - { "tzcntS", { Gv, Ev } }, - { "bsfS", { Gv, Ev } }, - { "(bad)", { XX } }, - }, - - /* PREGRP108 */ - { - { "bzhi", { Gv, Ev, Bv } }, - { "pext", { Gv, Bv, Ev } }, - { "(bad)", { XX } }, - { "pdep", { Gv, Bv, Ev } }, - }, - - /* PREGRP109 */ - { - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "rorx", { Gv, Ev, Ib } }, - }, -}; - -static const struct dis386 x86_64_table[][2] = { - { - { "pusha{P|}", { XX } }, - { "(bad)", { XX } }, - }, - { - { "popa{P|}", { XX } }, - { "(bad)", { XX } }, - }, - { - { "bound{S|}", { Gv, Ma } }, - { "(bad)", { XX } }, - }, - { - { "arpl", { Ew, Gw } }, - { "movs{||lq|xd}", { Gv, Ed } }, - }, -}; - -static const struct dis386 three_byte_table[][256] = { - /* THREE_BYTE_0 */ - { - /* 00 */ - { "pshufb", { MX, EM } }, - { "phaddw", { MX, EM } }, - { "phaddd", { MX, EM } }, - { "phaddsw", { MX, EM } }, - { "pmaddubsw", { MX, EM } }, - { "phsubw", { MX, EM } }, - { "phsubd", { MX, EM } }, - { "phsubsw", { MX, EM } }, - /* 08 */ - { "psignb", { MX, EM } }, - { "psignw", { MX, EM } }, - { "psignd", { MX, EM } }, - { "pmulhrsw", { MX, EM } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 10 */ - { PREGRP39 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { PREGRP40 }, - { PREGRP41 }, - { "(bad)", { XX } }, - { PREGRP42 }, - /* 18 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "pabsb", { MX, EM } }, - { "pabsw", { MX, EM } }, - { "pabsd", { MX, EM } }, - { "(bad)", { XX } }, - /* 20 */ - { PREGRP43 }, - { PREGRP44 }, - { PREGRP45 }, - { PREGRP46 }, - { PREGRP47 }, - { PREGRP48 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 28 */ - { PREGRP49 }, - { PREGRP50 }, - { PREGRP51 }, - { PREGRP52 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 30 */ - { PREGRP53 }, - { PREGRP54 }, - { PREGRP55 }, - { PREGRP56 }, - { PREGRP57 }, - { PREGRP58 }, - { "(bad)", { XX } }, - { PREGRP86 }, - /* 38 */ - { PREGRP59 }, - { PREGRP60 }, - { PREGRP61 }, - { PREGRP62 }, - { PREGRP63 }, - { PREGRP64 }, - { PREGRP65 }, - { PREGRP66 }, - /* 40 */ - { PREGRP67 }, - { PREGRP68 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 48 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 50 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 58 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 60 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 68 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 70 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 78 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 80 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 88 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 90 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 98 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* a0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* a8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* b0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* b8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* c0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* c8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* d0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* d8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { PREGRP99 }, - { PREGRP100 }, - { PREGRP101 }, - { PREGRP102 }, - { PREGRP103 }, - /* e0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* e8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* f0 */ - { PREGRP87 }, - { PREGRP88 }, - { PREGRP105 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { PREGRP108 }, - { "(bad)", { XX } }, - { PREGRP106 }, - /* f8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* THREE_BYTE_1 */ - { - /* 00 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 08 */ - { PREGRP69 }, - { PREGRP70 }, - { PREGRP71 }, - { PREGRP72 }, - { PREGRP73 }, - { PREGRP74 }, - { PREGRP75 }, - { "palignr", { MX, EM, Ib } }, - /* 10 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { PREGRP76 }, - { PREGRP77 }, - { PREGRP78 }, - { PREGRP79 }, - /* 18 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 20 */ - { PREGRP80 }, - { PREGRP81 }, - { PREGRP82 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 28 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 30 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 38 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 40 */ - { PREGRP83 }, - { PREGRP84 }, - { PREGRP85 }, - { "(bad)", { XX } }, - { PREGRP98 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 48 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 50 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 58 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 60 */ - { PREGRP89 }, - { PREGRP90 }, - { PREGRP91 }, - { PREGRP92 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 68 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 70 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 78 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 80 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 88 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 90 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* 98 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* a0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* a8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* b0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* b8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* c0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* c8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* d0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* d8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { PREGRP104 }, - /* e0 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* e8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* f0 */ - { PREGRP109 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - /* f8 */ - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - } -}; - -#define INTERNAL_DISASSEMBLER_ERROR "" - -static void -ckprefix (void) -{ - int newrex; - rex = 0; - prefixes = 0; - used_prefixes = 0; - rex_used = 0; - while (1) - { - fetch_data(the_info, codep + 1); - newrex = 0; - switch (*codep) - { - /* REX prefixes family. */ - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4a: - case 0x4b: - case 0x4c: - case 0x4d: - case 0x4e: - case 0x4f: - if (address_mode == mode_64bit) - newrex = *codep; - else - return; - break; - case 0xf3: - prefixes |= PREFIX_REPZ; - break; - case 0xf2: - prefixes |= PREFIX_REPNZ; - break; - case 0xf0: - prefixes |= PREFIX_LOCK; - break; - case 0x2e: - prefixes |= PREFIX_CS; - break; - case 0x36: - prefixes |= PREFIX_SS; - break; - case 0x3e: - prefixes |= PREFIX_DS; - break; - case 0x26: - prefixes |= PREFIX_ES; - break; - case 0x64: - prefixes |= PREFIX_FS; - break; - case 0x65: - prefixes |= PREFIX_GS; - break; - case 0x66: - prefixes |= PREFIX_DATA; - break; - case 0x67: - prefixes |= PREFIX_ADDR; - break; - case FWAIT_OPCODE: - /* fwait is really an instruction. If there are prefixes - before the fwait, they belong to the fwait, *not* to the - following instruction. */ - if (prefixes || rex) - { - prefixes |= PREFIX_FWAIT; - codep++; - return; - } - prefixes = PREFIX_FWAIT; - break; - default: - return; - } - /* Rex is ignored when followed by another prefix. */ - if (rex) - { - rex_used = rex; - return; - } - rex = newrex; - codep++; - } -} - -static void -ckvexprefix (void) -{ - int op, vex2, vex3, newrex = 0, newpfx = prefixes; - - if (address_mode == mode_16bit) { - return; - } - - fetch_data(the_info, codep + 1); - op = *codep; - - if (op != 0xc4 && op != 0xc5) { - return; - } - - fetch_data(the_info, codep + 2); - vex2 = codep[1]; - - if (address_mode == mode_32bit && (vex2 & 0xc0) != 0xc0) { - return; - } - - if (op == 0xc4) { - /* Three byte VEX prefix. */ - fetch_data(the_info, codep + 3); - vex3 = codep[2]; - - newrex |= (vex2 & 0x80 ? 0 : REX_R); - newrex |= (vex2 & 0x40 ? 0 : REX_X); - newrex |= (vex2 & 0x20 ? 0 : REX_B); - newrex |= (vex3 & 0x80 ? REX_W : 0); - switch (vex2 & 0x1f) { /* VEX.m-mmmm */ - case 1: - newpfx |= PREFIX_VEX_0F; - break; - case 2: - newpfx |= PREFIX_VEX_0F | PREFIX_VEX_0F38; - break; - case 3: - newpfx |= PREFIX_VEX_0F | PREFIX_VEX_0F3A; - break; - } - vex2 = vex3; - codep += 3; - } else { - /* Two byte VEX prefix. */ - newrex |= (vex2 & 0x80 ? 0 : REX_R); - newpfx |= PREFIX_VEX_0F; - codep += 2; - } - - vex_reg = (~vex2 >> 3) & 15; /* VEX.vvvv */ - switch (vex2 & 3) { /* VEX.pp */ - case 1: - newpfx |= PREFIX_DATA; /* 0x66 */ - break; - case 2: - newpfx |= PREFIX_REPZ; /* 0xf3 */ - break; - case 3: - newpfx |= PREFIX_REPNZ; /* 0xf2 */ - break; - } - - rex = newrex; - prefixes = newpfx; -} - -/* Return the name of the prefix byte PREF, or NULL if PREF is not a - prefix byte. */ - -static const char * -prefix_name (int pref, int sizeflag) -{ - static const char * const rexes [16] = - { - "rex", /* 0x40 */ - "rex.B", /* 0x41 */ - "rex.X", /* 0x42 */ - "rex.XB", /* 0x43 */ - "rex.R", /* 0x44 */ - "rex.RB", /* 0x45 */ - "rex.RX", /* 0x46 */ - "rex.RXB", /* 0x47 */ - "rex.W", /* 0x48 */ - "rex.WB", /* 0x49 */ - "rex.WX", /* 0x4a */ - "rex.WXB", /* 0x4b */ - "rex.WR", /* 0x4c */ - "rex.WRB", /* 0x4d */ - "rex.WRX", /* 0x4e */ - "rex.WRXB", /* 0x4f */ - }; - - switch (pref) - { - /* REX prefixes family. */ - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4a: - case 0x4b: - case 0x4c: - case 0x4d: - case 0x4e: - case 0x4f: - return rexes [pref - 0x40]; - case 0xf3: - return "repz"; - case 0xf2: - return "repnz"; - case 0xf0: - return "lock"; - case 0x2e: - return "cs"; - case 0x36: - return "ss"; - case 0x3e: - return "ds"; - case 0x26: - return "es"; - case 0x64: - return "fs"; - case 0x65: - return "gs"; - case 0x66: - return (sizeflag & DFLAG) ? "data16" : "data32"; - case 0x67: - if (address_mode == mode_64bit) - return (sizeflag & AFLAG) ? "addr32" : "addr64"; - else - return (sizeflag & AFLAG) ? "addr16" : "addr32"; - case FWAIT_OPCODE: - return "fwait"; - default: - return NULL; - } -} - -static char op_out[MAX_OPERANDS][100]; -static int op_ad, op_index[MAX_OPERANDS]; -static int two_source_ops; -static bfd_vma op_address[MAX_OPERANDS]; -static bfd_vma op_riprel[MAX_OPERANDS]; -static bfd_vma start_pc; - -/* - * On the 386's of 1988, the maximum length of an instruction is 15 bytes. - * (see topic "Redundant prefixes" in the "Differences from 8086" - * section of the "Virtual 8086 Mode" chapter.) - * 'pc' should be the address of this instruction, it will - * be used to print the target address if this is a relative jump or call - * The function returns the length of this instruction in bytes. - */ - -static char intel_syntax; -static char open_char; -static char close_char; -static char separator_char; -static char scale_char; - -int -print_insn_i386 (bfd_vma pc, disassemble_info *info) -{ - intel_syntax = -1; - - return print_insn (pc, info); -} - -static int -print_insn (bfd_vma pc, disassemble_info *info) -{ - const struct dis386 *dp; - int i; - char *op_txt[MAX_OPERANDS]; - int needcomma; - unsigned char uses_DATA_prefix, uses_LOCK_prefix; - unsigned char uses_REPNZ_prefix, uses_REPZ_prefix; - int sizeflag; - const char *p; - struct dis_private priv; - unsigned char op; - unsigned char threebyte; - - if (info->mach == bfd_mach_x86_64_intel_syntax - || info->mach == bfd_mach_x86_64) - address_mode = mode_64bit; - else - address_mode = mode_32bit; - - if (intel_syntax == (char) -1) - intel_syntax = (info->mach == bfd_mach_i386_i386_intel_syntax - || info->mach == bfd_mach_x86_64_intel_syntax); - - if (info->mach == bfd_mach_i386_i386 - || info->mach == bfd_mach_x86_64 - || info->mach == bfd_mach_i386_i386_intel_syntax - || info->mach == bfd_mach_x86_64_intel_syntax) - priv.orig_sizeflag = AFLAG | DFLAG; - else if (info->mach == bfd_mach_i386_i8086) - priv.orig_sizeflag = 0; - else - abort (); - - for (p = info->disassembler_options; p != NULL; ) - { - if (strncmp (p, "x86-64", 6) == 0) - { - address_mode = mode_64bit; - priv.orig_sizeflag = AFLAG | DFLAG; - } - else if (strncmp (p, "i386", 4) == 0) - { - address_mode = mode_32bit; - priv.orig_sizeflag = AFLAG | DFLAG; - } - else if (strncmp (p, "i8086", 5) == 0) - { - address_mode = mode_16bit; - priv.orig_sizeflag = 0; - } - else if (strncmp (p, "intel", 5) == 0) - { - intel_syntax = 1; - } - else if (strncmp (p, "att", 3) == 0) - { - intel_syntax = 0; - } - else if (strncmp (p, "addr", 4) == 0) - { - if (address_mode == mode_64bit) - { - if (p[4] == '3' && p[5] == '2') - priv.orig_sizeflag &= ~AFLAG; - else if (p[4] == '6' && p[5] == '4') - priv.orig_sizeflag |= AFLAG; - } - else - { - if (p[4] == '1' && p[5] == '6') - priv.orig_sizeflag &= ~AFLAG; - else if (p[4] == '3' && p[5] == '2') - priv.orig_sizeflag |= AFLAG; - } - } - else if (strncmp (p, "data", 4) == 0) - { - if (p[4] == '1' && p[5] == '6') - priv.orig_sizeflag &= ~DFLAG; - else if (p[4] == '3' && p[5] == '2') - priv.orig_sizeflag |= DFLAG; - } - else if (strncmp (p, "suffix", 6) == 0) - priv.orig_sizeflag |= SUFFIX_ALWAYS; - - p = strchr (p, ','); - if (p != NULL) - p++; - } - - if (intel_syntax) - { - names64 = intel_names64; - names32 = intel_names32; - names16 = intel_names16; - names8 = intel_names8; - names8rex = intel_names8rex; - names_seg = intel_names_seg; - index16 = intel_index16; - open_char = '['; - close_char = ']'; - separator_char = '+'; - scale_char = '*'; - } - else - { - names64 = att_names64; - names32 = att_names32; - names16 = att_names16; - names8 = att_names8; - names8rex = att_names8rex; - names_seg = att_names_seg; - index16 = att_index16; - open_char = '('; - close_char = ')'; - separator_char = ','; - scale_char = ','; - } - - /* The output looks better if we put 7 bytes on a line, since that - puts most long word instructions on a single line. */ - info->bytes_per_line = 7; - - info->private_data = &priv; - priv.max_fetched = priv.the_buffer; - priv.insn_start = pc; - - obuf[0] = 0; - for (i = 0; i < MAX_OPERANDS; ++i) - { - op_out[i][0] = 0; - op_index[i] = -1; - } - - the_info = info; - start_pc = pc; - start_codep = priv.the_buffer; - codep = priv.the_buffer; - - if (sigsetjmp(priv.bailout, 0) != 0) - { - const char *name; - - /* Getting here means we tried for data but didn't get it. That - means we have an incomplete instruction of some sort. Just - print the first byte as a prefix or a .byte pseudo-op. */ - if (codep > priv.the_buffer) - { - name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); - if (name != NULL) - (*info->fprintf_func) (info->stream, "%s", name); - else - { - /* Just print the first byte as a .byte instruction. */ - (*info->fprintf_func) (info->stream, ".byte 0x%x", - (unsigned int) priv.the_buffer[0]); - } - - return 1; - } - - return -1; - } - - obufp = obuf; - ckprefix (); - ckvexprefix (); - - insn_codep = codep; - sizeflag = priv.orig_sizeflag; - - fetch_data(info, codep + 1); - two_source_ops = (*codep == 0x62) || (*codep == 0xc8); - - if (((prefixes & PREFIX_FWAIT) - && ((*codep < 0xd8) || (*codep > 0xdf))) - || (rex && rex_used)) - { - const char *name; - - /* fwait not followed by floating point instruction, or rex followed - by other prefixes. Print the first prefix. */ - name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); - if (name == NULL) - name = INTERNAL_DISASSEMBLER_ERROR; - (*info->fprintf_func) (info->stream, "%s", name); - return 1; - } - - op = 0; - if (prefixes & PREFIX_VEX_0F) - { - used_prefixes |= PREFIX_VEX_0F | PREFIX_VEX_0F38 | PREFIX_VEX_0F3A; - if (prefixes & PREFIX_VEX_0F38) - threebyte = 0x38; - else if (prefixes & PREFIX_VEX_0F3A) - threebyte = 0x3a; - else - threebyte = *codep++; - goto vex_opcode; - } - if (*codep == 0x0f) - { - fetch_data(info, codep + 2); - threebyte = codep[1]; - codep += 2; - vex_opcode: - dp = &dis386_twobyte[threebyte]; - need_modrm = twobyte_has_modrm[threebyte]; - uses_DATA_prefix = twobyte_uses_DATA_prefix[threebyte]; - uses_REPNZ_prefix = twobyte_uses_REPNZ_prefix[threebyte]; - uses_REPZ_prefix = twobyte_uses_REPZ_prefix[threebyte]; - uses_LOCK_prefix = (threebyte & ~0x02) == 0x20; - if (dp->name == NULL && dp->op[0].bytemode == IS_3BYTE_OPCODE) - { - fetch_data(info, codep + 2); - op = *codep++; - switch (threebyte) - { - case 0x38: - uses_DATA_prefix = threebyte_0x38_uses_DATA_prefix[op]; - uses_REPNZ_prefix = threebyte_0x38_uses_REPNZ_prefix[op]; - uses_REPZ_prefix = threebyte_0x38_uses_REPZ_prefix[op]; - break; - case 0x3a: - uses_DATA_prefix = threebyte_0x3a_uses_DATA_prefix[op]; - uses_REPNZ_prefix = threebyte_0x3a_uses_REPNZ_prefix[op]; - uses_REPZ_prefix = threebyte_0x3a_uses_REPZ_prefix[op]; - break; - default: - break; - } - } - } - else - { - dp = &dis386[*codep]; - need_modrm = onebyte_has_modrm[*codep]; - uses_DATA_prefix = 0; - uses_REPNZ_prefix = 0; - /* pause is 0xf3 0x90. */ - uses_REPZ_prefix = *codep == 0x90; - uses_LOCK_prefix = 0; - codep++; - } - - if (!uses_REPZ_prefix && (prefixes & PREFIX_REPZ)) - { - oappend ("repz "); - used_prefixes |= PREFIX_REPZ; - } - if (!uses_REPNZ_prefix && (prefixes & PREFIX_REPNZ)) - { - oappend ("repnz "); - used_prefixes |= PREFIX_REPNZ; - } - - if (!uses_LOCK_prefix && (prefixes & PREFIX_LOCK)) - { - oappend ("lock "); - used_prefixes |= PREFIX_LOCK; - } - - if (prefixes & PREFIX_ADDR) - { - sizeflag ^= AFLAG; - if (dp->op[2].bytemode != loop_jcxz_mode || intel_syntax) - { - if ((sizeflag & AFLAG) || address_mode == mode_64bit) - oappend ("addr32 "); - else - oappend ("addr16 "); - used_prefixes |= PREFIX_ADDR; - } - } - - if (!uses_DATA_prefix && (prefixes & PREFIX_DATA)) - { - sizeflag ^= DFLAG; - if (dp->op[2].bytemode == cond_jump_mode - && dp->op[0].bytemode == v_mode - && !intel_syntax) - { - if (sizeflag & DFLAG) - oappend ("data32 "); - else - oappend ("data16 "); - used_prefixes |= PREFIX_DATA; - } - } - - if (dp->name == NULL && dp->op[0].bytemode == IS_3BYTE_OPCODE) - { - dp = &three_byte_table[dp->op[1].bytemode][op]; - modrm.mod = (*codep >> 6) & 3; - modrm.reg = (*codep >> 3) & 7; - modrm.rm = *codep & 7; - } - else if (need_modrm) - { - fetch_data(info, codep + 1); - modrm.mod = (*codep >> 6) & 3; - modrm.reg = (*codep >> 3) & 7; - modrm.rm = *codep & 7; - } - - if (dp->name == NULL && dp->op[0].bytemode == FLOATCODE) - { - dofloat (sizeflag); - } - else - { - int index; - if (dp->name == NULL) - { - switch (dp->op[0].bytemode) - { - case USE_GROUPS: - dp = &grps[dp->op[1].bytemode][modrm.reg]; - break; - - case USE_PREFIX_USER_TABLE: - index = 0; - used_prefixes |= (prefixes & PREFIX_REPZ); - if (prefixes & PREFIX_REPZ) - index = 1; - else - { - /* We should check PREFIX_REPNZ and PREFIX_REPZ - before PREFIX_DATA. */ - used_prefixes |= (prefixes & PREFIX_REPNZ); - if (prefixes & PREFIX_REPNZ) - index = 3; - else - { - used_prefixes |= (prefixes & PREFIX_DATA); - if (prefixes & PREFIX_DATA) - index = 2; - } - } - dp = &prefix_user_table[dp->op[1].bytemode][index]; - break; - - case X86_64_SPECIAL: - index = address_mode == mode_64bit ? 1 : 0; - dp = &x86_64_table[dp->op[1].bytemode][index]; - break; - - default: - oappend (INTERNAL_DISASSEMBLER_ERROR); - break; - } - } - - if (dp->name != NULL && putop (dp->name, sizeflag) == 0) - { - for (i = 0; i < MAX_OPERANDS; ++i) - { - obufp = op_out[i]; - op_ad = MAX_OPERANDS - 1 - i; - if (dp->op[i].rtn) - (*dp->op[i].rtn) (dp->op[i].bytemode, sizeflag); - } - } - } - - /* See if any prefixes were not used. If so, print the first one - separately. If we don't do this, we'll wind up printing an - instruction stream which does not precisely correspond to the - bytes we are disassembling. */ - if ((prefixes & ~used_prefixes) != 0) - { - const char *name; - - name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); - if (name == NULL) - name = INTERNAL_DISASSEMBLER_ERROR; - (*info->fprintf_func) (info->stream, "%s", name); - return 1; - } - if (rex & ~rex_used) - { - const char *name; - name = prefix_name (rex | 0x40, priv.orig_sizeflag); - if (name == NULL) - name = INTERNAL_DISASSEMBLER_ERROR; - (*info->fprintf_func) (info->stream, "%s ", name); - } - - obufp = obuf + strlen (obuf); - for (i = strlen (obuf); i < 6; i++) - oappend (" "); - oappend (" "); - (*info->fprintf_func) (info->stream, "%s", obuf); - - /* The enter and bound instructions are printed with operands in the same - order as the intel book; everything else is printed in reverse order. */ - if (intel_syntax || two_source_ops) - { - bfd_vma riprel; - - for (i = 0; i < MAX_OPERANDS; ++i) - op_txt[i] = op_out[i]; - - for (i = 0; i < (MAX_OPERANDS >> 1); ++i) - { - op_ad = op_index[i]; - op_index[i] = op_index[MAX_OPERANDS - 1 - i]; - op_index[MAX_OPERANDS - 1 - i] = op_ad; - riprel = op_riprel[i]; - op_riprel[i] = op_riprel [MAX_OPERANDS - 1 - i]; - op_riprel[MAX_OPERANDS - 1 - i] = riprel; - } - } - else - { - for (i = 0; i < MAX_OPERANDS; ++i) - op_txt[MAX_OPERANDS - 1 - i] = op_out[i]; - } - - needcomma = 0; - for (i = 0; i < MAX_OPERANDS; ++i) - if (*op_txt[i]) - { - if (needcomma) - (*info->fprintf_func) (info->stream, ","); - if (op_index[i] != -1 && !op_riprel[i]) - (*info->print_address_func) ((bfd_vma) op_address[op_index[i]], info); - else - (*info->fprintf_func) (info->stream, "%s", op_txt[i]); - needcomma = 1; - } - - for (i = 0; i < MAX_OPERANDS; i++) - if (op_index[i] != -1 && op_riprel[i]) - { - (*info->fprintf_func) (info->stream, " # "); - (*info->print_address_func) ((bfd_vma) (start_pc + codep - start_codep - + op_address[op_index[i]]), info); - break; - } - return codep - priv.the_buffer; -} - -static const char *float_mem[] = { - /* d8 */ - "fadd{s||s|}", - "fmul{s||s|}", - "fcom{s||s|}", - "fcomp{s||s|}", - "fsub{s||s|}", - "fsubr{s||s|}", - "fdiv{s||s|}", - "fdivr{s||s|}", - /* d9 */ - "fld{s||s|}", - "(bad)", - "fst{s||s|}", - "fstp{s||s|}", - "fldenvIC", - "fldcw", - "fNstenvIC", - "fNstcw", - /* da */ - "fiadd{l||l|}", - "fimul{l||l|}", - "ficom{l||l|}", - "ficomp{l||l|}", - "fisub{l||l|}", - "fisubr{l||l|}", - "fidiv{l||l|}", - "fidivr{l||l|}", - /* db */ - "fild{l||l|}", - "fisttp{l||l|}", - "fist{l||l|}", - "fistp{l||l|}", - "(bad)", - "fld{t||t|}", - "(bad)", - "fstp{t||t|}", - /* dc */ - "fadd{l||l|}", - "fmul{l||l|}", - "fcom{l||l|}", - "fcomp{l||l|}", - "fsub{l||l|}", - "fsubr{l||l|}", - "fdiv{l||l|}", - "fdivr{l||l|}", - /* dd */ - "fld{l||l|}", - "fisttp{ll||ll|}", - "fst{l||l|}", - "fstp{l||l|}", - "frstorIC", - "(bad)", - "fNsaveIC", - "fNstsw", - /* de */ - "fiadd", - "fimul", - "ficom", - "ficomp", - "fisub", - "fisubr", - "fidiv", - "fidivr", - /* df */ - "fild", - "fisttp", - "fist", - "fistp", - "fbld", - "fild{ll||ll|}", - "fbstp", - "fistp{ll||ll|}", -}; - -static const unsigned char float_mem_mode[] = { - /* d8 */ - d_mode, - d_mode, - d_mode, - d_mode, - d_mode, - d_mode, - d_mode, - d_mode, - /* d9 */ - d_mode, - 0, - d_mode, - d_mode, - 0, - w_mode, - 0, - w_mode, - /* da */ - d_mode, - d_mode, - d_mode, - d_mode, - d_mode, - d_mode, - d_mode, - d_mode, - /* db */ - d_mode, - d_mode, - d_mode, - d_mode, - 0, - t_mode, - 0, - t_mode, - /* dc */ - q_mode, - q_mode, - q_mode, - q_mode, - q_mode, - q_mode, - q_mode, - q_mode, - /* dd */ - q_mode, - q_mode, - q_mode, - q_mode, - 0, - 0, - 0, - w_mode, - /* de */ - w_mode, - w_mode, - w_mode, - w_mode, - w_mode, - w_mode, - w_mode, - w_mode, - /* df */ - w_mode, - w_mode, - w_mode, - w_mode, - t_mode, - q_mode, - t_mode, - q_mode -}; - -#define ST { OP_ST, 0 } -#define STi { OP_STi, 0 } - -#define FGRPd9_2 NULL, { { NULL, 0 } } -#define FGRPd9_4 NULL, { { NULL, 1 } } -#define FGRPd9_5 NULL, { { NULL, 2 } } -#define FGRPd9_6 NULL, { { NULL, 3 } } -#define FGRPd9_7 NULL, { { NULL, 4 } } -#define FGRPda_5 NULL, { { NULL, 5 } } -#define FGRPdb_4 NULL, { { NULL, 6 } } -#define FGRPde_3 NULL, { { NULL, 7 } } -#define FGRPdf_4 NULL, { { NULL, 8 } } - -static const struct dis386 float_reg[][8] = { - /* d8 */ - { - { "fadd", { ST, STi } }, - { "fmul", { ST, STi } }, - { "fcom", { STi } }, - { "fcomp", { STi } }, - { "fsub", { ST, STi } }, - { "fsubr", { ST, STi } }, - { "fdiv", { ST, STi } }, - { "fdivr", { ST, STi } }, - }, - /* d9 */ - { - { "fld", { STi } }, - { "fxch", { STi } }, - { FGRPd9_2 }, - { "(bad)", { XX } }, - { FGRPd9_4 }, - { FGRPd9_5 }, - { FGRPd9_6 }, - { FGRPd9_7 }, - }, - /* da */ - { - { "fcmovb", { ST, STi } }, - { "fcmove", { ST, STi } }, - { "fcmovbe",{ ST, STi } }, - { "fcmovu", { ST, STi } }, - { "(bad)", { XX } }, - { FGRPda_5 }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* db */ - { - { "fcmovnb",{ ST, STi } }, - { "fcmovne",{ ST, STi } }, - { "fcmovnbe",{ ST, STi } }, - { "fcmovnu",{ ST, STi } }, - { FGRPdb_4 }, - { "fucomi", { ST, STi } }, - { "fcomi", { ST, STi } }, - { "(bad)", { XX } }, - }, - /* dc */ - { - { "fadd", { STi, ST } }, - { "fmul", { STi, ST } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, -#if SYSV386_COMPAT - { "fsub", { STi, ST } }, - { "fsubr", { STi, ST } }, - { "fdiv", { STi, ST } }, - { "fdivr", { STi, ST } }, -#else - { "fsubr", { STi, ST } }, - { "fsub", { STi, ST } }, - { "fdivr", { STi, ST } }, - { "fdiv", { STi, ST } }, -#endif - }, - /* dd */ - { - { "ffree", { STi } }, - { "(bad)", { XX } }, - { "fst", { STi } }, - { "fstp", { STi } }, - { "fucom", { STi } }, - { "fucomp", { STi } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - }, - /* de */ - { - { "faddp", { STi, ST } }, - { "fmulp", { STi, ST } }, - { "(bad)", { XX } }, - { FGRPde_3 }, -#if SYSV386_COMPAT - { "fsubp", { STi, ST } }, - { "fsubrp", { STi, ST } }, - { "fdivp", { STi, ST } }, - { "fdivrp", { STi, ST } }, -#else - { "fsubrp", { STi, ST } }, - { "fsubp", { STi, ST } }, - { "fdivrp", { STi, ST } }, - { "fdivp", { STi, ST } }, -#endif - }, - /* df */ - { - { "ffreep", { STi } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { "(bad)", { XX } }, - { FGRPdf_4 }, - { "fucomip", { ST, STi } }, - { "fcomip", { ST, STi } }, - { "(bad)", { XX } }, - }, -}; - -static const char *fgrps[][8] = { - /* d9_2 0 */ - { - "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", - }, - - /* d9_4 1 */ - { - "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)", - }, - - /* d9_5 2 */ - { - "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)", - }, - - /* d9_6 3 */ - { - "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp", - }, - - /* d9_7 4 */ - { - "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos", - }, - - /* da_5 5 */ - { - "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", - }, - - /* db_4 6 */ - { - "feni(287 only)","fdisi(287 only)","fNclex","fNinit", - "fNsetpm(287 only)","(bad)","(bad)","(bad)", - }, - - /* de_3 7 */ - { - "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", - }, - - /* df_4 8 */ - { - "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", - }, -}; - -static void -dofloat (int sizeflag) -{ - const struct dis386 *dp; - unsigned char floatop; - - floatop = codep[-1]; - - if (modrm.mod != 3) - { - int fp_indx = (floatop - 0xd8) * 8 + modrm.reg; - - putop (float_mem[fp_indx], sizeflag); - obufp = op_out[0]; - op_ad = 2; - OP_E (float_mem_mode[fp_indx], sizeflag); - return; - } - /* Skip mod/rm byte. */ - MODRM_CHECK; - codep++; - - dp = &float_reg[floatop - 0xd8][modrm.reg]; - if (dp->name == NULL) - { - putop (fgrps[dp->op[0].bytemode][modrm.rm], sizeflag); - - /* Instruction fnstsw is only one with strange arg. */ - if (floatop == 0xdf && codep[-1] == 0xe0) - pstrcpy (op_out[0], sizeof(op_out[0]), names16[0]); - } - else - { - putop (dp->name, sizeflag); - - obufp = op_out[0]; - op_ad = 2; - if (dp->op[0].rtn) - (*dp->op[0].rtn) (dp->op[0].bytemode, sizeflag); - - obufp = op_out[1]; - op_ad = 1; - if (dp->op[1].rtn) - (*dp->op[1].rtn) (dp->op[1].bytemode, sizeflag); - } -} - -static void -OP_ST (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - oappend ("%st" + intel_syntax); -} - -static void -OP_STi (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - snprintf (scratchbuf, sizeof(scratchbuf), "%%st(%d)", modrm.rm); - oappend (scratchbuf + intel_syntax); -} - -/* Capital letters in template are macros. */ -static int -putop (const char *template, int sizeflag) -{ - const char *p; - int alt = 0; - - for (p = template; *p; p++) - { - switch (*p) - { - default: - *obufp++ = *p; - break; - case '{': - alt = 0; - if (intel_syntax) - alt += 1; - if (address_mode == mode_64bit) - alt += 2; - while (alt != 0) - { - while (*++p != '|') - { - if (*p == '}') - { - /* Alternative not valid. */ - pstrcpy (obuf, sizeof(obuf), "(bad)"); - obufp = obuf + 5; - return 1; - } - else if (*p == '\0') - abort (); - } - alt--; - } - /* Fall through. */ - case 'I': - alt = 1; - continue; - case '|': - while (*++p != '}') - { - if (*p == '\0') - abort (); - } - break; - case '}': - break; - case 'A': - if (intel_syntax) - break; - if (modrm.mod != 3 || (sizeflag & SUFFIX_ALWAYS)) - *obufp++ = 'b'; - break; - case 'B': - if (intel_syntax) - break; - if (sizeflag & SUFFIX_ALWAYS) - *obufp++ = 'b'; - break; - case 'C': - if (intel_syntax && !alt) - break; - if ((prefixes & PREFIX_DATA) || (sizeflag & SUFFIX_ALWAYS)) - { - if (sizeflag & DFLAG) - *obufp++ = intel_syntax ? 'd' : 'l'; - else - *obufp++ = intel_syntax ? 'w' : 's'; - used_prefixes |= (prefixes & PREFIX_DATA); - } - break; - case 'D': - if (intel_syntax || !(sizeflag & SUFFIX_ALWAYS)) - break; - USED_REX (REX_W); - if (modrm.mod == 3) - { - if (rex & REX_W) - *obufp++ = 'q'; - else if (sizeflag & DFLAG) - *obufp++ = intel_syntax ? 'd' : 'l'; - else - *obufp++ = 'w'; - used_prefixes |= (prefixes & PREFIX_DATA); - } - else - *obufp++ = 'w'; - break; - case 'E': /* For jcxz/jecxz */ - if (address_mode == mode_64bit) - { - if (sizeflag & AFLAG) - *obufp++ = 'r'; - else - *obufp++ = 'e'; - } - else - if (sizeflag & AFLAG) - *obufp++ = 'e'; - used_prefixes |= (prefixes & PREFIX_ADDR); - break; - case 'F': - if (intel_syntax) - break; - if ((prefixes & PREFIX_ADDR) || (sizeflag & SUFFIX_ALWAYS)) - { - if (sizeflag & AFLAG) - *obufp++ = address_mode == mode_64bit ? 'q' : 'l'; - else - *obufp++ = address_mode == mode_64bit ? 'l' : 'w'; - used_prefixes |= (prefixes & PREFIX_ADDR); - } - break; - case 'G': - if (intel_syntax || (obufp[-1] != 's' && !(sizeflag & SUFFIX_ALWAYS))) - break; - if ((rex & REX_W) || (sizeflag & DFLAG)) - *obufp++ = 'l'; - else - *obufp++ = 'w'; - if (!(rex & REX_W)) - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case 'H': - if (intel_syntax) - break; - if ((prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_CS - || (prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_DS) - { - used_prefixes |= prefixes & (PREFIX_CS | PREFIX_DS); - *obufp++ = ','; - *obufp++ = 'p'; - if (prefixes & PREFIX_DS) - *obufp++ = 't'; - else - *obufp++ = 'n'; - } - break; - case 'J': - if (intel_syntax) - break; - *obufp++ = 'l'; - break; - case 'K': - USED_REX (REX_W); - if (rex & REX_W) - *obufp++ = 'q'; - else - *obufp++ = 'd'; - break; - case 'Z': - if (intel_syntax) - break; - if (address_mode == mode_64bit && (sizeflag & SUFFIX_ALWAYS)) - { - *obufp++ = 'q'; - break; - } - /* Fall through. */ - case 'L': - if (intel_syntax) - break; - if (sizeflag & SUFFIX_ALWAYS) - *obufp++ = 'l'; - break; - case 'N': - if ((prefixes & PREFIX_FWAIT) == 0) - *obufp++ = 'n'; - else - used_prefixes |= PREFIX_FWAIT; - break; - case 'O': - USED_REX (REX_W); - if (rex & REX_W) - *obufp++ = 'o'; - else if (intel_syntax && (sizeflag & DFLAG)) - *obufp++ = 'q'; - else - *obufp++ = 'd'; - if (!(rex & REX_W)) - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case 'T': - if (intel_syntax) - break; - if (address_mode == mode_64bit && (sizeflag & DFLAG)) - { - *obufp++ = 'q'; - break; - } - /* Fall through. */ - case 'P': - if (intel_syntax) - break; - if ((prefixes & PREFIX_DATA) - || (rex & REX_W) - || (sizeflag & SUFFIX_ALWAYS)) - { - USED_REX (REX_W); - if (rex & REX_W) - *obufp++ = 'q'; - else - { - if (sizeflag & DFLAG) - *obufp++ = 'l'; - else - *obufp++ = 'w'; - } - used_prefixes |= (prefixes & PREFIX_DATA); - } - break; - case 'U': - if (intel_syntax) - break; - if (address_mode == mode_64bit && (sizeflag & DFLAG)) - { - if (modrm.mod != 3 || (sizeflag & SUFFIX_ALWAYS)) - *obufp++ = 'q'; - break; - } - /* Fall through. */ - case 'Q': - if (intel_syntax && !alt) - break; - USED_REX (REX_W); - if (modrm.mod != 3 || (sizeflag & SUFFIX_ALWAYS)) - { - if (rex & REX_W) - *obufp++ = 'q'; - else - { - if (sizeflag & DFLAG) - *obufp++ = intel_syntax ? 'd' : 'l'; - else - *obufp++ = 'w'; - } - used_prefixes |= (prefixes & PREFIX_DATA); - } - break; - case 'R': - USED_REX (REX_W); - if (rex & REX_W) - *obufp++ = 'q'; - else if (sizeflag & DFLAG) - { - if (intel_syntax) - *obufp++ = 'd'; - else - *obufp++ = 'l'; - } - else - *obufp++ = 'w'; - if (intel_syntax && !p[1] - && ((rex & REX_W) || (sizeflag & DFLAG))) - *obufp++ = 'e'; - if (!(rex & REX_W)) - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case 'V': - if (intel_syntax) - break; - if (address_mode == mode_64bit && (sizeflag & DFLAG)) - { - if (sizeflag & SUFFIX_ALWAYS) - *obufp++ = 'q'; - break; - } - /* Fall through. */ - case 'S': - if (intel_syntax) - break; - if (sizeflag & SUFFIX_ALWAYS) - { - if (rex & REX_W) - *obufp++ = 'q'; - else - { - if (sizeflag & DFLAG) - *obufp++ = 'l'; - else - *obufp++ = 'w'; - used_prefixes |= (prefixes & PREFIX_DATA); - } - } - break; - case 'X': - if (prefixes & PREFIX_DATA) - *obufp++ = 'd'; - else - *obufp++ = 's'; - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case 'Y': - if (intel_syntax) - break; - if (rex & REX_W) - { - USED_REX (REX_W); - *obufp++ = 'q'; - } - break; - /* implicit operand size 'l' for i386 or 'q' for x86-64 */ - case 'W': - /* operand size flag for cwtl, cbtw */ - USED_REX (REX_W); - if (rex & REX_W) - { - if (intel_syntax) - *obufp++ = 'd'; - else - *obufp++ = 'l'; - } - else if (sizeflag & DFLAG) - *obufp++ = 'w'; - else - *obufp++ = 'b'; - if (!(rex & REX_W)) - used_prefixes |= (prefixes & PREFIX_DATA); - break; - } - alt = 0; - } - *obufp = 0; - return 0; -} - -static void -oappend (const char *s) -{ - strcpy (obufp, s); - obufp += strlen (s); -} - -static void -append_seg (void) -{ - if (prefixes & PREFIX_CS) - { - used_prefixes |= PREFIX_CS; - oappend ("%cs:" + intel_syntax); - } - if (prefixes & PREFIX_DS) - { - used_prefixes |= PREFIX_DS; - oappend ("%ds:" + intel_syntax); - } - if (prefixes & PREFIX_SS) - { - used_prefixes |= PREFIX_SS; - oappend ("%ss:" + intel_syntax); - } - if (prefixes & PREFIX_ES) - { - used_prefixes |= PREFIX_ES; - oappend ("%es:" + intel_syntax); - } - if (prefixes & PREFIX_FS) - { - used_prefixes |= PREFIX_FS; - oappend ("%fs:" + intel_syntax); - } - if (prefixes & PREFIX_GS) - { - used_prefixes |= PREFIX_GS; - oappend ("%gs:" + intel_syntax); - } -} - -static void -OP_indirE (int bytemode, int sizeflag) -{ - if (!intel_syntax) - oappend ("*"); - OP_E (bytemode, sizeflag); -} - -static void -print_operand_value (char *buf, size_t bufsize, int hex, bfd_vma disp) -{ - if (address_mode == mode_64bit) - { - if (hex) - { - char tmp[30]; - int i; - buf[0] = '0'; - buf[1] = 'x'; - snprintf_vma (tmp, sizeof(tmp), disp); - for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++) { - } - pstrcpy (buf + 2, bufsize - 2, tmp + i); - } - else - { - bfd_signed_vma v = disp; - char tmp[30]; - int i; - if (v < 0) - { - *(buf++) = '-'; - v = -disp; - /* Check for possible overflow on 0x8000000000000000. */ - if (v < 0) - { - pstrcpy (buf, bufsize, "9223372036854775808"); - return; - } - } - if (!v) - { - pstrcpy (buf, bufsize, "0"); - return; - } - - i = 0; - tmp[29] = 0; - while (v) - { - tmp[28 - i] = (v % 10) + '0'; - v /= 10; - i++; - } - pstrcpy (buf, bufsize, tmp + 29 - i); - } - } - else - { - if (hex) - snprintf (buf, bufsize, "0x%x", (unsigned int) disp); - else - snprintf (buf, bufsize, "%d", (int) disp); - } -} - -/* Put DISP in BUF as signed hex number. */ - -static void -print_displacement (char *buf, bfd_vma disp) -{ - bfd_signed_vma val = disp; - char tmp[30]; - int i, j = 0; - - if (val < 0) - { - buf[j++] = '-'; - val = -disp; - - /* Check for possible overflow. */ - if (val < 0) - { - switch (address_mode) - { - case mode_64bit: - strcpy (buf + j, "0x8000000000000000"); - break; - case mode_32bit: - strcpy (buf + j, "0x80000000"); - break; - case mode_16bit: - strcpy (buf + j, "0x8000"); - break; - } - return; - } - } - - buf[j++] = '0'; - buf[j++] = 'x'; - - snprintf_vma (tmp, sizeof(tmp), val); - for (i = 0; tmp[i] == '0'; i++) - continue; - if (tmp[i] == '\0') - i--; - strcpy (buf + j, tmp + i); -} - -static void -intel_operand_size (int bytemode, int sizeflag) -{ - switch (bytemode) - { - case b_mode: - case dqb_mode: - oappend ("BYTE PTR "); - break; - case w_mode: - case dqw_mode: - oappend ("WORD PTR "); - break; - case stack_v_mode: - if (address_mode == mode_64bit && (sizeflag & DFLAG)) - { - oappend ("QWORD PTR "); - used_prefixes |= (prefixes & PREFIX_DATA); - break; - } - /* FALLTHRU */ - case v_mode: - case dq_mode: - USED_REX (REX_W); - if (rex & REX_W) - oappend ("QWORD PTR "); - else if ((sizeflag & DFLAG) || bytemode == dq_mode) - oappend ("DWORD PTR "); - else - oappend ("WORD PTR "); - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case z_mode: - if ((rex & REX_W) || (sizeflag & DFLAG)) - *obufp++ = 'D'; - oappend ("WORD PTR "); - if (!(rex & REX_W)) - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case d_mode: - case dqd_mode: - oappend ("DWORD PTR "); - break; - case q_mode: - oappend ("QWORD PTR "); - break; - case m_mode: - if (address_mode == mode_64bit) - oappend ("QWORD PTR "); - else - oappend ("DWORD PTR "); - break; - case f_mode: - if (sizeflag & DFLAG) - oappend ("FWORD PTR "); - else - oappend ("DWORD PTR "); - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case t_mode: - oappend ("TBYTE PTR "); - break; - case x_mode: - oappend ("XMMWORD PTR "); - break; - case o_mode: - oappend ("OWORD PTR "); - break; - default: - break; - } -} - -static void -OP_E (int bytemode, int sizeflag) -{ - bfd_vma disp; - int add = 0; - int riprel = 0; - USED_REX (REX_B); - if (rex & REX_B) - add += 8; - - /* Skip mod/rm byte. */ - MODRM_CHECK; - codep++; - - if (modrm.mod == 3) - { - switch (bytemode) - { - case b_mode: - USED_REX (0); - if (rex) - oappend (names8rex[modrm.rm + add]); - else - oappend (names8[modrm.rm + add]); - break; - case w_mode: - oappend (names16[modrm.rm + add]); - break; - case d_mode: - oappend (names32[modrm.rm + add]); - break; - case q_mode: - oappend (names64[modrm.rm + add]); - break; - case m_mode: - if (address_mode == mode_64bit) - oappend (names64[modrm.rm + add]); - else - oappend (names32[modrm.rm + add]); - break; - case stack_v_mode: - if (address_mode == mode_64bit && (sizeflag & DFLAG)) - { - oappend (names64[modrm.rm + add]); - used_prefixes |= (prefixes & PREFIX_DATA); - break; - } - bytemode = v_mode; - /* FALLTHRU */ - case v_mode: - case dq_mode: - case dqb_mode: - case dqd_mode: - case dqw_mode: - USED_REX (REX_W); - if (rex & REX_W) - oappend (names64[modrm.rm + add]); - else if ((sizeflag & DFLAG) || bytemode != v_mode) - oappend (names32[modrm.rm + add]); - else - oappend (names16[modrm.rm + add]); - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case 0: - break; - default: - oappend (INTERNAL_DISASSEMBLER_ERROR); - break; - } - return; - } - - disp = 0; - if (intel_syntax) - intel_operand_size (bytemode, sizeflag); - append_seg (); - - if ((sizeflag & AFLAG) || address_mode == mode_64bit) - { - /* 32/64 bit address mode */ - int havedisp; - int havesib; - int havebase; - int base; - int index = 0; - int scale = 0; - - havesib = 0; - havebase = 1; - base = modrm.rm; - - if (base == 4) - { - havesib = 1; - fetch_data(the_info, codep + 1); - index = (*codep >> 3) & 7; - if (address_mode == mode_64bit || index != 0x4) - /* When INDEX == 0x4 in 32 bit mode, SCALE is ignored. */ - scale = (*codep >> 6) & 3; - base = *codep & 7; - USED_REX (REX_X); - if (rex & REX_X) - index += 8; - codep++; - } - base += add; - - switch (modrm.mod) - { - case 0: - if ((base & 7) == 5) - { - havebase = 0; - if (address_mode == mode_64bit && !havesib) - riprel = 1; - disp = get32s (); - } - break; - case 1: - fetch_data (the_info, codep + 1); - disp = *codep++; - if ((disp & 0x80) != 0) - disp -= 0x100; - break; - case 2: - disp = get32s (); - break; - } - - havedisp = havebase || (havesib && (index != 4 || scale != 0)); - - if (!intel_syntax) - if (modrm.mod != 0 || (base & 7) == 5) - { - if (havedisp || riprel) - print_displacement (scratchbuf, disp); - else - print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp); - oappend (scratchbuf); - if (riprel) - { - set_op (disp, 1); - oappend ("(%rip)"); - } - } - - if (havedisp || (intel_syntax && riprel)) - { - *obufp++ = open_char; - if (intel_syntax && riprel) - { - set_op (disp, 1); - oappend ("rip"); - } - *obufp = '\0'; - if (havebase) - oappend (address_mode == mode_64bit && (sizeflag & AFLAG) - ? names64[base] : names32[base]); - if (havesib) - { - if (index != 4) - { - if (!intel_syntax || havebase) - { - *obufp++ = separator_char; - *obufp = '\0'; - } - oappend (address_mode == mode_64bit && (sizeflag & AFLAG) - ? names64[index] : names32[index]); - } - if (scale != 0 || (!intel_syntax && index != 4)) - { - *obufp++ = scale_char; - *obufp = '\0'; - snprintf (scratchbuf, sizeof(scratchbuf), "%d", 1 << scale); - oappend (scratchbuf); - } - } - if (intel_syntax - && (disp || modrm.mod != 0 || (base & 7) == 5)) - { - if ((bfd_signed_vma) disp >= 0) - { - *obufp++ = '+'; - *obufp = '\0'; - } - else if (modrm.mod != 1) - { - *obufp++ = '-'; - *obufp = '\0'; - disp = - (bfd_signed_vma) disp; - } - - print_displacement (scratchbuf, disp); - oappend (scratchbuf); - } - - *obufp++ = close_char; - *obufp = '\0'; - } - else if (intel_syntax) - { - if (modrm.mod != 0 || (base & 7) == 5) - { - if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS - | PREFIX_ES | PREFIX_FS | PREFIX_GS)) - ; - else - { - oappend (names_seg[ds_reg - es_reg]); - oappend (":"); - } - print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp); - oappend (scratchbuf); - } - } - } - else - { /* 16 bit address mode */ - switch (modrm.mod) - { - case 0: - if (modrm.rm == 6) - { - disp = get16 (); - if ((disp & 0x8000) != 0) - disp -= 0x10000; - } - break; - case 1: - fetch_data(the_info, codep + 1); - disp = *codep++; - if ((disp & 0x80) != 0) - disp -= 0x100; - break; - case 2: - disp = get16 (); - if ((disp & 0x8000) != 0) - disp -= 0x10000; - break; - } - - if (!intel_syntax) - if (modrm.mod != 0 || modrm.rm == 6) - { - print_displacement (scratchbuf, disp); - oappend (scratchbuf); - } - - if (modrm.mod != 0 || modrm.rm != 6) - { - *obufp++ = open_char; - *obufp = '\0'; - oappend (index16[modrm.rm]); - if (intel_syntax - && (disp || modrm.mod != 0 || modrm.rm == 6)) - { - if ((bfd_signed_vma) disp >= 0) - { - *obufp++ = '+'; - *obufp = '\0'; - } - else if (modrm.mod != 1) - { - *obufp++ = '-'; - *obufp = '\0'; - disp = - (bfd_signed_vma) disp; - } - - print_displacement (scratchbuf, disp); - oappend (scratchbuf); - } - - *obufp++ = close_char; - *obufp = '\0'; - } - else if (intel_syntax) - { - if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS - | PREFIX_ES | PREFIX_FS | PREFIX_GS)) - ; - else - { - oappend (names_seg[ds_reg - es_reg]); - oappend (":"); - } - print_operand_value (scratchbuf, sizeof(scratchbuf), 1, - disp & 0xffff); - oappend (scratchbuf); - } - } -} - -static void -OP_G (int bytemode, int sizeflag) -{ - int add = 0; - USED_REX (REX_R); - if (rex & REX_R) - add += 8; - switch (bytemode) - { - case b_mode: - USED_REX (0); - if (rex) - oappend (names8rex[modrm.reg + add]); - else - oappend (names8[modrm.reg + add]); - break; - case w_mode: - oappend (names16[modrm.reg + add]); - break; - case d_mode: - oappend (names32[modrm.reg + add]); - break; - case q_mode: - oappend (names64[modrm.reg + add]); - break; - case v_mode: - case dq_mode: - case dqb_mode: - case dqd_mode: - case dqw_mode: - USED_REX (REX_W); - if (rex & REX_W) - oappend (names64[modrm.reg + add]); - else if ((sizeflag & DFLAG) || bytemode != v_mode) - oappend (names32[modrm.reg + add]); - else - oappend (names16[modrm.reg + add]); - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case m_mode: - if (address_mode == mode_64bit) - oappend (names64[modrm.reg + add]); - else - oappend (names32[modrm.reg + add]); - break; - default: - oappend (INTERNAL_DISASSEMBLER_ERROR); - break; - } -} - -static void -OP_vvvv (int bytemode, int sizeflags) -{ - USED_REX (REX_W); - if (rex & REX_W) { - oappend(names64[vex_reg]); - } else { - oappend(names32[vex_reg]); - } -} - -static bfd_vma -get64 (void) -{ - bfd_vma x; -#ifdef BFD64 - unsigned int a; - unsigned int b; - - fetch_data(the_info, codep + 8); - a = *codep++ & 0xff; - a |= (*codep++ & 0xff) << 8; - a |= (*codep++ & 0xff) << 16; - a |= (*codep++ & 0xff) << 24; - b = *codep++ & 0xff; - b |= (*codep++ & 0xff) << 8; - b |= (*codep++ & 0xff) << 16; - b |= (*codep++ & 0xff) << 24; - x = a + ((bfd_vma) b << 32); -#else - abort (); - x = 0; -#endif - return x; -} - -static bfd_signed_vma -get32 (void) -{ - bfd_signed_vma x = 0; - - fetch_data(the_info, codep + 4); - x = *codep++ & (bfd_signed_vma) 0xff; - x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; - x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; - x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; - return x; -} - -static bfd_signed_vma -get32s (void) -{ - bfd_signed_vma x = 0; - - fetch_data(the_info, codep + 4); - x = *codep++ & (bfd_signed_vma) 0xff; - x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; - x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; - x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; - - x = (x ^ ((bfd_signed_vma) 1 << 31)) - ((bfd_signed_vma) 1 << 31); - - return x; -} - -static int -get16 (void) -{ - int x = 0; - - fetch_data(the_info, codep + 2); - x = *codep++ & 0xff; - x |= (*codep++ & 0xff) << 8; - return x; -} - -static void -set_op (bfd_vma op, int riprel) -{ - op_index[op_ad] = op_ad; - if (address_mode == mode_64bit) - { - op_address[op_ad] = op; - op_riprel[op_ad] = riprel; - } - else - { - /* Mask to get a 32-bit address. */ - op_address[op_ad] = op & 0xffffffff; - op_riprel[op_ad] = riprel & 0xffffffff; - } -} - -static void -OP_REG (int code, int sizeflag) -{ - const char *s; - int add = 0; - USED_REX (REX_B); - if (rex & REX_B) - add = 8; - - switch (code) - { - case ax_reg: case cx_reg: case dx_reg: case bx_reg: - case sp_reg: case bp_reg: case si_reg: case di_reg: - s = names16[code - ax_reg + add]; - break; - case es_reg: case ss_reg: case cs_reg: - case ds_reg: case fs_reg: case gs_reg: - s = names_seg[code - es_reg + add]; - break; - case al_reg: case ah_reg: case cl_reg: case ch_reg: - case dl_reg: case dh_reg: case bl_reg: case bh_reg: - USED_REX (0); - if (rex) - s = names8rex[code - al_reg + add]; - else - s = names8[code - al_reg]; - break; - case rAX_reg: case rCX_reg: case rDX_reg: case rBX_reg: - case rSP_reg: case rBP_reg: case rSI_reg: case rDI_reg: - if (address_mode == mode_64bit && (sizeflag & DFLAG)) - { - s = names64[code - rAX_reg + add]; - break; - } - code += eAX_reg - rAX_reg; - /* Fall through. */ - case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: - case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: - USED_REX (REX_W); - if (rex & REX_W) - s = names64[code - eAX_reg + add]; - else if (sizeflag & DFLAG) - s = names32[code - eAX_reg + add]; - else - s = names16[code - eAX_reg + add]; - used_prefixes |= (prefixes & PREFIX_DATA); - break; - default: - s = INTERNAL_DISASSEMBLER_ERROR; - break; - } - oappend (s); -} - -static void -OP_IMREG (int code, int sizeflag) -{ - const char *s; - - switch (code) - { - case indir_dx_reg: - if (intel_syntax) - s = "dx"; - else - s = "(%dx)"; - break; - case ax_reg: case cx_reg: case dx_reg: case bx_reg: - case sp_reg: case bp_reg: case si_reg: case di_reg: - s = names16[code - ax_reg]; - break; - case es_reg: case ss_reg: case cs_reg: - case ds_reg: case fs_reg: case gs_reg: - s = names_seg[code - es_reg]; - break; - case al_reg: case ah_reg: case cl_reg: case ch_reg: - case dl_reg: case dh_reg: case bl_reg: case bh_reg: - USED_REX (0); - if (rex) - s = names8rex[code - al_reg]; - else - s = names8[code - al_reg]; - break; - case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: - case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: - USED_REX (REX_W); - if (rex & REX_W) - s = names64[code - eAX_reg]; - else if (sizeflag & DFLAG) - s = names32[code - eAX_reg]; - else - s = names16[code - eAX_reg]; - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case z_mode_ax_reg: - if ((rex & REX_W) || (sizeflag & DFLAG)) - s = *names32; - else - s = *names16; - if (!(rex & REX_W)) - used_prefixes |= (prefixes & PREFIX_DATA); - break; - default: - s = INTERNAL_DISASSEMBLER_ERROR; - break; - } - oappend (s); -} - -static void -OP_I (int bytemode, int sizeflag) -{ - bfd_signed_vma op; - bfd_signed_vma mask = -1; - - switch (bytemode) - { - case b_mode: - fetch_data(the_info, codep + 1); - op = *codep++; - mask = 0xff; - break; - case q_mode: - if (address_mode == mode_64bit) - { - op = get32s (); - break; - } - /* Fall through. */ - case v_mode: - USED_REX (REX_W); - if (rex & REX_W) - op = get32s (); - else if (sizeflag & DFLAG) - { - op = get32 (); - mask = 0xffffffff; - } - else - { - op = get16 (); - mask = 0xfffff; - } - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case w_mode: - mask = 0xfffff; - op = get16 (); - break; - case const_1_mode: - if (intel_syntax) - oappend ("1"); - return; - default: - oappend (INTERNAL_DISASSEMBLER_ERROR); - return; - } - - op &= mask; - scratchbuf[0] = '$'; - print_operand_value (scratchbuf + 1, sizeof(scratchbuf) - 1, 1, op); - oappend (scratchbuf + intel_syntax); - scratchbuf[0] = '\0'; -} - -static void -OP_I64 (int bytemode, int sizeflag) -{ - bfd_signed_vma op; - bfd_signed_vma mask = -1; - - if (address_mode != mode_64bit) - { - OP_I (bytemode, sizeflag); - return; - } - - switch (bytemode) - { - case b_mode: - fetch_data(the_info, codep + 1); - op = *codep++; - mask = 0xff; - break; - case v_mode: - USED_REX (REX_W); - if (rex & REX_W) - op = get64 (); - else if (sizeflag & DFLAG) - { - op = get32 (); - mask = 0xffffffff; - } - else - { - op = get16 (); - mask = 0xfffff; - } - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case w_mode: - mask = 0xfffff; - op = get16 (); - break; - default: - oappend (INTERNAL_DISASSEMBLER_ERROR); - return; - } - - op &= mask; - scratchbuf[0] = '$'; - print_operand_value (scratchbuf + 1, sizeof(scratchbuf) - 1, 1, op); - oappend (scratchbuf + intel_syntax); - scratchbuf[0] = '\0'; -} - -static void -OP_sI (int bytemode, int sizeflag) -{ - bfd_signed_vma op; - - switch (bytemode) - { - case b_mode: - fetch_data(the_info, codep + 1); - op = *codep++; - if ((op & 0x80) != 0) - op -= 0x100; - break; - case v_mode: - USED_REX (REX_W); - if (rex & REX_W) - op = get32s (); - else if (sizeflag & DFLAG) - { - op = get32s (); - } - else - { - op = get16 (); - if ((op & 0x8000) != 0) - op -= 0x10000; - } - used_prefixes |= (prefixes & PREFIX_DATA); - break; - case w_mode: - op = get16 (); - if ((op & 0x8000) != 0) - op -= 0x10000; - break; - default: - oappend (INTERNAL_DISASSEMBLER_ERROR); - return; - } - - scratchbuf[0] = '$'; - print_operand_value (scratchbuf + 1, sizeof(scratchbuf) - 1, 1, op); - oappend (scratchbuf + intel_syntax); -} - -static void -OP_J (int bytemode, int sizeflag) -{ - bfd_vma disp; - bfd_vma mask = -1; - bfd_vma segment = 0; - - switch (bytemode) - { - case b_mode: - fetch_data(the_info, codep + 1); - disp = *codep++; - if ((disp & 0x80) != 0) - disp -= 0x100; - break; - case v_mode: - if ((sizeflag & DFLAG) || (rex & REX_W)) - disp = get32s (); - else - { - disp = get16 (); - if ((disp & 0x8000) != 0) - disp -= 0x10000; - /* In 16bit mode, address is wrapped around at 64k within - the same segment. Otherwise, a data16 prefix on a jump - instruction means that the pc is masked to 16 bits after - the displacement is added! */ - mask = 0xffff; - if ((prefixes & PREFIX_DATA) == 0) - segment = ((start_pc + codep - start_codep) - & ~((bfd_vma) 0xffff)); - } - used_prefixes |= (prefixes & PREFIX_DATA); - break; - default: - oappend (INTERNAL_DISASSEMBLER_ERROR); - return; - } - disp = ((start_pc + codep - start_codep + disp) & mask) | segment; - set_op (disp, 0); - print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp); - oappend (scratchbuf); -} - -static void -OP_SEG (int bytemode, int sizeflag) -{ - if (bytemode == w_mode) - oappend (names_seg[modrm.reg]); - else - OP_E (modrm.mod == 3 ? bytemode : w_mode, sizeflag); -} - -static void -OP_DIR (int dummy ATTRIBUTE_UNUSED, int sizeflag) -{ - int seg, offset; - - if (sizeflag & DFLAG) - { - offset = get32 (); - seg = get16 (); - } - else - { - offset = get16 (); - seg = get16 (); - } - used_prefixes |= (prefixes & PREFIX_DATA); - if (intel_syntax) - snprintf (scratchbuf, sizeof(scratchbuf), "0x%x:0x%x", seg, offset); - else - snprintf (scratchbuf, sizeof(scratchbuf), "$0x%x,$0x%x", seg, offset); - oappend (scratchbuf); -} - -static void -OP_OFF (int bytemode, int sizeflag) -{ - bfd_vma off; - - if (intel_syntax && (sizeflag & SUFFIX_ALWAYS)) - intel_operand_size (bytemode, sizeflag); - append_seg (); - - if ((sizeflag & AFLAG) || address_mode == mode_64bit) - off = get32 (); - else - off = get16 (); - - if (intel_syntax) - { - if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS - | PREFIX_ES | PREFIX_FS | PREFIX_GS))) - { - oappend (names_seg[ds_reg - es_reg]); - oappend (":"); - } - } - print_operand_value (scratchbuf, sizeof(scratchbuf), 1, off); - oappend (scratchbuf); -} - -static void -OP_OFF64 (int bytemode, int sizeflag) -{ - bfd_vma off; - - if (address_mode != mode_64bit - || (prefixes & PREFIX_ADDR)) - { - OP_OFF (bytemode, sizeflag); - return; - } - - if (intel_syntax && (sizeflag & SUFFIX_ALWAYS)) - intel_operand_size (bytemode, sizeflag); - append_seg (); - - off = get64 (); - - if (intel_syntax) - { - if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS - | PREFIX_ES | PREFIX_FS | PREFIX_GS))) - { - oappend (names_seg[ds_reg - es_reg]); - oappend (":"); - } - } - print_operand_value (scratchbuf, sizeof(scratchbuf), 1, off); - oappend (scratchbuf); -} - -static void -ptr_reg (int code, int sizeflag) -{ - const char *s; - - *obufp++ = open_char; - used_prefixes |= (prefixes & PREFIX_ADDR); - if (address_mode == mode_64bit) - { - if (!(sizeflag & AFLAG)) - s = names32[code - eAX_reg]; - else - s = names64[code - eAX_reg]; - } - else if (sizeflag & AFLAG) - s = names32[code - eAX_reg]; - else - s = names16[code - eAX_reg]; - oappend (s); - *obufp++ = close_char; - *obufp = 0; -} - -static void -OP_ESreg (int code, int sizeflag) -{ - if (intel_syntax) - { - switch (codep[-1]) - { - case 0x6d: /* insw/insl */ - intel_operand_size (z_mode, sizeflag); - break; - case 0xa5: /* movsw/movsl/movsq */ - case 0xa7: /* cmpsw/cmpsl/cmpsq */ - case 0xab: /* stosw/stosl */ - case 0xaf: /* scasw/scasl */ - intel_operand_size (v_mode, sizeflag); - break; - default: - intel_operand_size (b_mode, sizeflag); - } - } - oappend ("%es:" + intel_syntax); - ptr_reg (code, sizeflag); -} - -static void -OP_DSreg (int code, int sizeflag) -{ - if (intel_syntax) - { - switch (codep[-1]) - { - case 0x6f: /* outsw/outsl */ - intel_operand_size (z_mode, sizeflag); - break; - case 0xa5: /* movsw/movsl/movsq */ - case 0xa7: /* cmpsw/cmpsl/cmpsq */ - case 0xad: /* lodsw/lodsl/lodsq */ - intel_operand_size (v_mode, sizeflag); - break; - default: - intel_operand_size (b_mode, sizeflag); - } - } - if ((prefixes - & (PREFIX_CS - | PREFIX_DS - | PREFIX_SS - | PREFIX_ES - | PREFIX_FS - | PREFIX_GS)) == 0) - prefixes |= PREFIX_DS; - append_seg (); - ptr_reg (code, sizeflag); -} - -static void -OP_C (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - int add = 0; - if (rex & REX_R) - { - USED_REX (REX_R); - add = 8; - } - else if (address_mode != mode_64bit && (prefixes & PREFIX_LOCK)) - { - used_prefixes |= PREFIX_LOCK; - add = 8; - } - snprintf (scratchbuf, sizeof(scratchbuf), "%%cr%d", modrm.reg + add); - oappend (scratchbuf + intel_syntax); -} - -static void -OP_D (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - int add = 0; - USED_REX (REX_R); - if (rex & REX_R) - add = 8; - if (intel_syntax) - snprintf (scratchbuf, sizeof(scratchbuf), "db%d", modrm.reg + add); - else - snprintf (scratchbuf, sizeof(scratchbuf), "%%db%d", modrm.reg + add); - oappend (scratchbuf); -} - -static void -OP_T (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - snprintf (scratchbuf, sizeof(scratchbuf), "%%tr%d", modrm.reg); - oappend (scratchbuf + intel_syntax); -} - -static void -OP_R (int bytemode, int sizeflag) -{ - if (modrm.mod == 3) - OP_E (bytemode, sizeflag); - else - BadOp (); -} - -static void -OP_MMX (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - used_prefixes |= (prefixes & PREFIX_DATA); - if (prefixes & PREFIX_DATA) - { - int add = 0; - USED_REX (REX_R); - if (rex & REX_R) - add = 8; - snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.reg + add); - } - else - snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.reg); - oappend (scratchbuf + intel_syntax); -} - -static void -OP_XMM (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - int add = 0; - USED_REX (REX_R); - if (rex & REX_R) - add = 8; - snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.reg + add); - oappend (scratchbuf + intel_syntax); -} - -static void -OP_EM (int bytemode, int sizeflag) -{ - if (modrm.mod != 3) - { - if (intel_syntax && bytemode == v_mode) - { - bytemode = (prefixes & PREFIX_DATA) ? x_mode : q_mode; - used_prefixes |= (prefixes & PREFIX_DATA); - } - OP_E (bytemode, sizeflag); - return; - } - - /* Skip mod/rm byte. */ - MODRM_CHECK; - codep++; - used_prefixes |= (prefixes & PREFIX_DATA); - if (prefixes & PREFIX_DATA) - { - int add = 0; - - USED_REX (REX_B); - if (rex & REX_B) - add = 8; - snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.rm + add); - } - else - snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.rm); - oappend (scratchbuf + intel_syntax); -} - -/* cvt* are the only instructions in sse2 which have - both SSE and MMX operands and also have 0x66 prefix - in their opcode. 0x66 was originally used to differentiate - between SSE and MMX instruction(operands). So we have to handle the - cvt* separately using OP_EMC and OP_MXC */ -static void -OP_EMC (int bytemode, int sizeflag) -{ - if (modrm.mod != 3) - { - if (intel_syntax && bytemode == v_mode) - { - bytemode = (prefixes & PREFIX_DATA) ? x_mode : q_mode; - used_prefixes |= (prefixes & PREFIX_DATA); - } - OP_E (bytemode, sizeflag); - return; - } - - /* Skip mod/rm byte. */ - MODRM_CHECK; - codep++; - used_prefixes |= (prefixes & PREFIX_DATA); - snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.rm); - oappend (scratchbuf + intel_syntax); -} - -static void -OP_MXC (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - used_prefixes |= (prefixes & PREFIX_DATA); - snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.reg); - oappend (scratchbuf + intel_syntax); -} - -static void -OP_EX (int bytemode, int sizeflag) -{ - int add = 0; - if (modrm.mod != 3) - { - OP_E (bytemode, sizeflag); - return; - } - USED_REX (REX_B); - if (rex & REX_B) - add = 8; - - /* Skip mod/rm byte. */ - MODRM_CHECK; - codep++; - snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.rm + add); - oappend (scratchbuf + intel_syntax); -} - -static void -OP_MS (int bytemode, int sizeflag) -{ - if (modrm.mod == 3) - OP_EM (bytemode, sizeflag); - else - BadOp (); -} - -static void -OP_XS (int bytemode, int sizeflag) -{ - if (modrm.mod == 3) - OP_EX (bytemode, sizeflag); - else - BadOp (); -} - -static void -OP_M (int bytemode, int sizeflag) -{ - if (modrm.mod == 3) - /* bad bound,lea,lds,les,lfs,lgs,lss,cmpxchg8b,vmptrst modrm */ - BadOp (); - else - OP_E (bytemode, sizeflag); -} - -static void -OP_0f07 (int bytemode, int sizeflag) -{ - if (modrm.mod != 3 || modrm.rm != 0) - BadOp (); - else - OP_E (bytemode, sizeflag); -} - -static void -OP_0fae (int bytemode, int sizeflag) -{ - if (modrm.mod == 3) - { - if (modrm.reg == 7) - strcpy (obuf + strlen (obuf) - sizeof ("clflush") + 1, "sfence"); - - if (modrm.reg < 5 || modrm.rm != 0) - { - BadOp (); /* bad sfence, mfence, or lfence */ - return; - } - } - else if (modrm.reg != 7) - { - BadOp (); /* bad clflush */ - return; - } - - OP_E (bytemode, sizeflag); -} - -/* NOP is an alias of "xchg %ax,%ax" in 16bit mode, "xchg %eax,%eax" in - 32bit mode and "xchg %rax,%rax" in 64bit mode. */ - -static void -NOP_Fixup1 (int bytemode, int sizeflag) -{ - if ((prefixes & PREFIX_DATA) != 0 - || (rex != 0 - && rex != 0x48 - && address_mode == mode_64bit)) - OP_REG (bytemode, sizeflag); - else - strcpy (obuf, "nop"); -} - -static void -NOP_Fixup2 (int bytemode, int sizeflag) -{ - if ((prefixes & PREFIX_DATA) != 0 - || (rex != 0 - && rex != 0x48 - && address_mode == mode_64bit)) - OP_IMREG (bytemode, sizeflag); -} - -static const char *Suffix3DNow[] = { -/* 00 */ NULL, NULL, NULL, NULL, -/* 04 */ NULL, NULL, NULL, NULL, -/* 08 */ NULL, NULL, NULL, NULL, -/* 0C */ "pi2fw", "pi2fd", NULL, NULL, -/* 10 */ NULL, NULL, NULL, NULL, -/* 14 */ NULL, NULL, NULL, NULL, -/* 18 */ NULL, NULL, NULL, NULL, -/* 1C */ "pf2iw", "pf2id", NULL, NULL, -/* 20 */ NULL, NULL, NULL, NULL, -/* 24 */ NULL, NULL, NULL, NULL, -/* 28 */ NULL, NULL, NULL, NULL, -/* 2C */ NULL, NULL, NULL, NULL, -/* 30 */ NULL, NULL, NULL, NULL, -/* 34 */ NULL, NULL, NULL, NULL, -/* 38 */ NULL, NULL, NULL, NULL, -/* 3C */ NULL, NULL, NULL, NULL, -/* 40 */ NULL, NULL, NULL, NULL, -/* 44 */ NULL, NULL, NULL, NULL, -/* 48 */ NULL, NULL, NULL, NULL, -/* 4C */ NULL, NULL, NULL, NULL, -/* 50 */ NULL, NULL, NULL, NULL, -/* 54 */ NULL, NULL, NULL, NULL, -/* 58 */ NULL, NULL, NULL, NULL, -/* 5C */ NULL, NULL, NULL, NULL, -/* 60 */ NULL, NULL, NULL, NULL, -/* 64 */ NULL, NULL, NULL, NULL, -/* 68 */ NULL, NULL, NULL, NULL, -/* 6C */ NULL, NULL, NULL, NULL, -/* 70 */ NULL, NULL, NULL, NULL, -/* 74 */ NULL, NULL, NULL, NULL, -/* 78 */ NULL, NULL, NULL, NULL, -/* 7C */ NULL, NULL, NULL, NULL, -/* 80 */ NULL, NULL, NULL, NULL, -/* 84 */ NULL, NULL, NULL, NULL, -/* 88 */ NULL, NULL, "pfnacc", NULL, -/* 8C */ NULL, NULL, "pfpnacc", NULL, -/* 90 */ "pfcmpge", NULL, NULL, NULL, -/* 94 */ "pfmin", NULL, "pfrcp", "pfrsqrt", -/* 98 */ NULL, NULL, "pfsub", NULL, -/* 9C */ NULL, NULL, "pfadd", NULL, -/* A0 */ "pfcmpgt", NULL, NULL, NULL, -/* A4 */ "pfmax", NULL, "pfrcpit1", "pfrsqit1", -/* A8 */ NULL, NULL, "pfsubr", NULL, -/* AC */ NULL, NULL, "pfacc", NULL, -/* B0 */ "pfcmpeq", NULL, NULL, NULL, -/* B4 */ "pfmul", NULL, "pfrcpit2", "pmulhrw", -/* B8 */ NULL, NULL, NULL, "pswapd", -/* BC */ NULL, NULL, NULL, "pavgusb", -/* C0 */ NULL, NULL, NULL, NULL, -/* C4 */ NULL, NULL, NULL, NULL, -/* C8 */ NULL, NULL, NULL, NULL, -/* CC */ NULL, NULL, NULL, NULL, -/* D0 */ NULL, NULL, NULL, NULL, -/* D4 */ NULL, NULL, NULL, NULL, -/* D8 */ NULL, NULL, NULL, NULL, -/* DC */ NULL, NULL, NULL, NULL, -/* E0 */ NULL, NULL, NULL, NULL, -/* E4 */ NULL, NULL, NULL, NULL, -/* E8 */ NULL, NULL, NULL, NULL, -/* EC */ NULL, NULL, NULL, NULL, -/* F0 */ NULL, NULL, NULL, NULL, -/* F4 */ NULL, NULL, NULL, NULL, -/* F8 */ NULL, NULL, NULL, NULL, -/* FC */ NULL, NULL, NULL, NULL, -}; - -static void -OP_3DNowSuffix (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - const char *mnemonic; - - fetch_data(the_info, codep + 1); - /* AMD 3DNow! instructions are specified by an opcode suffix in the - place where an 8-bit immediate would normally go. ie. the last - byte of the instruction. */ - obufp = obuf + strlen (obuf); - mnemonic = Suffix3DNow[*codep++ & 0xff]; - if (mnemonic) - oappend (mnemonic); - else - { - /* Since a variable sized modrm/sib chunk is between the start - of the opcode (0x0f0f) and the opcode suffix, we need to do - all the modrm processing first, and don't know until now that - we have a bad opcode. This necessitates some cleaning up. */ - op_out[0][0] = '\0'; - op_out[1][0] = '\0'; - BadOp (); - } -} - -static const char *simd_cmp_op[] = { - "eq", - "lt", - "le", - "unord", - "neq", - "nlt", - "nle", - "ord" -}; - -static void -OP_SIMD_Suffix (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) -{ - unsigned int cmp_type; - - fetch_data(the_info, codep + 1); - obufp = obuf + strlen (obuf); - cmp_type = *codep++ & 0xff; - if (cmp_type < 8) - { - char suffix1 = 'p', suffix2 = 's'; - used_prefixes |= (prefixes & PREFIX_REPZ); - if (prefixes & PREFIX_REPZ) - suffix1 = 's'; - else - { - used_prefixes |= (prefixes & PREFIX_DATA); - if (prefixes & PREFIX_DATA) - suffix2 = 'd'; - else - { - used_prefixes |= (prefixes & PREFIX_REPNZ); - if (prefixes & PREFIX_REPNZ) - suffix1 = 's', suffix2 = 'd'; - } - } - snprintf (scratchbuf, sizeof(scratchbuf), "cmp%s%c%c", - simd_cmp_op[cmp_type], suffix1, suffix2); - used_prefixes |= (prefixes & PREFIX_REPZ); - oappend (scratchbuf); - } - else - { - /* We have a bad extension byte. Clean up. */ - op_out[0][0] = '\0'; - op_out[1][0] = '\0'; - BadOp (); - } -} - -static void -SIMD_Fixup (int extrachar, int sizeflag ATTRIBUTE_UNUSED) -{ - /* Change movlps/movhps to movhlps/movlhps for 2 register operand - forms of these instructions. */ - if (modrm.mod == 3) - { - char *p = obuf + strlen (obuf); - *(p + 1) = '\0'; - *p = *(p - 1); - *(p - 1) = *(p - 2); - *(p - 2) = *(p - 3); - *(p - 3) = extrachar; - } -} - -static void -PNI_Fixup (int extrachar ATTRIBUTE_UNUSED, int sizeflag) -{ - if (modrm.mod == 3 && modrm.reg == 1 && modrm.rm <= 1) - { - /* Override "sidt". */ - size_t olen = strlen (obuf); - char *p = obuf + olen - 4; - const char * const *names = (address_mode == mode_64bit - ? names64 : names32); - - /* We might have a suffix when disassembling with -Msuffix. */ - if (*p == 'i') - --p; - - /* Remove "addr16/addr32" if we aren't in Intel mode. */ - if (!intel_syntax - && (prefixes & PREFIX_ADDR) - && olen >= (4 + 7) - && *(p - 1) == ' ' - && strncmp (p - 7, "addr", 4) == 0 - && (strncmp (p - 3, "16", 2) == 0 - || strncmp (p - 3, "32", 2) == 0)) - p -= 7; - - if (modrm.rm) - { - /* mwait %eax,%ecx */ - strcpy (p, "mwait"); - if (!intel_syntax) - strcpy (op_out[0], names[0]); - } - else - { - /* monitor %eax,%ecx,%edx" */ - strcpy (p, "monitor"); - if (!intel_syntax) - { - const char * const *op1_names; - if (!(prefixes & PREFIX_ADDR)) - op1_names = (address_mode == mode_16bit - ? names16 : names); - else - { - op1_names = (address_mode != mode_32bit - ? names32 : names16); - used_prefixes |= PREFIX_ADDR; - } - strcpy (op_out[0], op1_names[0]); - strcpy (op_out[2], names[2]); - } - } - if (!intel_syntax) - { - strcpy (op_out[1], names[1]); - two_source_ops = 1; - } - - codep++; - } - else - OP_M (0, sizeflag); -} - -static void -SVME_Fixup (int bytemode, int sizeflag) -{ - const char *alt; - char *p; - - switch (*codep) - { - case 0xd8: - alt = "vmrun"; - break; - case 0xd9: - alt = "vmmcall"; - break; - case 0xda: - alt = "vmload"; - break; - case 0xdb: - alt = "vmsave"; - break; - case 0xdc: - alt = "stgi"; - break; - case 0xdd: - alt = "clgi"; - break; - case 0xde: - alt = "skinit"; - break; - case 0xdf: - alt = "invlpga"; - break; - default: - OP_M (bytemode, sizeflag); - return; - } - /* Override "lidt". */ - p = obuf + strlen (obuf) - 4; - /* We might have a suffix. */ - if (*p == 'i') - --p; - strcpy (p, alt); - if (!(prefixes & PREFIX_ADDR)) - { - ++codep; - return; - } - used_prefixes |= PREFIX_ADDR; - switch (*codep++) - { - case 0xdf: - strcpy (op_out[1], names32[1]); - two_source_ops = 1; - /* Fall through. */ - case 0xd8: - case 0xda: - case 0xdb: - *obufp++ = open_char; - if (address_mode == mode_64bit || (sizeflag & AFLAG)) - alt = names32[0]; - else - alt = names16[0]; - strcpy (obufp, alt); - obufp += strlen (alt); - *obufp++ = close_char; - *obufp = '\0'; - break; - } -} - -static void -INVLPG_Fixup (int bytemode, int sizeflag) -{ - const char *alt; - - switch (*codep) - { - case 0xf8: - alt = "swapgs"; - break; - case 0xf9: - alt = "rdtscp"; - break; - default: - OP_M (bytemode, sizeflag); - return; - } - /* Override "invlpg". */ - strcpy (obuf + strlen (obuf) - 6, alt); - codep++; -} - -static void -BadOp (void) -{ - /* Throw away prefixes and 1st. opcode byte. */ - codep = insn_codep + 1; - oappend ("(bad)"); -} - -static void -VMX_Fixup (int extrachar ATTRIBUTE_UNUSED, int sizeflag) -{ - if (modrm.mod == 3 - && modrm.reg == 0 - && modrm.rm >=1 - && modrm.rm <= 4) - { - /* Override "sgdt". */ - char *p = obuf + strlen (obuf) - 4; - - /* We might have a suffix when disassembling with -Msuffix. */ - if (*p == 'g') - --p; - - switch (modrm.rm) - { - case 1: - strcpy (p, "vmcall"); - break; - case 2: - strcpy (p, "vmlaunch"); - break; - case 3: - strcpy (p, "vmresume"); - break; - case 4: - strcpy (p, "vmxoff"); - break; - } - - codep++; - } - else - OP_E (0, sizeflag); -} - -static void -OP_VMX (int bytemode, int sizeflag) -{ - used_prefixes |= (prefixes & (PREFIX_DATA | PREFIX_REPZ)); - if (prefixes & PREFIX_DATA) - strcpy (obuf, "vmclear"); - else if (prefixes & PREFIX_REPZ) - strcpy (obuf, "vmxon"); - else - strcpy (obuf, "vmptrld"); - OP_E (bytemode, sizeflag); -} - -static void -REP_Fixup (int bytemode, int sizeflag) -{ - /* The 0xf3 prefix should be displayed as "rep" for ins, outs, movs, - lods and stos. */ - size_t ilen = 0; - - if (prefixes & PREFIX_REPZ) - switch (*insn_codep) - { - case 0x6e: /* outsb */ - case 0x6f: /* outsw/outsl */ - case 0xa4: /* movsb */ - case 0xa5: /* movsw/movsl/movsq */ - if (!intel_syntax) - ilen = 5; - else - ilen = 4; - break; - case 0xaa: /* stosb */ - case 0xab: /* stosw/stosl/stosq */ - case 0xac: /* lodsb */ - case 0xad: /* lodsw/lodsl/lodsq */ - if (!intel_syntax && (sizeflag & SUFFIX_ALWAYS)) - ilen = 5; - else - ilen = 4; - break; - case 0x6c: /* insb */ - case 0x6d: /* insl/insw */ - if (!intel_syntax) - ilen = 4; - else - ilen = 3; - break; - default: - abort (); - break; - } - - if (ilen != 0) - { - size_t olen; - char *p; - - olen = strlen (obuf); - p = obuf + olen - ilen - 1 - 4; - /* Handle "repz [addr16|addr32]". */ - if ((prefixes & PREFIX_ADDR)) - p -= 1 + 6; - - memmove (p + 3, p + 4, olen - (p + 3 - obuf)); - } - - switch (bytemode) - { - case al_reg: - case eAX_reg: - case indir_dx_reg: - OP_IMREG (bytemode, sizeflag); - break; - case eDI_reg: - OP_ESreg (bytemode, sizeflag); - break; - case eSI_reg: - OP_DSreg (bytemode, sizeflag); - break; - default: - abort (); - break; - } -} - -static void -CMPXCHG8B_Fixup (int bytemode, int sizeflag) -{ - USED_REX (REX_W); - if (rex & REX_W) - { - /* Change cmpxchg8b to cmpxchg16b. */ - char *p = obuf + strlen (obuf) - 2; - strcpy (p, "16b"); - bytemode = o_mode; - } - OP_M (bytemode, sizeflag); -} - -static void -XMM_Fixup (int reg, int sizeflag ATTRIBUTE_UNUSED) -{ - snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", reg); - oappend (scratchbuf + intel_syntax); -} - -static void -CRC32_Fixup (int bytemode, int sizeflag) -{ - /* Add proper suffix to "crc32". */ - char *p = obuf + strlen (obuf); - - switch (bytemode) - { - case b_mode: - if (intel_syntax) - break; - - *p++ = 'b'; - break; - case v_mode: - if (intel_syntax) - break; - - USED_REX (REX_W); - if (rex & REX_W) - *p++ = 'q'; - else if (sizeflag & DFLAG) - *p++ = 'l'; - else - *p++ = 'w'; - used_prefixes |= (prefixes & PREFIX_DATA); - break; - default: - oappend (INTERNAL_DISASSEMBLER_ERROR); - break; - } - *p = '\0'; - - if (modrm.mod == 3) - { - int add; - - /* Skip mod/rm byte. */ - MODRM_CHECK; - codep++; - - USED_REX (REX_B); - add = (rex & REX_B) ? 8 : 0; - if (bytemode == b_mode) - { - USED_REX (0); - if (rex) - oappend (names8rex[modrm.rm + add]); - else - oappend (names8[modrm.rm + add]); - } - else - { - USED_REX (REX_W); - if (rex & REX_W) - oappend (names64[modrm.rm + add]); - else if ((prefixes & PREFIX_DATA)) - oappend (names16[modrm.rm + add]); - else - oappend (names32[modrm.rm + add]); - } - } - else - OP_E (bytemode, sizeflag); -} diff --git a/disas/meson.build b/disas/meson.build index a6402e7e1c..b0d18b9d47 100644 --- a/disas/meson.build +++ b/disas/meson.build @@ -7,7 +7,6 @@ common_ss.add_all(when: 'CONFIG_ARM_A64_DIS', if_true: libvixl_ss) common_ss.add(when: 'CONFIG_CRIS_DIS', if_true: files('cris.c')) common_ss.add(when: 'CONFIG_HEXAGON_DIS', if_true: files('hexagon.c')) common_ss.add(when: 'CONFIG_HPPA_DIS', if_true: files('hppa.c')) -common_ss.add(when: 'CONFIG_I386_DIS', if_true: files('i386.c')) common_ss.add(when: 'CONFIG_M68K_DIS', if_true: files('m68k.c')) common_ss.add(when: 'CONFIG_MICROBLAZE_DIS', if_true: files('microblaze.c')) common_ss.add(when: 'CONFIG_MIPS_DIS', if_true: files('mips.c')) diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h index e857f0ae8b..6484caca9e 100644 --- a/include/disas/dis-asm.h +++ b/include/disas/dis-asm.h @@ -418,7 +418,6 @@ int print_insn_tci(bfd_vma, disassemble_info*); int print_insn_big_mips (bfd_vma, disassemble_info*); int print_insn_little_mips (bfd_vma, disassemble_info*); int print_insn_nanomips (bfd_vma, disassemble_info*); -int print_insn_i386 (bfd_vma, disassemble_info*); int print_insn_m68k (bfd_vma, disassemble_info*); int print_insn_z8001 (bfd_vma, disassemble_info*); int print_insn_z8002 (bfd_vma, disassemble_info*); diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 99343be926..62c240fa91 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6821,7 +6821,6 @@ static void x86_disas_set_info(CPUState *cs, disassemble_info *info) info->mach = (env->hflags & HF_CS64_MASK ? bfd_mach_x86_64 : env->hflags & HF_CS32_MASK ? bfd_mach_i386_i386 : bfd_mach_i386_i8086); - info->print_insn = print_insn_i386; info->cap_arch = CS_ARCH_X86; info->cap_mode = (env->hflags & HF_CS64_MASK ? CS_MODE_64 From 333f944c15e7a6f5503f92d80529a368519d6638 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 5 May 2022 19:36:19 +0200 Subject: [PATCH 177/935] disas: Remove old libopcode ppc disassembler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Capstone should be superior to the old libopcode disassembler, so we can drop the old file nowadays. Message-Id: <20220505173619.488350-1-thuth@redhat.com> Reviewed-by: Cédric Le Goater Signed-off-by: Thomas Huth --- MAINTAINERS | 2 - disas.c | 2 - disas/meson.build | 1 - disas/ppc.c | 5435 --------------------------------------- include/disas/dis-asm.h | 1 - target/ppc/cpu_init.c | 2 - 6 files changed, 5443 deletions(-) delete mode 100644 disas/ppc.c diff --git a/MAINTAINERS b/MAINTAINERS index 85d593a41f..aee6d623b7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -271,7 +271,6 @@ F: target/ppc/ F: hw/ppc/ppc.c F: hw/ppc/ppc_booke.c F: include/hw/ppc/ppc.h -F: disas/ppc.c RISC-V TCG CPUs M: Palmer Dabbelt @@ -3293,7 +3292,6 @@ PPC TCG target M: Richard Henderson S: Odd Fixes F: tcg/ppc/ -F: disas/ppc.c RISC-V TCG target M: Palmer Dabbelt diff --git a/disas.c b/disas.c index b6f4dc73b2..b2753e1902 100644 --- a/disas.c +++ b/disas.c @@ -164,8 +164,6 @@ static void initialize_debug_host(CPUDebug *s) s->info.cap_insn_unit = 1; s->info.cap_insn_split = 8; #elif defined(_ARCH_PPC) - s->info.disassembler_options = (char *)"any"; - s->info.print_insn = print_insn_ppc; s->info.cap_arch = CS_ARCH_PPC; # ifdef _ARCH_PPC64 s->info.cap_mode = CS_MODE_64; diff --git a/disas/meson.build b/disas/meson.build index b0d18b9d47..7da48ea74a 100644 --- a/disas/meson.build +++ b/disas/meson.build @@ -12,7 +12,6 @@ common_ss.add(when: 'CONFIG_MICROBLAZE_DIS', if_true: files('microblaze.c')) common_ss.add(when: 'CONFIG_MIPS_DIS', if_true: files('mips.c')) common_ss.add(when: 'CONFIG_NANOMIPS_DIS', if_true: files('nanomips.cpp')) common_ss.add(when: 'CONFIG_NIOS2_DIS', if_true: files('nios2.c')) -common_ss.add(when: 'CONFIG_PPC_DIS', if_true: files('ppc.c')) common_ss.add(when: 'CONFIG_RISCV_DIS', if_true: files('riscv.c')) common_ss.add(when: 'CONFIG_SH4_DIS', if_true: files('sh4.c')) common_ss.add(when: 'CONFIG_SPARC_DIS', if_true: files('sparc.c')) diff --git a/disas/ppc.c b/disas/ppc.c deleted file mode 100644 index 02be878198..0000000000 --- a/disas/ppc.c +++ /dev/null @@ -1,5435 +0,0 @@ -/* ppc-dis.c -- Disassemble PowerPC instructions - Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 - Free Software Foundation, Inc. - Written by Ian Lance Taylor, Cygnus Support - -This file is part of GDB, GAS, and the GNU binutils. - -GDB, GAS, and the GNU binutils are free software; you can redistribute -them and/or modify them under the terms of the GNU General Public -License as published by the Free Software Foundation; either version -2, or (at your option) any later version. - -GDB, GAS, and the GNU binutils are distributed in the hope that they -will be useful, but WITHOUT ANY WARRANTY; without even the implied -warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this file; see the file COPYING. If not, -see . */ -#include "qemu/osdep.h" -#include "disas/dis-asm.h" -#define BFD_DEFAULT_TARGET_SIZE 64 - -/* ppc.h -- Header file for PowerPC opcode table - Copyright 1994, 1995, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2007 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Cygnus Support - -This file is part of GDB, GAS, and the GNU binutils. - -GDB, GAS, and the GNU binutils are free software; you can redistribute -them and/or modify them under the terms of the GNU General Public -License as published by the Free Software Foundation; either version -1, or (at your option) any later version. - -GDB, GAS, and the GNU binutils are distributed in the hope that they -will be useful, but WITHOUT ANY WARRANTY; without even the implied -warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this file; see the file COPYING. If not, -see . */ - -/* The opcode table is an array of struct powerpc_opcode. */ - -struct powerpc_opcode -{ - /* The opcode name. */ - const char *name; - - /* The opcode itself. Those bits which will be filled in with - operands are zeroes. */ - unsigned long opcode; - - /* The opcode mask. This is used by the disassembler. This is a - mask containing ones indicating those bits which must match the - opcode field, and zeroes indicating those bits which need not - match (and are presumably filled in by operands). */ - unsigned long mask; - - /* One bit flags for the opcode. These are used to indicate which - specific processors support the instructions. The defined values - are listed below. */ - unsigned long flags; - - /* An array of operand codes. Each code is an index into the - operand table. They appear in the order which the operands must - appear in assembly code, and are terminated by a zero. */ - unsigned char operands[8]; -}; - -/* The table itself is sorted by major opcode number, and is otherwise - in the order in which the disassembler should consider - instructions. */ -extern const struct powerpc_opcode powerpc_opcodes[]; -extern const int powerpc_num_opcodes; - -/* Values defined for the flags field of a struct powerpc_opcode. */ - -/* Opcode is defined for the PowerPC architecture. */ -#define PPC_OPCODE_PPC 1 - -/* Opcode is defined for the POWER (RS/6000) architecture. */ -#define PPC_OPCODE_POWER 2 - -/* Opcode is defined for the POWER2 (Rios 2) architecture. */ -#define PPC_OPCODE_POWER2 4 - -/* Opcode is only defined on 32 bit architectures. */ -#define PPC_OPCODE_32 8 - -/* Opcode is only defined on 64 bit architectures. */ -#define PPC_OPCODE_64 0x10 - -/* Opcode is supported by the Motorola PowerPC 601 processor. The 601 - is assumed to support all PowerPC (PPC_OPCODE_PPC) instructions, - but it also supports many additional POWER instructions. */ -#define PPC_OPCODE_601 0x20 - -/* Opcode is supported in both the Power and PowerPC architectures - (ie, compiler's -mcpu=common or assembler's -mcom). */ -#define PPC_OPCODE_COMMON 0x40 - -/* Opcode is supported for any Power or PowerPC platform (this is - for the assembler's -many option, and it eliminates duplicates). */ -#define PPC_OPCODE_ANY 0x80 - -/* Opcode is supported as part of the 64-bit bridge. */ -#define PPC_OPCODE_64_BRIDGE 0x100 - -/* Opcode is supported by Altivec Vector Unit */ -#define PPC_OPCODE_ALTIVEC 0x200 - -/* Opcode is supported by PowerPC 403 processor. */ -#define PPC_OPCODE_403 0x400 - -/* Opcode is supported by PowerPC BookE processor. */ -#define PPC_OPCODE_BOOKE 0x800 - -/* Opcode is only supported by 64-bit PowerPC BookE processor. */ -#define PPC_OPCODE_BOOKE64 0x1000 - -/* Opcode is supported by PowerPC 440 processor. */ -#define PPC_OPCODE_440 0x2000 - -/* Opcode is only supported by Power4 architecture. */ -#define PPC_OPCODE_POWER4 0x4000 - -/* Opcode isn't supported by Power4 architecture. */ -#define PPC_OPCODE_NOPOWER4 0x8000 - -/* Opcode is only supported by POWERPC Classic architecture. */ -#define PPC_OPCODE_CLASSIC 0x10000 - -/* Opcode is only supported by e500x2 Core. */ -#define PPC_OPCODE_SPE 0x20000 - -/* Opcode is supported by e500x2 Integer select APU. */ -#define PPC_OPCODE_ISEL 0x40000 - -/* Opcode is an e500 SPE floating point instruction. */ -#define PPC_OPCODE_EFS 0x80000 - -/* Opcode is supported by branch locking APU. */ -#define PPC_OPCODE_BRLOCK 0x100000 - -/* Opcode is supported by performance monitor APU. */ -#define PPC_OPCODE_PMR 0x200000 - -/* Opcode is supported by cache locking APU. */ -#define PPC_OPCODE_CACHELCK 0x400000 - -/* Opcode is supported by machine check APU. */ -#define PPC_OPCODE_RFMCI 0x800000 - -/* Opcode is only supported by Power5 architecture. */ -#define PPC_OPCODE_POWER5 0x1000000 - -/* Opcode is supported by PowerPC e300 family. */ -#define PPC_OPCODE_E300 0x2000000 - -/* Opcode is only supported by Power6 architecture. */ -#define PPC_OPCODE_POWER6 0x4000000 - -/* Opcode is only supported by PowerPC Cell family. */ -#define PPC_OPCODE_CELL 0x8000000 - -/* A macro to extract the major opcode from an instruction. */ -#define PPC_OP(i) (((i) >> 26) & 0x3f) - -/* The operands table is an array of struct powerpc_operand. */ - -struct powerpc_operand -{ - /* A bitmask of bits in the operand. */ - unsigned int bitm; - - /* How far the operand is left shifted in the instruction. - -1 to indicate that BITM and SHIFT cannot be used to determine - where the operand goes in the insn. */ - int shift; - - /* Insertion function. This is used by the assembler. To insert an - operand value into an instruction, check this field. - - If it is NULL, execute - i |= (op & o->bitm) << o->shift; - (i is the instruction which we are filling in, o is a pointer to - this structure, and op is the operand value). - - If this field is not NULL, then simply call it with the - instruction and the operand value. It will return the new value - of the instruction. If the ERRMSG argument is not NULL, then if - the operand value is illegal, *ERRMSG will be set to a warning - string (the operand will be inserted in any case). If the - operand value is legal, *ERRMSG will be unchanged (most operands - can accept any value). */ - unsigned long (*insert) - (unsigned long instruction, long op, int dialect, const char **errmsg); - - /* Extraction function. This is used by the disassembler. To - extract this operand type from an instruction, check this field. - - If it is NULL, compute - op = (i >> o->shift) & o->bitm; - if ((o->flags & PPC_OPERAND_SIGNED) != 0) - sign_extend (op); - (i is the instruction, o is a pointer to this structure, and op - is the result). - - If this field is not NULL, then simply call it with the - instruction value. It will return the value of the operand. If - the INVALID argument is not NULL, *INVALID will be set to - non-zero if this operand type can not actually be extracted from - this operand (i.e., the instruction does not match). If the - operand is valid, *INVALID will not be changed. */ - long (*extract) (unsigned long instruction, int dialect, int *invalid); - - /* One bit syntax flags. */ - unsigned long flags; -}; - -/* Elements in the table are retrieved by indexing with values from - the operands field of the powerpc_opcodes table. */ - -extern const struct powerpc_operand powerpc_operands[]; -extern const unsigned int num_powerpc_operands; - -/* Values defined for the flags field of a struct powerpc_operand. */ - -/* This operand takes signed values. */ -#define PPC_OPERAND_SIGNED (0x1) - -/* This operand takes signed values, but also accepts a full positive - range of values when running in 32 bit mode. That is, if bits is - 16, it takes any value from -0x8000 to 0xffff. In 64 bit mode, - this flag is ignored. */ -#define PPC_OPERAND_SIGNOPT (0x2) - -/* This operand does not actually exist in the assembler input. This - is used to support extended mnemonics such as mr, for which two - operands fields are identical. The assembler should call the - insert function with any op value. The disassembler should call - the extract function, ignore the return value, and check the value - placed in the valid argument. */ -#define PPC_OPERAND_FAKE (0x4) - -/* The next operand should be wrapped in parentheses rather than - separated from this one by a comma. This is used for the load and - store instructions which want their operands to look like - reg,displacement(reg) - */ -#define PPC_OPERAND_PARENS (0x8) - -/* This operand may use the symbolic names for the CR fields, which - are - lt 0 gt 1 eq 2 so 3 un 3 - cr0 0 cr1 1 cr2 2 cr3 3 - cr4 4 cr5 5 cr6 6 cr7 7 - These may be combined arithmetically, as in cr2*4+gt. These are - only supported on the PowerPC, not the POWER. */ -#define PPC_OPERAND_CR (0x10) - -/* This operand names a register. The disassembler uses this to print - register names with a leading 'r'. */ -#define PPC_OPERAND_GPR (0x20) - -/* Like PPC_OPERAND_GPR, but don't print a leading 'r' for r0. */ -#define PPC_OPERAND_GPR_0 (0x40) - -/* This operand names a floating point register. The disassembler - prints these with a leading 'f'. */ -#define PPC_OPERAND_FPR (0x80) - -/* This operand is a relative branch displacement. The disassembler - prints these symbolically if possible. */ -#define PPC_OPERAND_RELATIVE (0x100) - -/* This operand is an absolute branch address. The disassembler - prints these symbolically if possible. */ -#define PPC_OPERAND_ABSOLUTE (0x200) - -/* This operand is optional, and is zero if omitted. This is used for - example, in the optional BF field in the comparison instructions. The - assembler must count the number of operands remaining on the line, - and the number of operands remaining for the opcode, and decide - whether this operand is present or not. The disassembler should - print this operand out only if it is not zero. */ -#define PPC_OPERAND_OPTIONAL (0x400) - -/* This flag is only used with PPC_OPERAND_OPTIONAL. If this operand - is omitted, then for the next operand use this operand value plus - 1, ignoring the next operand field for the opcode. This wretched - hack is needed because the Power rotate instructions can take - either 4 or 5 operands. The disassembler should print this operand - out regardless of the PPC_OPERAND_OPTIONAL field. */ -#define PPC_OPERAND_NEXT (0x800) - -/* This operand should be regarded as a negative number for the - purposes of overflow checking (i.e., the normal most negative - number is disallowed and one more than the normal most positive - number is allowed). This flag will only be set for a signed - operand. */ -#define PPC_OPERAND_NEGATIVE (0x1000) - -/* This operand names a vector unit register. The disassembler - prints these with a leading 'v'. */ -#define PPC_OPERAND_VR (0x2000) - -/* This operand is for the DS field in a DS form instruction. */ -#define PPC_OPERAND_DS (0x4000) - -/* This operand is for the DQ field in a DQ form instruction. */ -#define PPC_OPERAND_DQ (0x8000) - -/* Valid range of operand is 0..n rather than 0..n-1. */ -#define PPC_OPERAND_PLUS1 (0x10000) - -/* The POWER and PowerPC assemblers use a few macros. We keep them - with the operands table for simplicity. The macro table is an - array of struct powerpc_macro. */ - -struct powerpc_macro -{ - /* The macro name. */ - const char *name; - - /* The number of operands the macro takes. */ - unsigned int operands; - - /* One bit flags for the opcode. These are used to indicate which - specific processors support the instructions. The values are the - same as those for the struct powerpc_opcode flags field. */ - unsigned long flags; - - /* A format string to turn the macro into a normal instruction. - Each %N in the string is replaced with operand number N (zero - based). */ - const char *format; -}; - -extern const struct powerpc_macro powerpc_macros[]; -extern const int powerpc_num_macros; - -/* ppc-opc.c -- PowerPC opcode list - Copyright 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Cygnus Support - - This file is part of GDB, GAS, and the GNU binutils. - - GDB, GAS, and the GNU binutils are free software; you can redistribute - them and/or modify them under the terms of the GNU General Public - License as published by the Free Software Foundation; either version - 2, or (at your option) any later version. - - GDB, GAS, and the GNU binutils are distributed in the hope that they - will be useful, but WITHOUT ANY WARRANTY; without even the implied - warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this file; see the file COPYING. - If not, see . */ - -/* This file holds the PowerPC opcode table. The opcode table - includes almost all of the extended instruction mnemonics. This - permits the disassembler to use them, and simplifies the assembler - logic, at the cost of increasing the table size. The table is - strictly constant data, so the compiler should be able to put it in - the .text section. - - This file also holds the operand table. All knowledge about - inserting operands into instructions and vice-versa is kept in this - file. */ - -/* Local insertion and extraction functions. */ - -static unsigned long insert_bat (unsigned long, long, int, const char **); -static long extract_bat (unsigned long, int, int *); -static unsigned long insert_bba (unsigned long, long, int, const char **); -static long extract_bba (unsigned long, int, int *); -static unsigned long insert_bdm (unsigned long, long, int, const char **); -static long extract_bdm (unsigned long, int, int *); -static unsigned long insert_bdp (unsigned long, long, int, const char **); -static long extract_bdp (unsigned long, int, int *); -static unsigned long insert_bo (unsigned long, long, int, const char **); -static long extract_bo (unsigned long, int, int *); -static unsigned long insert_boe (unsigned long, long, int, const char **); -static long extract_boe (unsigned long, int, int *); -static unsigned long insert_fxm (unsigned long, long, int, const char **); -static long extract_fxm (unsigned long, int, int *); -static unsigned long insert_mbe (unsigned long, long, int, const char **); -static long extract_mbe (unsigned long, int, int *); -static unsigned long insert_mb6 (unsigned long, long, int, const char **); -static long extract_mb6 (unsigned long, int, int *); -static long extract_nb (unsigned long, int, int *); -static unsigned long insert_nsi (unsigned long, long, int, const char **); -static long extract_nsi (unsigned long, int, int *); -static unsigned long insert_ral (unsigned long, long, int, const char **); -static unsigned long insert_ram (unsigned long, long, int, const char **); -static unsigned long insert_raq (unsigned long, long, int, const char **); -static unsigned long insert_ras (unsigned long, long, int, const char **); -static unsigned long insert_rbs (unsigned long, long, int, const char **); -static long extract_rbs (unsigned long, int, int *); -static unsigned long insert_sh6 (unsigned long, long, int, const char **); -static long extract_sh6 (unsigned long, int, int *); -static unsigned long insert_spr (unsigned long, long, int, const char **); -static long extract_spr (unsigned long, int, int *); -static unsigned long insert_sprg (unsigned long, long, int, const char **); -static long extract_sprg (unsigned long, int, int *); -static unsigned long insert_tbr (unsigned long, long, int, const char **); -static long extract_tbr (unsigned long, int, int *); - -/* The operands table. - - The fields are bitm, shift, insert, extract, flags. - - We used to put parens around the various additions, like the one - for BA just below. However, that caused trouble with feeble - compilers with a limit on depth of a parenthesized expression, like - (reportedly) the compiler in Microsoft Developer Studio 5. So we - omit the parens, since the macros are never used in a context where - the addition will be ambiguous. */ - -const struct powerpc_operand powerpc_operands[] = -{ - /* The zero index is used to indicate the end of the list of - operands. */ -#define UNUSED 0 - { 0, 0, NULL, NULL, 0 }, - - /* The BA field in an XL form instruction. */ -#define BA UNUSED + 1 - /* The BI field in a B form or XL form instruction. */ -#define BI BA -#define BI_MASK (0x1f << 16) - { 0x1f, 16, NULL, NULL, PPC_OPERAND_CR }, - - /* The BA field in an XL form instruction when it must be the same - as the BT field in the same instruction. */ -#define BAT BA + 1 - { 0x1f, 16, insert_bat, extract_bat, PPC_OPERAND_FAKE }, - - /* The BB field in an XL form instruction. */ -#define BB BAT + 1 -#define BB_MASK (0x1f << 11) - { 0x1f, 11, NULL, NULL, PPC_OPERAND_CR }, - - /* The BB field in an XL form instruction when it must be the same - as the BA field in the same instruction. */ -#define BBA BB + 1 - { 0x1f, 11, insert_bba, extract_bba, PPC_OPERAND_FAKE }, - - /* The BD field in a B form instruction. The lower two bits are - forced to zero. */ -#define BD BBA + 1 - { 0xfffc, 0, NULL, NULL, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, - - /* The BD field in a B form instruction when absolute addressing is - used. */ -#define BDA BD + 1 - { 0xfffc, 0, NULL, NULL, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, - - /* The BD field in a B form instruction when the - modifier is used. - This sets the y bit of the BO field appropriately. */ -#define BDM BDA + 1 - { 0xfffc, 0, insert_bdm, extract_bdm, - PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, - - /* The BD field in a B form instruction when the - modifier is used - and absolute address is used. */ -#define BDMA BDM + 1 - { 0xfffc, 0, insert_bdm, extract_bdm, - PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, - - /* The BD field in a B form instruction when the + modifier is used. - This sets the y bit of the BO field appropriately. */ -#define BDP BDMA + 1 - { 0xfffc, 0, insert_bdp, extract_bdp, - PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, - - /* The BD field in a B form instruction when the + modifier is used - and absolute addressing is used. */ -#define BDPA BDP + 1 - { 0xfffc, 0, insert_bdp, extract_bdp, - PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, - - /* The BF field in an X or XL form instruction. */ -#define BF BDPA + 1 - /* The CRFD field in an X form instruction. */ -#define CRFD BF - { 0x7, 23, NULL, NULL, PPC_OPERAND_CR }, - - /* The BF field in an X or XL form instruction. */ -#define BFF BF + 1 - { 0x7, 23, NULL, NULL, 0 }, - - /* An optional BF field. This is used for comparison instructions, - in which an omitted BF field is taken as zero. */ -#define OBF BFF + 1 - { 0x7, 23, NULL, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL }, - - /* The BFA field in an X or XL form instruction. */ -#define BFA OBF + 1 - { 0x7, 18, NULL, NULL, PPC_OPERAND_CR }, - - /* The BO field in a B form instruction. Certain values are - illegal. */ -#define BO BFA + 1 -#define BO_MASK (0x1f << 21) - { 0x1f, 21, insert_bo, extract_bo, 0 }, - - /* The BO field in a B form instruction when the + or - modifier is - used. This is like the BO field, but it must be even. */ -#define BOE BO + 1 - { 0x1e, 21, insert_boe, extract_boe, 0 }, - -#define BH BOE + 1 - { 0x3, 11, NULL, NULL, PPC_OPERAND_OPTIONAL }, - - /* The BT field in an X or XL form instruction. */ -#define BT BH + 1 - { 0x1f, 21, NULL, NULL, PPC_OPERAND_CR }, - - /* The condition register number portion of the BI field in a B form - or XL form instruction. This is used for the extended - conditional branch mnemonics, which set the lower two bits of the - BI field. This field is optional. */ -#define CR BT + 1 - { 0x7, 18, NULL, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL }, - - /* The CRB field in an X form instruction. */ -#define CRB CR + 1 - /* The MB field in an M form instruction. */ -#define MB CRB -#define MB_MASK (0x1f << 6) - { 0x1f, 6, NULL, NULL, 0 }, - - /* The CRFS field in an X form instruction. */ -#define CRFS CRB + 1 - { 0x7, 0, NULL, NULL, PPC_OPERAND_CR }, - - /* The CT field in an X form instruction. */ -#define CT CRFS + 1 - /* The MO field in an mbar instruction. */ -#define MO CT - { 0x1f, 21, NULL, NULL, PPC_OPERAND_OPTIONAL }, - - /* The D field in a D form instruction. This is a displacement off - a register, and implies that the next operand is a register in - parentheses. */ -#define D CT + 1 - { 0xffff, 0, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED }, - - /* The DE field in a DE form instruction. This is like D, but is 12 - bits only. */ -#define DE D + 1 - { 0xfff, 4, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED }, - - /* The DES field in a DES form instruction. This is like DS, but is 14 - bits only (12 stored.) */ -#define DES DE + 1 - { 0x3ffc, 2, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED }, - - /* The DQ field in a DQ form instruction. This is like D, but the - lower four bits are forced to zero. */ -#define DQ DES + 1 - { 0xfff0, 0, NULL, NULL, - PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED | PPC_OPERAND_DQ }, - - /* The DS field in a DS form instruction. This is like D, but the - lower two bits are forced to zero. */ -#undef DS -#define DS DQ + 1 - { 0xfffc, 0, NULL, NULL, - PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED | PPC_OPERAND_DS }, - - /* The E field in a wrteei instruction. */ -#define E DS + 1 - { 0x1, 15, NULL, NULL, 0 }, - - /* The FL1 field in a POWER SC form instruction. */ -#define FL1 E + 1 - /* The U field in an X form instruction. */ -#define U FL1 - { 0xf, 12, NULL, NULL, 0 }, - - /* The FL2 field in a POWER SC form instruction. */ -#define FL2 FL1 + 1 - { 0x7, 2, NULL, NULL, 0 }, - - /* The FLM field in an XFL form instruction. */ -#define FLM FL2 + 1 - { 0xff, 17, NULL, NULL, 0 }, - - /* The FRA field in an X or A form instruction. */ -#define FRA FLM + 1 -#define FRA_MASK (0x1f << 16) - { 0x1f, 16, NULL, NULL, PPC_OPERAND_FPR }, - - /* The FRB field in an X or A form instruction. */ -#define FRB FRA + 1 -#define FRB_MASK (0x1f << 11) - { 0x1f, 11, NULL, NULL, PPC_OPERAND_FPR }, - - /* The FRC field in an A form instruction. */ -#define FRC FRB + 1 -#define FRC_MASK (0x1f << 6) - { 0x1f, 6, NULL, NULL, PPC_OPERAND_FPR }, - - /* The FRS field in an X form instruction or the FRT field in a D, X - or A form instruction. */ -#define FRS FRC + 1 -#define FRT FRS - { 0x1f, 21, NULL, NULL, PPC_OPERAND_FPR }, - - /* The FXM field in an XFX instruction. */ -#define FXM FRS + 1 - { 0xff, 12, insert_fxm, extract_fxm, 0 }, - - /* Power4 version for mfcr. */ -#define FXM4 FXM + 1 - { 0xff, 12, insert_fxm, extract_fxm, PPC_OPERAND_OPTIONAL }, - - /* The L field in a D or X form instruction. */ -#define L FXM4 + 1 - { 0x1, 21, NULL, NULL, PPC_OPERAND_OPTIONAL }, - - /* The LEV field in a POWER SVC form instruction. */ -#define SVC_LEV L + 1 - { 0x7f, 5, NULL, NULL, 0 }, - - /* The LEV field in an SC form instruction. */ -#define LEV SVC_LEV + 1 - { 0x7f, 5, NULL, NULL, PPC_OPERAND_OPTIONAL }, - - /* The LI field in an I form instruction. The lower two bits are - forced to zero. */ -#define LI LEV + 1 - { 0x3fffffc, 0, NULL, NULL, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, - - /* The LI field in an I form instruction when used as an absolute - address. */ -#define LIA LI + 1 - { 0x3fffffc, 0, NULL, NULL, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, - - /* The LS field in an X (sync) form instruction. */ -#define LS LIA + 1 - { 0x3, 21, NULL, NULL, PPC_OPERAND_OPTIONAL }, - - /* The ME field in an M form instruction. */ -#define ME LS + 1 -#define ME_MASK (0x1f << 1) - { 0x1f, 1, NULL, NULL, 0 }, - - /* The MB and ME fields in an M form instruction expressed a single - operand which is a bitmask indicating which bits to select. This - is a two operand form using PPC_OPERAND_NEXT. See the - description in opcode/ppc.h for what this means. */ -#define MBE ME + 1 - { 0x1f, 6, NULL, NULL, PPC_OPERAND_OPTIONAL | PPC_OPERAND_NEXT }, - { -1, 0, insert_mbe, extract_mbe, 0 }, - - /* The MB or ME field in an MD or MDS form instruction. The high - bit is wrapped to the low end. */ -#define MB6 MBE + 2 -#define ME6 MB6 -#define MB6_MASK (0x3f << 5) - { 0x3f, 5, insert_mb6, extract_mb6, 0 }, - - /* The NB field in an X form instruction. The value 32 is stored as - 0. */ -#define NB MB6 + 1 - { 0x1f, 11, NULL, extract_nb, PPC_OPERAND_PLUS1 }, - - /* The NSI field in a D form instruction. This is the same as the - SI field, only negated. */ -#define NSI NB + 1 - { 0xffff, 0, insert_nsi, extract_nsi, - PPC_OPERAND_NEGATIVE | PPC_OPERAND_SIGNED }, - - /* The RA field in an D, DS, DQ, X, XO, M, or MDS form instruction. */ -#define RA NSI + 1 -#define RA_MASK (0x1f << 16) - { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR }, - - /* As above, but 0 in the RA field means zero, not r0. */ -#define RA0 RA + 1 - { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR_0 }, - - /* The RA field in the DQ form lq instruction, which has special - value restrictions. */ -#define RAQ RA0 + 1 - { 0x1f, 16, insert_raq, NULL, PPC_OPERAND_GPR_0 }, - - /* The RA field in a D or X form instruction which is an updating - load, which means that the RA field may not be zero and may not - equal the RT field. */ -#define RAL RAQ + 1 - { 0x1f, 16, insert_ral, NULL, PPC_OPERAND_GPR_0 }, - - /* The RA field in an lmw instruction, which has special value - restrictions. */ -#define RAM RAL + 1 - { 0x1f, 16, insert_ram, NULL, PPC_OPERAND_GPR_0 }, - - /* The RA field in a D or X form instruction which is an updating - store or an updating floating point load, which means that the RA - field may not be zero. */ -#define RAS RAM + 1 - { 0x1f, 16, insert_ras, NULL, PPC_OPERAND_GPR_0 }, - - /* The RA field of the tlbwe instruction, which is optional. */ -#define RAOPT RAS + 1 - { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR | PPC_OPERAND_OPTIONAL }, - - /* The RB field in an X, XO, M, or MDS form instruction. */ -#define RB RAOPT + 1 -#define RB_MASK (0x1f << 11) - { 0x1f, 11, NULL, NULL, PPC_OPERAND_GPR }, - - /* The RB field in an X form instruction when it must be the same as - the RS field in the instruction. This is used for extended - mnemonics like mr. */ -#define RBS RB + 1 - { 0x1f, 11, insert_rbs, extract_rbs, PPC_OPERAND_FAKE }, - - /* The RS field in a D, DS, X, XFX, XS, M, MD or MDS form - instruction or the RT field in a D, DS, X, XFX or XO form - instruction. */ -#define RS RBS + 1 -#define RT RS -#define RT_MASK (0x1f << 21) - { 0x1f, 21, NULL, NULL, PPC_OPERAND_GPR }, - - /* The RS and RT fields of the DS form stq instruction, which have - special value restrictions. */ -#define RSQ RS + 1 -#define RTQ RSQ - { 0x1e, 21, NULL, NULL, PPC_OPERAND_GPR_0 }, - - /* The RS field of the tlbwe instruction, which is optional. */ -#define RSO RSQ + 1 -#define RTO RSO - { 0x1f, 21, NULL, NULL, PPC_OPERAND_GPR | PPC_OPERAND_OPTIONAL }, - - /* The SH field in an X or M form instruction. */ -#define SH RSO + 1 -#define SH_MASK (0x1f << 11) - /* The other UIMM field in a EVX form instruction. */ -#define EVUIMM SH - { 0x1f, 11, NULL, NULL, 0 }, - - /* The SH field in an MD form instruction. This is split. */ -#define SH6 SH + 1 -#define SH6_MASK ((0x1f << 11) | (1 << 1)) - { 0x3f, -1, insert_sh6, extract_sh6, 0 }, - - /* The SH field of the tlbwe instruction, which is optional. */ -#define SHO SH6 + 1 - { 0x1f, 11, NULL, NULL, PPC_OPERAND_OPTIONAL }, - - /* The SI field in a D form instruction. */ -#define SI SHO + 1 - { 0xffff, 0, NULL, NULL, PPC_OPERAND_SIGNED }, - - /* The SI field in a D form instruction when we accept a wide range - of positive values. */ -#define SISIGNOPT SI + 1 - { 0xffff, 0, NULL, NULL, PPC_OPERAND_SIGNED | PPC_OPERAND_SIGNOPT }, - - /* The SPR field in an XFX form instruction. This is flipped--the - lower 5 bits are stored in the upper 5 and vice- versa. */ -#define SPR SISIGNOPT + 1 -#define PMR SPR -#define SPR_MASK (0x3ff << 11) - { 0x3ff, 11, insert_spr, extract_spr, 0 }, - - /* The BAT index number in an XFX form m[ft]ibat[lu] instruction. */ -#define SPRBAT SPR + 1 -#define SPRBAT_MASK (0x3 << 17) - { 0x3, 17, NULL, NULL, 0 }, - - /* The SPRG register number in an XFX form m[ft]sprg instruction. */ -#define SPRG SPRBAT + 1 - { 0x1f, 16, insert_sprg, extract_sprg, 0 }, - - /* The SR field in an X form instruction. */ -#define SR SPRG + 1 - { 0xf, 16, NULL, NULL, 0 }, - - /* The STRM field in an X AltiVec form instruction. */ -#define STRM SR + 1 - { 0x3, 21, NULL, NULL, 0 }, - - /* The SV field in a POWER SC form instruction. */ -#define SV STRM + 1 - { 0x3fff, 2, NULL, NULL, 0 }, - - /* The TBR field in an XFX form instruction. This is like the SPR - field, but it is optional. */ -#define TBR SV + 1 - { 0x3ff, 11, insert_tbr, extract_tbr, PPC_OPERAND_OPTIONAL }, - - /* The TO field in a D or X form instruction. */ -#define TO TBR + 1 -#define TO_MASK (0x1f << 21) - { 0x1f, 21, NULL, NULL, 0 }, - - /* The UI field in a D form instruction. */ -#define UI TO + 1 - { 0xffff, 0, NULL, NULL, 0 }, - - /* The VA field in a VA, VX or VXR form instruction. */ -#define VA UI + 1 - { 0x1f, 16, NULL, NULL, PPC_OPERAND_VR }, - - /* The VB field in a VA, VX or VXR form instruction. */ -#define VB VA + 1 - { 0x1f, 11, NULL, NULL, PPC_OPERAND_VR }, - - /* The VC field in a VA form instruction. */ -#define VC VB + 1 - { 0x1f, 6, NULL, NULL, PPC_OPERAND_VR }, - - /* The VD or VS field in a VA, VX, VXR or X form instruction. */ -#define VD VC + 1 -#define VS VD - { 0x1f, 21, NULL, NULL, PPC_OPERAND_VR }, - - /* The SIMM field in a VX form instruction. */ -#define SIMM VD + 1 - { 0x1f, 16, NULL, NULL, PPC_OPERAND_SIGNED}, - - /* The UIMM field in a VX form instruction, and TE in Z form. */ -#define UIMM SIMM + 1 -#define TE UIMM - { 0x1f, 16, NULL, NULL, 0 }, - - /* The SHB field in a VA form instruction. */ -#define SHB UIMM + 1 - { 0xf, 6, NULL, NULL, 0 }, - - /* The other UIMM field in a half word EVX form instruction. */ -#define EVUIMM_2 SHB + 1 - { 0x3e, 10, NULL, NULL, PPC_OPERAND_PARENS }, - - /* The other UIMM field in a word EVX form instruction. */ -#define EVUIMM_4 EVUIMM_2 + 1 - { 0x7c, 9, NULL, NULL, PPC_OPERAND_PARENS }, - - /* The other UIMM field in a double EVX form instruction. */ -#define EVUIMM_8 EVUIMM_4 + 1 - { 0xf8, 8, NULL, NULL, PPC_OPERAND_PARENS }, - - /* The WS field. */ -#define WS EVUIMM_8 + 1 - { 0x7, 11, NULL, NULL, 0 }, - - /* The L field in an mtmsrd or A form instruction or W in an X form. */ -#define A_L WS + 1 -#define W A_L - { 0x1, 16, NULL, NULL, PPC_OPERAND_OPTIONAL }, - -#define RMC A_L + 1 - { 0x3, 9, NULL, NULL, 0 }, - -#define R RMC + 1 - { 0x1, 16, NULL, NULL, 0 }, - -#define SP R + 1 - { 0x3, 19, NULL, NULL, 0 }, - -#define S SP + 1 - { 0x1, 20, NULL, NULL, 0 }, - - /* SH field starting at bit position 16. */ -#define SH16 S + 1 - /* The DCM and DGM fields in a Z form instruction. */ -#define DCM SH16 -#define DGM DCM - { 0x3f, 10, NULL, NULL, 0 }, - - /* The EH field in larx instruction. */ -#define EH SH16 + 1 - { 0x1, 0, NULL, NULL, PPC_OPERAND_OPTIONAL }, - - /* The L field in an mtfsf or XFL form instruction. */ -#define XFL_L EH + 1 - { 0x1, 25, NULL, NULL, PPC_OPERAND_OPTIONAL}, -}; - -const unsigned int num_powerpc_operands = (sizeof (powerpc_operands) - / sizeof (powerpc_operands[0])); - -/* The functions used to insert and extract complicated operands. */ - -/* The BA field in an XL form instruction when it must be the same as - the BT field in the same instruction. This operand is marked FAKE. - The insertion function just copies the BT field into the BA field, - and the extraction function just checks that the fields are the - same. */ - -static unsigned long -insert_bat (unsigned long insn, - long value ATTRIBUTE_UNUSED, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg ATTRIBUTE_UNUSED) -{ - return insn | (((insn >> 21) & 0x1f) << 16); -} - -static long -extract_bat (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid) -{ - if (((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f)) - *invalid = 1; - return 0; -} - -/* The BB field in an XL form instruction when it must be the same as - the BA field in the same instruction. This operand is marked FAKE. - The insertion function just copies the BA field into the BB field, - and the extraction function just checks that the fields are the - same. */ - -static unsigned long -insert_bba (unsigned long insn, - long value ATTRIBUTE_UNUSED, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg ATTRIBUTE_UNUSED) -{ - return insn | (((insn >> 16) & 0x1f) << 11); -} - -static long -extract_bba (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid) -{ - if (((insn >> 16) & 0x1f) != ((insn >> 11) & 0x1f)) - *invalid = 1; - return 0; -} - -/* The BD field in a B form instruction when the - modifier is used. - This modifier means that the branch is not expected to be taken. - For chips built to versions of the architecture prior to version 2 - (ie. not Power4 compatible), we set the y bit of the BO field to 1 - if the offset is negative. When extracting, we require that the y - bit be 1 and that the offset be positive, since if the y bit is 0 - we just want to print the normal form of the instruction. - Power4 compatible targets use two bits, "a", and "t", instead of - the "y" bit. "at" == 00 => no hint, "at" == 01 => unpredictable, - "at" == 10 => not taken, "at" == 11 => taken. The "t" bit is 00001 - in BO field, the "a" bit is 00010 for branch on CR(BI) and 01000 - for branch on CTR. We only handle the taken/not-taken hint here. - Note that we don't relax the conditions tested here when - disassembling with -Many because insns using extract_bdm and - extract_bdp always occur in pairs. One or the other will always - be valid. */ - -static unsigned long -insert_bdm (unsigned long insn, - long value, - int dialect, - const char **errmsg ATTRIBUTE_UNUSED) -{ - if ((dialect & PPC_OPCODE_POWER4) == 0) - { - if ((value & 0x8000) != 0) - insn |= 1 << 21; - } - else - { - if ((insn & (0x14 << 21)) == (0x04 << 21)) - insn |= 0x02 << 21; - else if ((insn & (0x14 << 21)) == (0x10 << 21)) - insn |= 0x08 << 21; - } - return insn | (value & 0xfffc); -} - -static long -extract_bdm (unsigned long insn, - int dialect, - int *invalid) -{ - if ((dialect & PPC_OPCODE_POWER4) == 0) - { - if (((insn & (1 << 21)) == 0) != ((insn & (1 << 15)) == 0)) - *invalid = 1; - } - else - { - if ((insn & (0x17 << 21)) != (0x06 << 21) - && (insn & (0x1d << 21)) != (0x18 << 21)) - *invalid = 1; - } - - return ((insn & 0xfffc) ^ 0x8000) - 0x8000; -} - -/* The BD field in a B form instruction when the + modifier is used. - This is like BDM, above, except that the branch is expected to be - taken. */ - -static unsigned long -insert_bdp (unsigned long insn, - long value, - int dialect, - const char **errmsg ATTRIBUTE_UNUSED) -{ - if ((dialect & PPC_OPCODE_POWER4) == 0) - { - if ((value & 0x8000) == 0) - insn |= 1 << 21; - } - else - { - if ((insn & (0x14 << 21)) == (0x04 << 21)) - insn |= 0x03 << 21; - else if ((insn & (0x14 << 21)) == (0x10 << 21)) - insn |= 0x09 << 21; - } - return insn | (value & 0xfffc); -} - -static long -extract_bdp (unsigned long insn, - int dialect, - int *invalid) -{ - if ((dialect & PPC_OPCODE_POWER4) == 0) - { - if (((insn & (1 << 21)) == 0) == ((insn & (1 << 15)) == 0)) - *invalid = 1; - } - else - { - if ((insn & (0x17 << 21)) != (0x07 << 21) - && (insn & (0x1d << 21)) != (0x19 << 21)) - *invalid = 1; - } - - return ((insn & 0xfffc) ^ 0x8000) - 0x8000; -} - -/* Check for legal values of a BO field. */ - -static int -valid_bo (long value, int dialect, int extract) -{ - if ((dialect & PPC_OPCODE_POWER4) == 0) - { - int valid; - /* Certain encodings have bits that are required to be zero. - These are (z must be zero, y may be anything): - 001zy - 011zy - 1z00y - 1z01y - 1z1zz - */ - switch (value & 0x14) - { - default: - case 0: - valid = 1; - break; - case 0x4: - valid = (value & 0x2) == 0; - break; - case 0x10: - valid = (value & 0x8) == 0; - break; - case 0x14: - valid = value == 0x14; - break; - } - /* When disassembling with -Many, accept power4 encodings too. */ - if (valid - || (dialect & PPC_OPCODE_ANY) == 0 - || !extract) - return valid; - } - - /* Certain encodings have bits that are required to be zero. - These are (z must be zero, a & t may be anything): - 0000z - 0001z - 0100z - 0101z - 001at - 011at - 1a00t - 1a01t - 1z1zz - */ - if ((value & 0x14) == 0) - return (value & 0x1) == 0; - else if ((value & 0x14) == 0x14) - return value == 0x14; - else - return 1; -} - -/* The BO field in a B form instruction. Warn about attempts to set - the field to an illegal value. */ - -static unsigned long -insert_bo (unsigned long insn, - long value, - int dialect, - const char **errmsg) -{ - if (!valid_bo (value, dialect, 0)) - *errmsg = "invalid conditional option"; - return insn | ((value & 0x1f) << 21); -} - -static long -extract_bo (unsigned long insn, - int dialect, - int *invalid) -{ - long value; - - value = (insn >> 21) & 0x1f; - if (!valid_bo (value, dialect, 1)) - *invalid = 1; - return value; -} - -/* The BO field in a B form instruction when the + or - modifier is - used. This is like the BO field, but it must be even. When - extracting it, we force it to be even. */ - -static unsigned long -insert_boe (unsigned long insn, - long value, - int dialect, - const char **errmsg) -{ - if (!valid_bo (value, dialect, 0)) - *errmsg = "invalid conditional option"; - else if ((value & 1) != 0) - *errmsg = "attempt to set y bit when using + or - modifier"; - - return insn | ((value & 0x1f) << 21); -} - -static long -extract_boe (unsigned long insn, - int dialect, - int *invalid) -{ - long value; - - value = (insn >> 21) & 0x1f; - if (!valid_bo (value, dialect, 1)) - *invalid = 1; - return value & 0x1e; -} - -/* FXM mask in mfcr and mtcrf instructions. */ - -static unsigned long -insert_fxm (unsigned long insn, - long value, - int dialect, - const char **errmsg) -{ - /* If we're handling the mfocrf and mtocrf insns ensure that exactly - one bit of the mask field is set. */ - if ((insn & (1 << 20)) != 0) - { - if (value == 0 || (value & -value) != value) - { - *errmsg = "invalid mask field"; - value = 0; - } - } - - /* If the optional field on mfcr is missing that means we want to use - the old form of the instruction that moves the whole cr. In that - case we'll have VALUE zero. There doesn't seem to be a way to - distinguish this from the case where someone writes mfcr %r3,0. */ - else if (value == 0) - ; - - /* If only one bit of the FXM field is set, we can use the new form - of the instruction, which is faster. Unlike the Power4 branch hint - encoding, this is not backward compatible. Do not generate the - new form unless -mpower4 has been given, or -many and the two - operand form of mfcr was used. */ - else if ((value & -value) == value - && ((dialect & PPC_OPCODE_POWER4) != 0 - || ((dialect & PPC_OPCODE_ANY) != 0 - && (insn & (0x3ff << 1)) == 19 << 1))) - insn |= 1 << 20; - - /* Any other value on mfcr is an error. */ - else if ((insn & (0x3ff << 1)) == 19 << 1) - { - *errmsg = "ignoring invalid mfcr mask"; - value = 0; - } - - return insn | ((value & 0xff) << 12); -} - -static long -extract_fxm (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid) -{ - long mask = (insn >> 12) & 0xff; - - /* Is this a Power4 insn? */ - if ((insn & (1 << 20)) != 0) - { - /* Exactly one bit of MASK should be set. */ - if (mask == 0 || (mask & -mask) != mask) - *invalid = 1; - } - - /* Check that non-power4 form of mfcr has a zero MASK. */ - else if ((insn & (0x3ff << 1)) == 19 << 1) - { - if (mask != 0) - *invalid = 1; - } - - return mask; -} - -/* The MB and ME fields in an M form instruction expressed as a single - operand which is itself a bitmask. The extraction function always - marks it as invalid, since we never want to recognize an - instruction which uses a field of this type. */ - -static unsigned long -insert_mbe (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg) -{ - unsigned long uval, mask; - int mb, me, mx, count, last; - - uval = value; - - if (uval == 0) - { - *errmsg = "illegal bitmask"; - return insn; - } - - mb = 0; - me = 32; - if ((uval & 1) != 0) - last = 1; - else - last = 0; - count = 0; - - /* mb: location of last 0->1 transition */ - /* me: location of last 1->0 transition */ - /* count: # transitions */ - - for (mx = 0, mask = 1L << 31; mx < 32; ++mx, mask >>= 1) - { - if ((uval & mask) && !last) - { - ++count; - mb = mx; - last = 1; - } - else if (!(uval & mask) && last) - { - ++count; - me = mx; - last = 0; - } - } - if (me == 0) - me = 32; - - if (count != 2 && (count != 0 || ! last)) - *errmsg = "illegal bitmask"; - - return insn | (mb << 6) | ((me - 1) << 1); -} - -static long -extract_mbe (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid) -{ - long ret; - int mb, me; - int i; - - *invalid = 1; - - mb = (insn >> 6) & 0x1f; - me = (insn >> 1) & 0x1f; - if (mb < me + 1) - { - ret = 0; - for (i = mb; i <= me; i++) - ret |= 1L << (31 - i); - } - else if (mb == me + 1) - ret = ~0; - else /* (mb > me + 1) */ - { - ret = ~0; - for (i = me + 1; i < mb; i++) - ret &= ~(1L << (31 - i)); - } - return ret; -} - -/* The MB or ME field in an MD or MDS form instruction. The high bit - is wrapped to the low end. */ - -static unsigned long -insert_mb6 (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg ATTRIBUTE_UNUSED) -{ - return insn | ((value & 0x1f) << 6) | (value & 0x20); -} - -static long -extract_mb6 (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid ATTRIBUTE_UNUSED) -{ - return ((insn >> 6) & 0x1f) | (insn & 0x20); -} - -/* The NB field in an X form instruction. The value 32 is stored as - 0. */ - -static long -extract_nb (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid ATTRIBUTE_UNUSED) -{ - long ret; - - ret = (insn >> 11) & 0x1f; - if (ret == 0) - ret = 32; - return ret; -} - -/* The NSI field in a D form instruction. This is the same as the SI - field, only negated. The extraction function always marks it as - invalid, since we never want to recognize an instruction which uses - a field of this type. */ - -static unsigned long -insert_nsi (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg ATTRIBUTE_UNUSED) -{ - return insn | (-value & 0xffff); -} - -static long -extract_nsi (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid) -{ - *invalid = 1; - return -(((insn & 0xffff) ^ 0x8000) - 0x8000); -} - -/* The RA field in a D or X form instruction which is an updating - load, which means that the RA field may not be zero and may not - equal the RT field. */ - -static unsigned long -insert_ral (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg) -{ - if (value == 0 - || (unsigned long) value == ((insn >> 21) & 0x1f)) - *errmsg = "invalid register operand when updating"; - return insn | ((value & 0x1f) << 16); -} - -/* The RA field in an lmw instruction, which has special value - restrictions. */ - -static unsigned long -insert_ram (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg) -{ - if ((unsigned long) value >= ((insn >> 21) & 0x1f)) - *errmsg = "index register in load range"; - return insn | ((value & 0x1f) << 16); -} - -/* The RA field in the DQ form lq instruction, which has special - value restrictions. */ - -static unsigned long -insert_raq (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg) -{ - long rtvalue = (insn & RT_MASK) >> 21; - - if (value == rtvalue) - *errmsg = "source and target register operands must be different"; - return insn | ((value & 0x1f) << 16); -} - -/* The RA field in a D or X form instruction which is an updating - store or an updating floating point load, which means that the RA - field may not be zero. */ - -static unsigned long -insert_ras (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg) -{ - if (value == 0) - *errmsg = "invalid register operand when updating"; - return insn | ((value & 0x1f) << 16); -} - -/* The RB field in an X form instruction when it must be the same as - the RS field in the instruction. This is used for extended - mnemonics like mr. This operand is marked FAKE. The insertion - function just copies the BT field into the BA field, and the - extraction function just checks that the fields are the same. */ - -static unsigned long -insert_rbs (unsigned long insn, - long value ATTRIBUTE_UNUSED, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg ATTRIBUTE_UNUSED) -{ - return insn | (((insn >> 21) & 0x1f) << 11); -} - -static long -extract_rbs (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid) -{ - if (((insn >> 21) & 0x1f) != ((insn >> 11) & 0x1f)) - *invalid = 1; - return 0; -} - -/* The SH field in an MD form instruction. This is split. */ - -static unsigned long -insert_sh6 (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg ATTRIBUTE_UNUSED) -{ - return insn | ((value & 0x1f) << 11) | ((value & 0x20) >> 4); -} - -static long -extract_sh6 (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid ATTRIBUTE_UNUSED) -{ - return ((insn >> 11) & 0x1f) | ((insn << 4) & 0x20); -} - -/* The SPR field in an XFX form instruction. This is flipped--the - lower 5 bits are stored in the upper 5 and vice- versa. */ - -static unsigned long -insert_spr (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg ATTRIBUTE_UNUSED) -{ - return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6); -} - -static long -extract_spr (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid ATTRIBUTE_UNUSED) -{ - return ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0); -} - -/* Some dialects have 8 SPRG registers instead of the standard 4. */ - -static unsigned long -insert_sprg (unsigned long insn, - long value, - int dialect, - const char **errmsg) -{ - /* This check uses PPC_OPCODE_403 because PPC405 is later defined - as a synonym. If ever a 405 specific dialect is added this - check should use that instead. */ - if (value > 7 - || (value > 3 - && (dialect & (PPC_OPCODE_BOOKE | PPC_OPCODE_403)) == 0)) - *errmsg = "invalid sprg number"; - - /* If this is mfsprg4..7 then use spr 260..263 which can be read in - user mode. Anything else must use spr 272..279. */ - if (value <= 3 || (insn & 0x100) != 0) - value |= 0x10; - - return insn | ((value & 0x17) << 16); -} - -static long -extract_sprg (unsigned long insn, - int dialect, - int *invalid) -{ - unsigned long val = (insn >> 16) & 0x1f; - - /* mfsprg can use 260..263 and 272..279. mtsprg only uses spr 272..279 - If not BOOKE or 405, then both use only 272..275. */ - if (val <= 3 - || (val < 0x10 && (insn & 0x100) != 0) - || (val - 0x10 > 3 - && (dialect & (PPC_OPCODE_BOOKE | PPC_OPCODE_403)) == 0)) - *invalid = 1; - return val & 7; -} - -/* The TBR field in an XFX instruction. This is just like SPR, but it - is optional. When TBR is omitted, it must be inserted as 268 (the - magic number of the TB register). These functions treat 0 - (indicating an omitted optional operand) as 268. This means that - ``mftb 4,0'' is not handled correctly. This does not matter very - much, since the architecture manual does not define mftb as - accepting any values other than 268 or 269. */ - -#define TB (268) - -static unsigned long -insert_tbr (unsigned long insn, - long value, - int dialect ATTRIBUTE_UNUSED, - const char **errmsg ATTRIBUTE_UNUSED) -{ - if (value == 0) - value = TB; - return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6); -} - -static long -extract_tbr (unsigned long insn, - int dialect ATTRIBUTE_UNUSED, - int *invalid ATTRIBUTE_UNUSED) -{ - long ret; - - ret = ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0); - if (ret == TB) - ret = 0; - return ret; -} - -/* Macros used to form opcodes. */ - -/* The main opcode. */ -#define OP(x) ((((unsigned long)(x)) & 0x3f) << 26) -#define OP_MASK OP (0x3f) - -/* The main opcode combined with a trap code in the TO field of a D - form instruction. Used for extended mnemonics for the trap - instructions. */ -#define OPTO(x,to) (OP (x) | ((((unsigned long)(to)) & 0x1f) << 21)) -#define OPTO_MASK (OP_MASK | TO_MASK) - -/* The main opcode combined with a comparison size bit in the L field - of a D form or X form instruction. Used for extended mnemonics for - the comparison instructions. */ -#define OPL(x,l) (OP (x) | ((((unsigned long)(l)) & 1) << 21)) -#define OPL_MASK OPL (0x3f,1) - -/* An A form instruction. */ -#define A(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x1f) << 1) | (((unsigned long)(rc)) & 1)) -#define A_MASK A (0x3f, 0x1f, 1) - -/* An A_MASK with the FRB field fixed. */ -#define AFRB_MASK (A_MASK | FRB_MASK) - -/* An A_MASK with the FRC field fixed. */ -#define AFRC_MASK (A_MASK | FRC_MASK) - -/* An A_MASK with the FRA and FRC fields fixed. */ -#define AFRAFRC_MASK (A_MASK | FRA_MASK | FRC_MASK) - -/* An AFRAFRC_MASK, but with L bit clear. */ -#define AFRALFRC_MASK (AFRAFRC_MASK & ~((unsigned long) 1 << 16)) - -/* A B form instruction. */ -#define B(op, aa, lk) (OP (op) | ((((unsigned long)(aa)) & 1) << 1) | ((lk) & 1)) -#define B_MASK B (0x3f, 1, 1) - -/* A B form instruction setting the BO field. */ -#define BBO(op, bo, aa, lk) (B ((op), (aa), (lk)) | ((((unsigned long)(bo)) & 0x1f) << 21)) -#define BBO_MASK BBO (0x3f, 0x1f, 1, 1) - -/* A BBO_MASK with the y bit of the BO field removed. This permits - matching a conditional branch regardless of the setting of the y - bit. Similarly for the 'at' bits used for power4 branch hints. */ -#define Y_MASK (((unsigned long) 1) << 21) -#define AT1_MASK (((unsigned long) 3) << 21) -#define AT2_MASK (((unsigned long) 9) << 21) -#define BBOY_MASK (BBO_MASK &~ Y_MASK) -#define BBOAT_MASK (BBO_MASK &~ AT1_MASK) - -/* A B form instruction setting the BO field and the condition bits of - the BI field. */ -#define BBOCB(op, bo, cb, aa, lk) \ - (BBO ((op), (bo), (aa), (lk)) | ((((unsigned long)(cb)) & 0x3) << 16)) -#define BBOCB_MASK BBOCB (0x3f, 0x1f, 0x3, 1, 1) - -/* A BBOCB_MASK with the y bit of the BO field removed. */ -#define BBOYCB_MASK (BBOCB_MASK &~ Y_MASK) -#define BBOATCB_MASK (BBOCB_MASK &~ AT1_MASK) -#define BBOAT2CB_MASK (BBOCB_MASK &~ AT2_MASK) - -/* A BBOYCB_MASK in which the BI field is fixed. */ -#define BBOYBI_MASK (BBOYCB_MASK | BI_MASK) -#define BBOATBI_MASK (BBOAT2CB_MASK | BI_MASK) - -/* A Context form instruction. */ -#define CTX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7)) -#define CTX_MASK CTX(0x3f, 0x7) - -/* A User Context form instruction. */ -#define UCTX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x1f)) -#define UCTX_MASK UCTX(0x3f, 0x1f) - -/* The main opcode mask with the RA field clear. */ -#define DRA_MASK (OP_MASK | RA_MASK) - -/* A DS form instruction. */ -#define DSO(op, xop) (OP (op) | ((xop) & 0x3)) -#define DS_MASK DSO (0x3f, 3) - -/* A DE form instruction. */ -#define DEO(op, xop) (OP (op) | ((xop) & 0xf)) -#define DE_MASK DEO (0x3e, 0xf) - -/* An EVSEL form instruction. */ -#define EVSEL(op, xop) (OP (op) | (((unsigned long)(xop)) & 0xff) << 3) -#define EVSEL_MASK EVSEL(0x3f, 0xff) - -/* An M form instruction. */ -#define M(op, rc) (OP (op) | ((rc) & 1)) -#define M_MASK M (0x3f, 1) - -/* An M form instruction with the ME field specified. */ -#define MME(op, me, rc) (M ((op), (rc)) | ((((unsigned long)(me)) & 0x1f) << 1)) - -/* An M_MASK with the MB and ME fields fixed. */ -#define MMBME_MASK (M_MASK | MB_MASK | ME_MASK) - -/* An M_MASK with the SH and ME fields fixed. */ -#define MSHME_MASK (M_MASK | SH_MASK | ME_MASK) - -/* An MD form instruction. */ -#define MD(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x7) << 2) | ((rc) & 1)) -#define MD_MASK MD (0x3f, 0x7, 1) - -/* An MD_MASK with the MB field fixed. */ -#define MDMB_MASK (MD_MASK | MB6_MASK) - -/* An MD_MASK with the SH field fixed. */ -#define MDSH_MASK (MD_MASK | SH6_MASK) - -/* An MDS form instruction. */ -#define MDS(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0xf) << 1) | ((rc) & 1)) -#define MDS_MASK MDS (0x3f, 0xf, 1) - -/* An MDS_MASK with the MB field fixed. */ -#define MDSMB_MASK (MDS_MASK | MB6_MASK) - -/* An SC form instruction. */ -#define SC(op, sa, lk) (OP (op) | ((((unsigned long)(sa)) & 1) << 1) | ((lk) & 1)) -#define SC_MASK (OP_MASK | (((unsigned long)0x3ff) << 16) | (((unsigned long)1) << 1) | 1) - -/* A VX form instruction. */ -#define VX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7ff)) - -/* The mask for an VX form instruction. */ -#define VX_MASK VX(0x3f, 0x7ff) - -/* A VA form instruction. */ -#define VXA(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x03f)) - -/* The mask for a VA form instruction. */ -#define VXA_MASK VXA(0x3f, 0x3f) - -/* A VXR form instruction. */ -#define VXR(op, xop, rc) (OP (op) | (((rc) & 1) << 10) | (((unsigned long)(xop)) & 0x3ff)) - -/* The mask for a VXR form instruction. */ -#define VXR_MASK VXR(0x3f, 0x3ff, 1) - -/* An X form instruction. */ -#define X(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1)) - -/* A Z form instruction. */ -#define Z(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 1)) - -/* An X form instruction with the RC bit specified. */ -#define XRC(op, xop, rc) (X ((op), (xop)) | ((rc) & 1)) - -/* A Z form instruction with the RC bit specified. */ -#define ZRC(op, xop, rc) (Z ((op), (xop)) | ((rc) & 1)) - -/* The mask for an X form instruction. */ -#define X_MASK XRC (0x3f, 0x3ff, 1) - -/* The mask for a Z form instruction. */ -#define Z_MASK ZRC (0x3f, 0x1ff, 1) -#define Z2_MASK ZRC (0x3f, 0xff, 1) - -/* An X_MASK with the RA field fixed. */ -#define XRA_MASK (X_MASK | RA_MASK) - -/* An XRA_MASK with the W field clear. */ -#define XWRA_MASK (XRA_MASK & ~((unsigned long) 1 << 16)) - -/* An X_MASK with the RB field fixed. */ -#define XRB_MASK (X_MASK | RB_MASK) - -/* An X_MASK with the RT field fixed. */ -#define XRT_MASK (X_MASK | RT_MASK) - -/* An XRT_MASK mask with the L bits clear. */ -#define XLRT_MASK (XRT_MASK & ~((unsigned long) 0x3 << 21)) - -/* An X_MASK with the RA and RB fields fixed. */ -#define XRARB_MASK (X_MASK | RA_MASK | RB_MASK) - -/* An X form instruction with the RA field fixed. */ -#define XRA(op, xop, ra) (X((op), (xop)) | (((ra) << 16) & XRA_MASK)) - -/* An XRARB_MASK, but with the L bit clear. */ -#define XRLARB_MASK (XRARB_MASK & ~((unsigned long) 1 << 16)) - -/* An X_MASK with the RT and RA fields fixed. */ -#define XRTRA_MASK (X_MASK | RT_MASK | RA_MASK) - -/* An XRTRA_MASK, but with L bit clear. */ -#define XRTLRA_MASK (XRTRA_MASK & ~((unsigned long) 1 << 21)) - -/* An X form instruction with the L bit specified. */ -#define XOPL(op, xop, l) (X ((op), (xop)) | ((((unsigned long)(l)) & 1) << 21)) - -/* The mask for an X form comparison instruction. */ -#define XCMP_MASK (X_MASK | (((unsigned long)1) << 22)) - -/* The mask for an X form comparison instruction with the L field - fixed. */ -#define XCMPL_MASK (XCMP_MASK | (((unsigned long)1) << 21)) - -/* An X form trap instruction with the TO field specified. */ -#define XTO(op, xop, to) (X ((op), (xop)) | ((((unsigned long)(to)) & 0x1f) << 21)) -#define XTO_MASK (X_MASK | TO_MASK) - -/* An X form tlb instruction with the SH field specified. */ -#define XTLB(op, xop, sh) (X ((op), (xop)) | ((((unsigned long)(sh)) & 0x1f) << 11)) -#define XTLB_MASK (X_MASK | SH_MASK) - -/* An X form sync instruction. */ -#define XSYNC(op, xop, l) (X ((op), (xop)) | ((((unsigned long)(l)) & 3) << 21)) - -/* An X form sync instruction with everything filled in except the LS field. */ -#define XSYNC_MASK (0xff9fffff) - -/* An X_MASK, but with the EH bit clear. */ -#define XEH_MASK (X_MASK & ~((unsigned long )1)) - -/* An X form AltiVec dss instruction. */ -#define XDSS(op, xop, a) (X ((op), (xop)) | ((((unsigned long)(a)) & 1) << 25)) -#define XDSS_MASK XDSS(0x3f, 0x3ff, 1) - -/* An XFL form instruction. */ -#define XFL(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1) | (((unsigned long)(rc)) & 1)) -#define XFL_MASK XFL (0x3f, 0x3ff, 1) - -/* An X form isel instruction. */ -#define XISEL(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x1f) << 1)) -#define XISEL_MASK XISEL(0x3f, 0x1f) - -/* An XL form instruction with the LK field set to 0. */ -#define XL(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1)) - -/* An XL form instruction which uses the LK field. */ -#define XLLK(op, xop, lk) (XL ((op), (xop)) | ((lk) & 1)) - -/* The mask for an XL form instruction. */ -#define XL_MASK XLLK (0x3f, 0x3ff, 1) - -/* An XL form instruction which explicitly sets the BO field. */ -#define XLO(op, bo, xop, lk) \ - (XLLK ((op), (xop), (lk)) | ((((unsigned long)(bo)) & 0x1f) << 21)) -#define XLO_MASK (XL_MASK | BO_MASK) - -/* An XL form instruction which explicitly sets the y bit of the BO - field. */ -#define XLYLK(op, xop, y, lk) (XLLK ((op), (xop), (lk)) | ((((unsigned long)(y)) & 1) << 21)) -#define XLYLK_MASK (XL_MASK | Y_MASK) - -/* An XL form instruction which sets the BO field and the condition - bits of the BI field. */ -#define XLOCB(op, bo, cb, xop, lk) \ - (XLO ((op), (bo), (xop), (lk)) | ((((unsigned long)(cb)) & 3) << 16)) -#define XLOCB_MASK XLOCB (0x3f, 0x1f, 0x3, 0x3ff, 1) - -/* An XL_MASK or XLYLK_MASK or XLOCB_MASK with the BB field fixed. */ -#define XLBB_MASK (XL_MASK | BB_MASK) -#define XLYBB_MASK (XLYLK_MASK | BB_MASK) -#define XLBOCBBB_MASK (XLOCB_MASK | BB_MASK) - -/* A mask for branch instructions using the BH field. */ -#define XLBH_MASK (XL_MASK | (0x1c << 11)) - -/* An XL_MASK with the BO and BB fields fixed. */ -#define XLBOBB_MASK (XL_MASK | BO_MASK | BB_MASK) - -/* An XL_MASK with the BO, BI and BB fields fixed. */ -#define XLBOBIBB_MASK (XL_MASK | BO_MASK | BI_MASK | BB_MASK) - -/* An XO form instruction. */ -#define XO(op, xop, oe, rc) \ - (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 1) | ((((unsigned long)(oe)) & 1) << 10) | (((unsigned long)(rc)) & 1)) -#define XO_MASK XO (0x3f, 0x1ff, 1, 1) - -/* An XO_MASK with the RB field fixed. */ -#define XORB_MASK (XO_MASK | RB_MASK) - -/* An XS form instruction. */ -#define XS(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 2) | (((unsigned long)(rc)) & 1)) -#define XS_MASK XS (0x3f, 0x1ff, 1) - -/* A mask for the FXM version of an XFX form instruction. */ -#define XFXFXM_MASK (X_MASK | (1 << 11) | (1 << 20)) - -/* An XFX form instruction with the FXM field filled in. */ -#define XFXM(op, xop, fxm, p4) \ - (X ((op), (xop)) | ((((unsigned long)(fxm)) & 0xff) << 12) \ - | ((unsigned long)(p4) << 20)) - -/* An XFX form instruction with the SPR field filled in. */ -#define XSPR(op, xop, spr) \ - (X ((op), (xop)) | ((((unsigned long)(spr)) & 0x1f) << 16) | ((((unsigned long)(spr)) & 0x3e0) << 6)) -#define XSPR_MASK (X_MASK | SPR_MASK) - -/* An XFX form instruction with the SPR field filled in except for the - SPRBAT field. */ -#define XSPRBAT_MASK (XSPR_MASK &~ SPRBAT_MASK) - -/* An XFX form instruction with the SPR field filled in except for the - SPRG field. */ -#define XSPRG_MASK (XSPR_MASK & ~(0x1f << 16)) - -/* An X form instruction with everything filled in except the E field. */ -#define XE_MASK (0xffff7fff) - -/* An X form user context instruction. */ -#define XUC(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x1f)) -#define XUC_MASK XUC(0x3f, 0x1f) - -/* The BO encodings used in extended conditional branch mnemonics. */ -#define BODNZF (0x0) -#define BODNZFP (0x1) -#define BODZF (0x2) -#define BODZFP (0x3) -#define BODNZT (0x8) -#define BODNZTP (0x9) -#define BODZT (0xa) -#define BODZTP (0xb) - -#define BOF (0x4) -#define BOFP (0x5) -#define BOFM4 (0x6) -#define BOFP4 (0x7) -#define BOT (0xc) -#define BOTP (0xd) -#define BOTM4 (0xe) -#define BOTP4 (0xf) - -#define BODNZ (0x10) -#define BODNZP (0x11) -#define BODZ (0x12) -#define BODZP (0x13) -#define BODNZM4 (0x18) -#define BODNZP4 (0x19) -#define BODZM4 (0x1a) -#define BODZP4 (0x1b) - -#define BOU (0x14) - -/* The BI condition bit encodings used in extended conditional branch - mnemonics. */ -#define CBLT (0) -#define CBGT (1) -#define CBEQ (2) -#define CBSO (3) - -/* The TO encodings used in extended trap mnemonics. */ -#define TOLGT (0x1) -#define TOLLT (0x2) -#define TOEQ (0x4) -#define TOLGE (0x5) -#define TOLNL (0x5) -#define TOLLE (0x6) -#define TOLNG (0x6) -#define TOGT (0x8) -#define TOGE (0xc) -#define TONL (0xc) -#define TOLT (0x10) -#define TOLE (0x14) -#define TONG (0x14) -#define TONE (0x18) -#define TOU (0x1f) - -/* Smaller names for the flags so each entry in the opcodes table will - fit on a single line. */ -#undef PPC -#define PPC PPC_OPCODE_PPC -#define PPCCOM PPC_OPCODE_PPC | PPC_OPCODE_COMMON -#define NOPOWER4 PPC_OPCODE_NOPOWER4 | PPCCOM -#define POWER4 PPC_OPCODE_POWER4 -#define POWER5 PPC_OPCODE_POWER5 -#define POWER6 PPC_OPCODE_POWER6 -/* Documentation purposes only; we don't actually check the isa for disas. */ -#define POWER7 PPC_OPCODE_POWER6 -#define POWER9 PPC_OPCODE_POWER6 -#define CELL PPC_OPCODE_CELL -#define PPC32 PPC_OPCODE_32 | PPC_OPCODE_PPC -#define PPC64 PPC_OPCODE_64 | PPC_OPCODE_PPC -#define PPC403 PPC_OPCODE_403 -#define PPC405 PPC403 -#define PPC440 PPC_OPCODE_440 -#define PPC750 PPC -#define PPC860 PPC -#define PPCVEC PPC_OPCODE_ALTIVEC -#define POWER PPC_OPCODE_POWER -#define POWER2 PPC_OPCODE_POWER | PPC_OPCODE_POWER2 -#define PPCPWR2 PPC_OPCODE_PPC | PPC_OPCODE_POWER | PPC_OPCODE_POWER2 -#define POWER32 PPC_OPCODE_POWER | PPC_OPCODE_32 -#define COM PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON -#define COM32 PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON | PPC_OPCODE_32 -#define M601 PPC_OPCODE_POWER | PPC_OPCODE_601 -#define PWRCOM PPC_OPCODE_POWER | PPC_OPCODE_601 | PPC_OPCODE_COMMON -#define MFDEC1 PPC_OPCODE_POWER -#define MFDEC2 PPC_OPCODE_PPC | PPC_OPCODE_601 | PPC_OPCODE_BOOKE -#define BOOKE PPC_OPCODE_BOOKE -#define BOOKE64 PPC_OPCODE_BOOKE64 -#define CLASSIC PPC_OPCODE_CLASSIC -#define PPCE300 PPC_OPCODE_E300 -#define PPCSPE PPC_OPCODE_SPE -#define PPCISEL PPC_OPCODE_ISEL -#define PPCEFS PPC_OPCODE_EFS -#define PPCBRLK PPC_OPCODE_BRLOCK -#define PPCPMR PPC_OPCODE_PMR -#define PPCCHLK PPC_OPCODE_CACHELCK -#define PPCCHLK64 PPC_OPCODE_CACHELCK | PPC_OPCODE_BOOKE64 -#define PPCRFMCI PPC_OPCODE_RFMCI - -/* The opcode table. - - The format of the opcode table is: - - NAME OPCODE MASK FLAGS { OPERANDS } - - NAME is the name of the instruction. - OPCODE is the instruction opcode. - MASK is the opcode mask; this is used to tell the disassembler - which bits in the actual opcode must match OPCODE. - FLAGS are flags indicated what processors support the instruction. - OPERANDS is the list of operands. - - The disassembler reads the table in order and prints the first - instruction which matches, so this table is sorted to put more - specific instructions before more general instructions. It is also - sorted by major opcode. */ - -const struct powerpc_opcode powerpc_opcodes[] = { -{ "attn", X(0,256), X_MASK, POWER4, { 0 } }, -{ "tdlgti", OPTO(2,TOLGT), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdllti", OPTO(2,TOLLT), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdeqi", OPTO(2,TOEQ), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdlgei", OPTO(2,TOLGE), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdlnli", OPTO(2,TOLNL), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdllei", OPTO(2,TOLLE), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdlngi", OPTO(2,TOLNG), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdgti", OPTO(2,TOGT), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdgei", OPTO(2,TOGE), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdnli", OPTO(2,TONL), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdlti", OPTO(2,TOLT), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdlei", OPTO(2,TOLE), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdngi", OPTO(2,TONG), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdnei", OPTO(2,TONE), OPTO_MASK, PPC64, { RA, SI } }, -{ "tdi", OP(2), OP_MASK, PPC64, { TO, RA, SI } }, - -{ "twlgti", OPTO(3,TOLGT), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tlgti", OPTO(3,TOLGT), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twllti", OPTO(3,TOLLT), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tllti", OPTO(3,TOLLT), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "tweqi", OPTO(3,TOEQ), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "teqi", OPTO(3,TOEQ), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twlgei", OPTO(3,TOLGE), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tlgei", OPTO(3,TOLGE), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twlnli", OPTO(3,TOLNL), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tlnli", OPTO(3,TOLNL), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twllei", OPTO(3,TOLLE), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tllei", OPTO(3,TOLLE), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twlngi", OPTO(3,TOLNG), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tlngi", OPTO(3,TOLNG), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twgti", OPTO(3,TOGT), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tgti", OPTO(3,TOGT), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twgei", OPTO(3,TOGE), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tgei", OPTO(3,TOGE), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twnli", OPTO(3,TONL), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tnli", OPTO(3,TONL), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twlti", OPTO(3,TOLT), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tlti", OPTO(3,TOLT), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twlei", OPTO(3,TOLE), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tlei", OPTO(3,TOLE), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twngi", OPTO(3,TONG), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tngi", OPTO(3,TONG), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twnei", OPTO(3,TONE), OPTO_MASK, PPCCOM, { RA, SI } }, -{ "tnei", OPTO(3,TONE), OPTO_MASK, PWRCOM, { RA, SI } }, -{ "twi", OP(3), OP_MASK, PPCCOM, { TO, RA, SI } }, -{ "ti", OP(3), OP_MASK, PWRCOM, { TO, RA, SI } }, - -{ "macchw", XO(4,172,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchw.", XO(4,172,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwo", XO(4,172,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwo.", XO(4,172,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchws", XO(4,236,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchws.", XO(4,236,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwso", XO(4,236,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwso.", XO(4,236,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwsu", XO(4,204,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwsu.", XO(4,204,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwsuo", XO(4,204,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwsuo.", XO(4,204,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwu", XO(4,140,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwu.", XO(4,140,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwuo", XO(4,140,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "macchwuo.", XO(4,140,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhw", XO(4,44,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhw.", XO(4,44,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwo", XO(4,44,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwo.", XO(4,44,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhws", XO(4,108,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhws.", XO(4,108,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwso", XO(4,108,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwso.", XO(4,108,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwsu", XO(4,76,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwsu.", XO(4,76,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwsuo", XO(4,76,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwsuo.", XO(4,76,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwu", XO(4,12,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwu.", XO(4,12,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwuo", XO(4,12,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "machhwuo.", XO(4,12,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhw", XO(4,428,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhw.", XO(4,428,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwo", XO(4,428,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwo.", XO(4,428,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhws", XO(4,492,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhws.", XO(4,492,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwso", XO(4,492,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwso.", XO(4,492,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwsu", XO(4,460,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwsu.", XO(4,460,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwsuo", XO(4,460,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwsuo.", XO(4,460,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwu", XO(4,396,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwu.", XO(4,396,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwuo", XO(4,396,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "maclhwuo.", XO(4,396,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mulchw", XRC(4,168,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mulchw.", XRC(4,168,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mulchwu", XRC(4,136,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mulchwu.", XRC(4,136,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mulhhw", XRC(4,40,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mulhhw.", XRC(4,40,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mulhhwu", XRC(4,8,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mulhhwu.", XRC(4,8,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mullhw", XRC(4,424,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mullhw.", XRC(4,424,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mullhwu", XRC(4,392,0), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mullhwu.", XRC(4,392,1), X_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmacchw", XO(4,174,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmacchw.", XO(4,174,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmacchwo", XO(4,174,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmacchwo.", XO(4,174,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmacchws", XO(4,238,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmacchws.", XO(4,238,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmacchwso", XO(4,238,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmacchwso.", XO(4,238,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmachhw", XO(4,46,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmachhw.", XO(4,46,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmachhwo", XO(4,46,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmachhwo.", XO(4,46,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmachhws", XO(4,110,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmachhws.", XO(4,110,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmachhwso", XO(4,110,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmachhwso.", XO(4,110,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmaclhw", XO(4,430,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmaclhw.", XO(4,430,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmaclhwo", XO(4,430,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmaclhwo.", XO(4,430,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmaclhws", XO(4,494,0,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmaclhws.", XO(4,494,0,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmaclhwso", XO(4,494,1,0), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "nmaclhwso.", XO(4,494,1,1), XO_MASK, PPC405|PPC440, { RT, RA, RB } }, -{ "mfvscr", VX(4, 1540), VX_MASK, PPCVEC, { VD } }, -{ "mtvscr", VX(4, 1604), VX_MASK, PPCVEC, { VB } }, - - /* Double-precision opcodes. */ - /* Some of these conflict with AltiVec, so move them before, since - PPCVEC includes the PPC_OPCODE_PPC set. */ -{ "efscfd", VX(4, 719), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdabs", VX(4, 740), VX_MASK, PPCEFS, { RS, RA } }, -{ "efdnabs", VX(4, 741), VX_MASK, PPCEFS, { RS, RA } }, -{ "efdneg", VX(4, 742), VX_MASK, PPCEFS, { RS, RA } }, -{ "efdadd", VX(4, 736), VX_MASK, PPCEFS, { RS, RA, RB } }, -{ "efdsub", VX(4, 737), VX_MASK, PPCEFS, { RS, RA, RB } }, -{ "efdmul", VX(4, 744), VX_MASK, PPCEFS, { RS, RA, RB } }, -{ "efddiv", VX(4, 745), VX_MASK, PPCEFS, { RS, RA, RB } }, -{ "efdcmpgt", VX(4, 748), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efdcmplt", VX(4, 749), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efdcmpeq", VX(4, 750), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efdtstgt", VX(4, 764), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efdtstlt", VX(4, 765), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efdtsteq", VX(4, 766), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efdcfsi", VX(4, 753), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdcfsid", VX(4, 739), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdcfui", VX(4, 752), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdcfuid", VX(4, 738), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdcfsf", VX(4, 755), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdcfuf", VX(4, 754), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdctsi", VX(4, 757), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdctsidz",VX(4, 747), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdctsiz", VX(4, 762), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdctui", VX(4, 756), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdctuidz",VX(4, 746), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdctuiz", VX(4, 760), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdctsf", VX(4, 759), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdctuf", VX(4, 758), VX_MASK, PPCEFS, { RS, RB } }, -{ "efdcfs", VX(4, 751), VX_MASK, PPCEFS, { RS, RB } }, - /* End of double-precision opcodes. */ - -{ "vaddcuw", VX(4, 384), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vaddfp", VX(4, 10), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vaddsbs", VX(4, 768), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vaddshs", VX(4, 832), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vaddsws", VX(4, 896), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vaddubm", VX(4, 0), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vaddubs", VX(4, 512), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vadduhm", VX(4, 64), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vadduhs", VX(4, 576), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vadduwm", VX(4, 128), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vadduws", VX(4, 640), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vand", VX(4, 1028), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vandc", VX(4, 1092), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vavgsb", VX(4, 1282), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vavgsh", VX(4, 1346), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vavgsw", VX(4, 1410), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vavgub", VX(4, 1026), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vavguh", VX(4, 1090), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vavguw", VX(4, 1154), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcfsx", VX(4, 842), VX_MASK, PPCVEC, { VD, VB, UIMM } }, -{ "vcfux", VX(4, 778), VX_MASK, PPCVEC, { VD, VB, UIMM } }, -{ "vcmpbfp", VXR(4, 966, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpbfp.", VXR(4, 966, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpeqfp", VXR(4, 198, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpeqfp.", VXR(4, 198, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpequb", VXR(4, 6, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpequb.", VXR(4, 6, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpequh", VXR(4, 70, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpequh.", VXR(4, 70, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpequw", VXR(4, 134, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpequw.", VXR(4, 134, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgefp", VXR(4, 454, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgefp.", VXR(4, 454, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtfp", VXR(4, 710, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtfp.", VXR(4, 710, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtsb", VXR(4, 774, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtsb.", VXR(4, 774, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtsh", VXR(4, 838, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtsh.", VXR(4, 838, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtsw", VXR(4, 902, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtsw.", VXR(4, 902, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtub", VXR(4, 518, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtub.", VXR(4, 518, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtuh", VXR(4, 582, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtuh.", VXR(4, 582, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtuw", VXR(4, 646, 0), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vcmpgtuw.", VXR(4, 646, 1), VXR_MASK, PPCVEC, { VD, VA, VB } }, -{ "vctsxs", VX(4, 970), VX_MASK, PPCVEC, { VD, VB, UIMM } }, -{ "vctuxs", VX(4, 906), VX_MASK, PPCVEC, { VD, VB, UIMM } }, -{ "vexptefp", VX(4, 394), VX_MASK, PPCVEC, { VD, VB } }, -{ "vlogefp", VX(4, 458), VX_MASK, PPCVEC, { VD, VB } }, -{ "vmaddfp", VXA(4, 46), VXA_MASK, PPCVEC, { VD, VA, VC, VB } }, -{ "vmaxfp", VX(4, 1034), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmaxsb", VX(4, 258), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmaxsh", VX(4, 322), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmaxsw", VX(4, 386), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmaxub", VX(4, 2), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmaxuh", VX(4, 66), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmaxuw", VX(4, 130), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmhaddshs", VXA(4, 32), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vmhraddshs", VXA(4, 33), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vminfp", VX(4, 1098), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vminsb", VX(4, 770), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vminsh", VX(4, 834), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vminsw", VX(4, 898), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vminub", VX(4, 514), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vminuh", VX(4, 578), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vminuw", VX(4, 642), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmladduhm", VXA(4, 34), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vmrghb", VX(4, 12), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmrghh", VX(4, 76), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmrghw", VX(4, 140), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmrglb", VX(4, 268), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmrglh", VX(4, 332), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmrglw", VX(4, 396), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmsummbm", VXA(4, 37), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vmsumshm", VXA(4, 40), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vmsumshs", VXA(4, 41), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vmsumubm", VXA(4, 36), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vmsumuhm", VXA(4, 38), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vmsumuhs", VXA(4, 39), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vmulesb", VX(4, 776), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmulesh", VX(4, 840), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmuleub", VX(4, 520), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmuleuh", VX(4, 584), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmulosb", VX(4, 264), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmulosh", VX(4, 328), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmuloub", VX(4, 8), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vmulouh", VX(4, 72), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vnmsubfp", VXA(4, 47), VXA_MASK, PPCVEC, { VD, VA, VC, VB } }, -{ "vnor", VX(4, 1284), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vor", VX(4, 1156), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vperm", VXA(4, 43), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vpkpx", VX(4, 782), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vpkshss", VX(4, 398), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vpkshus", VX(4, 270), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vpkswss", VX(4, 462), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vpkswus", VX(4, 334), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vpkuhum", VX(4, 14), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vpkuhus", VX(4, 142), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vpkuwum", VX(4, 78), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vpkuwus", VX(4, 206), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vrefp", VX(4, 266), VX_MASK, PPCVEC, { VD, VB } }, -{ "vrfim", VX(4, 714), VX_MASK, PPCVEC, { VD, VB } }, -{ "vrfin", VX(4, 522), VX_MASK, PPCVEC, { VD, VB } }, -{ "vrfip", VX(4, 650), VX_MASK, PPCVEC, { VD, VB } }, -{ "vrfiz", VX(4, 586), VX_MASK, PPCVEC, { VD, VB } }, -{ "vrlb", VX(4, 4), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vrlh", VX(4, 68), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vrlw", VX(4, 132), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vrsqrtefp", VX(4, 330), VX_MASK, PPCVEC, { VD, VB } }, -{ "vrldmi", VX(4, 197), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vrldnm", VX(4, 453), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vrlwmi", VX(4, 133), VX_MASK, PPCVEC, { VD, VA, VB} }, -{ "vrlwnm", VX(4, 389), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsel", VXA(4, 42), VXA_MASK, PPCVEC, { VD, VA, VB, VC } }, -{ "vsl", VX(4, 452), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vslb", VX(4, 260), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsldoi", VXA(4, 44), VXA_MASK, PPCVEC, { VD, VA, VB, SHB } }, -{ "vslh", VX(4, 324), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vslo", VX(4, 1036), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vslw", VX(4, 388), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vspltb", VX(4, 524), VX_MASK, PPCVEC, { VD, VB, UIMM } }, -{ "vsplth", VX(4, 588), VX_MASK, PPCVEC, { VD, VB, UIMM } }, -{ "vspltisb", VX(4, 780), VX_MASK, PPCVEC, { VD, SIMM } }, -{ "vspltish", VX(4, 844), VX_MASK, PPCVEC, { VD, SIMM } }, -{ "vspltisw", VX(4, 908), VX_MASK, PPCVEC, { VD, SIMM } }, -{ "vspltw", VX(4, 652), VX_MASK, PPCVEC, { VD, VB, UIMM } }, -{ "vsr", VX(4, 708), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsrab", VX(4, 772), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsrah", VX(4, 836), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsraw", VX(4, 900), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsrb", VX(4, 516), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsrh", VX(4, 580), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsro", VX(4, 1100), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsrw", VX(4, 644), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsubcuw", VX(4, 1408), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsubfp", VX(4, 74), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsubsbs", VX(4, 1792), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsubshs", VX(4, 1856), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsubsws", VX(4, 1920), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsububm", VX(4, 1024), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsububs", VX(4, 1536), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsubuhm", VX(4, 1088), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsubuhs", VX(4, 1600), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsubuwm", VX(4, 1152), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsubuws", VX(4, 1664), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsumsws", VX(4, 1928), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsum2sws", VX(4, 1672), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsum4sbs", VX(4, 1800), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsum4shs", VX(4, 1608), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vsum4ubs", VX(4, 1544), VX_MASK, PPCVEC, { VD, VA, VB } }, -{ "vupkhpx", VX(4, 846), VX_MASK, PPCVEC, { VD, VB } }, -{ "vupkhsb", VX(4, 526), VX_MASK, PPCVEC, { VD, VB } }, -{ "vupkhsh", VX(4, 590), VX_MASK, PPCVEC, { VD, VB } }, -{ "vupklpx", VX(4, 974), VX_MASK, PPCVEC, { VD, VB } }, -{ "vupklsb", VX(4, 654), VX_MASK, PPCVEC, { VD, VB } }, -{ "vupklsh", VX(4, 718), VX_MASK, PPCVEC, { VD, VB } }, -{ "vxor", VX(4, 1220), VX_MASK, PPCVEC, { VD, VA, VB } }, - -{ "evaddw", VX(4, 512), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evaddiw", VX(4, 514), VX_MASK, PPCSPE, { RS, RB, UIMM } }, -{ "evsubfw", VX(4, 516), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evsubw", VX(4, 516), VX_MASK, PPCSPE, { RS, RB, RA } }, -{ "evsubifw", VX(4, 518), VX_MASK, PPCSPE, { RS, UIMM, RB } }, -{ "evsubiw", VX(4, 518), VX_MASK, PPCSPE, { RS, RB, UIMM } }, -{ "evabs", VX(4, 520), VX_MASK, PPCSPE, { RS, RA } }, -{ "evneg", VX(4, 521), VX_MASK, PPCSPE, { RS, RA } }, -{ "evextsb", VX(4, 522), VX_MASK, PPCSPE, { RS, RA } }, -{ "evextsh", VX(4, 523), VX_MASK, PPCSPE, { RS, RA } }, -{ "evrndw", VX(4, 524), VX_MASK, PPCSPE, { RS, RA } }, -{ "evcntlzw", VX(4, 525), VX_MASK, PPCSPE, { RS, RA } }, -{ "evcntlsw", VX(4, 526), VX_MASK, PPCSPE, { RS, RA } }, - -{ "brinc", VX(4, 527), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evand", VX(4, 529), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evandc", VX(4, 530), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmr", VX(4, 535), VX_MASK, PPCSPE, { RS, RA, BBA } }, -{ "evor", VX(4, 535), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evorc", VX(4, 539), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evxor", VX(4, 534), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "eveqv", VX(4, 537), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evnand", VX(4, 542), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evnot", VX(4, 536), VX_MASK, PPCSPE, { RS, RA, BBA } }, -{ "evnor", VX(4, 536), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evrlw", VX(4, 552), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evrlwi", VX(4, 554), VX_MASK, PPCSPE, { RS, RA, EVUIMM } }, -{ "evslw", VX(4, 548), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evslwi", VX(4, 550), VX_MASK, PPCSPE, { RS, RA, EVUIMM } }, -{ "evsrws", VX(4, 545), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evsrwu", VX(4, 544), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evsrwis", VX(4, 547), VX_MASK, PPCSPE, { RS, RA, EVUIMM } }, -{ "evsrwiu", VX(4, 546), VX_MASK, PPCSPE, { RS, RA, EVUIMM } }, -{ "evsplati", VX(4, 553), VX_MASK, PPCSPE, { RS, SIMM } }, -{ "evsplatfi", VX(4, 555), VX_MASK, PPCSPE, { RS, SIMM } }, -{ "evmergehi", VX(4, 556), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmergelo", VX(4, 557), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmergehilo",VX(4,558), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmergelohi",VX(4,559), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evcmpgts", VX(4, 561), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evcmpgtu", VX(4, 560), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evcmplts", VX(4, 563), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evcmpltu", VX(4, 562), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evcmpeq", VX(4, 564), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evsel", EVSEL(4,79),EVSEL_MASK, PPCSPE, { RS, RA, RB, CRFS } }, - -{ "evldd", VX(4, 769), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, -{ "evlddx", VX(4, 768), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evldw", VX(4, 771), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, -{ "evldwx", VX(4, 770), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evldh", VX(4, 773), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, -{ "evldhx", VX(4, 772), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evlwhe", VX(4, 785), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, -{ "evlwhex", VX(4, 784), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evlwhou", VX(4, 789), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, -{ "evlwhoux", VX(4, 788), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evlwhos", VX(4, 791), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, -{ "evlwhosx", VX(4, 790), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evlwwsplat",VX(4, 793), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, -{ "evlwwsplatx",VX(4, 792), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evlwhsplat",VX(4, 797), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, -{ "evlwhsplatx",VX(4, 796), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evlhhesplat",VX(4, 777), VX_MASK, PPCSPE, { RS, EVUIMM_2, RA } }, -{ "evlhhesplatx",VX(4, 776), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evlhhousplat",VX(4, 781), VX_MASK, PPCSPE, { RS, EVUIMM_2, RA } }, -{ "evlhhousplatx",VX(4, 780), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evlhhossplat",VX(4, 783), VX_MASK, PPCSPE, { RS, EVUIMM_2, RA } }, -{ "evlhhossplatx",VX(4, 782), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evstdd", VX(4, 801), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, -{ "evstddx", VX(4, 800), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evstdw", VX(4, 803), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, -{ "evstdwx", VX(4, 802), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evstdh", VX(4, 805), VX_MASK, PPCSPE, { RS, EVUIMM_8, RA } }, -{ "evstdhx", VX(4, 804), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evstwwe", VX(4, 825), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, -{ "evstwwex", VX(4, 824), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evstwwo", VX(4, 829), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, -{ "evstwwox", VX(4, 828), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evstwhe", VX(4, 817), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, -{ "evstwhex", VX(4, 816), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evstwho", VX(4, 821), VX_MASK, PPCSPE, { RS, EVUIMM_4, RA } }, -{ "evstwhox", VX(4, 820), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evfsabs", VX(4, 644), VX_MASK, PPCSPE, { RS, RA } }, -{ "evfsnabs", VX(4, 645), VX_MASK, PPCSPE, { RS, RA } }, -{ "evfsneg", VX(4, 646), VX_MASK, PPCSPE, { RS, RA } }, -{ "evfsadd", VX(4, 640), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evfssub", VX(4, 641), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evfsmul", VX(4, 648), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evfsdiv", VX(4, 649), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evfscmpgt", VX(4, 652), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evfscmplt", VX(4, 653), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evfscmpeq", VX(4, 654), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evfststgt", VX(4, 668), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evfststlt", VX(4, 669), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evfststeq", VX(4, 670), VX_MASK, PPCSPE, { CRFD, RA, RB } }, -{ "evfscfui", VX(4, 656), VX_MASK, PPCSPE, { RS, RB } }, -{ "evfsctuiz", VX(4, 664), VX_MASK, PPCSPE, { RS, RB } }, -{ "evfscfsi", VX(4, 657), VX_MASK, PPCSPE, { RS, RB } }, -{ "evfscfuf", VX(4, 658), VX_MASK, PPCSPE, { RS, RB } }, -{ "evfscfsf", VX(4, 659), VX_MASK, PPCSPE, { RS, RB } }, -{ "evfsctui", VX(4, 660), VX_MASK, PPCSPE, { RS, RB } }, -{ "evfsctsi", VX(4, 661), VX_MASK, PPCSPE, { RS, RB } }, -{ "evfsctsiz", VX(4, 666), VX_MASK, PPCSPE, { RS, RB } }, -{ "evfsctuf", VX(4, 662), VX_MASK, PPCSPE, { RS, RB } }, -{ "evfsctsf", VX(4, 663), VX_MASK, PPCSPE, { RS, RB } }, - -{ "efsabs", VX(4, 708), VX_MASK, PPCEFS, { RS, RA } }, -{ "efsnabs", VX(4, 709), VX_MASK, PPCEFS, { RS, RA } }, -{ "efsneg", VX(4, 710), VX_MASK, PPCEFS, { RS, RA } }, -{ "efsadd", VX(4, 704), VX_MASK, PPCEFS, { RS, RA, RB } }, -{ "efssub", VX(4, 705), VX_MASK, PPCEFS, { RS, RA, RB } }, -{ "efsmul", VX(4, 712), VX_MASK, PPCEFS, { RS, RA, RB } }, -{ "efsdiv", VX(4, 713), VX_MASK, PPCEFS, { RS, RA, RB } }, -{ "efscmpgt", VX(4, 716), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efscmplt", VX(4, 717), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efscmpeq", VX(4, 718), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efststgt", VX(4, 732), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efststlt", VX(4, 733), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efststeq", VX(4, 734), VX_MASK, PPCEFS, { CRFD, RA, RB } }, -{ "efscfui", VX(4, 720), VX_MASK, PPCEFS, { RS, RB } }, -{ "efsctuiz", VX(4, 728), VX_MASK, PPCEFS, { RS, RB } }, -{ "efscfsi", VX(4, 721), VX_MASK, PPCEFS, { RS, RB } }, -{ "efscfuf", VX(4, 722), VX_MASK, PPCEFS, { RS, RB } }, -{ "efscfsf", VX(4, 723), VX_MASK, PPCEFS, { RS, RB } }, -{ "efsctui", VX(4, 724), VX_MASK, PPCEFS, { RS, RB } }, -{ "efsctsi", VX(4, 725), VX_MASK, PPCEFS, { RS, RB } }, -{ "efsctsiz", VX(4, 730), VX_MASK, PPCEFS, { RS, RB } }, -{ "efsctuf", VX(4, 726), VX_MASK, PPCEFS, { RS, RB } }, -{ "efsctsf", VX(4, 727), VX_MASK, PPCEFS, { RS, RB } }, - -{ "evmhossf", VX(4, 1031), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhossfa", VX(4, 1063), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhosmf", VX(4, 1039), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhosmfa", VX(4, 1071), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhosmi", VX(4, 1037), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhosmia", VX(4, 1069), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhoumi", VX(4, 1036), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhoumia", VX(4, 1068), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhessf", VX(4, 1027), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhessfa", VX(4, 1059), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhesmf", VX(4, 1035), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhesmfa", VX(4, 1067), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhesmi", VX(4, 1033), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhesmia", VX(4, 1065), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmheumi", VX(4, 1032), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmheumia", VX(4, 1064), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmhossfaaw",VX(4, 1287), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhossiaaw",VX(4, 1285), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhosmfaaw",VX(4, 1295), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhosmiaaw",VX(4, 1293), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhousiaaw",VX(4, 1284), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhoumiaaw",VX(4, 1292), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhessfaaw",VX(4, 1283), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhessiaaw",VX(4, 1281), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhesmfaaw",VX(4, 1291), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhesmiaaw",VX(4, 1289), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmheusiaaw",VX(4, 1280), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmheumiaaw",VX(4, 1288), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmhossfanw",VX(4, 1415), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhossianw",VX(4, 1413), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhosmfanw",VX(4, 1423), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhosmianw",VX(4, 1421), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhousianw",VX(4, 1412), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhoumianw",VX(4, 1420), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhessfanw",VX(4, 1411), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhessianw",VX(4, 1409), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhesmfanw",VX(4, 1419), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhesmianw",VX(4, 1417), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmheusianw",VX(4, 1408), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmheumianw",VX(4, 1416), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmhogsmfaa",VX(4, 1327), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhogsmiaa",VX(4, 1325), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhogumiaa",VX(4, 1324), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhegsmfaa",VX(4, 1323), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhegsmiaa",VX(4, 1321), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhegumiaa",VX(4, 1320), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmhogsmfan",VX(4, 1455), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhogsmian",VX(4, 1453), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhogumian",VX(4, 1452), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhegsmfan",VX(4, 1451), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhegsmian",VX(4, 1449), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmhegumian",VX(4, 1448), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmwhssf", VX(4, 1095), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwhssfa", VX(4, 1127), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwhsmf", VX(4, 1103), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwhsmfa", VX(4, 1135), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwhsmi", VX(4, 1101), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwhsmia", VX(4, 1133), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwhumi", VX(4, 1100), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwhumia", VX(4, 1132), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmwlumi", VX(4, 1096), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwlumia", VX(4, 1128), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmwlssiaaw",VX(4, 1345), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwlsmiaaw",VX(4, 1353), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwlusiaaw",VX(4, 1344), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwlumiaaw",VX(4, 1352), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmwlssianw",VX(4, 1473), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwlsmianw",VX(4, 1481), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwlusianw",VX(4, 1472), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwlumianw",VX(4, 1480), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmwssf", VX(4, 1107), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwssfa", VX(4, 1139), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwsmf", VX(4, 1115), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwsmfa", VX(4, 1147), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwsmi", VX(4, 1113), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwsmia", VX(4, 1145), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwumi", VX(4, 1112), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwumia", VX(4, 1144), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmwssfaa", VX(4, 1363), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwsmfaa", VX(4, 1371), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwsmiaa", VX(4, 1369), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwumiaa", VX(4, 1368), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evmwssfan", VX(4, 1491), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwsmfan", VX(4, 1499), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwsmian", VX(4, 1497), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evmwumian", VX(4, 1496), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "evaddssiaaw",VX(4, 1217), VX_MASK, PPCSPE, { RS, RA } }, -{ "evaddsmiaaw",VX(4, 1225), VX_MASK, PPCSPE, { RS, RA } }, -{ "evaddusiaaw",VX(4, 1216), VX_MASK, PPCSPE, { RS, RA } }, -{ "evaddumiaaw",VX(4, 1224), VX_MASK, PPCSPE, { RS, RA } }, - -{ "evsubfssiaaw",VX(4, 1219), VX_MASK, PPCSPE, { RS, RA } }, -{ "evsubfsmiaaw",VX(4, 1227), VX_MASK, PPCSPE, { RS, RA } }, -{ "evsubfusiaaw",VX(4, 1218), VX_MASK, PPCSPE, { RS, RA } }, -{ "evsubfumiaaw",VX(4, 1226), VX_MASK, PPCSPE, { RS, RA } }, - -{ "evmra", VX(4, 1220), VX_MASK, PPCSPE, { RS, RA } }, - -{ "evdivws", VX(4, 1222), VX_MASK, PPCSPE, { RS, RA, RB } }, -{ "evdivwu", VX(4, 1223), VX_MASK, PPCSPE, { RS, RA, RB } }, - -{ "mulli", OP(7), OP_MASK, PPCCOM, { RT, RA, SI } }, -{ "muli", OP(7), OP_MASK, PWRCOM, { RT, RA, SI } }, - -{ "subfic", OP(8), OP_MASK, PPCCOM, { RT, RA, SI } }, -{ "sfi", OP(8), OP_MASK, PWRCOM, { RT, RA, SI } }, - -{ "dozi", OP(9), OP_MASK, M601, { RT, RA, SI } }, - -{ "bce", B(9,0,0), B_MASK, BOOKE64, { BO, BI, BD } }, -{ "bcel", B(9,0,1), B_MASK, BOOKE64, { BO, BI, BD } }, -{ "bcea", B(9,1,0), B_MASK, BOOKE64, { BO, BI, BDA } }, -{ "bcela", B(9,1,1), B_MASK, BOOKE64, { BO, BI, BDA } }, - -{ "cmplwi", OPL(10,0), OPL_MASK, PPCCOM, { OBF, RA, UI } }, -{ "cmpldi", OPL(10,1), OPL_MASK, PPC64, { OBF, RA, UI } }, -{ "cmpli", OP(10), OP_MASK, PPC, { BF, L, RA, UI } }, -{ "cmpli", OP(10), OP_MASK, PWRCOM, { BF, RA, UI } }, - -{ "cmpwi", OPL(11,0), OPL_MASK, PPCCOM, { OBF, RA, SI } }, -{ "cmpdi", OPL(11,1), OPL_MASK, PPC64, { OBF, RA, SI } }, -{ "cmpi", OP(11), OP_MASK, PPC, { BF, L, RA, SI } }, -{ "cmpi", OP(11), OP_MASK, PWRCOM, { BF, RA, SI } }, - -{ "addic", OP(12), OP_MASK, PPCCOM, { RT, RA, SI } }, -{ "ai", OP(12), OP_MASK, PWRCOM, { RT, RA, SI } }, -{ "subic", OP(12), OP_MASK, PPCCOM, { RT, RA, NSI } }, - -{ "addic.", OP(13), OP_MASK, PPCCOM, { RT, RA, SI } }, -{ "ai.", OP(13), OP_MASK, PWRCOM, { RT, RA, SI } }, -{ "subic.", OP(13), OP_MASK, PPCCOM, { RT, RA, NSI } }, - -{ "li", OP(14), DRA_MASK, PPCCOM, { RT, SI } }, -{ "lil", OP(14), DRA_MASK, PWRCOM, { RT, SI } }, -{ "addi", OP(14), OP_MASK, PPCCOM, { RT, RA0, SI } }, -{ "cal", OP(14), OP_MASK, PWRCOM, { RT, D, RA0 } }, -{ "subi", OP(14), OP_MASK, PPCCOM, { RT, RA0, NSI } }, -{ "la", OP(14), OP_MASK, PPCCOM, { RT, D, RA0 } }, - -{ "lis", OP(15), DRA_MASK, PPCCOM, { RT, SISIGNOPT } }, -{ "liu", OP(15), DRA_MASK, PWRCOM, { RT, SISIGNOPT } }, -{ "addis", OP(15), OP_MASK, PPCCOM, { RT,RA0,SISIGNOPT } }, -{ "cau", OP(15), OP_MASK, PWRCOM, { RT,RA0,SISIGNOPT } }, -{ "subis", OP(15), OP_MASK, PPCCOM, { RT, RA0, NSI } }, - -{ "bdnz-", BBO(16,BODNZ,0,0), BBOATBI_MASK, PPCCOM, { BDM } }, -{ "bdnz+", BBO(16,BODNZ,0,0), BBOATBI_MASK, PPCCOM, { BDP } }, -{ "bdnz", BBO(16,BODNZ,0,0), BBOATBI_MASK, PPCCOM, { BD } }, -{ "bdn", BBO(16,BODNZ,0,0), BBOATBI_MASK, PWRCOM, { BD } }, -{ "bdnzl-", BBO(16,BODNZ,0,1), BBOATBI_MASK, PPCCOM, { BDM } }, -{ "bdnzl+", BBO(16,BODNZ,0,1), BBOATBI_MASK, PPCCOM, { BDP } }, -{ "bdnzl", BBO(16,BODNZ,0,1), BBOATBI_MASK, PPCCOM, { BD } }, -{ "bdnl", BBO(16,BODNZ,0,1), BBOATBI_MASK, PWRCOM, { BD } }, -{ "bdnza-", BBO(16,BODNZ,1,0), BBOATBI_MASK, PPCCOM, { BDMA } }, -{ "bdnza+", BBO(16,BODNZ,1,0), BBOATBI_MASK, PPCCOM, { BDPA } }, -{ "bdnza", BBO(16,BODNZ,1,0), BBOATBI_MASK, PPCCOM, { BDA } }, -{ "bdna", BBO(16,BODNZ,1,0), BBOATBI_MASK, PWRCOM, { BDA } }, -{ "bdnzla-", BBO(16,BODNZ,1,1), BBOATBI_MASK, PPCCOM, { BDMA } }, -{ "bdnzla+", BBO(16,BODNZ,1,1), BBOATBI_MASK, PPCCOM, { BDPA } }, -{ "bdnzla", BBO(16,BODNZ,1,1), BBOATBI_MASK, PPCCOM, { BDA } }, -{ "bdnla", BBO(16,BODNZ,1,1), BBOATBI_MASK, PWRCOM, { BDA } }, -{ "bdz-", BBO(16,BODZ,0,0), BBOATBI_MASK, PPCCOM, { BDM } }, -{ "bdz+", BBO(16,BODZ,0,0), BBOATBI_MASK, PPCCOM, { BDP } }, -{ "bdz", BBO(16,BODZ,0,0), BBOATBI_MASK, COM, { BD } }, -{ "bdzl-", BBO(16,BODZ,0,1), BBOATBI_MASK, PPCCOM, { BDM } }, -{ "bdzl+", BBO(16,BODZ,0,1), BBOATBI_MASK, PPCCOM, { BDP } }, -{ "bdzl", BBO(16,BODZ,0,1), BBOATBI_MASK, COM, { BD } }, -{ "bdza-", BBO(16,BODZ,1,0), BBOATBI_MASK, PPCCOM, { BDMA } }, -{ "bdza+", BBO(16,BODZ,1,0), BBOATBI_MASK, PPCCOM, { BDPA } }, -{ "bdza", BBO(16,BODZ,1,0), BBOATBI_MASK, COM, { BDA } }, -{ "bdzla-", BBO(16,BODZ,1,1), BBOATBI_MASK, PPCCOM, { BDMA } }, -{ "bdzla+", BBO(16,BODZ,1,1), BBOATBI_MASK, PPCCOM, { BDPA } }, -{ "bdzla", BBO(16,BODZ,1,1), BBOATBI_MASK, COM, { BDA } }, -{ "blt-", BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "blt+", BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "blt", BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "bltl-", BBOCB(16,BOT,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bltl+", BBOCB(16,BOT,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bltl", BBOCB(16,BOT,CBLT,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "blta-", BBOCB(16,BOT,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "blta+", BBOCB(16,BOT,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "blta", BBOCB(16,BOT,CBLT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bltla-", BBOCB(16,BOT,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bltla+", BBOCB(16,BOT,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bltla", BBOCB(16,BOT,CBLT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bgt-", BBOCB(16,BOT,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bgt+", BBOCB(16,BOT,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bgt", BBOCB(16,BOT,CBGT,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "bgtl-", BBOCB(16,BOT,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bgtl+", BBOCB(16,BOT,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bgtl", BBOCB(16,BOT,CBGT,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "bgta-", BBOCB(16,BOT,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bgta+", BBOCB(16,BOT,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bgta", BBOCB(16,BOT,CBGT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bgtla-", BBOCB(16,BOT,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bgtla+", BBOCB(16,BOT,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bgtla", BBOCB(16,BOT,CBGT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "beq-", BBOCB(16,BOT,CBEQ,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "beq+", BBOCB(16,BOT,CBEQ,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "beq", BBOCB(16,BOT,CBEQ,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "beql-", BBOCB(16,BOT,CBEQ,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "beql+", BBOCB(16,BOT,CBEQ,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "beql", BBOCB(16,BOT,CBEQ,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "beqa-", BBOCB(16,BOT,CBEQ,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "beqa+", BBOCB(16,BOT,CBEQ,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "beqa", BBOCB(16,BOT,CBEQ,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "beqla-", BBOCB(16,BOT,CBEQ,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "beqla+", BBOCB(16,BOT,CBEQ,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "beqla", BBOCB(16,BOT,CBEQ,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bso-", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bso+", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bso", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "bsol-", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bsol+", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bsol", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "bsoa-", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bsoa+", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bsoa", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bsola-", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bsola+", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bsola", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bun-", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bun+", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bun", BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BD } }, -{ "bunl-", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bunl+", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bunl", BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BD } }, -{ "buna-", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "buna+", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "buna", BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDA } }, -{ "bunla-", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bunla+", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bunla", BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDA } }, -{ "bge-", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bge+", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bge", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "bgel-", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bgel+", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bgel", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "bgea-", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bgea+", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bgea", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bgela-", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bgela+", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bgela", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bnl-", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bnl+", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bnl", BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "bnll-", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bnll+", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bnll", BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "bnla-", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bnla+", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bnla", BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bnlla-", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bnlla+", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bnlla", BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "ble-", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "ble+", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "ble", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "blel-", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "blel+", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "blel", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "blea-", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "blea+", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "blea", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "blela-", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "blela+", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "blela", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bng-", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bng+", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bng", BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "bngl-", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bngl+", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bngl", BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "bnga-", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bnga+", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bnga", BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bngla-", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bngla+", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bngla", BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bne-", BBOCB(16,BOF,CBEQ,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bne+", BBOCB(16,BOF,CBEQ,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bne", BBOCB(16,BOF,CBEQ,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "bnel-", BBOCB(16,BOF,CBEQ,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bnel+", BBOCB(16,BOF,CBEQ,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bnel", BBOCB(16,BOF,CBEQ,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "bnea-", BBOCB(16,BOF,CBEQ,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bnea+", BBOCB(16,BOF,CBEQ,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bnea", BBOCB(16,BOF,CBEQ,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bnela-", BBOCB(16,BOF,CBEQ,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bnela+", BBOCB(16,BOF,CBEQ,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bnela", BBOCB(16,BOF,CBEQ,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bns-", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bns+", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bns", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, COM, { CR, BD } }, -{ "bnsl-", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bnsl+", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bnsl", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, COM, { CR, BD } }, -{ "bnsa-", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bnsa+", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bnsa", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bnsla-", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bnsla+", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bnsla", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, COM, { CR, BDA } }, -{ "bnu-", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bnu+", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bnu", BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM, { CR, BD } }, -{ "bnul-", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDM } }, -{ "bnul+", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BDP } }, -{ "bnul", BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM, { CR, BD } }, -{ "bnua-", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bnua+", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bnua", BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM, { CR, BDA } }, -{ "bnula-", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDMA } }, -{ "bnula+", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDPA } }, -{ "bnula", BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM, { CR, BDA } }, -{ "bdnzt-", BBO(16,BODNZT,0,0), BBOY_MASK, NOPOWER4, { BI, BDM } }, -{ "bdnzt+", BBO(16,BODNZT,0,0), BBOY_MASK, NOPOWER4, { BI, BDP } }, -{ "bdnzt", BBO(16,BODNZT,0,0), BBOY_MASK, PPCCOM, { BI, BD } }, -{ "bdnztl-", BBO(16,BODNZT,0,1), BBOY_MASK, NOPOWER4, { BI, BDM } }, -{ "bdnztl+", BBO(16,BODNZT,0,1), BBOY_MASK, NOPOWER4, { BI, BDP } }, -{ "bdnztl", BBO(16,BODNZT,0,1), BBOY_MASK, PPCCOM, { BI, BD } }, -{ "bdnzta-", BBO(16,BODNZT,1,0), BBOY_MASK, NOPOWER4, { BI, BDMA } }, -{ "bdnzta+", BBO(16,BODNZT,1,0), BBOY_MASK, NOPOWER4, { BI, BDPA } }, -{ "bdnzta", BBO(16,BODNZT,1,0), BBOY_MASK, PPCCOM, { BI, BDA } }, -{ "bdnztla-",BBO(16,BODNZT,1,1), BBOY_MASK, NOPOWER4, { BI, BDMA } }, -{ "bdnztla+",BBO(16,BODNZT,1,1), BBOY_MASK, NOPOWER4, { BI, BDPA } }, -{ "bdnztla", BBO(16,BODNZT,1,1), BBOY_MASK, PPCCOM, { BI, BDA } }, -{ "bdnzf-", BBO(16,BODNZF,0,0), BBOY_MASK, NOPOWER4, { BI, BDM } }, -{ "bdnzf+", BBO(16,BODNZF,0,0), BBOY_MASK, NOPOWER4, { BI, BDP } }, -{ "bdnzf", BBO(16,BODNZF,0,0), BBOY_MASK, PPCCOM, { BI, BD } }, -{ "bdnzfl-", BBO(16,BODNZF,0,1), BBOY_MASK, NOPOWER4, { BI, BDM } }, -{ "bdnzfl+", BBO(16,BODNZF,0,1), BBOY_MASK, NOPOWER4, { BI, BDP } }, -{ "bdnzfl", BBO(16,BODNZF,0,1), BBOY_MASK, PPCCOM, { BI, BD } }, -{ "bdnzfa-", BBO(16,BODNZF,1,0), BBOY_MASK, NOPOWER4, { BI, BDMA } }, -{ "bdnzfa+", BBO(16,BODNZF,1,0), BBOY_MASK, NOPOWER4, { BI, BDPA } }, -{ "bdnzfa", BBO(16,BODNZF,1,0), BBOY_MASK, PPCCOM, { BI, BDA } }, -{ "bdnzfla-",BBO(16,BODNZF,1,1), BBOY_MASK, NOPOWER4, { BI, BDMA } }, -{ "bdnzfla+",BBO(16,BODNZF,1,1), BBOY_MASK, NOPOWER4, { BI, BDPA } }, -{ "bdnzfla", BBO(16,BODNZF,1,1), BBOY_MASK, PPCCOM, { BI, BDA } }, -{ "bt-", BBO(16,BOT,0,0), BBOAT_MASK, PPCCOM, { BI, BDM } }, -{ "bt+", BBO(16,BOT,0,0), BBOAT_MASK, PPCCOM, { BI, BDP } }, -{ "bt", BBO(16,BOT,0,0), BBOAT_MASK, PPCCOM, { BI, BD } }, -{ "bbt", BBO(16,BOT,0,0), BBOAT_MASK, PWRCOM, { BI, BD } }, -{ "btl-", BBO(16,BOT,0,1), BBOAT_MASK, PPCCOM, { BI, BDM } }, -{ "btl+", BBO(16,BOT,0,1), BBOAT_MASK, PPCCOM, { BI, BDP } }, -{ "btl", BBO(16,BOT,0,1), BBOAT_MASK, PPCCOM, { BI, BD } }, -{ "bbtl", BBO(16,BOT,0,1), BBOAT_MASK, PWRCOM, { BI, BD } }, -{ "bta-", BBO(16,BOT,1,0), BBOAT_MASK, PPCCOM, { BI, BDMA } }, -{ "bta+", BBO(16,BOT,1,0), BBOAT_MASK, PPCCOM, { BI, BDPA } }, -{ "bta", BBO(16,BOT,1,0), BBOAT_MASK, PPCCOM, { BI, BDA } }, -{ "bbta", BBO(16,BOT,1,0), BBOAT_MASK, PWRCOM, { BI, BDA } }, -{ "btla-", BBO(16,BOT,1,1), BBOAT_MASK, PPCCOM, { BI, BDMA } }, -{ "btla+", BBO(16,BOT,1,1), BBOAT_MASK, PPCCOM, { BI, BDPA } }, -{ "btla", BBO(16,BOT,1,1), BBOAT_MASK, PPCCOM, { BI, BDA } }, -{ "bbtla", BBO(16,BOT,1,1), BBOAT_MASK, PWRCOM, { BI, BDA } }, -{ "bf-", BBO(16,BOF,0,0), BBOAT_MASK, PPCCOM, { BI, BDM } }, -{ "bf+", BBO(16,BOF,0,0), BBOAT_MASK, PPCCOM, { BI, BDP } }, -{ "bf", BBO(16,BOF,0,0), BBOAT_MASK, PPCCOM, { BI, BD } }, -{ "bbf", BBO(16,BOF,0,0), BBOAT_MASK, PWRCOM, { BI, BD } }, -{ "bfl-", BBO(16,BOF,0,1), BBOAT_MASK, PPCCOM, { BI, BDM } }, -{ "bfl+", BBO(16,BOF,0,1), BBOAT_MASK, PPCCOM, { BI, BDP } }, -{ "bfl", BBO(16,BOF,0,1), BBOAT_MASK, PPCCOM, { BI, BD } }, -{ "bbfl", BBO(16,BOF,0,1), BBOAT_MASK, PWRCOM, { BI, BD } }, -{ "bfa-", BBO(16,BOF,1,0), BBOAT_MASK, PPCCOM, { BI, BDMA } }, -{ "bfa+", BBO(16,BOF,1,0), BBOAT_MASK, PPCCOM, { BI, BDPA } }, -{ "bfa", BBO(16,BOF,1,0), BBOAT_MASK, PPCCOM, { BI, BDA } }, -{ "bbfa", BBO(16,BOF,1,0), BBOAT_MASK, PWRCOM, { BI, BDA } }, -{ "bfla-", BBO(16,BOF,1,1), BBOAT_MASK, PPCCOM, { BI, BDMA } }, -{ "bfla+", BBO(16,BOF,1,1), BBOAT_MASK, PPCCOM, { BI, BDPA } }, -{ "bfla", BBO(16,BOF,1,1), BBOAT_MASK, PPCCOM, { BI, BDA } }, -{ "bbfla", BBO(16,BOF,1,1), BBOAT_MASK, PWRCOM, { BI, BDA } }, -{ "bdzt-", BBO(16,BODZT,0,0), BBOY_MASK, NOPOWER4, { BI, BDM } }, -{ "bdzt+", BBO(16,BODZT,0,0), BBOY_MASK, NOPOWER4, { BI, BDP } }, -{ "bdzt", BBO(16,BODZT,0,0), BBOY_MASK, PPCCOM, { BI, BD } }, -{ "bdztl-", BBO(16,BODZT,0,1), BBOY_MASK, NOPOWER4, { BI, BDM } }, -{ "bdztl+", BBO(16,BODZT,0,1), BBOY_MASK, NOPOWER4, { BI, BDP } }, -{ "bdztl", BBO(16,BODZT,0,1), BBOY_MASK, PPCCOM, { BI, BD } }, -{ "bdzta-", BBO(16,BODZT,1,0), BBOY_MASK, NOPOWER4, { BI, BDMA } }, -{ "bdzta+", BBO(16,BODZT,1,0), BBOY_MASK, NOPOWER4, { BI, BDPA } }, -{ "bdzta", BBO(16,BODZT,1,0), BBOY_MASK, PPCCOM, { BI, BDA } }, -{ "bdztla-", BBO(16,BODZT,1,1), BBOY_MASK, NOPOWER4, { BI, BDMA } }, -{ "bdztla+", BBO(16,BODZT,1,1), BBOY_MASK, NOPOWER4, { BI, BDPA } }, -{ "bdztla", BBO(16,BODZT,1,1), BBOY_MASK, PPCCOM, { BI, BDA } }, -{ "bdzf-", BBO(16,BODZF,0,0), BBOY_MASK, NOPOWER4, { BI, BDM } }, -{ "bdzf+", BBO(16,BODZF,0,0), BBOY_MASK, NOPOWER4, { BI, BDP } }, -{ "bdzf", BBO(16,BODZF,0,0), BBOY_MASK, PPCCOM, { BI, BD } }, -{ "bdzfl-", BBO(16,BODZF,0,1), BBOY_MASK, NOPOWER4, { BI, BDM } }, -{ "bdzfl+", BBO(16,BODZF,0,1), BBOY_MASK, NOPOWER4, { BI, BDP } }, -{ "bdzfl", BBO(16,BODZF,0,1), BBOY_MASK, PPCCOM, { BI, BD } }, -{ "bdzfa-", BBO(16,BODZF,1,0), BBOY_MASK, NOPOWER4, { BI, BDMA } }, -{ "bdzfa+", BBO(16,BODZF,1,0), BBOY_MASK, NOPOWER4, { BI, BDPA } }, -{ "bdzfa", BBO(16,BODZF,1,0), BBOY_MASK, PPCCOM, { BI, BDA } }, -{ "bdzfla-", BBO(16,BODZF,1,1), BBOY_MASK, NOPOWER4, { BI, BDMA } }, -{ "bdzfla+", BBO(16,BODZF,1,1), BBOY_MASK, NOPOWER4, { BI, BDPA } }, -{ "bdzfla", BBO(16,BODZF,1,1), BBOY_MASK, PPCCOM, { BI, BDA } }, -{ "bc-", B(16,0,0), B_MASK, PPCCOM, { BOE, BI, BDM } }, -{ "bc+", B(16,0,0), B_MASK, PPCCOM, { BOE, BI, BDP } }, -{ "bc", B(16,0,0), B_MASK, COM, { BO, BI, BD } }, -{ "bcl-", B(16,0,1), B_MASK, PPCCOM, { BOE, BI, BDM } }, -{ "bcl+", B(16,0,1), B_MASK, PPCCOM, { BOE, BI, BDP } }, -{ "bcl", B(16,0,1), B_MASK, COM, { BO, BI, BD } }, -{ "bca-", B(16,1,0), B_MASK, PPCCOM, { BOE, BI, BDMA } }, -{ "bca+", B(16,1,0), B_MASK, PPCCOM, { BOE, BI, BDPA } }, -{ "bca", B(16,1,0), B_MASK, COM, { BO, BI, BDA } }, -{ "bcla-", B(16,1,1), B_MASK, PPCCOM, { BOE, BI, BDMA } }, -{ "bcla+", B(16,1,1), B_MASK, PPCCOM, { BOE, BI, BDPA } }, -{ "bcla", B(16,1,1), B_MASK, COM, { BO, BI, BDA } }, - -{ "sc", SC(17,1,0), SC_MASK, PPC, { LEV } }, -{ "svc", SC(17,0,0), SC_MASK, POWER, { SVC_LEV, FL1, FL2 } }, -{ "svcl", SC(17,0,1), SC_MASK, POWER, { SVC_LEV, FL1, FL2 } }, -{ "svca", SC(17,1,0), SC_MASK, PWRCOM, { SV } }, -{ "svcla", SC(17,1,1), SC_MASK, POWER, { SV } }, - -{ "b", B(18,0,0), B_MASK, COM, { LI } }, -{ "bl", B(18,0,1), B_MASK, COM, { LI } }, -{ "ba", B(18,1,0), B_MASK, COM, { LIA } }, -{ "bla", B(18,1,1), B_MASK, COM, { LIA } }, - -{ "mcrf", XL(19,0), XLBB_MASK|(3 << 21)|(3 << 16), COM, { BF, BFA } }, - -{ "blr", XLO(19,BOU,16,0), XLBOBIBB_MASK, PPCCOM, { 0 } }, -{ "br", XLO(19,BOU,16,0), XLBOBIBB_MASK, PWRCOM, { 0 } }, -{ "blrl", XLO(19,BOU,16,1), XLBOBIBB_MASK, PPCCOM, { 0 } }, -{ "brl", XLO(19,BOU,16,1), XLBOBIBB_MASK, PWRCOM, { 0 } }, -{ "bdnzlr", XLO(19,BODNZ,16,0), XLBOBIBB_MASK, PPCCOM, { 0 } }, -{ "bdnzlr-", XLO(19,BODNZ,16,0), XLBOBIBB_MASK, NOPOWER4, { 0 } }, -{ "bdnzlr-", XLO(19,BODNZM4,16,0), XLBOBIBB_MASK, POWER4, { 0 } }, -{ "bdnzlr+", XLO(19,BODNZP,16,0), XLBOBIBB_MASK, NOPOWER4, { 0 } }, -{ "bdnzlr+", XLO(19,BODNZP4,16,0), XLBOBIBB_MASK, POWER4, { 0 } }, -{ "bdnzlrl", XLO(19,BODNZ,16,1), XLBOBIBB_MASK, PPCCOM, { 0 } }, -{ "bdnzlrl-",XLO(19,BODNZ,16,1), XLBOBIBB_MASK, NOPOWER4, { 0 } }, -{ "bdnzlrl-",XLO(19,BODNZM4,16,1), XLBOBIBB_MASK, POWER4, { 0 } }, -{ "bdnzlrl+",XLO(19,BODNZP,16,1), XLBOBIBB_MASK, NOPOWER4, { 0 } }, -{ "bdnzlrl+",XLO(19,BODNZP4,16,1), XLBOBIBB_MASK, POWER4, { 0 } }, -{ "bdzlr", XLO(19,BODZ,16,0), XLBOBIBB_MASK, PPCCOM, { 0 } }, -{ "bdzlr-", XLO(19,BODZ,16,0), XLBOBIBB_MASK, NOPOWER4, { 0 } }, -{ "bdzlr-", XLO(19,BODZM4,16,0), XLBOBIBB_MASK, POWER4, { 0 } }, -{ "bdzlr+", XLO(19,BODZP,16,0), XLBOBIBB_MASK, NOPOWER4, { 0 } }, -{ "bdzlr+", XLO(19,BODZP4,16,0), XLBOBIBB_MASK, POWER4, { 0 } }, -{ "bdzlrl", XLO(19,BODZ,16,1), XLBOBIBB_MASK, PPCCOM, { 0 } }, -{ "bdzlrl-", XLO(19,BODZ,16,1), XLBOBIBB_MASK, NOPOWER4, { 0 } }, -{ "bdzlrl-", XLO(19,BODZM4,16,1), XLBOBIBB_MASK, POWER4, { 0 } }, -{ "bdzlrl+", XLO(19,BODZP,16,1), XLBOBIBB_MASK, NOPOWER4, { 0 } }, -{ "bdzlrl+", XLO(19,BODZP4,16,1), XLBOBIBB_MASK, POWER4, { 0 } }, -{ "bltlr", XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bltlr-", XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bltlr-", XLOCB(19,BOTM4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bltlr+", XLOCB(19,BOTP,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bltlr+", XLOCB(19,BOTP4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bltr", XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bltlrl", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bltlrl-", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bltlrl-", XLOCB(19,BOTM4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bltlrl+", XLOCB(19,BOTP,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bltlrl+", XLOCB(19,BOTP4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bltrl", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bgtlr", XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bgtlr-", XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgtlr-", XLOCB(19,BOTM4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgtlr+", XLOCB(19,BOTP,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgtlr+", XLOCB(19,BOTP4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgtr", XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bgtlrl", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bgtlrl-", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgtlrl-", XLOCB(19,BOTM4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgtlrl+", XLOCB(19,BOTP,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgtlrl+", XLOCB(19,BOTP4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgtrl", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "beqlr", XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "beqlr-", XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "beqlr-", XLOCB(19,BOTM4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "beqlr+", XLOCB(19,BOTP,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "beqlr+", XLOCB(19,BOTP4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "beqr", XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "beqlrl", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "beqlrl-", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "beqlrl-", XLOCB(19,BOTM4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "beqlrl+", XLOCB(19,BOTP,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "beqlrl+", XLOCB(19,BOTP4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "beqrl", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bsolr", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bsolr-", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bsolr-", XLOCB(19,BOTM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bsolr+", XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bsolr+", XLOCB(19,BOTP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bsor", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bsolrl", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bsolrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bsolrl-", XLOCB(19,BOTM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bsolrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bsolrl+", XLOCB(19,BOTP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bsorl", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bunlr", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bunlr-", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bunlr-", XLOCB(19,BOTM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bunlr+", XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bunlr+", XLOCB(19,BOTP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bunlrl", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bunlrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bunlrl-", XLOCB(19,BOTM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bunlrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bunlrl+", XLOCB(19,BOTP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgelr", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bgelr-", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgelr-", XLOCB(19,BOFM4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgelr+", XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgelr+", XLOCB(19,BOFP4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bger", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bgelrl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bgelrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgelrl-", XLOCB(19,BOFM4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgelrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgelrl+", XLOCB(19,BOFP4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgerl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bnllr", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnllr-", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnllr-", XLOCB(19,BOFM4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnllr+", XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnllr+", XLOCB(19,BOFP4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnlr", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bnllrl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnllrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnllrl-", XLOCB(19,BOFM4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnllrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnllrl+", XLOCB(19,BOFP4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnlrl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "blelr", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "blelr-", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "blelr-", XLOCB(19,BOFM4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "blelr+", XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "blelr+", XLOCB(19,BOFP4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bler", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "blelrl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "blelrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "blelrl-", XLOCB(19,BOFM4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "blelrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "blelrl+", XLOCB(19,BOFP4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "blerl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bnglr", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnglr-", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnglr-", XLOCB(19,BOFM4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnglr+", XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnglr+", XLOCB(19,BOFP4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bngr", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bnglrl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnglrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnglrl-", XLOCB(19,BOFM4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnglrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnglrl+", XLOCB(19,BOFP4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bngrl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bnelr", XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnelr-", XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnelr-", XLOCB(19,BOFM4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnelr+", XLOCB(19,BOFP,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnelr+", XLOCB(19,BOFP4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bner", XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bnelrl", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnelrl-", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnelrl-", XLOCB(19,BOFM4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnelrl+", XLOCB(19,BOFP,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnelrl+", XLOCB(19,BOFP4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnerl", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bnslr", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnslr-", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnslr-", XLOCB(19,BOFM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnslr+", XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnslr+", XLOCB(19,BOFP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnsr", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bnslrl", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnslrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnslrl-", XLOCB(19,BOFM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnslrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnslrl+", XLOCB(19,BOFP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnsrl", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PWRCOM, { CR } }, -{ "bnulr", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnulr-", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnulr-", XLOCB(19,BOFM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnulr+", XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnulr+", XLOCB(19,BOFP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnulrl", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnulrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnulrl-", XLOCB(19,BOFM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnulrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnulrl+", XLOCB(19,BOFP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "btlr", XLO(19,BOT,16,0), XLBOBB_MASK, PPCCOM, { BI } }, -{ "btlr-", XLO(19,BOT,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "btlr-", XLO(19,BOTM4,16,0), XLBOBB_MASK, POWER4, { BI } }, -{ "btlr+", XLO(19,BOTP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "btlr+", XLO(19,BOTP4,16,0), XLBOBB_MASK, POWER4, { BI } }, -{ "bbtr", XLO(19,BOT,16,0), XLBOBB_MASK, PWRCOM, { BI } }, -{ "btlrl", XLO(19,BOT,16,1), XLBOBB_MASK, PPCCOM, { BI } }, -{ "btlrl-", XLO(19,BOT,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "btlrl-", XLO(19,BOTM4,16,1), XLBOBB_MASK, POWER4, { BI } }, -{ "btlrl+", XLO(19,BOTP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "btlrl+", XLO(19,BOTP4,16,1), XLBOBB_MASK, POWER4, { BI } }, -{ "bbtrl", XLO(19,BOT,16,1), XLBOBB_MASK, PWRCOM, { BI } }, -{ "bflr", XLO(19,BOF,16,0), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bflr-", XLO(19,BOF,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bflr-", XLO(19,BOFM4,16,0), XLBOBB_MASK, POWER4, { BI } }, -{ "bflr+", XLO(19,BOFP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bflr+", XLO(19,BOFP4,16,0), XLBOBB_MASK, POWER4, { BI } }, -{ "bbfr", XLO(19,BOF,16,0), XLBOBB_MASK, PWRCOM, { BI } }, -{ "bflrl", XLO(19,BOF,16,1), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bflrl-", XLO(19,BOF,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bflrl-", XLO(19,BOFM4,16,1), XLBOBB_MASK, POWER4, { BI } }, -{ "bflrl+", XLO(19,BOFP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bflrl+", XLO(19,BOFP4,16,1), XLBOBB_MASK, POWER4, { BI } }, -{ "bbfrl", XLO(19,BOF,16,1), XLBOBB_MASK, PWRCOM, { BI } }, -{ "bdnztlr", XLO(19,BODNZT,16,0), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bdnztlr-",XLO(19,BODNZT,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdnztlr+",XLO(19,BODNZTP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdnztlrl",XLO(19,BODNZT,16,1), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bdnztlrl-",XLO(19,BODNZT,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdnztlrl+",XLO(19,BODNZTP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdnzflr", XLO(19,BODNZF,16,0), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bdnzflr-",XLO(19,BODNZF,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdnzflr+",XLO(19,BODNZFP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdnzflrl",XLO(19,BODNZF,16,1), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bdnzflrl-",XLO(19,BODNZF,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdnzflrl+",XLO(19,BODNZFP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdztlr", XLO(19,BODZT,16,0), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bdztlr-", XLO(19,BODZT,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdztlr+", XLO(19,BODZTP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdztlrl", XLO(19,BODZT,16,1), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bdztlrl-",XLO(19,BODZT,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdztlrl+",XLO(19,BODZTP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdzflr", XLO(19,BODZF,16,0), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bdzflr-", XLO(19,BODZF,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdzflr+", XLO(19,BODZFP,16,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdzflrl", XLO(19,BODZF,16,1), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bdzflrl-",XLO(19,BODZF,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bdzflrl+",XLO(19,BODZFP,16,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bclr+", XLYLK(19,16,1,0), XLYBB_MASK, PPCCOM, { BOE, BI } }, -{ "bclrl+", XLYLK(19,16,1,1), XLYBB_MASK, PPCCOM, { BOE, BI } }, -{ "bclr-", XLYLK(19,16,0,0), XLYBB_MASK, PPCCOM, { BOE, BI } }, -{ "bclrl-", XLYLK(19,16,0,1), XLYBB_MASK, PPCCOM, { BOE, BI } }, -{ "bclr", XLLK(19,16,0), XLBH_MASK, PPCCOM, { BO, BI, BH } }, -{ "bclrl", XLLK(19,16,1), XLBH_MASK, PPCCOM, { BO, BI, BH } }, -{ "bcr", XLLK(19,16,0), XLBB_MASK, PWRCOM, { BO, BI } }, -{ "bcrl", XLLK(19,16,1), XLBB_MASK, PWRCOM, { BO, BI } }, -{ "bclre", XLLK(19,17,0), XLBB_MASK, BOOKE64, { BO, BI } }, -{ "bclrel", XLLK(19,17,1), XLBB_MASK, BOOKE64, { BO, BI } }, - -{ "rfid", XL(19,18), 0xffffffff, PPC64, { 0 } }, - -{ "crnot", XL(19,33), XL_MASK, PPCCOM, { BT, BA, BBA } }, -{ "crnor", XL(19,33), XL_MASK, COM, { BT, BA, BB } }, -{ "rfmci", X(19,38), 0xffffffff, PPCRFMCI, { 0 } }, - -{ "rfi", XL(19,50), 0xffffffff, COM, { 0 } }, -{ "rfci", XL(19,51), 0xffffffff, PPC403 | BOOKE, { 0 } }, - -{ "rfsvc", XL(19,82), 0xffffffff, POWER, { 0 } }, - -{ "crandc", XL(19,129), XL_MASK, COM, { BT, BA, BB } }, - -{ "isync", XL(19,150), 0xffffffff, PPCCOM, { 0 } }, -{ "ics", XL(19,150), 0xffffffff, PWRCOM, { 0 } }, - -{ "crclr", XL(19,193), XL_MASK, PPCCOM, { BT, BAT, BBA } }, -{ "crxor", XL(19,193), XL_MASK, COM, { BT, BA, BB } }, - -{ "crnand", XL(19,225), XL_MASK, COM, { BT, BA, BB } }, - -{ "crand", XL(19,257), XL_MASK, COM, { BT, BA, BB } }, - -{ "hrfid", XL(19,274), 0xffffffff, POWER5 | CELL, { 0 } }, - -{ "crset", XL(19,289), XL_MASK, PPCCOM, { BT, BAT, BBA } }, -{ "creqv", XL(19,289), XL_MASK, COM, { BT, BA, BB } }, - -{ "doze", XL(19,402), 0xffffffff, POWER6, { 0 } }, - -{ "crorc", XL(19,417), XL_MASK, COM, { BT, BA, BB } }, - -{ "nap", XL(19,434), 0xffffffff, POWER6, { 0 } }, - -{ "crmove", XL(19,449), XL_MASK, PPCCOM, { BT, BA, BBA } }, -{ "cror", XL(19,449), XL_MASK, COM, { BT, BA, BB } }, - -{ "sleep", XL(19,466), 0xffffffff, POWER6, { 0 } }, -{ "rvwinkle", XL(19,498), 0xffffffff, POWER6, { 0 } }, - -{ "bctr", XLO(19,BOU,528,0), XLBOBIBB_MASK, COM, { 0 } }, -{ "bctrl", XLO(19,BOU,528,1), XLBOBIBB_MASK, COM, { 0 } }, -{ "bltctr", XLOCB(19,BOT,CBLT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bltctr-", XLOCB(19,BOT,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bltctr-", XLOCB(19,BOTM4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bltctr+", XLOCB(19,BOTP,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bltctr+", XLOCB(19,BOTP4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bltctrl", XLOCB(19,BOT,CBLT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bltctrl-",XLOCB(19,BOT,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bltctrl-",XLOCB(19,BOTM4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bltctrl+",XLOCB(19,BOTP,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bltctrl+",XLOCB(19,BOTP4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgtctr", XLOCB(19,BOT,CBGT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bgtctr-", XLOCB(19,BOT,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgtctr-", XLOCB(19,BOTM4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgtctr+", XLOCB(19,BOTP,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgtctr+", XLOCB(19,BOTP4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgtctrl", XLOCB(19,BOT,CBGT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bgtctrl-",XLOCB(19,BOT,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgtctrl-",XLOCB(19,BOTM4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgtctrl+",XLOCB(19,BOTP,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgtctrl+",XLOCB(19,BOTP4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "beqctr", XLOCB(19,BOT,CBEQ,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "beqctr-", XLOCB(19,BOT,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "beqctr-", XLOCB(19,BOTM4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "beqctr+", XLOCB(19,BOTP,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "beqctr+", XLOCB(19,BOTP4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "beqctrl", XLOCB(19,BOT,CBEQ,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "beqctrl-",XLOCB(19,BOT,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "beqctrl-",XLOCB(19,BOTM4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "beqctrl+",XLOCB(19,BOTP,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "beqctrl+",XLOCB(19,BOTP4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bsoctr", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bsoctr-", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bsoctr-", XLOCB(19,BOTM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bsoctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bsoctr+", XLOCB(19,BOTP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bsoctrl", XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bsoctrl-",XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bsoctrl-",XLOCB(19,BOTM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bsoctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bsoctrl+",XLOCB(19,BOTP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bunctr", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bunctr-", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bunctr-", XLOCB(19,BOTM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bunctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bunctr+", XLOCB(19,BOTP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bunctrl", XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bunctrl-",XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bunctrl-",XLOCB(19,BOTM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bunctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bunctrl+",XLOCB(19,BOTP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgectr", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bgectr-", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgectr-", XLOCB(19,BOFM4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgectr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgectr+", XLOCB(19,BOFP4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgectrl", XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bgectrl-",XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgectrl-",XLOCB(19,BOFM4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bgectrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bgectrl+",XLOCB(19,BOFP4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnlctr", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnlctr-", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnlctr-", XLOCB(19,BOFM4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnlctr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnlctr+", XLOCB(19,BOFP4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnlctrl", XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnlctrl-",XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnlctrl-",XLOCB(19,BOFM4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnlctrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnlctrl+",XLOCB(19,BOFP4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "blectr", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "blectr-", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "blectr-", XLOCB(19,BOFM4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "blectr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "blectr+", XLOCB(19,BOFP4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "blectrl", XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "blectrl-",XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "blectrl-",XLOCB(19,BOFM4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "blectrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "blectrl+",XLOCB(19,BOFP4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bngctr", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bngctr-", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bngctr-", XLOCB(19,BOFM4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bngctr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bngctr+", XLOCB(19,BOFP4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bngctrl", XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bngctrl-",XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bngctrl-",XLOCB(19,BOFM4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bngctrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bngctrl+",XLOCB(19,BOFP4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnectr", XLOCB(19,BOF,CBEQ,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnectr-", XLOCB(19,BOF,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnectr-", XLOCB(19,BOFM4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnectr+", XLOCB(19,BOFP,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnectr+", XLOCB(19,BOFP4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnectrl", XLOCB(19,BOF,CBEQ,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnectrl-",XLOCB(19,BOF,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnectrl-",XLOCB(19,BOFM4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnectrl+",XLOCB(19,BOFP,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnectrl+",XLOCB(19,BOFP4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnsctr", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnsctr-", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnsctr-", XLOCB(19,BOFM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnsctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnsctr+", XLOCB(19,BOFP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnsctrl", XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnsctrl-",XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnsctrl-",XLOCB(19,BOFM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnsctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnsctrl+",XLOCB(19,BOFP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnuctr", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnuctr-", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnuctr-", XLOCB(19,BOFM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnuctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnuctr+", XLOCB(19,BOFP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnuctrl", XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPCCOM, { CR } }, -{ "bnuctrl-",XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnuctrl-",XLOCB(19,BOFM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "bnuctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } }, -{ "bnuctrl+",XLOCB(19,BOFP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } }, -{ "btctr", XLO(19,BOT,528,0), XLBOBB_MASK, PPCCOM, { BI } }, -{ "btctr-", XLO(19,BOT,528,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "btctr-", XLO(19,BOTM4,528,0), XLBOBB_MASK, POWER4, { BI } }, -{ "btctr+", XLO(19,BOTP,528,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "btctr+", XLO(19,BOTP4,528,0), XLBOBB_MASK, POWER4, { BI } }, -{ "btctrl", XLO(19,BOT,528,1), XLBOBB_MASK, PPCCOM, { BI } }, -{ "btctrl-", XLO(19,BOT,528,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "btctrl-", XLO(19,BOTM4,528,1), XLBOBB_MASK, POWER4, { BI } }, -{ "btctrl+", XLO(19,BOTP,528,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "btctrl+", XLO(19,BOTP4,528,1), XLBOBB_MASK, POWER4, { BI } }, -{ "bfctr", XLO(19,BOF,528,0), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bfctr-", XLO(19,BOF,528,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bfctr-", XLO(19,BOFM4,528,0), XLBOBB_MASK, POWER4, { BI } }, -{ "bfctr+", XLO(19,BOFP,528,0), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bfctr+", XLO(19,BOFP4,528,0), XLBOBB_MASK, POWER4, { BI } }, -{ "bfctrl", XLO(19,BOF,528,1), XLBOBB_MASK, PPCCOM, { BI } }, -{ "bfctrl-", XLO(19,BOF,528,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bfctrl-", XLO(19,BOFM4,528,1), XLBOBB_MASK, POWER4, { BI } }, -{ "bfctrl+", XLO(19,BOFP,528,1), XLBOBB_MASK, NOPOWER4, { BI } }, -{ "bfctrl+", XLO(19,BOFP4,528,1), XLBOBB_MASK, POWER4, { BI } }, -{ "bcctr-", XLYLK(19,528,0,0), XLYBB_MASK, PPCCOM, { BOE, BI } }, -{ "bcctr+", XLYLK(19,528,1,0), XLYBB_MASK, PPCCOM, { BOE, BI } }, -{ "bcctrl-", XLYLK(19,528,0,1), XLYBB_MASK, PPCCOM, { BOE, BI } }, -{ "bcctrl+", XLYLK(19,528,1,1), XLYBB_MASK, PPCCOM, { BOE, BI } }, -{ "bcctr", XLLK(19,528,0), XLBH_MASK, PPCCOM, { BO, BI, BH } }, -{ "bcctrl", XLLK(19,528,1), XLBH_MASK, PPCCOM, { BO, BI, BH } }, -{ "bcc", XLLK(19,528,0), XLBB_MASK, PWRCOM, { BO, BI } }, -{ "bccl", XLLK(19,528,1), XLBB_MASK, PWRCOM, { BO, BI } }, -{ "bcctre", XLLK(19,529,0), XLBB_MASK, BOOKE64, { BO, BI } }, -{ "bcctrel", XLLK(19,529,1), XLBB_MASK, BOOKE64, { BO, BI } }, - -{ "rlwimi", M(20,0), M_MASK, PPCCOM, { RA,RS,SH,MBE,ME } }, -{ "rlimi", M(20,0), M_MASK, PWRCOM, { RA,RS,SH,MBE,ME } }, - -{ "rlwimi.", M(20,1), M_MASK, PPCCOM, { RA,RS,SH,MBE,ME } }, -{ "rlimi.", M(20,1), M_MASK, PWRCOM, { RA,RS,SH,MBE,ME } }, - -{ "rotlwi", MME(21,31,0), MMBME_MASK, PPCCOM, { RA, RS, SH } }, -{ "clrlwi", MME(21,31,0), MSHME_MASK, PPCCOM, { RA, RS, MB } }, -{ "rlwinm", M(21,0), M_MASK, PPCCOM, { RA,RS,SH,MBE,ME } }, -{ "rlinm", M(21,0), M_MASK, PWRCOM, { RA,RS,SH,MBE,ME } }, -{ "rotlwi.", MME(21,31,1), MMBME_MASK, PPCCOM, { RA,RS,SH } }, -{ "clrlwi.", MME(21,31,1), MSHME_MASK, PPCCOM, { RA, RS, MB } }, -{ "rlwinm.", M(21,1), M_MASK, PPCCOM, { RA,RS,SH,MBE,ME } }, -{ "rlinm.", M(21,1), M_MASK, PWRCOM, { RA,RS,SH,MBE,ME } }, - -{ "rlmi", M(22,0), M_MASK, M601, { RA,RS,RB,MBE,ME } }, -{ "rlmi.", M(22,1), M_MASK, M601, { RA,RS,RB,MBE,ME } }, - -{ "be", B(22,0,0), B_MASK, BOOKE64, { LI } }, -{ "bel", B(22,0,1), B_MASK, BOOKE64, { LI } }, -{ "bea", B(22,1,0), B_MASK, BOOKE64, { LIA } }, -{ "bela", B(22,1,1), B_MASK, BOOKE64, { LIA } }, - -{ "rotlw", MME(23,31,0), MMBME_MASK, PPCCOM, { RA, RS, RB } }, -{ "rlwnm", M(23,0), M_MASK, PPCCOM, { RA,RS,RB,MBE,ME } }, -{ "rlnm", M(23,0), M_MASK, PWRCOM, { RA,RS,RB,MBE,ME } }, -{ "rotlw.", MME(23,31,1), MMBME_MASK, PPCCOM, { RA, RS, RB } }, -{ "rlwnm.", M(23,1), M_MASK, PPCCOM, { RA,RS,RB,MBE,ME } }, -{ "rlnm.", M(23,1), M_MASK, PWRCOM, { RA,RS,RB,MBE,ME } }, - -{ "nop", OP(24), 0xffffffff, PPCCOM, { 0 } }, -{ "ori", OP(24), OP_MASK, PPCCOM, { RA, RS, UI } }, -{ "oril", OP(24), OP_MASK, PWRCOM, { RA, RS, UI } }, - -{ "oris", OP(25), OP_MASK, PPCCOM, { RA, RS, UI } }, -{ "oriu", OP(25), OP_MASK, PWRCOM, { RA, RS, UI } }, - -{ "xori", OP(26), OP_MASK, PPCCOM, { RA, RS, UI } }, -{ "xoril", OP(26), OP_MASK, PWRCOM, { RA, RS, UI } }, - -{ "xoris", OP(27), OP_MASK, PPCCOM, { RA, RS, UI } }, -{ "xoriu", OP(27), OP_MASK, PWRCOM, { RA, RS, UI } }, - -{ "andi.", OP(28), OP_MASK, PPCCOM, { RA, RS, UI } }, -{ "andil.", OP(28), OP_MASK, PWRCOM, { RA, RS, UI } }, - -{ "andis.", OP(29), OP_MASK, PPCCOM, { RA, RS, UI } }, -{ "andiu.", OP(29), OP_MASK, PWRCOM, { RA, RS, UI } }, - -{ "rotldi", MD(30,0,0), MDMB_MASK, PPC64, { RA, RS, SH6 } }, -{ "clrldi", MD(30,0,0), MDSH_MASK, PPC64, { RA, RS, MB6 } }, -{ "rldicl", MD(30,0,0), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, -{ "rotldi.", MD(30,0,1), MDMB_MASK, PPC64, { RA, RS, SH6 } }, -{ "clrldi.", MD(30,0,1), MDSH_MASK, PPC64, { RA, RS, MB6 } }, -{ "rldicl.", MD(30,0,1), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, - -{ "rldicr", MD(30,1,0), MD_MASK, PPC64, { RA, RS, SH6, ME6 } }, -{ "rldicr.", MD(30,1,1), MD_MASK, PPC64, { RA, RS, SH6, ME6 } }, - -{ "rldic", MD(30,2,0), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, -{ "rldic.", MD(30,2,1), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, - -{ "rldimi", MD(30,3,0), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, -{ "rldimi.", MD(30,3,1), MD_MASK, PPC64, { RA, RS, SH6, MB6 } }, - -{ "rotld", MDS(30,8,0), MDSMB_MASK, PPC64, { RA, RS, RB } }, -{ "rldcl", MDS(30,8,0), MDS_MASK, PPC64, { RA, RS, RB, MB6 } }, -{ "rotld.", MDS(30,8,1), MDSMB_MASK, PPC64, { RA, RS, RB } }, -{ "rldcl.", MDS(30,8,1), MDS_MASK, PPC64, { RA, RS, RB, MB6 } }, - -{ "rldcr", MDS(30,9,0), MDS_MASK, PPC64, { RA, RS, RB, ME6 } }, -{ "rldcr.", MDS(30,9,1), MDS_MASK, PPC64, { RA, RS, RB, ME6 } }, - -{ "cmpw", XOPL(31,0,0), XCMPL_MASK, PPCCOM, { OBF, RA, RB } }, -{ "cmpd", XOPL(31,0,1), XCMPL_MASK, PPC64, { OBF, RA, RB } }, -{ "cmp", X(31,0), XCMP_MASK, PPC, { BF, L, RA, RB } }, -{ "cmp", X(31,0), XCMPL_MASK, PWRCOM, { BF, RA, RB } }, - -{ "twlgt", XTO(31,4,TOLGT), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tlgt", XTO(31,4,TOLGT), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twllt", XTO(31,4,TOLLT), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tllt", XTO(31,4,TOLLT), XTO_MASK, PWRCOM, { RA, RB } }, -{ "tweq", XTO(31,4,TOEQ), XTO_MASK, PPCCOM, { RA, RB } }, -{ "teq", XTO(31,4,TOEQ), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twlge", XTO(31,4,TOLGE), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tlge", XTO(31,4,TOLGE), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twlnl", XTO(31,4,TOLNL), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tlnl", XTO(31,4,TOLNL), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twlle", XTO(31,4,TOLLE), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tlle", XTO(31,4,TOLLE), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twlng", XTO(31,4,TOLNG), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tlng", XTO(31,4,TOLNG), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twgt", XTO(31,4,TOGT), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tgt", XTO(31,4,TOGT), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twge", XTO(31,4,TOGE), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tge", XTO(31,4,TOGE), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twnl", XTO(31,4,TONL), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tnl", XTO(31,4,TONL), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twlt", XTO(31,4,TOLT), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tlt", XTO(31,4,TOLT), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twle", XTO(31,4,TOLE), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tle", XTO(31,4,TOLE), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twng", XTO(31,4,TONG), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tng", XTO(31,4,TONG), XTO_MASK, PWRCOM, { RA, RB } }, -{ "twne", XTO(31,4,TONE), XTO_MASK, PPCCOM, { RA, RB } }, -{ "tne", XTO(31,4,TONE), XTO_MASK, PWRCOM, { RA, RB } }, -{ "trap", XTO(31,4,TOU), 0xffffffff, PPCCOM, { 0 } }, -{ "tw", X(31,4), X_MASK, PPCCOM, { TO, RA, RB } }, -{ "t", X(31,4), X_MASK, PWRCOM, { TO, RA, RB } }, - -{ "subfc", XO(31,8,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "sf", XO(31,8,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "subc", XO(31,8,0,0), XO_MASK, PPC, { RT, RB, RA } }, -{ "subfc.", XO(31,8,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "sf.", XO(31,8,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "subc.", XO(31,8,0,1), XO_MASK, PPCCOM, { RT, RB, RA } }, -{ "subfco", XO(31,8,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "sfo", XO(31,8,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "subco", XO(31,8,1,0), XO_MASK, PPC, { RT, RB, RA } }, -{ "subfco.", XO(31,8,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "sfo.", XO(31,8,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "subco.", XO(31,8,1,1), XO_MASK, PPC, { RT, RB, RA } }, - -{ "mulhdu", XO(31,9,0,0), XO_MASK, PPC64, { RT, RA, RB } }, -{ "mulhdu.", XO(31,9,0,1), XO_MASK, PPC64, { RT, RA, RB } }, - -{ "addc", XO(31,10,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "a", XO(31,10,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "addc.", XO(31,10,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "a.", XO(31,10,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "addco", XO(31,10,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "ao", XO(31,10,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "addco.", XO(31,10,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "ao.", XO(31,10,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, - -{ "mulhwu", XO(31,11,0,0), XO_MASK, PPC, { RT, RA, RB } }, -{ "mulhwu.", XO(31,11,0,1), XO_MASK, PPC, { RT, RA, RB } }, - -{ "isellt", X(31,15), X_MASK, PPCISEL, { RT, RA, RB } }, -{ "iselgt", X(31,47), X_MASK, PPCISEL, { RT, RA, RB } }, -{ "iseleq", X(31,79), X_MASK, PPCISEL, { RT, RA, RB } }, -{ "isel", XISEL(31,15), XISEL_MASK, PPCISEL, { RT, RA, RB, CRB } }, - -{ "mfocrf", XFXM(31,19,0,1), XFXFXM_MASK, COM, { RT, FXM } }, -{ "mfcr", X(31,19), XRARB_MASK, NOPOWER4 | COM, { RT } }, -{ "mfcr", X(31,19), XFXFXM_MASK, POWER4, { RT, FXM4 } }, - -{ "lwarx", X(31,20), XEH_MASK, PPC, { RT, RA0, RB, EH } }, - -{ "ldx", X(31,21), X_MASK, PPC64, { RT, RA0, RB } }, - -{ "icbt", X(31,22), X_MASK, BOOKE|PPCE300, { CT, RA, RB } }, -{ "icbt", X(31,262), XRT_MASK, PPC403, { RA, RB } }, - -{ "lwzx", X(31,23), X_MASK, PPCCOM, { RT, RA0, RB } }, -{ "lx", X(31,23), X_MASK, PWRCOM, { RT, RA, RB } }, - -{ "slw", XRC(31,24,0), X_MASK, PPCCOM, { RA, RS, RB } }, -{ "sl", XRC(31,24,0), X_MASK, PWRCOM, { RA, RS, RB } }, -{ "slw.", XRC(31,24,1), X_MASK, PPCCOM, { RA, RS, RB } }, -{ "sl.", XRC(31,24,1), X_MASK, PWRCOM, { RA, RS, RB } }, - -{ "cntlzw", XRC(31,26,0), XRB_MASK, PPCCOM, { RA, RS } }, -{ "cntlz", XRC(31,26,0), XRB_MASK, PWRCOM, { RA, RS } }, -{ "cntlzw.", XRC(31,26,1), XRB_MASK, PPCCOM, { RA, RS } }, -{ "cntlz.", XRC(31,26,1), XRB_MASK, PWRCOM, { RA, RS } }, - -{ "sld", XRC(31,27,0), X_MASK, PPC64, { RA, RS, RB } }, -{ "sld.", XRC(31,27,1), X_MASK, PPC64, { RA, RS, RB } }, - -{ "and", XRC(31,28,0), X_MASK, COM, { RA, RS, RB } }, -{ "and.", XRC(31,28,1), X_MASK, COM, { RA, RS, RB } }, - -{ "maskg", XRC(31,29,0), X_MASK, M601, { RA, RS, RB } }, -{ "maskg.", XRC(31,29,1), X_MASK, M601, { RA, RS, RB } }, - -{ "icbte", X(31,30), X_MASK, BOOKE64, { CT, RA, RB } }, - -{ "lwzxe", X(31,31), X_MASK, BOOKE64, { RT, RA0, RB } }, - -{ "cmplw", XOPL(31,32,0), XCMPL_MASK, PPCCOM, { OBF, RA, RB } }, -{ "cmpld", XOPL(31,32,1), XCMPL_MASK, PPC64, { OBF, RA, RB } }, -{ "cmpl", X(31,32), XCMP_MASK, PPC, { BF, L, RA, RB } }, -{ "cmpl", X(31,32), XCMPL_MASK, PWRCOM, { BF, RA, RB } }, - -{ "subf", XO(31,40,0,0), XO_MASK, PPC, { RT, RA, RB } }, -{ "sub", XO(31,40,0,0), XO_MASK, PPC, { RT, RB, RA } }, -{ "subf.", XO(31,40,0,1), XO_MASK, PPC, { RT, RA, RB } }, -{ "sub.", XO(31,40,0,1), XO_MASK, PPC, { RT, RB, RA } }, -{ "subfo", XO(31,40,1,0), XO_MASK, PPC, { RT, RA, RB } }, -{ "subo", XO(31,40,1,0), XO_MASK, PPC, { RT, RB, RA } }, -{ "subfo.", XO(31,40,1,1), XO_MASK, PPC, { RT, RA, RB } }, -{ "subo.", XO(31,40,1,1), XO_MASK, PPC, { RT, RB, RA } }, - -{ "ldux", X(31,53), X_MASK, PPC64, { RT, RAL, RB } }, - -{ "dcbst", X(31,54), XRT_MASK, PPC, { RA, RB } }, - -{ "lwzux", X(31,55), X_MASK, PPCCOM, { RT, RAL, RB } }, -{ "lux", X(31,55), X_MASK, PWRCOM, { RT, RA, RB } }, - -{ "dcbste", X(31,62), XRT_MASK, BOOKE64, { RA, RB } }, - -{ "lwzuxe", X(31,63), X_MASK, BOOKE64, { RT, RAL, RB } }, - -{ "cntlzd", XRC(31,58,0), XRB_MASK, PPC64, { RA, RS } }, -{ "cntlzd.", XRC(31,58,1), XRB_MASK, PPC64, { RA, RS } }, - -{ "andc", XRC(31,60,0), X_MASK, COM, { RA, RS, RB } }, -{ "andc.", XRC(31,60,1), X_MASK, COM, { RA, RS, RB } }, - -{ "tdlgt", XTO(31,68,TOLGT), XTO_MASK, PPC64, { RA, RB } }, -{ "tdllt", XTO(31,68,TOLLT), XTO_MASK, PPC64, { RA, RB } }, -{ "tdeq", XTO(31,68,TOEQ), XTO_MASK, PPC64, { RA, RB } }, -{ "tdlge", XTO(31,68,TOLGE), XTO_MASK, PPC64, { RA, RB } }, -{ "tdlnl", XTO(31,68,TOLNL), XTO_MASK, PPC64, { RA, RB } }, -{ "tdlle", XTO(31,68,TOLLE), XTO_MASK, PPC64, { RA, RB } }, -{ "tdlng", XTO(31,68,TOLNG), XTO_MASK, PPC64, { RA, RB } }, -{ "tdgt", XTO(31,68,TOGT), XTO_MASK, PPC64, { RA, RB } }, -{ "tdge", XTO(31,68,TOGE), XTO_MASK, PPC64, { RA, RB } }, -{ "tdnl", XTO(31,68,TONL), XTO_MASK, PPC64, { RA, RB } }, -{ "tdlt", XTO(31,68,TOLT), XTO_MASK, PPC64, { RA, RB } }, -{ "tdle", XTO(31,68,TOLE), XTO_MASK, PPC64, { RA, RB } }, -{ "tdng", XTO(31,68,TONG), XTO_MASK, PPC64, { RA, RB } }, -{ "tdne", XTO(31,68,TONE), XTO_MASK, PPC64, { RA, RB } }, -{ "td", X(31,68), X_MASK, PPC64, { TO, RA, RB } }, - -{ "mulhd", XO(31,73,0,0), XO_MASK, PPC64, { RT, RA, RB } }, -{ "mulhd.", XO(31,73,0,1), XO_MASK, PPC64, { RT, RA, RB } }, - -{ "mulhw", XO(31,75,0,0), XO_MASK, PPC, { RT, RA, RB } }, -{ "mulhw.", XO(31,75,0,1), XO_MASK, PPC, { RT, RA, RB } }, - -{ "dlmzb", XRC(31,78,0), X_MASK, PPC403|PPC440, { RA, RS, RB } }, -{ "dlmzb.", XRC(31,78,1), X_MASK, PPC403|PPC440, { RA, RS, RB } }, - -{ "mtsrd", X(31,82), XRB_MASK|(1<<20), PPC64, { SR, RS } }, - -{ "mfmsr", X(31,83), XRARB_MASK, COM, { RT } }, - -{ "ldarx", X(31,84), XEH_MASK, PPC64, { RT, RA0, RB, EH } }, - -{ "dcbfl", XOPL(31,86,1), XRT_MASK, POWER5, { RA, RB } }, -{ "dcbf", X(31,86), XLRT_MASK, PPC, { RA, RB, L } }, - -{ "lbzx", X(31,87), X_MASK, COM, { RT, RA0, RB } }, - -{ "dcbfe", X(31,94), XRT_MASK, BOOKE64, { RA, RB } }, - -{ "lbzxe", X(31,95), X_MASK, BOOKE64, { RT, RA0, RB } }, - -{ "neg", XO(31,104,0,0), XORB_MASK, COM, { RT, RA } }, -{ "neg.", XO(31,104,0,1), XORB_MASK, COM, { RT, RA } }, -{ "nego", XO(31,104,1,0), XORB_MASK, COM, { RT, RA } }, -{ "nego.", XO(31,104,1,1), XORB_MASK, COM, { RT, RA } }, - -{ "mul", XO(31,107,0,0), XO_MASK, M601, { RT, RA, RB } }, -{ "mul.", XO(31,107,0,1), XO_MASK, M601, { RT, RA, RB } }, -{ "mulo", XO(31,107,1,0), XO_MASK, M601, { RT, RA, RB } }, -{ "mulo.", XO(31,107,1,1), XO_MASK, M601, { RT, RA, RB } }, - -{ "mtsrdin", X(31,114), XRA_MASK, PPC64, { RS, RB } }, - -{ "clf", X(31,118), XTO_MASK, POWER, { RA, RB } }, - -{ "lbzux", X(31,119), X_MASK, COM, { RT, RAL, RB } }, - -{ "popcntb", X(31,122), XRB_MASK, POWER5, { RA, RS } }, -{ "popcntw", X(31,378), XRB_MASK, POWER7, { RA, RS } }, -{ "popcntd", X(31,506), XRB_MASK, POWER7, { RA, RS } }, - -{ "cnttzw", XRC(31,538,0), XRB_MASK, POWER9, { RA, RS } }, -{ "cnttzw.", XRC(31,538,1), XRB_MASK, POWER9, { RA, RS } }, -{ "cnttzd", XRC(31,570,0), XRB_MASK, POWER9, { RA, RS } }, -{ "cnttzd.", XRC(31,570,1), XRB_MASK, POWER9, { RA, RS } }, - -{ "not", XRC(31,124,0), X_MASK, COM, { RA, RS, RBS } }, -{ "nor", XRC(31,124,0), X_MASK, COM, { RA, RS, RB } }, -{ "not.", XRC(31,124,1), X_MASK, COM, { RA, RS, RBS } }, -{ "nor.", XRC(31,124,1), X_MASK, COM, { RA, RS, RB } }, - -{ "lwarxe", X(31,126), X_MASK, BOOKE64, { RT, RA0, RB } }, - -{ "lbzuxe", X(31,127), X_MASK, BOOKE64, { RT, RAL, RB } }, - -{ "wrtee", X(31,131), XRARB_MASK, PPC403 | BOOKE, { RS } }, - -{ "dcbtstls",X(31,134), X_MASK, PPCCHLK, { CT, RA, RB }}, - -{ "subfe", XO(31,136,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "sfe", XO(31,136,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "subfe.", XO(31,136,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "sfe.", XO(31,136,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "subfeo", XO(31,136,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "sfeo", XO(31,136,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "subfeo.", XO(31,136,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "sfeo.", XO(31,136,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, - -{ "adde", XO(31,138,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "ae", XO(31,138,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "adde.", XO(31,138,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "ae.", XO(31,138,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "addeo", XO(31,138,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "aeo", XO(31,138,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "addeo.", XO(31,138,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "aeo.", XO(31,138,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, - -{ "dcbtstlse",X(31,142),X_MASK, PPCCHLK64, { CT, RA, RB }}, - -{ "mtocrf", XFXM(31,144,0,1), XFXFXM_MASK, COM, { FXM, RS } }, -{ "mtcr", XFXM(31,144,0xff,0), XRARB_MASK, COM, { RS }}, -{ "mtcrf", X(31,144), XFXFXM_MASK, COM, { FXM, RS } }, - -{ "mtmsr", X(31,146), XRARB_MASK, COM, { RS } }, - -{ "stdx", X(31,149), X_MASK, PPC64, { RS, RA0, RB } }, - -{ "stwcx.", XRC(31,150,1), X_MASK, PPC, { RS, RA0, RB } }, - -{ "stwx", X(31,151), X_MASK, PPCCOM, { RS, RA0, RB } }, -{ "stx", X(31,151), X_MASK, PWRCOM, { RS, RA, RB } }, - -{ "stwcxe.", XRC(31,158,1), X_MASK, BOOKE64, { RS, RA0, RB } }, - -{ "stwxe", X(31,159), X_MASK, BOOKE64, { RS, RA0, RB } }, - -{ "slq", XRC(31,152,0), X_MASK, M601, { RA, RS, RB } }, -{ "slq.", XRC(31,152,1), X_MASK, M601, { RA, RS, RB } }, - -{ "sle", XRC(31,153,0), X_MASK, M601, { RA, RS, RB } }, -{ "sle.", XRC(31,153,1), X_MASK, M601, { RA, RS, RB } }, - -{ "prtyw", X(31,154), XRB_MASK, POWER6, { RA, RS } }, - -{ "wrteei", X(31,163), XE_MASK, PPC403 | BOOKE, { E } }, - -{ "dcbtls", X(31,166), X_MASK, PPCCHLK, { CT, RA, RB }}, -{ "dcbtlse", X(31,174), X_MASK, PPCCHLK64, { CT, RA, RB }}, - -{ "mtmsrd", X(31,178), XRLARB_MASK, PPC64, { RS, A_L } }, - -{ "stdux", X(31,181), X_MASK, PPC64, { RS, RAS, RB } }, - -{ "stwux", X(31,183), X_MASK, PPCCOM, { RS, RAS, RB } }, -{ "stux", X(31,183), X_MASK, PWRCOM, { RS, RA0, RB } }, - -{ "sliq", XRC(31,184,0), X_MASK, M601, { RA, RS, SH } }, -{ "sliq.", XRC(31,184,1), X_MASK, M601, { RA, RS, SH } }, - -{ "prtyd", X(31,186), XRB_MASK, POWER6, { RA, RS } }, - -{ "stwuxe", X(31,191), X_MASK, BOOKE64, { RS, RAS, RB } }, - -{ "subfze", XO(31,200,0,0), XORB_MASK, PPCCOM, { RT, RA } }, -{ "sfze", XO(31,200,0,0), XORB_MASK, PWRCOM, { RT, RA } }, -{ "subfze.", XO(31,200,0,1), XORB_MASK, PPCCOM, { RT, RA } }, -{ "sfze.", XO(31,200,0,1), XORB_MASK, PWRCOM, { RT, RA } }, -{ "subfzeo", XO(31,200,1,0), XORB_MASK, PPCCOM, { RT, RA } }, -{ "sfzeo", XO(31,200,1,0), XORB_MASK, PWRCOM, { RT, RA } }, -{ "subfzeo.",XO(31,200,1,1), XORB_MASK, PPCCOM, { RT, RA } }, -{ "sfzeo.", XO(31,200,1,1), XORB_MASK, PWRCOM, { RT, RA } }, - -{ "addze", XO(31,202,0,0), XORB_MASK, PPCCOM, { RT, RA } }, -{ "aze", XO(31,202,0,0), XORB_MASK, PWRCOM, { RT, RA } }, -{ "addze.", XO(31,202,0,1), XORB_MASK, PPCCOM, { RT, RA } }, -{ "aze.", XO(31,202,0,1), XORB_MASK, PWRCOM, { RT, RA } }, -{ "addzeo", XO(31,202,1,0), XORB_MASK, PPCCOM, { RT, RA } }, -{ "azeo", XO(31,202,1,0), XORB_MASK, PWRCOM, { RT, RA } }, -{ "addzeo.", XO(31,202,1,1), XORB_MASK, PPCCOM, { RT, RA } }, -{ "azeo.", XO(31,202,1,1), XORB_MASK, PWRCOM, { RT, RA } }, - -{ "mtsr", X(31,210), XRB_MASK|(1<<20), COM32, { SR, RS } }, - -{ "stdcx.", XRC(31,214,1), X_MASK, PPC64, { RS, RA0, RB } }, - -{ "stbx", X(31,215), X_MASK, COM, { RS, RA0, RB } }, - -{ "sllq", XRC(31,216,0), X_MASK, M601, { RA, RS, RB } }, -{ "sllq.", XRC(31,216,1), X_MASK, M601, { RA, RS, RB } }, - -{ "sleq", XRC(31,217,0), X_MASK, M601, { RA, RS, RB } }, -{ "sleq.", XRC(31,217,1), X_MASK, M601, { RA, RS, RB } }, - -{ "stbxe", X(31,223), X_MASK, BOOKE64, { RS, RA0, RB } }, - -{ "icblc", X(31,230), X_MASK, PPCCHLK, { CT, RA, RB }}, - -{ "subfme", XO(31,232,0,0), XORB_MASK, PPCCOM, { RT, RA } }, -{ "sfme", XO(31,232,0,0), XORB_MASK, PWRCOM, { RT, RA } }, -{ "subfme.", XO(31,232,0,1), XORB_MASK, PPCCOM, { RT, RA } }, -{ "sfme.", XO(31,232,0,1), XORB_MASK, PWRCOM, { RT, RA } }, -{ "subfmeo", XO(31,232,1,0), XORB_MASK, PPCCOM, { RT, RA } }, -{ "sfmeo", XO(31,232,1,0), XORB_MASK, PWRCOM, { RT, RA } }, -{ "subfmeo.",XO(31,232,1,1), XORB_MASK, PPCCOM, { RT, RA } }, -{ "sfmeo.", XO(31,232,1,1), XORB_MASK, PWRCOM, { RT, RA } }, - -{ "mulld", XO(31,233,0,0), XO_MASK, PPC64, { RT, RA, RB } }, -{ "mulld.", XO(31,233,0,1), XO_MASK, PPC64, { RT, RA, RB } }, -{ "mulldo", XO(31,233,1,0), XO_MASK, PPC64, { RT, RA, RB } }, -{ "mulldo.", XO(31,233,1,1), XO_MASK, PPC64, { RT, RA, RB } }, - -{ "addme", XO(31,234,0,0), XORB_MASK, PPCCOM, { RT, RA } }, -{ "ame", XO(31,234,0,0), XORB_MASK, PWRCOM, { RT, RA } }, -{ "addme.", XO(31,234,0,1), XORB_MASK, PPCCOM, { RT, RA } }, -{ "ame.", XO(31,234,0,1), XORB_MASK, PWRCOM, { RT, RA } }, -{ "addmeo", XO(31,234,1,0), XORB_MASK, PPCCOM, { RT, RA } }, -{ "ameo", XO(31,234,1,0), XORB_MASK, PWRCOM, { RT, RA } }, -{ "addmeo.", XO(31,234,1,1), XORB_MASK, PPCCOM, { RT, RA } }, -{ "ameo.", XO(31,234,1,1), XORB_MASK, PWRCOM, { RT, RA } }, - -{ "addex", XO(31,170,0,0), XO_MASK, POWER9, { RT, RA, RB } }, - -{ "mullw", XO(31,235,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "muls", XO(31,235,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "mullw.", XO(31,235,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "muls.", XO(31,235,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "mullwo", XO(31,235,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "mulso", XO(31,235,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "mullwo.", XO(31,235,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "mulso.", XO(31,235,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, - -{ "icblce", X(31,238), X_MASK, PPCCHLK64, { CT, RA, RB }}, -{ "mtsrin", X(31,242), XRA_MASK, PPC32, { RS, RB } }, -{ "mtsri", X(31,242), XRA_MASK, POWER32, { RS, RB } }, - -{ "dcbtst", X(31,246), X_MASK, PPC, { CT, RA, RB } }, - -{ "stbux", X(31,247), X_MASK, COM, { RS, RAS, RB } }, - -{ "slliq", XRC(31,248,0), X_MASK, M601, { RA, RS, SH } }, -{ "slliq.", XRC(31,248,1), X_MASK, M601, { RA, RS, SH } }, - -{ "dcbtste", X(31,253), X_MASK, BOOKE64, { CT, RA, RB } }, - -{ "stbuxe", X(31,255), X_MASK, BOOKE64, { RS, RAS, RB } }, - -{ "mfdcrx", X(31,259), X_MASK, BOOKE, { RS, RA } }, - -{ "doz", XO(31,264,0,0), XO_MASK, M601, { RT, RA, RB } }, -{ "doz.", XO(31,264,0,1), XO_MASK, M601, { RT, RA, RB } }, -{ "dozo", XO(31,264,1,0), XO_MASK, M601, { RT, RA, RB } }, -{ "dozo.", XO(31,264,1,1), XO_MASK, M601, { RT, RA, RB } }, - -{ "add", XO(31,266,0,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "cax", XO(31,266,0,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "add.", XO(31,266,0,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "cax.", XO(31,266,0,1), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "addo", XO(31,266,1,0), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "caxo", XO(31,266,1,0), XO_MASK, PWRCOM, { RT, RA, RB } }, -{ "addo.", XO(31,266,1,1), XO_MASK, PPCCOM, { RT, RA, RB } }, -{ "caxo.", XO(31,266,1,1), XO_MASK, PWRCOM, { RT, RA, RB } }, - -{ "tlbiel", X(31,274), XRTLRA_MASK, POWER4, { RB, L } }, - -{ "mfapidi", X(31,275), X_MASK, BOOKE, { RT, RA } }, - -{ "lscbx", XRC(31,277,0), X_MASK, M601, { RT, RA, RB } }, -{ "lscbx.", XRC(31,277,1), X_MASK, M601, { RT, RA, RB } }, - -{ "dcbt", X(31,278), X_MASK, PPC, { CT, RA, RB } }, - -{ "lhzx", X(31,279), X_MASK, COM, { RT, RA0, RB } }, - -{ "eqv", XRC(31,284,0), X_MASK, COM, { RA, RS, RB } }, -{ "eqv.", XRC(31,284,1), X_MASK, COM, { RA, RS, RB } }, - -{ "dcbte", X(31,286), X_MASK, BOOKE64, { CT, RA, RB } }, - -{ "lhzxe", X(31,287), X_MASK, BOOKE64, { RT, RA0, RB } }, - -{ "tlbie", X(31,306), XRTLRA_MASK, PPC, { RB, L } }, -{ "tlbi", X(31,306), XRT_MASK, POWER, { RA0, RB } }, - -{ "eciwx", X(31,310), X_MASK, PPC, { RT, RA, RB } }, - -{ "lhzux", X(31,311), X_MASK, COM, { RT, RAL, RB } }, - -{ "xor", XRC(31,316,0), X_MASK, COM, { RA, RS, RB } }, -{ "xor.", XRC(31,316,1), X_MASK, COM, { RA, RS, RB } }, - -{ "lhzuxe", X(31,319), X_MASK, BOOKE64, { RT, RAL, RB } }, - -{ "mfexisr", XSPR(31,323,64), XSPR_MASK, PPC403, { RT } }, -{ "mfexier", XSPR(31,323,66), XSPR_MASK, PPC403, { RT } }, -{ "mfbr0", XSPR(31,323,128), XSPR_MASK, PPC403, { RT } }, -{ "mfbr1", XSPR(31,323,129), XSPR_MASK, PPC403, { RT } }, -{ "mfbr2", XSPR(31,323,130), XSPR_MASK, PPC403, { RT } }, -{ "mfbr3", XSPR(31,323,131), XSPR_MASK, PPC403, { RT } }, -{ "mfbr4", XSPR(31,323,132), XSPR_MASK, PPC403, { RT } }, -{ "mfbr5", XSPR(31,323,133), XSPR_MASK, PPC403, { RT } }, -{ "mfbr6", XSPR(31,323,134), XSPR_MASK, PPC403, { RT } }, -{ "mfbr7", XSPR(31,323,135), XSPR_MASK, PPC403, { RT } }, -{ "mfbear", XSPR(31,323,144), XSPR_MASK, PPC403, { RT } }, -{ "mfbesr", XSPR(31,323,145), XSPR_MASK, PPC403, { RT } }, -{ "mfiocr", XSPR(31,323,160), XSPR_MASK, PPC403, { RT } }, -{ "mfdmacr0", XSPR(31,323,192), XSPR_MASK, PPC403, { RT } }, -{ "mfdmact0", XSPR(31,323,193), XSPR_MASK, PPC403, { RT } }, -{ "mfdmada0", XSPR(31,323,194), XSPR_MASK, PPC403, { RT } }, -{ "mfdmasa0", XSPR(31,323,195), XSPR_MASK, PPC403, { RT } }, -{ "mfdmacc0", XSPR(31,323,196), XSPR_MASK, PPC403, { RT } }, -{ "mfdmacr1", XSPR(31,323,200), XSPR_MASK, PPC403, { RT } }, -{ "mfdmact1", XSPR(31,323,201), XSPR_MASK, PPC403, { RT } }, -{ "mfdmada1", XSPR(31,323,202), XSPR_MASK, PPC403, { RT } }, -{ "mfdmasa1", XSPR(31,323,203), XSPR_MASK, PPC403, { RT } }, -{ "mfdmacc1", XSPR(31,323,204), XSPR_MASK, PPC403, { RT } }, -{ "mfdmacr2", XSPR(31,323,208), XSPR_MASK, PPC403, { RT } }, -{ "mfdmact2", XSPR(31,323,209), XSPR_MASK, PPC403, { RT } }, -{ "mfdmada2", XSPR(31,323,210), XSPR_MASK, PPC403, { RT } }, -{ "mfdmasa2", XSPR(31,323,211), XSPR_MASK, PPC403, { RT } }, -{ "mfdmacc2", XSPR(31,323,212), XSPR_MASK, PPC403, { RT } }, -{ "mfdmacr3", XSPR(31,323,216), XSPR_MASK, PPC403, { RT } }, -{ "mfdmact3", XSPR(31,323,217), XSPR_MASK, PPC403, { RT } }, -{ "mfdmada3", XSPR(31,323,218), XSPR_MASK, PPC403, { RT } }, -{ "mfdmasa3", XSPR(31,323,219), XSPR_MASK, PPC403, { RT } }, -{ "mfdmacc3", XSPR(31,323,220), XSPR_MASK, PPC403, { RT } }, -{ "mfdmasr", XSPR(31,323,224), XSPR_MASK, PPC403, { RT } }, -{ "mfdcr", X(31,323), X_MASK, PPC403 | BOOKE, { RT, SPR } }, - -{ "div", XO(31,331,0,0), XO_MASK, M601, { RT, RA, RB } }, -{ "div.", XO(31,331,0,1), XO_MASK, M601, { RT, RA, RB } }, -{ "divo", XO(31,331,1,0), XO_MASK, M601, { RT, RA, RB } }, -{ "divo.", XO(31,331,1,1), XO_MASK, M601, { RT, RA, RB } }, - -{ "mfpmr", X(31,334), X_MASK, PPCPMR, { RT, PMR }}, - -{ "mfmq", XSPR(31,339,0), XSPR_MASK, M601, { RT } }, -{ "mfxer", XSPR(31,339,1), XSPR_MASK, COM, { RT } }, -{ "mfrtcu", XSPR(31,339,4), XSPR_MASK, COM, { RT } }, -{ "mfrtcl", XSPR(31,339,5), XSPR_MASK, COM, { RT } }, -{ "mfdec", XSPR(31,339,6), XSPR_MASK, MFDEC1, { RT } }, -{ "mfdec", XSPR(31,339,22), XSPR_MASK, MFDEC2, { RT } }, -{ "mflr", XSPR(31,339,8), XSPR_MASK, COM, { RT } }, -{ "mfctr", XSPR(31,339,9), XSPR_MASK, COM, { RT } }, -{ "mftid", XSPR(31,339,17), XSPR_MASK, POWER, { RT } }, -{ "mfdsisr", XSPR(31,339,18), XSPR_MASK, COM, { RT } }, -{ "mfdar", XSPR(31,339,19), XSPR_MASK, COM, { RT } }, -{ "mfsdr0", XSPR(31,339,24), XSPR_MASK, POWER, { RT } }, -{ "mfsdr1", XSPR(31,339,25), XSPR_MASK, COM, { RT } }, -{ "mfsrr0", XSPR(31,339,26), XSPR_MASK, COM, { RT } }, -{ "mfsrr1", XSPR(31,339,27), XSPR_MASK, COM, { RT } }, -{ "mfcfar", XSPR(31,339,28), XSPR_MASK, POWER6, { RT } }, -{ "mfpid", XSPR(31,339,48), XSPR_MASK, BOOKE, { RT } }, -{ "mfpid", XSPR(31,339,945), XSPR_MASK, PPC403, { RT } }, -{ "mfcsrr0", XSPR(31,339,58), XSPR_MASK, BOOKE, { RT } }, -{ "mfcsrr1", XSPR(31,339,59), XSPR_MASK, BOOKE, { RT } }, -{ "mfdear", XSPR(31,339,61), XSPR_MASK, BOOKE, { RT } }, -{ "mfdear", XSPR(31,339,981), XSPR_MASK, PPC403, { RT } }, -{ "mfesr", XSPR(31,339,62), XSPR_MASK, BOOKE, { RT } }, -{ "mfesr", XSPR(31,339,980), XSPR_MASK, PPC403, { RT } }, -{ "mfivpr", XSPR(31,339,63), XSPR_MASK, BOOKE, { RT } }, -{ "mfcmpa", XSPR(31,339,144), XSPR_MASK, PPC860, { RT } }, -{ "mfcmpb", XSPR(31,339,145), XSPR_MASK, PPC860, { RT } }, -{ "mfcmpc", XSPR(31,339,146), XSPR_MASK, PPC860, { RT } }, -{ "mfcmpd", XSPR(31,339,147), XSPR_MASK, PPC860, { RT } }, -{ "mficr", XSPR(31,339,148), XSPR_MASK, PPC860, { RT } }, -{ "mfder", XSPR(31,339,149), XSPR_MASK, PPC860, { RT } }, -{ "mfcounta", XSPR(31,339,150), XSPR_MASK, PPC860, { RT } }, -{ "mfcountb", XSPR(31,339,151), XSPR_MASK, PPC860, { RT } }, -{ "mfcmpe", XSPR(31,339,152), XSPR_MASK, PPC860, { RT } }, -{ "mfcmpf", XSPR(31,339,153), XSPR_MASK, PPC860, { RT } }, -{ "mfcmpg", XSPR(31,339,154), XSPR_MASK, PPC860, { RT } }, -{ "mfcmph", XSPR(31,339,155), XSPR_MASK, PPC860, { RT } }, -{ "mflctrl1", XSPR(31,339,156), XSPR_MASK, PPC860, { RT } }, -{ "mflctrl2", XSPR(31,339,157), XSPR_MASK, PPC860, { RT } }, -{ "mfictrl", XSPR(31,339,158), XSPR_MASK, PPC860, { RT } }, -{ "mfbar", XSPR(31,339,159), XSPR_MASK, PPC860, { RT } }, -{ "mfvrsave", XSPR(31,339,256), XSPR_MASK, PPCVEC, { RT } }, -{ "mfusprg0", XSPR(31,339,256), XSPR_MASK, BOOKE, { RT } }, -{ "mftb", X(31,371), X_MASK, CLASSIC, { RT, TBR } }, -{ "mftb", XSPR(31,339,268), XSPR_MASK, BOOKE, { RT } }, -{ "mftbl", XSPR(31,371,268), XSPR_MASK, CLASSIC, { RT } }, -{ "mftbl", XSPR(31,339,268), XSPR_MASK, BOOKE, { RT } }, -{ "mftbu", XSPR(31,371,269), XSPR_MASK, CLASSIC, { RT } }, -{ "mftbu", XSPR(31,339,269), XSPR_MASK, BOOKE, { RT } }, -{ "mfsprg", XSPR(31,339,256), XSPRG_MASK, PPC, { RT, SPRG } }, -{ "mfsprg0", XSPR(31,339,272), XSPR_MASK, PPC, { RT } }, -{ "mfsprg1", XSPR(31,339,273), XSPR_MASK, PPC, { RT } }, -{ "mfsprg2", XSPR(31,339,274), XSPR_MASK, PPC, { RT } }, -{ "mfsprg3", XSPR(31,339,275), XSPR_MASK, PPC, { RT } }, -{ "mfsprg4", XSPR(31,339,260), XSPR_MASK, PPC405 | BOOKE, { RT } }, -{ "mfsprg5", XSPR(31,339,261), XSPR_MASK, PPC405 | BOOKE, { RT } }, -{ "mfsprg6", XSPR(31,339,262), XSPR_MASK, PPC405 | BOOKE, { RT } }, -{ "mfsprg7", XSPR(31,339,263), XSPR_MASK, PPC405 | BOOKE, { RT } }, -{ "mfasr", XSPR(31,339,280), XSPR_MASK, PPC64, { RT } }, -{ "mfear", XSPR(31,339,282), XSPR_MASK, PPC, { RT } }, -{ "mfpir", XSPR(31,339,286), XSPR_MASK, BOOKE, { RT } }, -{ "mfpvr", XSPR(31,339,287), XSPR_MASK, PPC, { RT } }, -{ "mfdbsr", XSPR(31,339,304), XSPR_MASK, BOOKE, { RT } }, -{ "mfdbsr", XSPR(31,339,1008), XSPR_MASK, PPC403, { RT } }, -{ "mfdbcr0", XSPR(31,339,308), XSPR_MASK, BOOKE, { RT } }, -{ "mfdbcr0", XSPR(31,339,1010), XSPR_MASK, PPC405, { RT } }, -{ "mfdbcr1", XSPR(31,339,309), XSPR_MASK, BOOKE, { RT } }, -{ "mfdbcr1", XSPR(31,339,957), XSPR_MASK, PPC405, { RT } }, -{ "mfdbcr2", XSPR(31,339,310), XSPR_MASK, BOOKE, { RT } }, -{ "mfiac1", XSPR(31,339,312), XSPR_MASK, BOOKE, { RT } }, -{ "mfiac1", XSPR(31,339,1012), XSPR_MASK, PPC403, { RT } }, -{ "mfiac2", XSPR(31,339,313), XSPR_MASK, BOOKE, { RT } }, -{ "mfiac2", XSPR(31,339,1013), XSPR_MASK, PPC403, { RT } }, -{ "mfiac3", XSPR(31,339,314), XSPR_MASK, BOOKE, { RT } }, -{ "mfiac3", XSPR(31,339,948), XSPR_MASK, PPC405, { RT } }, -{ "mfiac4", XSPR(31,339,315), XSPR_MASK, BOOKE, { RT } }, -{ "mfiac4", XSPR(31,339,949), XSPR_MASK, PPC405, { RT } }, -{ "mfdac1", XSPR(31,339,316), XSPR_MASK, BOOKE, { RT } }, -{ "mfdac1", XSPR(31,339,1014), XSPR_MASK, PPC403, { RT } }, -{ "mfdac2", XSPR(31,339,317), XSPR_MASK, BOOKE, { RT } }, -{ "mfdac2", XSPR(31,339,1015), XSPR_MASK, PPC403, { RT } }, -{ "mfdvc1", XSPR(31,339,318), XSPR_MASK, BOOKE, { RT } }, -{ "mfdvc1", XSPR(31,339,950), XSPR_MASK, PPC405, { RT } }, -{ "mfdvc2", XSPR(31,339,319), XSPR_MASK, BOOKE, { RT } }, -{ "mfdvc2", XSPR(31,339,951), XSPR_MASK, PPC405, { RT } }, -{ "mftsr", XSPR(31,339,336), XSPR_MASK, BOOKE, { RT } }, -{ "mftsr", XSPR(31,339,984), XSPR_MASK, PPC403, { RT } }, -{ "mftcr", XSPR(31,339,340), XSPR_MASK, BOOKE, { RT } }, -{ "mftcr", XSPR(31,339,986), XSPR_MASK, PPC403, { RT } }, -{ "mfivor0", XSPR(31,339,400), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor1", XSPR(31,339,401), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor2", XSPR(31,339,402), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor3", XSPR(31,339,403), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor4", XSPR(31,339,404), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor5", XSPR(31,339,405), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor6", XSPR(31,339,406), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor7", XSPR(31,339,407), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor8", XSPR(31,339,408), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor9", XSPR(31,339,409), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor10", XSPR(31,339,410), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor11", XSPR(31,339,411), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor12", XSPR(31,339,412), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor13", XSPR(31,339,413), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor14", XSPR(31,339,414), XSPR_MASK, BOOKE, { RT } }, -{ "mfivor15", XSPR(31,339,415), XSPR_MASK, BOOKE, { RT } }, -{ "mfspefscr", XSPR(31,339,512), XSPR_MASK, PPCSPE, { RT } }, -{ "mfbbear", XSPR(31,339,513), XSPR_MASK, PPCBRLK, { RT } }, -{ "mfbbtar", XSPR(31,339,514), XSPR_MASK, PPCBRLK, { RT } }, -{ "mfivor32", XSPR(31,339,528), XSPR_MASK, PPCSPE, { RT } }, -{ "mfivor33", XSPR(31,339,529), XSPR_MASK, PPCSPE, { RT } }, -{ "mfivor34", XSPR(31,339,530), XSPR_MASK, PPCSPE, { RT } }, -{ "mfivor35", XSPR(31,339,531), XSPR_MASK, PPCPMR, { RT } }, -{ "mfibatu", XSPR(31,339,528), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, -{ "mfibatl", XSPR(31,339,529), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, -{ "mfdbatu", XSPR(31,339,536), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, -{ "mfdbatl", XSPR(31,339,537), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, -{ "mfic_cst", XSPR(31,339,560), XSPR_MASK, PPC860, { RT } }, -{ "mfic_adr", XSPR(31,339,561), XSPR_MASK, PPC860, { RT } }, -{ "mfic_dat", XSPR(31,339,562), XSPR_MASK, PPC860, { RT } }, -{ "mfdc_cst", XSPR(31,339,568), XSPR_MASK, PPC860, { RT } }, -{ "mfdc_adr", XSPR(31,339,569), XSPR_MASK, PPC860, { RT } }, -{ "mfmcsrr0", XSPR(31,339,570), XSPR_MASK, PPCRFMCI, { RT } }, -{ "mfdc_dat", XSPR(31,339,570), XSPR_MASK, PPC860, { RT } }, -{ "mfmcsrr1", XSPR(31,339,571), XSPR_MASK, PPCRFMCI, { RT } }, -{ "mfmcsr", XSPR(31,339,572), XSPR_MASK, PPCRFMCI, { RT } }, -{ "mfmcar", XSPR(31,339,573), XSPR_MASK, PPCRFMCI, { RT } }, -{ "mfdpdr", XSPR(31,339,630), XSPR_MASK, PPC860, { RT } }, -{ "mfdpir", XSPR(31,339,631), XSPR_MASK, PPC860, { RT } }, -{ "mfimmr", XSPR(31,339,638), XSPR_MASK, PPC860, { RT } }, -{ "mfmi_ctr", XSPR(31,339,784), XSPR_MASK, PPC860, { RT } }, -{ "mfmi_ap", XSPR(31,339,786), XSPR_MASK, PPC860, { RT } }, -{ "mfmi_epn", XSPR(31,339,787), XSPR_MASK, PPC860, { RT } }, -{ "mfmi_twc", XSPR(31,339,789), XSPR_MASK, PPC860, { RT } }, -{ "mfmi_rpn", XSPR(31,339,790), XSPR_MASK, PPC860, { RT } }, -{ "mfmd_ctr", XSPR(31,339,792), XSPR_MASK, PPC860, { RT } }, -{ "mfm_casid", XSPR(31,339,793), XSPR_MASK, PPC860, { RT } }, -{ "mfmd_ap", XSPR(31,339,794), XSPR_MASK, PPC860, { RT } }, -{ "mfmd_epn", XSPR(31,339,795), XSPR_MASK, PPC860, { RT } }, -{ "mfmd_twb", XSPR(31,339,796), XSPR_MASK, PPC860, { RT } }, -{ "mfmd_twc", XSPR(31,339,797), XSPR_MASK, PPC860, { RT } }, -{ "mfmd_rpn", XSPR(31,339,798), XSPR_MASK, PPC860, { RT } }, -{ "mfm_tw", XSPR(31,339,799), XSPR_MASK, PPC860, { RT } }, -{ "mfmi_dbcam", XSPR(31,339,816), XSPR_MASK, PPC860, { RT } }, -{ "mfmi_dbram0",XSPR(31,339,817), XSPR_MASK, PPC860, { RT } }, -{ "mfmi_dbram1",XSPR(31,339,818), XSPR_MASK, PPC860, { RT } }, -{ "mfmd_dbcam", XSPR(31,339,824), XSPR_MASK, PPC860, { RT } }, -{ "mfmd_dbram0",XSPR(31,339,825), XSPR_MASK, PPC860, { RT } }, -{ "mfmd_dbram1",XSPR(31,339,826), XSPR_MASK, PPC860, { RT } }, -{ "mfummcr0", XSPR(31,339,936), XSPR_MASK, PPC750, { RT } }, -{ "mfupmc1", XSPR(31,339,937), XSPR_MASK, PPC750, { RT } }, -{ "mfupmc2", XSPR(31,339,938), XSPR_MASK, PPC750, { RT } }, -{ "mfusia", XSPR(31,339,939), XSPR_MASK, PPC750, { RT } }, -{ "mfummcr1", XSPR(31,339,940), XSPR_MASK, PPC750, { RT } }, -{ "mfupmc3", XSPR(31,339,941), XSPR_MASK, PPC750, { RT } }, -{ "mfupmc4", XSPR(31,339,942), XSPR_MASK, PPC750, { RT } }, -{ "mfzpr", XSPR(31,339,944), XSPR_MASK, PPC403, { RT } }, -{ "mfccr0", XSPR(31,339,947), XSPR_MASK, PPC405, { RT } }, -{ "mfmmcr0", XSPR(31,339,952), XSPR_MASK, PPC750, { RT } }, -{ "mfpmc1", XSPR(31,339,953), XSPR_MASK, PPC750, { RT } }, -{ "mfsgr", XSPR(31,339,953), XSPR_MASK, PPC403, { RT } }, -{ "mfpmc2", XSPR(31,339,954), XSPR_MASK, PPC750, { RT } }, -{ "mfdcwr", XSPR(31,339,954), XSPR_MASK, PPC403, { RT } }, -{ "mfsia", XSPR(31,339,955), XSPR_MASK, PPC750, { RT } }, -{ "mfsler", XSPR(31,339,955), XSPR_MASK, PPC405, { RT } }, -{ "mfmmcr1", XSPR(31,339,956), XSPR_MASK, PPC750, { RT } }, -{ "mfsu0r", XSPR(31,339,956), XSPR_MASK, PPC405, { RT } }, -{ "mfpmc3", XSPR(31,339,957), XSPR_MASK, PPC750, { RT } }, -{ "mfpmc4", XSPR(31,339,958), XSPR_MASK, PPC750, { RT } }, -{ "mficdbdr", XSPR(31,339,979), XSPR_MASK, PPC403, { RT } }, -{ "mfevpr", XSPR(31,339,982), XSPR_MASK, PPC403, { RT } }, -{ "mfcdbcr", XSPR(31,339,983), XSPR_MASK, PPC403, { RT } }, -{ "mfpit", XSPR(31,339,987), XSPR_MASK, PPC403, { RT } }, -{ "mftbhi", XSPR(31,339,988), XSPR_MASK, PPC403, { RT } }, -{ "mftblo", XSPR(31,339,989), XSPR_MASK, PPC403, { RT } }, -{ "mfsrr2", XSPR(31,339,990), XSPR_MASK, PPC403, { RT } }, -{ "mfsrr3", XSPR(31,339,991), XSPR_MASK, PPC403, { RT } }, -{ "mfl2cr", XSPR(31,339,1017), XSPR_MASK, PPC750, { RT } }, -{ "mfdccr", XSPR(31,339,1018), XSPR_MASK, PPC403, { RT } }, -{ "mficcr", XSPR(31,339,1019), XSPR_MASK, PPC403, { RT } }, -{ "mfictc", XSPR(31,339,1019), XSPR_MASK, PPC750, { RT } }, -{ "mfpbl1", XSPR(31,339,1020), XSPR_MASK, PPC403, { RT } }, -{ "mfthrm1", XSPR(31,339,1020), XSPR_MASK, PPC750, { RT } }, -{ "mfpbu1", XSPR(31,339,1021), XSPR_MASK, PPC403, { RT } }, -{ "mfthrm2", XSPR(31,339,1021), XSPR_MASK, PPC750, { RT } }, -{ "mfpbl2", XSPR(31,339,1022), XSPR_MASK, PPC403, { RT } }, -{ "mfthrm3", XSPR(31,339,1022), XSPR_MASK, PPC750, { RT } }, -{ "mfpbu2", XSPR(31,339,1023), XSPR_MASK, PPC403, { RT } }, -{ "mfspr", X(31,339), X_MASK, COM, { RT, SPR } }, - -{ "lwax", X(31,341), X_MASK, PPC64, { RT, RA0, RB } }, - -{ "dst", XDSS(31,342,0), XDSS_MASK, PPCVEC, { RA, RB, STRM } }, -{ "dstt", XDSS(31,342,1), XDSS_MASK, PPCVEC, { RA, RB, STRM } }, - -{ "lhax", X(31,343), X_MASK, COM, { RT, RA0, RB } }, - -{ "lhaxe", X(31,351), X_MASK, BOOKE64, { RT, RA0, RB } }, - -{ "dstst", XDSS(31,374,0), XDSS_MASK, PPCVEC, { RA, RB, STRM } }, -{ "dststt", XDSS(31,374,1), XDSS_MASK, PPCVEC, { RA, RB, STRM } }, - -{ "dccci", X(31,454), XRT_MASK, PPC403|PPC440, { RA, RB } }, - -{ "abs", XO(31,360,0,0), XORB_MASK, M601, { RT, RA } }, -{ "abs.", XO(31,360,0,1), XORB_MASK, M601, { RT, RA } }, -{ "abso", XO(31,360,1,0), XORB_MASK, M601, { RT, RA } }, -{ "abso.", XO(31,360,1,1), XORB_MASK, M601, { RT, RA } }, - -{ "divs", XO(31,363,0,0), XO_MASK, M601, { RT, RA, RB } }, -{ "divs.", XO(31,363,0,1), XO_MASK, M601, { RT, RA, RB } }, -{ "divso", XO(31,363,1,0), XO_MASK, M601, { RT, RA, RB } }, -{ "divso.", XO(31,363,1,1), XO_MASK, M601, { RT, RA, RB } }, - -{ "tlbia", X(31,370), 0xffffffff, PPC, { 0 } }, - -{ "lwaux", X(31,373), X_MASK, PPC64, { RT, RAL, RB } }, - -{ "lhaux", X(31,375), X_MASK, COM, { RT, RAL, RB } }, - -{ "lhauxe", X(31,383), X_MASK, BOOKE64, { RT, RAL, RB } }, - -{ "mtdcrx", X(31,387), X_MASK, BOOKE, { RA, RS } }, - -{ "dcblc", X(31,390), X_MASK, PPCCHLK, { CT, RA, RB }}, - -{ "subfe64", XO(31,392,0,0), XO_MASK, BOOKE64, { RT, RA, RB } }, -{ "subfe64o",XO(31,392,1,0), XO_MASK, BOOKE64, { RT, RA, RB } }, - -{ "adde64", XO(31,394,0,0), XO_MASK, BOOKE64, { RT, RA, RB } }, -{ "adde64o", XO(31,394,1,0), XO_MASK, BOOKE64, { RT, RA, RB } }, - -{ "dcblce", X(31,398), X_MASK, PPCCHLK64, { CT, RA, RB }}, - -{ "slbmte", X(31,402), XRA_MASK, PPC64, { RS, RB } }, - -{ "sthx", X(31,407), X_MASK, COM, { RS, RA0, RB } }, - -{ "cmpb", X(31,508), X_MASK, POWER6, { RA, RS, RB } }, - -{ "lfqx", X(31,791), X_MASK, POWER2, { FRT, RA, RB } }, - -{ "lfdpx", X(31,791), X_MASK, POWER6, { FRT, RA, RB } }, - -{ "lfqux", X(31,823), X_MASK, POWER2, { FRT, RA, RB } }, - -{ "stfqx", X(31,919), X_MASK, POWER2, { FRS, RA, RB } }, - -{ "stfdpx", X(31,919), X_MASK, POWER6, { FRS, RA, RB } }, - -{ "stfqux", X(31,951), X_MASK, POWER2, { FRS, RA, RB } }, - -{ "orc", XRC(31,412,0), X_MASK, COM, { RA, RS, RB } }, -{ "orc.", XRC(31,412,1), X_MASK, COM, { RA, RS, RB } }, - -{ "sradi", XS(31,413,0), XS_MASK, PPC64, { RA, RS, SH6 } }, -{ "sradi.", XS(31,413,1), XS_MASK, PPC64, { RA, RS, SH6 } }, - -{ "sthxe", X(31,415), X_MASK, BOOKE64, { RS, RA0, RB } }, - -{ "slbie", X(31,434), XRTRA_MASK, PPC64, { RB } }, - -{ "ecowx", X(31,438), X_MASK, PPC, { RT, RA, RB } }, - -{ "sthux", X(31,439), X_MASK, COM, { RS, RAS, RB } }, - -{ "sthuxe", X(31,447), X_MASK, BOOKE64, { RS, RAS, RB } }, - -{ "cctpl", 0x7c210b78, 0xffffffff, CELL, { 0 }}, -{ "cctpm", 0x7c421378, 0xffffffff, CELL, { 0 }}, -{ "cctph", 0x7c631b78, 0xffffffff, CELL, { 0 }}, -{ "db8cyc", 0x7f9ce378, 0xffffffff, CELL, { 0 }}, -{ "db10cyc", 0x7fbdeb78, 0xffffffff, CELL, { 0 }}, -{ "db12cyc", 0x7fdef378, 0xffffffff, CELL, { 0 }}, -{ "db16cyc", 0x7ffffb78, 0xffffffff, CELL, { 0 }}, -{ "mr", XRC(31,444,0), X_MASK, COM, { RA, RS, RBS } }, -{ "or", XRC(31,444,0), X_MASK, COM, { RA, RS, RB } }, -{ "mr.", XRC(31,444,1), X_MASK, COM, { RA, RS, RBS } }, -{ "or.", XRC(31,444,1), X_MASK, COM, { RA, RS, RB } }, - -{ "mtexisr", XSPR(31,451,64), XSPR_MASK, PPC403, { RS } }, -{ "mtexier", XSPR(31,451,66), XSPR_MASK, PPC403, { RS } }, -{ "mtbr0", XSPR(31,451,128), XSPR_MASK, PPC403, { RS } }, -{ "mtbr1", XSPR(31,451,129), XSPR_MASK, PPC403, { RS } }, -{ "mtbr2", XSPR(31,451,130), XSPR_MASK, PPC403, { RS } }, -{ "mtbr3", XSPR(31,451,131), XSPR_MASK, PPC403, { RS } }, -{ "mtbr4", XSPR(31,451,132), XSPR_MASK, PPC403, { RS } }, -{ "mtbr5", XSPR(31,451,133), XSPR_MASK, PPC403, { RS } }, -{ "mtbr6", XSPR(31,451,134), XSPR_MASK, PPC403, { RS } }, -{ "mtbr7", XSPR(31,451,135), XSPR_MASK, PPC403, { RS } }, -{ "mtbear", XSPR(31,451,144), XSPR_MASK, PPC403, { RS } }, -{ "mtbesr", XSPR(31,451,145), XSPR_MASK, PPC403, { RS } }, -{ "mtiocr", XSPR(31,451,160), XSPR_MASK, PPC403, { RS } }, -{ "mtdmacr0", XSPR(31,451,192), XSPR_MASK, PPC403, { RS } }, -{ "mtdmact0", XSPR(31,451,193), XSPR_MASK, PPC403, { RS } }, -{ "mtdmada0", XSPR(31,451,194), XSPR_MASK, PPC403, { RS } }, -{ "mtdmasa0", XSPR(31,451,195), XSPR_MASK, PPC403, { RS } }, -{ "mtdmacc0", XSPR(31,451,196), XSPR_MASK, PPC403, { RS } }, -{ "mtdmacr1", XSPR(31,451,200), XSPR_MASK, PPC403, { RS } }, -{ "mtdmact1", XSPR(31,451,201), XSPR_MASK, PPC403, { RS } }, -{ "mtdmada1", XSPR(31,451,202), XSPR_MASK, PPC403, { RS } }, -{ "mtdmasa1", XSPR(31,451,203), XSPR_MASK, PPC403, { RS } }, -{ "mtdmacc1", XSPR(31,451,204), XSPR_MASK, PPC403, { RS } }, -{ "mtdmacr2", XSPR(31,451,208), XSPR_MASK, PPC403, { RS } }, -{ "mtdmact2", XSPR(31,451,209), XSPR_MASK, PPC403, { RS } }, -{ "mtdmada2", XSPR(31,451,210), XSPR_MASK, PPC403, { RS } }, -{ "mtdmasa2", XSPR(31,451,211), XSPR_MASK, PPC403, { RS } }, -{ "mtdmacc2", XSPR(31,451,212), XSPR_MASK, PPC403, { RS } }, -{ "mtdmacr3", XSPR(31,451,216), XSPR_MASK, PPC403, { RS } }, -{ "mtdmact3", XSPR(31,451,217), XSPR_MASK, PPC403, { RS } }, -{ "mtdmada3", XSPR(31,451,218), XSPR_MASK, PPC403, { RS } }, -{ "mtdmasa3", XSPR(31,451,219), XSPR_MASK, PPC403, { RS } }, -{ "mtdmacc3", XSPR(31,451,220), XSPR_MASK, PPC403, { RS } }, -{ "mtdmasr", XSPR(31,451,224), XSPR_MASK, PPC403, { RS } }, -{ "mtdcr", X(31,451), X_MASK, PPC403 | BOOKE, { SPR, RS } }, - -{ "subfze64",XO(31,456,0,0), XORB_MASK, BOOKE64, { RT, RA } }, -{ "subfze64o",XO(31,456,1,0), XORB_MASK, BOOKE64, { RT, RA } }, - -{ "divdu", XO(31,457,0,0), XO_MASK, PPC64, { RT, RA, RB } }, -{ "divdu.", XO(31,457,0,1), XO_MASK, PPC64, { RT, RA, RB } }, -{ "divduo", XO(31,457,1,0), XO_MASK, PPC64, { RT, RA, RB } }, -{ "divduo.", XO(31,457,1,1), XO_MASK, PPC64, { RT, RA, RB } }, - -{ "addze64", XO(31,458,0,0), XORB_MASK, BOOKE64, { RT, RA } }, -{ "addze64o",XO(31,458,1,0), XORB_MASK, BOOKE64, { RT, RA } }, - -{ "divwu", XO(31,459,0,0), XO_MASK, PPC, { RT, RA, RB } }, -{ "divwu.", XO(31,459,0,1), XO_MASK, PPC, { RT, RA, RB } }, -{ "divwuo", XO(31,459,1,0), XO_MASK, PPC, { RT, RA, RB } }, -{ "divwuo.", XO(31,459,1,1), XO_MASK, PPC, { RT, RA, RB } }, - -{ "mtmq", XSPR(31,467,0), XSPR_MASK, M601, { RS } }, -{ "mtxer", XSPR(31,467,1), XSPR_MASK, COM, { RS } }, -{ "mtlr", XSPR(31,467,8), XSPR_MASK, COM, { RS } }, -{ "mtctr", XSPR(31,467,9), XSPR_MASK, COM, { RS } }, -{ "mttid", XSPR(31,467,17), XSPR_MASK, POWER, { RS } }, -{ "mtdsisr", XSPR(31,467,18), XSPR_MASK, COM, { RS } }, -{ "mtdar", XSPR(31,467,19), XSPR_MASK, COM, { RS } }, -{ "mtrtcu", XSPR(31,467,20), XSPR_MASK, COM, { RS } }, -{ "mtrtcl", XSPR(31,467,21), XSPR_MASK, COM, { RS } }, -{ "mtdec", XSPR(31,467,22), XSPR_MASK, COM, { RS } }, -{ "mtsdr0", XSPR(31,467,24), XSPR_MASK, POWER, { RS } }, -{ "mtsdr1", XSPR(31,467,25), XSPR_MASK, COM, { RS } }, -{ "mtsrr0", XSPR(31,467,26), XSPR_MASK, COM, { RS } }, -{ "mtsrr1", XSPR(31,467,27), XSPR_MASK, COM, { RS } }, -{ "mtcfar", XSPR(31,467,28), XSPR_MASK, POWER6, { RS } }, -{ "mtpid", XSPR(31,467,48), XSPR_MASK, BOOKE, { RS } }, -{ "mtpid", XSPR(31,467,945), XSPR_MASK, PPC403, { RS } }, -{ "mtdecar", XSPR(31,467,54), XSPR_MASK, BOOKE, { RS } }, -{ "mtcsrr0", XSPR(31,467,58), XSPR_MASK, BOOKE, { RS } }, -{ "mtcsrr1", XSPR(31,467,59), XSPR_MASK, BOOKE, { RS } }, -{ "mtdear", XSPR(31,467,61), XSPR_MASK, BOOKE, { RS } }, -{ "mtdear", XSPR(31,467,981), XSPR_MASK, PPC403, { RS } }, -{ "mtesr", XSPR(31,467,62), XSPR_MASK, BOOKE, { RS } }, -{ "mtesr", XSPR(31,467,980), XSPR_MASK, PPC403, { RS } }, -{ "mtivpr", XSPR(31,467,63), XSPR_MASK, BOOKE, { RS } }, -{ "mtcmpa", XSPR(31,467,144), XSPR_MASK, PPC860, { RS } }, -{ "mtcmpb", XSPR(31,467,145), XSPR_MASK, PPC860, { RS } }, -{ "mtcmpc", XSPR(31,467,146), XSPR_MASK, PPC860, { RS } }, -{ "mtcmpd", XSPR(31,467,147), XSPR_MASK, PPC860, { RS } }, -{ "mticr", XSPR(31,467,148), XSPR_MASK, PPC860, { RS } }, -{ "mtder", XSPR(31,467,149), XSPR_MASK, PPC860, { RS } }, -{ "mtcounta", XSPR(31,467,150), XSPR_MASK, PPC860, { RS } }, -{ "mtcountb", XSPR(31,467,151), XSPR_MASK, PPC860, { RS } }, -{ "mtcmpe", XSPR(31,467,152), XSPR_MASK, PPC860, { RS } }, -{ "mtcmpf", XSPR(31,467,153), XSPR_MASK, PPC860, { RS } }, -{ "mtcmpg", XSPR(31,467,154), XSPR_MASK, PPC860, { RS } }, -{ "mtcmph", XSPR(31,467,155), XSPR_MASK, PPC860, { RS } }, -{ "mtlctrl1", XSPR(31,467,156), XSPR_MASK, PPC860, { RS } }, -{ "mtlctrl2", XSPR(31,467,157), XSPR_MASK, PPC860, { RS } }, -{ "mtictrl", XSPR(31,467,158), XSPR_MASK, PPC860, { RS } }, -{ "mtbar", XSPR(31,467,159), XSPR_MASK, PPC860, { RS } }, -{ "mtvrsave", XSPR(31,467,256), XSPR_MASK, PPCVEC, { RS } }, -{ "mtusprg0", XSPR(31,467,256), XSPR_MASK, BOOKE, { RS } }, -{ "mtsprg", XSPR(31,467,256), XSPRG_MASK,PPC, { SPRG, RS } }, -{ "mtsprg0", XSPR(31,467,272), XSPR_MASK, PPC, { RS } }, -{ "mtsprg1", XSPR(31,467,273), XSPR_MASK, PPC, { RS } }, -{ "mtsprg2", XSPR(31,467,274), XSPR_MASK, PPC, { RS } }, -{ "mtsprg3", XSPR(31,467,275), XSPR_MASK, PPC, { RS } }, -{ "mtsprg4", XSPR(31,467,276), XSPR_MASK, PPC405 | BOOKE, { RS } }, -{ "mtsprg5", XSPR(31,467,277), XSPR_MASK, PPC405 | BOOKE, { RS } }, -{ "mtsprg6", XSPR(31,467,278), XSPR_MASK, PPC405 | BOOKE, { RS } }, -{ "mtsprg7", XSPR(31,467,279), XSPR_MASK, PPC405 | BOOKE, { RS } }, -{ "mtasr", XSPR(31,467,280), XSPR_MASK, PPC64, { RS } }, -{ "mtear", XSPR(31,467,282), XSPR_MASK, PPC, { RS } }, -{ "mttbl", XSPR(31,467,284), XSPR_MASK, PPC, { RS } }, -{ "mttbu", XSPR(31,467,285), XSPR_MASK, PPC, { RS } }, -{ "mtdbsr", XSPR(31,467,304), XSPR_MASK, BOOKE, { RS } }, -{ "mtdbsr", XSPR(31,467,1008), XSPR_MASK, PPC403, { RS } }, -{ "mtdbcr0", XSPR(31,467,308), XSPR_MASK, BOOKE, { RS } }, -{ "mtdbcr0", XSPR(31,467,1010), XSPR_MASK, PPC405, { RS } }, -{ "mtdbcr1", XSPR(31,467,309), XSPR_MASK, BOOKE, { RS } }, -{ "mtdbcr1", XSPR(31,467,957), XSPR_MASK, PPC405, { RS } }, -{ "mtdbcr2", XSPR(31,467,310), XSPR_MASK, BOOKE, { RS } }, -{ "mtiac1", XSPR(31,467,312), XSPR_MASK, BOOKE, { RS } }, -{ "mtiac1", XSPR(31,467,1012), XSPR_MASK, PPC403, { RS } }, -{ "mtiac2", XSPR(31,467,313), XSPR_MASK, BOOKE, { RS } }, -{ "mtiac2", XSPR(31,467,1013), XSPR_MASK, PPC403, { RS } }, -{ "mtiac3", XSPR(31,467,314), XSPR_MASK, BOOKE, { RS } }, -{ "mtiac3", XSPR(31,467,948), XSPR_MASK, PPC405, { RS } }, -{ "mtiac4", XSPR(31,467,315), XSPR_MASK, BOOKE, { RS } }, -{ "mtiac4", XSPR(31,467,949), XSPR_MASK, PPC405, { RS } }, -{ "mtdac1", XSPR(31,467,316), XSPR_MASK, BOOKE, { RS } }, -{ "mtdac1", XSPR(31,467,1014), XSPR_MASK, PPC403, { RS } }, -{ "mtdac2", XSPR(31,467,317), XSPR_MASK, BOOKE, { RS } }, -{ "mtdac2", XSPR(31,467,1015), XSPR_MASK, PPC403, { RS } }, -{ "mtdvc1", XSPR(31,467,318), XSPR_MASK, BOOKE, { RS } }, -{ "mtdvc1", XSPR(31,467,950), XSPR_MASK, PPC405, { RS } }, -{ "mtdvc2", XSPR(31,467,319), XSPR_MASK, BOOKE, { RS } }, -{ "mtdvc2", XSPR(31,467,951), XSPR_MASK, PPC405, { RS } }, -{ "mttsr", XSPR(31,467,336), XSPR_MASK, BOOKE, { RS } }, -{ "mttsr", XSPR(31,467,984), XSPR_MASK, PPC403, { RS } }, -{ "mttcr", XSPR(31,467,340), XSPR_MASK, BOOKE, { RS } }, -{ "mttcr", XSPR(31,467,986), XSPR_MASK, PPC403, { RS } }, -{ "mtivor0", XSPR(31,467,400), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor1", XSPR(31,467,401), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor2", XSPR(31,467,402), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor3", XSPR(31,467,403), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor4", XSPR(31,467,404), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor5", XSPR(31,467,405), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor6", XSPR(31,467,406), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor7", XSPR(31,467,407), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor8", XSPR(31,467,408), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor9", XSPR(31,467,409), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor10", XSPR(31,467,410), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor11", XSPR(31,467,411), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor12", XSPR(31,467,412), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor13", XSPR(31,467,413), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor14", XSPR(31,467,414), XSPR_MASK, BOOKE, { RS } }, -{ "mtivor15", XSPR(31,467,415), XSPR_MASK, BOOKE, { RS } }, -{ "mtspefscr", XSPR(31,467,512), XSPR_MASK, PPCSPE, { RS } }, -{ "mtbbear", XSPR(31,467,513), XSPR_MASK, PPCBRLK, { RS } }, -{ "mtbbtar", XSPR(31,467,514), XSPR_MASK, PPCBRLK, { RS } }, -{ "mtivor32", XSPR(31,467,528), XSPR_MASK, PPCSPE, { RS } }, -{ "mtivor33", XSPR(31,467,529), XSPR_MASK, PPCSPE, { RS } }, -{ "mtivor34", XSPR(31,467,530), XSPR_MASK, PPCSPE, { RS } }, -{ "mtivor35", XSPR(31,467,531), XSPR_MASK, PPCPMR, { RS } }, -{ "mtibatu", XSPR(31,467,528), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, -{ "mtibatl", XSPR(31,467,529), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, -{ "mtdbatu", XSPR(31,467,536), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, -{ "mtdbatl", XSPR(31,467,537), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, -{ "mtmcsrr0", XSPR(31,467,570), XSPR_MASK, PPCRFMCI, { RS } }, -{ "mtmcsrr1", XSPR(31,467,571), XSPR_MASK, PPCRFMCI, { RS } }, -{ "mtmcsr", XSPR(31,467,572), XSPR_MASK, PPCRFMCI, { RS } }, -{ "mtummcr0", XSPR(31,467,936), XSPR_MASK, PPC750, { RS } }, -{ "mtupmc1", XSPR(31,467,937), XSPR_MASK, PPC750, { RS } }, -{ "mtupmc2", XSPR(31,467,938), XSPR_MASK, PPC750, { RS } }, -{ "mtusia", XSPR(31,467,939), XSPR_MASK, PPC750, { RS } }, -{ "mtummcr1", XSPR(31,467,940), XSPR_MASK, PPC750, { RS } }, -{ "mtupmc3", XSPR(31,467,941), XSPR_MASK, PPC750, { RS } }, -{ "mtupmc4", XSPR(31,467,942), XSPR_MASK, PPC750, { RS } }, -{ "mtzpr", XSPR(31,467,944), XSPR_MASK, PPC403, { RS } }, -{ "mtccr0", XSPR(31,467,947), XSPR_MASK, PPC405, { RS } }, -{ "mtmmcr0", XSPR(31,467,952), XSPR_MASK, PPC750, { RS } }, -{ "mtsgr", XSPR(31,467,953), XSPR_MASK, PPC403, { RS } }, -{ "mtpmc1", XSPR(31,467,953), XSPR_MASK, PPC750, { RS } }, -{ "mtdcwr", XSPR(31,467,954), XSPR_MASK, PPC403, { RS } }, -{ "mtpmc2", XSPR(31,467,954), XSPR_MASK, PPC750, { RS } }, -{ "mtsler", XSPR(31,467,955), XSPR_MASK, PPC405, { RS } }, -{ "mtsia", XSPR(31,467,955), XSPR_MASK, PPC750, { RS } }, -{ "mtsu0r", XSPR(31,467,956), XSPR_MASK, PPC405, { RS } }, -{ "mtmmcr1", XSPR(31,467,956), XSPR_MASK, PPC750, { RS } }, -{ "mtpmc3", XSPR(31,467,957), XSPR_MASK, PPC750, { RS } }, -{ "mtpmc4", XSPR(31,467,958), XSPR_MASK, PPC750, { RS } }, -{ "mticdbdr", XSPR(31,467,979), XSPR_MASK, PPC403, { RS } }, -{ "mtevpr", XSPR(31,467,982), XSPR_MASK, PPC403, { RS } }, -{ "mtcdbcr", XSPR(31,467,983), XSPR_MASK, PPC403, { RS } }, -{ "mtpit", XSPR(31,467,987), XSPR_MASK, PPC403, { RS } }, -{ "mttbhi", XSPR(31,467,988), XSPR_MASK, PPC403, { RS } }, -{ "mttblo", XSPR(31,467,989), XSPR_MASK, PPC403, { RS } }, -{ "mtsrr2", XSPR(31,467,990), XSPR_MASK, PPC403, { RS } }, -{ "mtsrr3", XSPR(31,467,991), XSPR_MASK, PPC403, { RS } }, -{ "mtl2cr", XSPR(31,467,1017), XSPR_MASK, PPC750, { RS } }, -{ "mtdccr", XSPR(31,467,1018), XSPR_MASK, PPC403, { RS } }, -{ "mticcr", XSPR(31,467,1019), XSPR_MASK, PPC403, { RS } }, -{ "mtictc", XSPR(31,467,1019), XSPR_MASK, PPC750, { RS } }, -{ "mtpbl1", XSPR(31,467,1020), XSPR_MASK, PPC403, { RS } }, -{ "mtthrm1", XSPR(31,467,1020), XSPR_MASK, PPC750, { RS } }, -{ "mtpbu1", XSPR(31,467,1021), XSPR_MASK, PPC403, { RS } }, -{ "mtthrm2", XSPR(31,467,1021), XSPR_MASK, PPC750, { RS } }, -{ "mtpbl2", XSPR(31,467,1022), XSPR_MASK, PPC403, { RS } }, -{ "mtthrm3", XSPR(31,467,1022), XSPR_MASK, PPC750, { RS } }, -{ "mtpbu2", XSPR(31,467,1023), XSPR_MASK, PPC403, { RS } }, -{ "mtspr", X(31,467), X_MASK, COM, { SPR, RS } }, - -{ "dcbi", X(31,470), XRT_MASK, PPC, { RA, RB } }, - -{ "nand", XRC(31,476,0), X_MASK, COM, { RA, RS, RB } }, -{ "nand.", XRC(31,476,1), X_MASK, COM, { RA, RS, RB } }, - -{ "dcbie", X(31,478), XRT_MASK, BOOKE64, { RA, RB } }, - -{ "dcread", X(31,486), X_MASK, PPC403|PPC440, { RT, RA, RB }}, - -{ "mtpmr", X(31,462), X_MASK, PPCPMR, { PMR, RS }}, - -{ "icbtls", X(31,486), X_MASK, PPCCHLK, { CT, RA, RB }}, - -{ "nabs", XO(31,488,0,0), XORB_MASK, M601, { RT, RA } }, -{ "subfme64",XO(31,488,0,0), XORB_MASK, BOOKE64, { RT, RA } }, -{ "nabs.", XO(31,488,0,1), XORB_MASK, M601, { RT, RA } }, -{ "nabso", XO(31,488,1,0), XORB_MASK, M601, { RT, RA } }, -{ "subfme64o",XO(31,488,1,0), XORB_MASK, BOOKE64, { RT, RA } }, -{ "nabso.", XO(31,488,1,1), XORB_MASK, M601, { RT, RA } }, - -{ "divd", XO(31,489,0,0), XO_MASK, PPC64, { RT, RA, RB } }, -{ "divd.", XO(31,489,0,1), XO_MASK, PPC64, { RT, RA, RB } }, -{ "divdo", XO(31,489,1,0), XO_MASK, PPC64, { RT, RA, RB } }, -{ "divdo.", XO(31,489,1,1), XO_MASK, PPC64, { RT, RA, RB } }, - -{ "addme64", XO(31,490,0,0), XORB_MASK, BOOKE64, { RT, RA } }, -{ "addme64o",XO(31,490,1,0), XORB_MASK, BOOKE64, { RT, RA } }, - -{ "divw", XO(31,491,0,0), XO_MASK, PPC, { RT, RA, RB } }, -{ "divw.", XO(31,491,0,1), XO_MASK, PPC, { RT, RA, RB } }, -{ "divwo", XO(31,491,1,0), XO_MASK, PPC, { RT, RA, RB } }, -{ "divwo.", XO(31,491,1,1), XO_MASK, PPC, { RT, RA, RB } }, - -{ "icbtlse", X(31,494), X_MASK, PPCCHLK64, { CT, RA, RB }}, - -{ "slbia", X(31,498), 0xffffffff, PPC64, { 0 } }, - -{ "cli", X(31,502), XRB_MASK, POWER, { RT, RA } }, - -{ "stdcxe.", XRC(31,511,1), X_MASK, BOOKE64, { RS, RA, RB } }, - -{ "mcrxr", X(31,512), XRARB_MASK|(3<<21), COM, { BF } }, - -{ "bblels", X(31,518), X_MASK, PPCBRLK, { 0 }}, -{ "mcrxr64", X(31,544), XRARB_MASK|(3<<21), BOOKE64, { BF } }, - -{ "clcs", X(31,531), XRB_MASK, M601, { RT, RA } }, - -{ "ldbrx", X(31,532), X_MASK, CELL, { RT, RA0, RB } }, - -{ "lswx", X(31,533), X_MASK, PPCCOM, { RT, RA0, RB } }, -{ "lsx", X(31,533), X_MASK, PWRCOM, { RT, RA, RB } }, - -{ "lwbrx", X(31,534), X_MASK, PPCCOM, { RT, RA0, RB } }, -{ "lbrx", X(31,534), X_MASK, PWRCOM, { RT, RA, RB } }, - -{ "lfsx", X(31,535), X_MASK, COM, { FRT, RA0, RB } }, - -{ "srw", XRC(31,536,0), X_MASK, PPCCOM, { RA, RS, RB } }, -{ "sr", XRC(31,536,0), X_MASK, PWRCOM, { RA, RS, RB } }, -{ "srw.", XRC(31,536,1), X_MASK, PPCCOM, { RA, RS, RB } }, -{ "sr.", XRC(31,536,1), X_MASK, PWRCOM, { RA, RS, RB } }, - -{ "rrib", XRC(31,537,0), X_MASK, M601, { RA, RS, RB } }, -{ "rrib.", XRC(31,537,1), X_MASK, M601, { RA, RS, RB } }, - -{ "srd", XRC(31,539,0), X_MASK, PPC64, { RA, RS, RB } }, -{ "srd.", XRC(31,539,1), X_MASK, PPC64, { RA, RS, RB } }, - -{ "maskir", XRC(31,541,0), X_MASK, M601, { RA, RS, RB } }, -{ "maskir.", XRC(31,541,1), X_MASK, M601, { RA, RS, RB } }, - -{ "lwbrxe", X(31,542), X_MASK, BOOKE64, { RT, RA0, RB } }, - -{ "lfsxe", X(31,543), X_MASK, BOOKE64, { FRT, RA0, RB } }, - -{ "bbelr", X(31,550), X_MASK, PPCBRLK, { 0 }}, - -{ "tlbsync", X(31,566), 0xffffffff, PPC, { 0 } }, - -{ "lfsux", X(31,567), X_MASK, COM, { FRT, RAS, RB } }, - -{ "lfsuxe", X(31,575), X_MASK, BOOKE64, { FRT, RAS, RB } }, - -{ "mfsr", X(31,595), XRB_MASK|(1<<20), COM32, { RT, SR } }, - -{ "lswi", X(31,597), X_MASK, PPCCOM, { RT, RA0, NB } }, -{ "lsi", X(31,597), X_MASK, PWRCOM, { RT, RA0, NB } }, - -{ "lwsync", XSYNC(31,598,1), 0xffffffff, PPC, { 0 } }, -{ "ptesync", XSYNC(31,598,2), 0xffffffff, PPC64, { 0 } }, -{ "msync", X(31,598), 0xffffffff, BOOKE, { 0 } }, -{ "sync", X(31,598), XSYNC_MASK, PPCCOM, { LS } }, -{ "dcs", X(31,598), 0xffffffff, PWRCOM, { 0 } }, - -{ "lfdx", X(31,599), X_MASK, COM, { FRT, RA0, RB } }, - -{ "lfdxe", X(31,607), X_MASK, BOOKE64, { FRT, RA0, RB } }, - -{ "mffgpr", XRC(31,607,0), XRA_MASK, POWER6, { FRT, RB } }, - -{ "mfsri", X(31,627), X_MASK, PWRCOM, { RT, RA, RB } }, - -{ "dclst", X(31,630), XRB_MASK, PWRCOM, { RS, RA } }, - -{ "lfdux", X(31,631), X_MASK, COM, { FRT, RAS, RB } }, - -{ "lfduxe", X(31,639), X_MASK, BOOKE64, { FRT, RAS, RB } }, - -{ "mfsrin", X(31,659), XRA_MASK, PPC32, { RT, RB } }, - -{ "stdbrx", X(31,660), X_MASK, CELL, { RS, RA0, RB } }, - -{ "stswx", X(31,661), X_MASK, PPCCOM, { RS, RA0, RB } }, -{ "stsx", X(31,661), X_MASK, PWRCOM, { RS, RA0, RB } }, - -{ "stwbrx", X(31,662), X_MASK, PPCCOM, { RS, RA0, RB } }, -{ "stbrx", X(31,662), X_MASK, PWRCOM, { RS, RA0, RB } }, - -{ "stfsx", X(31,663), X_MASK, COM, { FRS, RA0, RB } }, - -{ "srq", XRC(31,664,0), X_MASK, M601, { RA, RS, RB } }, -{ "srq.", XRC(31,664,1), X_MASK, M601, { RA, RS, RB } }, - -{ "sre", XRC(31,665,0), X_MASK, M601, { RA, RS, RB } }, -{ "sre.", XRC(31,665,1), X_MASK, M601, { RA, RS, RB } }, - -{ "stwbrxe", X(31,670), X_MASK, BOOKE64, { RS, RA0, RB } }, - -{ "stfsxe", X(31,671), X_MASK, BOOKE64, { FRS, RA0, RB } }, - -{ "stfsux", X(31,695), X_MASK, COM, { FRS, RAS, RB } }, - -{ "sriq", XRC(31,696,0), X_MASK, M601, { RA, RS, SH } }, -{ "sriq.", XRC(31,696,1), X_MASK, M601, { RA, RS, SH } }, - -{ "stfsuxe", X(31,703), X_MASK, BOOKE64, { FRS, RAS, RB } }, - -{ "stswi", X(31,725), X_MASK, PPCCOM, { RS, RA0, NB } }, -{ "stsi", X(31,725), X_MASK, PWRCOM, { RS, RA0, NB } }, - -{ "stfdx", X(31,727), X_MASK, COM, { FRS, RA0, RB } }, - -{ "srlq", XRC(31,728,0), X_MASK, M601, { RA, RS, RB } }, -{ "srlq.", XRC(31,728,1), X_MASK, M601, { RA, RS, RB } }, - -{ "sreq", XRC(31,729,0), X_MASK, M601, { RA, RS, RB } }, -{ "sreq.", XRC(31,729,1), X_MASK, M601, { RA, RS, RB } }, - -{ "stfdxe", X(31,735), X_MASK, BOOKE64, { FRS, RA0, RB } }, - -{ "mftgpr", XRC(31,735,0), XRA_MASK, POWER6, { RT, FRB } }, - -{ "dcba", X(31,758), XRT_MASK, PPC405 | BOOKE, { RA, RB } }, - -{ "stfdux", X(31,759), X_MASK, COM, { FRS, RAS, RB } }, - -{ "srliq", XRC(31,760,0), X_MASK, M601, { RA, RS, SH } }, -{ "srliq.", XRC(31,760,1), X_MASK, M601, { RA, RS, SH } }, - -{ "dcbae", X(31,766), XRT_MASK, BOOKE64, { RA, RB } }, - -{ "stfduxe", X(31,767), X_MASK, BOOKE64, { FRS, RAS, RB } }, - -{ "tlbivax", X(31,786), XRT_MASK, BOOKE, { RA, RB } }, -{ "tlbivaxe",X(31,787), XRT_MASK, BOOKE64, { RA, RB } }, - -{ "lwzcix", X(31,789), X_MASK, POWER6, { RT, RA0, RB } }, - -{ "lhbrx", X(31,790), X_MASK, COM, { RT, RA0, RB } }, - -{ "sraw", XRC(31,792,0), X_MASK, PPCCOM, { RA, RS, RB } }, -{ "sra", XRC(31,792,0), X_MASK, PWRCOM, { RA, RS, RB } }, -{ "sraw.", XRC(31,792,1), X_MASK, PPCCOM, { RA, RS, RB } }, -{ "sra.", XRC(31,792,1), X_MASK, PWRCOM, { RA, RS, RB } }, - -{ "srad", XRC(31,794,0), X_MASK, PPC64, { RA, RS, RB } }, -{ "srad.", XRC(31,794,1), X_MASK, PPC64, { RA, RS, RB } }, - -{ "lhbrxe", X(31,798), X_MASK, BOOKE64, { RT, RA0, RB } }, - -{ "ldxe", X(31,799), X_MASK, BOOKE64, { RT, RA0, RB } }, -{ "lduxe", X(31,831), X_MASK, BOOKE64, { RT, RA0, RB } }, - -{ "rac", X(31,818), X_MASK, PWRCOM, { RT, RA, RB } }, - -{ "lhzcix", X(31,821), X_MASK, POWER6, { RT, RA0, RB } }, - -{ "dss", XDSS(31,822,0), XDSS_MASK, PPCVEC, { STRM } }, -{ "dssall", XDSS(31,822,1), XDSS_MASK, PPCVEC, { 0 } }, - -{ "srawi", XRC(31,824,0), X_MASK, PPCCOM, { RA, RS, SH } }, -{ "srai", XRC(31,824,0), X_MASK, PWRCOM, { RA, RS, SH } }, -{ "srawi.", XRC(31,824,1), X_MASK, PPCCOM, { RA, RS, SH } }, -{ "srai.", XRC(31,824,1), X_MASK, PWRCOM, { RA, RS, SH } }, - -{ "slbmfev", X(31,851), XRA_MASK, PPC64, { RT, RB } }, - -{ "lbzcix", X(31,853), X_MASK, POWER6, { RT, RA0, RB } }, - -{ "mbar", X(31,854), X_MASK, BOOKE, { MO } }, -{ "eieio", X(31,854), 0xffffffff, PPC, { 0 } }, - -{ "lfiwax", X(31,855), X_MASK, POWER6, { FRT, RA0, RB } }, - -{ "ldcix", X(31,885), X_MASK, POWER6, { RT, RA0, RB } }, - -{ "tlbsx", XRC(31,914,0), X_MASK, PPC403|BOOKE, { RTO, RA, RB } }, -{ "tlbsx.", XRC(31,914,1), X_MASK, PPC403|BOOKE, { RTO, RA, RB } }, -{ "tlbsxe", XRC(31,915,0), X_MASK, BOOKE64, { RTO, RA, RB } }, -{ "tlbsxe.", XRC(31,915,1), X_MASK, BOOKE64, { RTO, RA, RB } }, - -{ "slbmfee", X(31,915), XRA_MASK, PPC64, { RT, RB } }, - -{ "stwcix", X(31,917), X_MASK, POWER6, { RS, RA0, RB } }, - -{ "sthbrx", X(31,918), X_MASK, COM, { RS, RA0, RB } }, - -{ "sraq", XRC(31,920,0), X_MASK, M601, { RA, RS, RB } }, -{ "sraq.", XRC(31,920,1), X_MASK, M601, { RA, RS, RB } }, - -{ "srea", XRC(31,921,0), X_MASK, M601, { RA, RS, RB } }, -{ "srea.", XRC(31,921,1), X_MASK, M601, { RA, RS, RB } }, - -{ "extsh", XRC(31,922,0), XRB_MASK, PPCCOM, { RA, RS } }, -{ "exts", XRC(31,922,0), XRB_MASK, PWRCOM, { RA, RS } }, -{ "extsh.", XRC(31,922,1), XRB_MASK, PPCCOM, { RA, RS } }, -{ "exts.", XRC(31,922,1), XRB_MASK, PWRCOM, { RA, RS } }, - -{ "sthbrxe", X(31,926), X_MASK, BOOKE64, { RS, RA0, RB } }, - -{ "stdxe", X(31,927), X_MASK, BOOKE64, { RS, RA0, RB } }, - -{ "tlbrehi", XTLB(31,946,0), XTLB_MASK, PPC403, { RT, RA } }, -{ "tlbrelo", XTLB(31,946,1), XTLB_MASK, PPC403, { RT, RA } }, -{ "tlbre", X(31,946), X_MASK, PPC403|BOOKE, { RSO, RAOPT, SHO } }, - -{ "sthcix", X(31,949), X_MASK, POWER6, { RS, RA0, RB } }, - -{ "sraiq", XRC(31,952,0), X_MASK, M601, { RA, RS, SH } }, -{ "sraiq.", XRC(31,952,1), X_MASK, M601, { RA, RS, SH } }, - -{ "extsb", XRC(31,954,0), XRB_MASK, PPC, { RA, RS} }, -{ "extsb.", XRC(31,954,1), XRB_MASK, PPC, { RA, RS} }, - -{ "stduxe", X(31,959), X_MASK, BOOKE64, { RS, RAS, RB } }, - -{ "iccci", X(31,966), XRT_MASK, PPC403|PPC440, { RA, RB } }, - -{ "tlbwehi", XTLB(31,978,0), XTLB_MASK, PPC403, { RT, RA } }, -{ "tlbwelo", XTLB(31,978,1), XTLB_MASK, PPC403, { RT, RA } }, -{ "tlbwe", X(31,978), X_MASK, PPC403|BOOKE, { RSO, RAOPT, SHO } }, -{ "tlbld", X(31,978), XRTRA_MASK, PPC, { RB } }, - -{ "stbcix", X(31,981), X_MASK, POWER6, { RS, RA0, RB } }, - -{ "icbi", X(31,982), XRT_MASK, PPC, { RA, RB } }, - -{ "stfiwx", X(31,983), X_MASK, PPC, { FRS, RA0, RB } }, - -{ "extsw", XRC(31,986,0), XRB_MASK, PPC64 | BOOKE64,{ RA, RS } }, -{ "extsw.", XRC(31,986,1), XRB_MASK, PPC64, { RA, RS } }, - -{ "icread", X(31,998), XRT_MASK, PPC403|PPC440, { RA, RB } }, - -{ "icbie", X(31,990), XRT_MASK, BOOKE64, { RA, RB } }, -{ "stfiwxe", X(31,991), X_MASK, BOOKE64, { FRS, RA0, RB } }, - -{ "tlbli", X(31,1010), XRTRA_MASK, PPC, { RB } }, - -{ "stdcix", X(31,1013), X_MASK, POWER6, { RS, RA0, RB } }, - -{ "dcbzl", XOPL(31,1014,1), XRT_MASK,POWER4, { RA, RB } }, -{ "dcbz", X(31,1014), XRT_MASK, PPC, { RA, RB } }, -{ "dclz", X(31,1014), XRT_MASK, PPC, { RA, RB } }, - -{ "dcbze", X(31,1022), XRT_MASK, BOOKE64, { RA, RB } }, - -{ "lvebx", X(31, 7), X_MASK, PPCVEC, { VD, RA, RB } }, -{ "lvehx", X(31, 39), X_MASK, PPCVEC, { VD, RA, RB } }, -{ "lvewx", X(31, 71), X_MASK, PPCVEC, { VD, RA, RB } }, -{ "lvsl", X(31, 6), X_MASK, PPCVEC, { VD, RA, RB } }, -{ "lvsr", X(31, 38), X_MASK, PPCVEC, { VD, RA, RB } }, -{ "lvx", X(31, 103), X_MASK, PPCVEC, { VD, RA, RB } }, -{ "lvxl", X(31, 359), X_MASK, PPCVEC, { VD, RA, RB } }, -{ "stvebx", X(31, 135), X_MASK, PPCVEC, { VS, RA, RB } }, -{ "stvehx", X(31, 167), X_MASK, PPCVEC, { VS, RA, RB } }, -{ "stvewx", X(31, 199), X_MASK, PPCVEC, { VS, RA, RB } }, -{ "stvx", X(31, 231), X_MASK, PPCVEC, { VS, RA, RB } }, -{ "stvxl", X(31, 487), X_MASK, PPCVEC, { VS, RA, RB } }, - -/* New load/store left/right index vector instructions that are in the Cell only. */ -{ "lvlx", X(31, 519), X_MASK, CELL, { VD, RA0, RB } }, -{ "lvlxl", X(31, 775), X_MASK, CELL, { VD, RA0, RB } }, -{ "lvrx", X(31, 551), X_MASK, CELL, { VD, RA0, RB } }, -{ "lvrxl", X(31, 807), X_MASK, CELL, { VD, RA0, RB } }, -{ "stvlx", X(31, 647), X_MASK, CELL, { VS, RA0, RB } }, -{ "stvlxl", X(31, 903), X_MASK, CELL, { VS, RA0, RB } }, -{ "stvrx", X(31, 679), X_MASK, CELL, { VS, RA0, RB } }, -{ "stvrxl", X(31, 935), X_MASK, CELL, { VS, RA0, RB } }, - -{ "lwz", OP(32), OP_MASK, PPCCOM, { RT, D, RA0 } }, -{ "l", OP(32), OP_MASK, PWRCOM, { RT, D, RA0 } }, - -{ "lwzu", OP(33), OP_MASK, PPCCOM, { RT, D, RAL } }, -{ "lu", OP(33), OP_MASK, PWRCOM, { RT, D, RA0 } }, - -{ "lbz", OP(34), OP_MASK, COM, { RT, D, RA0 } }, - -{ "lbzu", OP(35), OP_MASK, COM, { RT, D, RAL } }, - -{ "stw", OP(36), OP_MASK, PPCCOM, { RS, D, RA0 } }, -{ "st", OP(36), OP_MASK, PWRCOM, { RS, D, RA0 } }, - -{ "stwu", OP(37), OP_MASK, PPCCOM, { RS, D, RAS } }, -{ "stu", OP(37), OP_MASK, PWRCOM, { RS, D, RA0 } }, - -{ "stb", OP(38), OP_MASK, COM, { RS, D, RA0 } }, - -{ "stbu", OP(39), OP_MASK, COM, { RS, D, RAS } }, - -{ "lhz", OP(40), OP_MASK, COM, { RT, D, RA0 } }, - -{ "lhzu", OP(41), OP_MASK, COM, { RT, D, RAL } }, - -{ "lha", OP(42), OP_MASK, COM, { RT, D, RA0 } }, - -{ "lhau", OP(43), OP_MASK, COM, { RT, D, RAL } }, - -{ "sth", OP(44), OP_MASK, COM, { RS, D, RA0 } }, - -{ "sthu", OP(45), OP_MASK, COM, { RS, D, RAS } }, - -{ "lmw", OP(46), OP_MASK, PPCCOM, { RT, D, RAM } }, -{ "lm", OP(46), OP_MASK, PWRCOM, { RT, D, RA0 } }, - -{ "stmw", OP(47), OP_MASK, PPCCOM, { RS, D, RA0 } }, -{ "stm", OP(47), OP_MASK, PWRCOM, { RS, D, RA0 } }, - -{ "lfs", OP(48), OP_MASK, COM, { FRT, D, RA0 } }, - -{ "lfsu", OP(49), OP_MASK, COM, { FRT, D, RAS } }, - -{ "lfd", OP(50), OP_MASK, COM, { FRT, D, RA0 } }, - -{ "lfdu", OP(51), OP_MASK, COM, { FRT, D, RAS } }, - -{ "stfs", OP(52), OP_MASK, COM, { FRS, D, RA0 } }, - -{ "stfsu", OP(53), OP_MASK, COM, { FRS, D, RAS } }, - -{ "stfd", OP(54), OP_MASK, COM, { FRS, D, RA0 } }, - -{ "stfdu", OP(55), OP_MASK, COM, { FRS, D, RAS } }, - -{ "lq", OP(56), OP_MASK, POWER4, { RTQ, DQ, RAQ } }, - -{ "lfq", OP(56), OP_MASK, POWER2, { FRT, D, RA0 } }, - -{ "lfqu", OP(57), OP_MASK, POWER2, { FRT, D, RA0 } }, - -{ "lfdp", OP(57), OP_MASK, POWER6, { FRT, D, RA0 } }, - -{ "lbze", DEO(58,0), DE_MASK, BOOKE64, { RT, DE, RA0 } }, -{ "lbzue", DEO(58,1), DE_MASK, BOOKE64, { RT, DE, RAL } }, -{ "lhze", DEO(58,2), DE_MASK, BOOKE64, { RT, DE, RA0 } }, -{ "lhzue", DEO(58,3), DE_MASK, BOOKE64, { RT, DE, RAL } }, -{ "lhae", DEO(58,4), DE_MASK, BOOKE64, { RT, DE, RA0 } }, -{ "lhaue", DEO(58,5), DE_MASK, BOOKE64, { RT, DE, RAL } }, -{ "lwze", DEO(58,6), DE_MASK, BOOKE64, { RT, DE, RA0 } }, -{ "lwzue", DEO(58,7), DE_MASK, BOOKE64, { RT, DE, RAL } }, -{ "stbe", DEO(58,8), DE_MASK, BOOKE64, { RS, DE, RA0 } }, -{ "stbue", DEO(58,9), DE_MASK, BOOKE64, { RS, DE, RAS } }, -{ "sthe", DEO(58,10), DE_MASK, BOOKE64, { RS, DE, RA0 } }, -{ "sthue", DEO(58,11), DE_MASK, BOOKE64, { RS, DE, RAS } }, -{ "stwe", DEO(58,14), DE_MASK, BOOKE64, { RS, DE, RA0 } }, -{ "stwue", DEO(58,15), DE_MASK, BOOKE64, { RS, DE, RAS } }, - -{ "ld", DSO(58,0), DS_MASK, PPC64, { RT, DS, RA0 } }, - -{ "ldu", DSO(58,1), DS_MASK, PPC64, { RT, DS, RAL } }, - -{ "lwa", DSO(58,2), DS_MASK, PPC64, { RT, DS, RA0 } }, - -{ "dadd", XRC(59,2,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "dadd.", XRC(59,2,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "dqua", ZRC(59,3,0), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, -{ "dqua.", ZRC(59,3,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, - -{ "fdivs", A(59,18,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, -{ "fdivs.", A(59,18,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, - -{ "fsubs", A(59,20,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, -{ "fsubs.", A(59,20,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, - -{ "fadds", A(59,21,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, -{ "fadds.", A(59,21,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, - -{ "fsqrts", A(59,22,0), AFRAFRC_MASK, PPC, { FRT, FRB } }, -{ "fsqrts.", A(59,22,1), AFRAFRC_MASK, PPC, { FRT, FRB } }, - -{ "fres", A(59,24,0), AFRALFRC_MASK, PPC, { FRT, FRB, A_L } }, -{ "fres.", A(59,24,1), AFRALFRC_MASK, PPC, { FRT, FRB, A_L } }, - -{ "fmuls", A(59,25,0), AFRB_MASK, PPC, { FRT, FRA, FRC } }, -{ "fmuls.", A(59,25,1), AFRB_MASK, PPC, { FRT, FRA, FRC } }, - -{ "frsqrtes", A(59,26,0), AFRALFRC_MASK,POWER5, { FRT, FRB, A_L } }, -{ "frsqrtes.",A(59,26,1), AFRALFRC_MASK,POWER5, { FRT, FRB, A_L } }, - -{ "fmsubs", A(59,28,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, -{ "fmsubs.", A(59,28,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, - -{ "fmadds", A(59,29,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, -{ "fmadds.", A(59,29,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, - -{ "fnmsubs", A(59,30,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, -{ "fnmsubs.",A(59,30,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, - -{ "fnmadds", A(59,31,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, -{ "fnmadds.",A(59,31,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, - -{ "dmul", XRC(59,34,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "dmul.", XRC(59,34,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "drrnd", ZRC(59,35,0), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, -{ "drrnd.", ZRC(59,35,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, - -{ "dscli", ZRC(59,66,0), Z_MASK, POWER6, { FRT, FRA, SH16 } }, -{ "dscli.", ZRC(59,66,1), Z_MASK, POWER6, { FRT, FRA, SH16 } }, - -{ "dquai", ZRC(59,67,0), Z2_MASK, POWER6, { TE, FRT, FRB, RMC } }, -{ "dquai.", ZRC(59,67,1), Z2_MASK, POWER6, { TE, FRT, FRB, RMC } }, - -{ "dscri", ZRC(59,98,0), Z_MASK, POWER6, { FRT, FRA, SH16 } }, -{ "dscri.", ZRC(59,98,1), Z_MASK, POWER6, { FRT, FRA, SH16 } }, - -{ "drintx", ZRC(59,99,0), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, -{ "drintx.", ZRC(59,99,1), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, - -{ "dcmpo", X(59,130), X_MASK, POWER6, { BF, FRA, FRB } }, - -{ "dtstex", X(59,162), X_MASK, POWER6, { BF, FRA, FRB } }, -{ "dtstdc", Z(59,194), Z_MASK, POWER6, { BF, FRA, DCM } }, -{ "dtstdg", Z(59,226), Z_MASK, POWER6, { BF, FRA, DGM } }, - -{ "drintn", ZRC(59,227,0), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, -{ "drintn.", ZRC(59,227,1), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, - -{ "dctdp", XRC(59,258,0), X_MASK, POWER6, { FRT, FRB } }, -{ "dctdp.", XRC(59,258,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "dctfix", XRC(59,290,0), X_MASK, POWER6, { FRT, FRB } }, -{ "dctfix.", XRC(59,290,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "ddedpd", XRC(59,322,0), X_MASK, POWER6, { SP, FRT, FRB } }, -{ "ddedpd.", XRC(59,322,1), X_MASK, POWER6, { SP, FRT, FRB } }, - -{ "dxex", XRC(59,354,0), X_MASK, POWER6, { FRT, FRB } }, -{ "dxex.", XRC(59,354,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "dsub", XRC(59,514,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "dsub.", XRC(59,514,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "ddiv", XRC(59,546,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "ddiv.", XRC(59,546,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "dcmpu", X(59,642), X_MASK, POWER6, { BF, FRA, FRB } }, - -{ "dtstsf", X(59,674), X_MASK, POWER6, { BF, FRA, FRB } }, - -{ "drsp", XRC(59,770,0), X_MASK, POWER6, { FRT, FRB } }, -{ "drsp.", XRC(59,770,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "dcffix", XRC(59,802,0), X_MASK, POWER6, { FRT, FRB } }, -{ "dcffix.", XRC(59,802,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "denbcd", XRC(59,834,0), X_MASK, POWER6, { S, FRT, FRB } }, -{ "denbcd.", XRC(59,834,1), X_MASK, POWER6, { S, FRT, FRB } }, - -{ "diex", XRC(59,866,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "diex.", XRC(59,866,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "stfq", OP(60), OP_MASK, POWER2, { FRS, D, RA } }, - -{ "stfqu", OP(61), OP_MASK, POWER2, { FRS, D, RA } }, - -{ "stfdp", OP(61), OP_MASK, POWER6, { FRT, D, RA0 } }, - -{ "lde", DEO(62,0), DE_MASK, BOOKE64, { RT, DES, RA0 } }, -{ "ldue", DEO(62,1), DE_MASK, BOOKE64, { RT, DES, RA0 } }, -{ "lfse", DEO(62,4), DE_MASK, BOOKE64, { FRT, DES, RA0 } }, -{ "lfsue", DEO(62,5), DE_MASK, BOOKE64, { FRT, DES, RAS } }, -{ "lfde", DEO(62,6), DE_MASK, BOOKE64, { FRT, DES, RA0 } }, -{ "lfdue", DEO(62,7), DE_MASK, BOOKE64, { FRT, DES, RAS } }, -{ "stde", DEO(62,8), DE_MASK, BOOKE64, { RS, DES, RA0 } }, -{ "stdue", DEO(62,9), DE_MASK, BOOKE64, { RS, DES, RAS } }, -{ "stfse", DEO(62,12), DE_MASK, BOOKE64, { FRS, DES, RA0 } }, -{ "stfsue", DEO(62,13), DE_MASK, BOOKE64, { FRS, DES, RAS } }, -{ "stfde", DEO(62,14), DE_MASK, BOOKE64, { FRS, DES, RA0 } }, -{ "stfdue", DEO(62,15), DE_MASK, BOOKE64, { FRS, DES, RAS } }, - -{ "std", DSO(62,0), DS_MASK, PPC64, { RS, DS, RA0 } }, - -{ "stdu", DSO(62,1), DS_MASK, PPC64, { RS, DS, RAS } }, - -{ "stq", DSO(62,2), DS_MASK, POWER4, { RSQ, DS, RA0 } }, - -{ "fcmpu", X(63,0), X_MASK|(3<<21), COM, { BF, FRA, FRB } }, - -{ "daddq", XRC(63,2,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "daddq.", XRC(63,2,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "dquaq", ZRC(63,3,0), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, -{ "dquaq.", ZRC(63,3,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, - -{ "fcpsgn", XRC(63,8,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "fcpsgn.", XRC(63,8,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "frsp", XRC(63,12,0), XRA_MASK, COM, { FRT, FRB } }, -{ "frsp.", XRC(63,12,1), XRA_MASK, COM, { FRT, FRB } }, - -{ "fctiw", XRC(63,14,0), XRA_MASK, PPCCOM, { FRT, FRB } }, -{ "fcir", XRC(63,14,0), XRA_MASK, POWER2, { FRT, FRB } }, -{ "fctiw.", XRC(63,14,1), XRA_MASK, PPCCOM, { FRT, FRB } }, -{ "fcir.", XRC(63,14,1), XRA_MASK, POWER2, { FRT, FRB } }, - -{ "fctiwz", XRC(63,15,0), XRA_MASK, PPCCOM, { FRT, FRB } }, -{ "fcirz", XRC(63,15,0), XRA_MASK, POWER2, { FRT, FRB } }, -{ "fctiwz.", XRC(63,15,1), XRA_MASK, PPCCOM, { FRT, FRB } }, -{ "fcirz.", XRC(63,15,1), XRA_MASK, POWER2, { FRT, FRB } }, - -{ "fdiv", A(63,18,0), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, -{ "fd", A(63,18,0), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, -{ "fdiv.", A(63,18,1), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, -{ "fd.", A(63,18,1), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, - -{ "fsub", A(63,20,0), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, -{ "fs", A(63,20,0), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, -{ "fsub.", A(63,20,1), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, -{ "fs.", A(63,20,1), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, - -{ "fadd", A(63,21,0), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, -{ "fa", A(63,21,0), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, -{ "fadd.", A(63,21,1), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } }, -{ "fa.", A(63,21,1), AFRC_MASK, PWRCOM, { FRT, FRA, FRB } }, - -{ "fsqrt", A(63,22,0), AFRAFRC_MASK, PPCPWR2, { FRT, FRB } }, -{ "fsqrt.", A(63,22,1), AFRAFRC_MASK, PPCPWR2, { FRT, FRB } }, - -{ "fsel", A(63,23,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, -{ "fsel.", A(63,23,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, - -{ "fre", A(63,24,0), AFRALFRC_MASK, POWER5, { FRT, FRB, A_L } }, -{ "fre.", A(63,24,1), AFRALFRC_MASK, POWER5, { FRT, FRB, A_L } }, - -{ "fmul", A(63,25,0), AFRB_MASK, PPCCOM, { FRT, FRA, FRC } }, -{ "fm", A(63,25,0), AFRB_MASK, PWRCOM, { FRT, FRA, FRC } }, -{ "fmul.", A(63,25,1), AFRB_MASK, PPCCOM, { FRT, FRA, FRC } }, -{ "fm.", A(63,25,1), AFRB_MASK, PWRCOM, { FRT, FRA, FRC } }, - -{ "frsqrte", A(63,26,0), AFRALFRC_MASK, PPC, { FRT, FRB, A_L } }, -{ "frsqrte.",A(63,26,1), AFRALFRC_MASK, PPC, { FRT, FRB, A_L } }, - -{ "fmsub", A(63,28,0), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, -{ "fms", A(63,28,0), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, -{ "fmsub.", A(63,28,1), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, -{ "fms.", A(63,28,1), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, - -{ "fmadd", A(63,29,0), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, -{ "fma", A(63,29,0), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, -{ "fmadd.", A(63,29,1), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, -{ "fma.", A(63,29,1), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, - -{ "fnmsub", A(63,30,0), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, -{ "fnms", A(63,30,0), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, -{ "fnmsub.", A(63,30,1), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, -{ "fnms.", A(63,30,1), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, - -{ "fnmadd", A(63,31,0), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, -{ "fnma", A(63,31,0), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, -{ "fnmadd.", A(63,31,1), A_MASK, PPCCOM, { FRT,FRA,FRC,FRB } }, -{ "fnma.", A(63,31,1), A_MASK, PWRCOM, { FRT,FRA,FRC,FRB } }, - -{ "fcmpo", X(63,32), X_MASK|(3<<21), COM, { BF, FRA, FRB } }, - -{ "dmulq", XRC(63,34,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "dmulq.", XRC(63,34,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "drrndq", ZRC(63,35,0), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, -{ "drrndq.", ZRC(63,35,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, - -{ "mtfsb1", XRC(63,38,0), XRARB_MASK, COM, { BT } }, -{ "mtfsb1.", XRC(63,38,1), XRARB_MASK, COM, { BT } }, - -{ "fneg", XRC(63,40,0), XRA_MASK, COM, { FRT, FRB } }, -{ "fneg.", XRC(63,40,1), XRA_MASK, COM, { FRT, FRB } }, - -{ "mcrfs", X(63,64), XRB_MASK|(3<<21)|(3<<16), COM, { BF, BFA } }, - -{ "dscliq", ZRC(63,66,0), Z_MASK, POWER6, { FRT, FRA, SH16 } }, -{ "dscliq.", ZRC(63,66,1), Z_MASK, POWER6, { FRT, FRA, SH16 } }, - -{ "dquaiq", ZRC(63,67,0), Z2_MASK, POWER6, { TE, FRT, FRB, RMC } }, -{ "dquaiq.", ZRC(63,67,1), Z2_MASK, POWER6, { FRT, FRA, FRB, RMC } }, - -{ "mtfsb0", XRC(63,70,0), XRARB_MASK, COM, { BT } }, -{ "mtfsb0.", XRC(63,70,1), XRARB_MASK, COM, { BT } }, - -{ "fmr", XRC(63,72,0), XRA_MASK, COM, { FRT, FRB } }, -{ "fmr.", XRC(63,72,1), XRA_MASK, COM, { FRT, FRB } }, - -{ "dscriq", ZRC(63,98,0), Z_MASK, POWER6, { FRT, FRA, SH16 } }, -{ "dscriq.", ZRC(63,98,1), Z_MASK, POWER6, { FRT, FRA, SH16 } }, - -{ "drintxq", ZRC(63,99,0), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, -{ "drintxq.",ZRC(63,99,1), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, - -{ "dcmpoq", X(63,130), X_MASK, POWER6, { BF, FRA, FRB } }, - -{ "mtfsfi", XRC(63,134,0), XWRA_MASK|(3<<21)|(1<<11), COM, { BFF, U, W } }, -{ "mtfsfi.", XRC(63,134,1), XWRA_MASK|(3<<21)|(1<<11), COM, { BFF, U, W } }, - -{ "fnabs", XRC(63,136,0), XRA_MASK, COM, { FRT, FRB } }, -{ "fnabs.", XRC(63,136,1), XRA_MASK, COM, { FRT, FRB } }, - -{ "dtstexq", X(63,162), X_MASK, POWER6, { BF, FRA, FRB } }, -{ "dtstdcq", Z(63,194), Z_MASK, POWER6, { BF, FRA, DCM } }, -{ "dtstdgq", Z(63,226), Z_MASK, POWER6, { BF, FRA, DGM } }, - -{ "drintnq", ZRC(63,227,0), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, -{ "drintnq.",ZRC(63,227,1), Z2_MASK, POWER6, { R, FRT, FRB, RMC } }, - -{ "dctqpq", XRC(63,258,0), X_MASK, POWER6, { FRT, FRB } }, -{ "dctqpq.", XRC(63,258,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "fabs", XRC(63,264,0), XRA_MASK, COM, { FRT, FRB } }, -{ "fabs.", XRC(63,264,1), XRA_MASK, COM, { FRT, FRB } }, - -{ "dctfixq", XRC(63,290,0), X_MASK, POWER6, { FRT, FRB } }, -{ "dctfixq.",XRC(63,290,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "ddedpdq", XRC(63,322,0), X_MASK, POWER6, { SP, FRT, FRB } }, -{ "ddedpdq.",XRC(63,322,1), X_MASK, POWER6, { SP, FRT, FRB } }, - -{ "dxexq", XRC(63,354,0), X_MASK, POWER6, { FRT, FRB } }, -{ "dxexq.", XRC(63,354,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "frin", XRC(63,392,0), XRA_MASK, POWER5, { FRT, FRB } }, -{ "frin.", XRC(63,392,1), XRA_MASK, POWER5, { FRT, FRB } }, -{ "friz", XRC(63,424,0), XRA_MASK, POWER5, { FRT, FRB } }, -{ "friz.", XRC(63,424,1), XRA_MASK, POWER5, { FRT, FRB } }, -{ "frip", XRC(63,456,0), XRA_MASK, POWER5, { FRT, FRB } }, -{ "frip.", XRC(63,456,1), XRA_MASK, POWER5, { FRT, FRB } }, -{ "frim", XRC(63,488,0), XRA_MASK, POWER5, { FRT, FRB } }, -{ "frim.", XRC(63,488,1), XRA_MASK, POWER5, { FRT, FRB } }, - -{ "dsubq", XRC(63,514,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "dsubq.", XRC(63,514,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "ddivq", XRC(63,546,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "ddivq.", XRC(63,546,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -{ "mffsl", XRA(63,583,12), XRARB_MASK, POWER9, { FRT } }, - -{ "mffs", XRC(63,583,0), XRARB_MASK, COM, { FRT } }, -{ "mffs.", XRC(63,583,1), XRARB_MASK, COM, { FRT } }, - -{ "dcmpuq", X(63,642), X_MASK, POWER6, { BF, FRA, FRB } }, - -{ "dtstsfq", X(63,674), X_MASK, POWER6, { BF, FRA, FRB } }, - -{ "mtfsf", XFL(63,711,0), XFL_MASK, COM, { FLM, FRB, XFL_L, W } }, -{ "mtfsf.", XFL(63,711,1), XFL_MASK, COM, { FLM, FRB, XFL_L, W } }, - -{ "drdpq", XRC(63,770,0), X_MASK, POWER6, { FRT, FRB } }, -{ "drdpq.", XRC(63,770,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "dcffixq", XRC(63,802,0), X_MASK, POWER6, { FRT, FRB } }, -{ "dcffixq.",XRC(63,802,1), X_MASK, POWER6, { FRT, FRB } }, - -{ "fctid", XRC(63,814,0), XRA_MASK, PPC64, { FRT, FRB } }, -{ "fctid.", XRC(63,814,1), XRA_MASK, PPC64, { FRT, FRB } }, - -{ "fctidz", XRC(63,815,0), XRA_MASK, PPC64, { FRT, FRB } }, -{ "fctidz.", XRC(63,815,1), XRA_MASK, PPC64, { FRT, FRB } }, - -{ "denbcdq", XRC(63,834,0), X_MASK, POWER6, { S, FRT, FRB } }, -{ "denbcdq.",XRC(63,834,1), X_MASK, POWER6, { S, FRT, FRB } }, - -{ "fcfid", XRC(63,846,0), XRA_MASK, PPC64, { FRT, FRB } }, -{ "fcfid.", XRC(63,846,1), XRA_MASK, PPC64, { FRT, FRB } }, - -{ "diexq", XRC(63,866,0), X_MASK, POWER6, { FRT, FRA, FRB } }, -{ "diexq.", XRC(63,866,1), X_MASK, POWER6, { FRT, FRA, FRB } }, - -}; - -const int powerpc_num_opcodes = - sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]); - -/* The macro table. This is only used by the assembler. */ - -/* The expressions of the form (-x ! 31) & (x | 31) have the value 0 - when x=0; 32-x when x is between 1 and 31; are negative if x is - negative; and are 32 or more otherwise. This is what you want - when, for instance, you are emulating a right shift by a - rotate-left-and-mask, because the underlying instructions support - shifts of size 0 but not shifts of size 32. By comparison, when - extracting x bits from some word you want to use just 32-x, because - the underlying instructions don't support extracting 0 bits but do - support extracting the whole word (32 bits in this case). */ - -const struct powerpc_macro powerpc_macros[] = { -{ "extldi", 4, PPC64, "rldicr %0,%1,%3,(%2)-1" }, -{ "extldi.", 4, PPC64, "rldicr. %0,%1,%3,(%2)-1" }, -{ "extrdi", 4, PPC64, "rldicl %0,%1,(%2)+(%3),64-(%2)" }, -{ "extrdi.", 4, PPC64, "rldicl. %0,%1,(%2)+(%3),64-(%2)" }, -{ "insrdi", 4, PPC64, "rldimi %0,%1,64-((%2)+(%3)),%3" }, -{ "insrdi.", 4, PPC64, "rldimi. %0,%1,64-((%2)+(%3)),%3" }, -{ "rotrdi", 3, PPC64, "rldicl %0,%1,(-(%2)!63)&((%2)|63),0" }, -{ "rotrdi.", 3, PPC64, "rldicl. %0,%1,(-(%2)!63)&((%2)|63),0" }, -{ "sldi", 3, PPC64, "rldicr %0,%1,%2,63-(%2)" }, -{ "sldi.", 3, PPC64, "rldicr. %0,%1,%2,63-(%2)" }, -{ "srdi", 3, PPC64, "rldicl %0,%1,(-(%2)!63)&((%2)|63),%2" }, -{ "srdi.", 3, PPC64, "rldicl. %0,%1,(-(%2)!63)&((%2)|63),%2" }, -{ "clrrdi", 3, PPC64, "rldicr %0,%1,0,63-(%2)" }, -{ "clrrdi.", 3, PPC64, "rldicr. %0,%1,0,63-(%2)" }, -{ "clrlsldi",4, PPC64, "rldic %0,%1,%3,(%2)-(%3)" }, -{ "clrlsldi.",4, PPC64, "rldic. %0,%1,%3,(%2)-(%3)" }, - -{ "extlwi", 4, PPCCOM, "rlwinm %0,%1,%3,0,(%2)-1" }, -{ "extlwi.", 4, PPCCOM, "rlwinm. %0,%1,%3,0,(%2)-1" }, -{ "extrwi", 4, PPCCOM, "rlwinm %0,%1,((%2)+(%3))&((%2)+(%3)<>32),32-(%2),31" }, -{ "extrwi.", 4, PPCCOM, "rlwinm. %0,%1,((%2)+(%3))&((%2)+(%3)<>32),32-(%2),31" }, -{ "inslwi", 4, PPCCOM, "rlwimi %0,%1,(-(%3)!31)&((%3)|31),%3,(%2)+(%3)-1" }, -{ "inslwi.", 4, PPCCOM, "rlwimi. %0,%1,(-(%3)!31)&((%3)|31),%3,(%2)+(%3)-1"}, -{ "insrwi", 4, PPCCOM, "rlwimi %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1" }, -{ "insrwi.", 4, PPCCOM, "rlwimi. %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1"}, -{ "rotrwi", 3, PPCCOM, "rlwinm %0,%1,(-(%2)!31)&((%2)|31),0,31" }, -{ "rotrwi.", 3, PPCCOM, "rlwinm. %0,%1,(-(%2)!31)&((%2)|31),0,31" }, -{ "slwi", 3, PPCCOM, "rlwinm %0,%1,%2,0,31-(%2)" }, -{ "sli", 3, PWRCOM, "rlinm %0,%1,%2,0,31-(%2)" }, -{ "slwi.", 3, PPCCOM, "rlwinm. %0,%1,%2,0,31-(%2)" }, -{ "sli.", 3, PWRCOM, "rlinm. %0,%1,%2,0,31-(%2)" }, -{ "srwi", 3, PPCCOM, "rlwinm %0,%1,(-(%2)!31)&((%2)|31),%2,31" }, -{ "sri", 3, PWRCOM, "rlinm %0,%1,(-(%2)!31)&((%2)|31),%2,31" }, -{ "srwi.", 3, PPCCOM, "rlwinm. %0,%1,(-(%2)!31)&((%2)|31),%2,31" }, -{ "sri.", 3, PWRCOM, "rlinm. %0,%1,(-(%2)!31)&((%2)|31),%2,31" }, -{ "clrrwi", 3, PPCCOM, "rlwinm %0,%1,0,0,31-(%2)" }, -{ "clrrwi.", 3, PPCCOM, "rlwinm. %0,%1,0,0,31-(%2)" }, -{ "clrlslwi",4, PPCCOM, "rlwinm %0,%1,%3,(%2)-(%3),31-(%3)" }, -{ "clrlslwi.",4, PPCCOM, "rlwinm. %0,%1,%3,(%2)-(%3),31-(%3)" }, -}; - -const int powerpc_num_macros = - sizeof (powerpc_macros) / sizeof (powerpc_macros[0]); - - -/* This file provides several disassembler functions, all of which use - the disassembler interface defined in dis-asm.h. Several functions - are provided because this file handles disassembly for the PowerPC - in both big and little endian mode and also for the POWER (RS/6000) - chip. */ - -static int print_insn_powerpc (bfd_vma, struct disassemble_info *, int, int); - -/* Determine which set of machines to disassemble for. PPC403/601 or - BookE. For convenience, also disassemble instructions supported - by the AltiVec vector unit. */ - -static int -powerpc_dialect (struct disassemble_info *info) -{ - int dialect = PPC_OPCODE_PPC; - - if (BFD_DEFAULT_TARGET_SIZE == 64) - dialect |= PPC_OPCODE_64; - - if (info->disassembler_options - && strstr (info->disassembler_options, "booke") != NULL) - dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_BOOKE64; - else if ((info->mach == bfd_mach_ppc_e500) - || (info->disassembler_options - && strstr (info->disassembler_options, "e500") != NULL)) - dialect |= (PPC_OPCODE_BOOKE - | PPC_OPCODE_SPE | PPC_OPCODE_ISEL - | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK - | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK - | PPC_OPCODE_RFMCI); - else if (info->disassembler_options - && strstr (info->disassembler_options, "efs") != NULL) - dialect |= PPC_OPCODE_EFS; - else if (info->disassembler_options - && strstr (info->disassembler_options, "e300") != NULL) - dialect |= PPC_OPCODE_E300 | PPC_OPCODE_CLASSIC | PPC_OPCODE_COMMON; - else if (info->disassembler_options - && strstr (info->disassembler_options, "440") != NULL) - dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_32 - | PPC_OPCODE_440 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI; - else - dialect |= (PPC_OPCODE_403 | PPC_OPCODE_601 | PPC_OPCODE_CLASSIC - | PPC_OPCODE_COMMON | PPC_OPCODE_ALTIVEC); - - if (info->disassembler_options - && strstr (info->disassembler_options, "power4") != NULL) - dialect |= PPC_OPCODE_POWER4; - - if (info->disassembler_options - && strstr (info->disassembler_options, "power5") != NULL) - dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5; - - if (info->disassembler_options - && strstr (info->disassembler_options, "cell") != NULL) - dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC; - - if (info->disassembler_options - && strstr (info->disassembler_options, "power6") != NULL) - dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC; - - if (info->disassembler_options - && strstr (info->disassembler_options, "any") != NULL) - dialect |= PPC_OPCODE_ANY; - - if (info->disassembler_options) - { - if (strstr (info->disassembler_options, "32") != NULL) - dialect &= ~PPC_OPCODE_64; - else if (strstr (info->disassembler_options, "64") != NULL) - dialect |= PPC_OPCODE_64; - } - - info->private_data = (char *) 0 + dialect; - return dialect; -} - -/* QEMU default */ -int -print_insn_ppc (bfd_vma memaddr, struct disassemble_info *info) -{ - int dialect = (char *) info->private_data - (char *) 0; - return print_insn_powerpc (memaddr, info, info->endian == BFD_ENDIAN_BIG, - dialect); -} - -/* Print a big endian PowerPC instruction. */ - -int -print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info) -{ - int dialect = (char *) info->private_data - (char *) 0; - return print_insn_powerpc (memaddr, info, 1, dialect); -} - -/* Print a little endian PowerPC instruction. */ - -int -print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info) -{ - int dialect = (char *) info->private_data - (char *) 0; - return print_insn_powerpc (memaddr, info, 0, dialect); -} - -/* Print a POWER (RS/6000) instruction. */ - -int -print_insn_rs6000 (bfd_vma memaddr, struct disassemble_info *info) -{ - return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER); -} - -/* Extract the operand value from the PowerPC or POWER instruction. */ - -static long -operand_value_powerpc (const struct powerpc_operand *operand, - unsigned long insn, int dialect) -{ - long value; - int invalid; - /* Extract the value from the instruction. */ - if (operand->extract) - value = (*operand->extract) (insn, dialect, &invalid); - else - { - value = (insn >> operand->shift) & operand->bitm; - if ((operand->flags & PPC_OPERAND_SIGNED) != 0) - { - /* BITM is always some number of zeros followed by some - number of ones, followed by some number of zeros. */ - unsigned long top = operand->bitm; - /* top & -top gives the rightmost 1 bit, so this - fills in any trailing zeros. */ - top |= (top & -top) - 1; - top &= ~(top >> 1); - value = (value ^ top) - top; - } - } - - return value; -} - -/* Determine whether the optional operand(s) should be printed. */ - -static int -skip_optional_operands (const unsigned char *opindex, - unsigned long insn, int dialect) -{ - const struct powerpc_operand *operand; - - for (; *opindex != 0; opindex++) - { - operand = &powerpc_operands[*opindex]; - if ((operand->flags & PPC_OPERAND_NEXT) != 0 - || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 - && operand_value_powerpc (operand, insn, dialect) != 0)) - return 0; - } - - return 1; -} - -/* Print a PowerPC or POWER instruction. */ - -static int -print_insn_powerpc (bfd_vma memaddr, - struct disassemble_info *info, - int bigendian, - int dialect) -{ - bfd_byte buffer[4]; - int status; - unsigned long insn; - const struct powerpc_opcode *opcode; - const struct powerpc_opcode *opcode_end; - unsigned long op; - - if (dialect == 0) - dialect = powerpc_dialect (info); - - status = (*info->read_memory_func) (memaddr, buffer, 4, info); - if (status != 0) - { - (*info->memory_error_func) (status, memaddr, info); - return -1; - } - - if (bigendian) - insn = bfd_getb32 (buffer); - else - insn = bfd_getl32 (buffer); - - /* Get the major opcode of the instruction. */ - op = PPC_OP (insn); - - /* Find the first match in the opcode table. We could speed this up - a bit by doing a binary search on the major opcode. */ - opcode_end = powerpc_opcodes + powerpc_num_opcodes; - again: - for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++) - { - unsigned long table_op; - const unsigned char *opindex; - const struct powerpc_operand *operand; - int invalid; - int need_comma; - int need_paren; - int skip_optional; - - table_op = PPC_OP (opcode->opcode); - if (op < table_op) - break; - if (op > table_op) - continue; - - if ((insn & opcode->mask) != opcode->opcode - || (opcode->flags & dialect) == 0) - continue; - - /* Make two passes over the operands. First see if any of them - have extraction functions, and, if they do, make sure the - instruction is valid. */ - invalid = 0; - for (opindex = opcode->operands; *opindex != 0; opindex++) - { - operand = powerpc_operands + *opindex; - if (operand->extract) - (*operand->extract) (insn, dialect, &invalid); - } - if (invalid) - continue; - - /* The instruction is valid. */ - if (opcode->operands[0] != 0) - (*info->fprintf_func) (info->stream, "%-7s ", opcode->name); - else - (*info->fprintf_func) (info->stream, "%s", opcode->name); - - /* Now extract and print the operands. */ - need_comma = 0; - need_paren = 0; - skip_optional = -1; - for (opindex = opcode->operands; *opindex != 0; opindex++) - { - long value; - - operand = powerpc_operands + *opindex; - - /* Operands that are marked FAKE are simply ignored. We - already made sure that the extract function considered - the instruction to be valid. */ - if ((operand->flags & PPC_OPERAND_FAKE) != 0) - continue; - - /* If all of the optional operands have the value zero, - then don't print any of them. */ - if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0) - { - if (skip_optional < 0) - skip_optional = skip_optional_operands (opindex, insn, - dialect); - if (skip_optional) - continue; - } - - value = operand_value_powerpc (operand, insn, dialect); - - if (need_comma) - { - (*info->fprintf_func) (info->stream, ","); - need_comma = 0; - } - - /* Print the operand as directed by the flags. */ - if ((operand->flags & PPC_OPERAND_GPR) != 0 - || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0)) - (*info->fprintf_func) (info->stream, "r%ld", value); - else if ((operand->flags & PPC_OPERAND_FPR) != 0) - (*info->fprintf_func) (info->stream, "f%ld", value); - else if ((operand->flags & PPC_OPERAND_VR) != 0) - (*info->fprintf_func) (info->stream, "v%ld", value); - else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0) - (*info->print_address_func) (memaddr + value, info); - else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) - (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info); - else if ((operand->flags & PPC_OPERAND_CR) == 0 - || (dialect & PPC_OPCODE_PPC) == 0) - (*info->fprintf_func) (info->stream, "%ld", value); - else - { - if (operand->bitm == 7) - (*info->fprintf_func) (info->stream, "cr%ld", value); - else - { - static const char *cbnames[4] = { "lt", "gt", "eq", "so" }; - int cr; - int cc; - - cr = value >> 2; - if (cr != 0) - (*info->fprintf_func) (info->stream, "4*cr%d+", cr); - cc = value & 3; - (*info->fprintf_func) (info->stream, "%s", cbnames[cc]); - } - } - - if (need_paren) - { - (*info->fprintf_func) (info->stream, ")"); - need_paren = 0; - } - - if ((operand->flags & PPC_OPERAND_PARENS) == 0) - need_comma = 1; - else - { - (*info->fprintf_func) (info->stream, "("); - need_paren = 1; - } - } - - /* We have found and printed an instruction; return. */ - return 4; - } - - if ((dialect & PPC_OPCODE_ANY) != 0) - { - dialect = ~PPC_OPCODE_ANY; - goto again; - } - - /* We could not find a match. */ - (*info->fprintf_func) (info->stream, ".long 0x%lx", insn); - - return 4; -} diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h index 6484caca9e..fc7cb7af5a 100644 --- a/include/disas/dis-asm.h +++ b/include/disas/dis-asm.h @@ -447,7 +447,6 @@ int print_insn_w65 (bfd_vma, disassemble_info*); int print_insn_d10v (bfd_vma, disassemble_info*); int print_insn_v850 (bfd_vma, disassemble_info*); int print_insn_tic30 (bfd_vma, disassemble_info*); -int print_insn_ppc (bfd_vma, disassemble_info*); int print_insn_crisv32 (bfd_vma, disassemble_info*); int print_insn_crisv10 (bfd_vma, disassemble_info*); int print_insn_microblaze (bfd_vma, disassemble_info*); diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index d4c7813de5..527ad40fcb 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -7309,8 +7309,6 @@ static void ppc_disas_set_info(CPUState *cs, disassemble_info *info) info->mach = bfd_mach_ppc; #endif } - info->disassembler_options = (char *)"any"; - info->print_insn = print_insn_ppc; info->cap_arch = CS_ARCH_PPC; #ifdef TARGET_PPC64 From f07b3a830ff4ab98ab1cf9dd3f006c55b0fc61f3 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 27 Apr 2022 14:33:16 +0200 Subject: [PATCH 178/935] softmmu/vl: Fence 'xenfb' if Xen support is not compiled in The 'xenfb' parameter for the '-vga' command line option is currently always enabled unconditionally (since the xenfb is not a proper QOM device that could be tested via its class name). That means it also shows up if Xen is not enabled at all, e.g. like this: $ ./qemu-system-sparc -vga help none no graphic card xenfb Xen paravirtualized framebuffer tcx TCX framebuffer (default) cg3 CG3 framebuffer Let's avoid this situation by fencing the parameter with the CONFIG_XEN_BACKEND switch. Message-Id: <20220427123316.329312-1-thuth@redhat.com> Acked-by: Anthony PERARD Signed-off-by: Thomas Huth --- softmmu/vl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/softmmu/vl.c b/softmmu/vl.c index c2919579fd..ad886fb878 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -934,10 +934,12 @@ static const VGAInterfaceInfo vga_interfaces[VGA_TYPE_MAX] = { .name = "CG3 framebuffer", .class_names = { "cgthree" }, }, +#ifdef CONFIG_XEN_BACKEND [VGA_XENFB] = { .opt_name = "xenfb", .name = "Xen paravirtualized framebuffer", }, +#endif }; static bool vga_interface_available(VGAInterfaceType t) From eeb3647cbc4716e27ca8504e0fa72bcfd16fbc35 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 27 Apr 2022 15:31:56 +0200 Subject: [PATCH 179/935] qemu-options: Limit the -xen options to x86 and arm The Xen hypervisor is only available on x86 and arm - thus let's limit the related options to these targets. Message-Id: <20220427133156.344418-1-thuth@redhat.com> Acked-by: Anthony PERARD Signed-off-by: Thomas Huth --- qemu-options.hx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 5f69b94b8e..796229c433 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4186,16 +4186,17 @@ SRST ERST DEF("xen-domid", HAS_ARG, QEMU_OPTION_xen_domid, - "-xen-domid id specify xen guest domain id\n", QEMU_ARCH_ALL) + "-xen-domid id specify xen guest domain id\n", + QEMU_ARCH_ARM | QEMU_ARCH_I386) DEF("xen-attach", 0, QEMU_OPTION_xen_attach, "-xen-attach attach to existing xen domain\n" " libxl will use this when starting QEMU\n", - QEMU_ARCH_ALL) + QEMU_ARCH_ARM | QEMU_ARCH_I386) DEF("xen-domid-restrict", 0, QEMU_OPTION_xen_domid_restrict, "-xen-domid-restrict restrict set of available xen operations\n" " to specified domain id. (Does not affect\n" " xenpv machine type).\n", - QEMU_ARCH_ALL) + QEMU_ARCH_ARM | QEMU_ARCH_I386) SRST ``-xen-domid id`` Specify xen guest domain id (XEN only). From 4c7793027982dbaa6c3ca1bef44370ca51d4bb95 Mon Sep 17 00:00:00 2001 From: Yonggang Luo Date: Fri, 2 Oct 2020 00:27:05 +0800 Subject: [PATCH 180/935] doc: remove hxtool-conv.pl This script doesn't need anymore as all texi are already convert to rST Signed-off-by: Yonggang Luo Message-Id: <20201001162705.219-3-luoyonggang@gmail.com> Signed-off-by: Thomas Huth --- scripts/hxtool-conv.pl | 137 ----------------------------------------- 1 file changed, 137 deletions(-) delete mode 100755 scripts/hxtool-conv.pl diff --git a/scripts/hxtool-conv.pl b/scripts/hxtool-conv.pl deleted file mode 100755 index eede40b346..0000000000 --- a/scripts/hxtool-conv.pl +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/perl -w -# -# Script to convert .hx file STEXI/ETEXI blocks to SRST/ERST -# -# Copyright (C) 2020 Linaro -# -# This work is licensed under the terms of the GNU GPL, version 2 or -# (at your option) any later version. See the COPYING file in the -# top-level directory. - -# This script was only ever intended as a one-off conversion operation. -# Please excuse the places where it is a bit hacky. -# Some manual intervention after the conversion is expected, as are -# some warnings from makeinfo. -# Warning: this script is not idempotent: don't try to run it on -# a .hx file that already has SRST/ERST sections. - -# Expected usage: -# scripts/hxtool-conv.pl file.hx > file.hx.new - -use utf8; - -my $reading_texi = 0; -my $texiblock = ''; -my @tables = (); - -sub update_tables($) { - my ($texi) = @_; - # Update our list of open table directives: every @table - # line in the texi fragment is added to the list, and every - # @end table line means we remove an entry from the list. - # If this fragment had a completely self contained table with - # both the @table and @end table lines, this will be a no-op. - foreach (split(/\n/, $texi)) { - push @tables, $_ if /^\@table/; - pop @tables if /^\@end table/; - } -} - -sub only_table_directives($) { - # Return true if every line in the fragment is a start or end table directive - my ($texi) = @_; - foreach (split(/\n/, $texi)) { - return 0 unless /^\@table/ or /^\@end table/; - } - return 1; -} - -sub output_rstblock($) { - # Write the output to /tmp/frag.texi, wrapped in whatever current @table - # lines we need. - my ($texi) = @_; - - # As a special case, if this fragment is only table directives and - # nothing else, update our set of open table directives but otherwise - # ignore it. This avoids emitting an empty SRST/ERST block. - if (only_table_directives($texi)) { - update_tables($texi); - return; - } - - open(my $fragfh, '>', '/tmp/frag.texi'); - # First output the currently active set of open table directives - print $fragfh join("\n", @tables); - # Next, update our list of open table directives. - # We need to do this before we emit the closing table directives - # so that we emit the right number if this fragment had an - # unbalanced set of directives. - update_tables($texi); - # Then emit the texi fragment itself. - print $fragfh "\n$texi\n"; - # Finally, add the necessary closing table directives. - print $fragfh "\@end table\n" x scalar @tables; - close $fragfh; - - # Now invoke makeinfo/pandoc on it and slurp the results into a string - open(my $fh, '-|', "makeinfo --force -o - --docbook " - . "-D 'qemu_system_x86 QEMU_SYSTEM_X86_MACRO' " - . "-D 'qemu_system QEMU_SYSTEM_MACRO' /tmp/frag.texi " - . " | pandoc -f docbook -t rst") - or die "can't start makeinfo/pandoc: $!"; - - binmode $fh, ':encoding(utf8)'; - - print "SRST\n"; - - # Slurp the whole thing into a string so we can do multiline - # string matches on it. - my $rst = do { - local $/ = undef; - <$fh>; - }; - $rst =~ s/^- − /- /gm; - $rst =~ s/“/"/gm; - $rst =~ s/”/"/gm; - $rst =~ s/‘/'/gm; - $rst =~ s/’/'/gm; - $rst =~ s/QEMU_SYSTEM_MACRO/|qemu_system|/g; - $rst =~ s/QEMU_SYSTEM_X86_MACRO/|qemu_system_x86|/g; - $rst =~ s/(?=::\n\n +\|qemu)/.. parsed-literal/g; - $rst =~ s/:\n\n::$/::/gm; - - # Fix up the invalid reference format makeinfo/pandoc emit: - # `Some string here <#anchorname>`__ - # should be: - # :ref:`anchorname` - $rst =~ s/\`[^<`]+\<\#([^>]+)\>\`__/:ref:`$1`/gm; - print $rst; - - close $fh or die "error on close: $!"; - print "ERST\n"; -} - -# Read the whole .hx input file. -while (<>) { - # Always print the current line - print; - if (/STEXI/) { - $reading_texi = 1; - $texiblock = ''; - next; - } - if (/ETEXI/) { - $reading_texi = 0; - # dump RST version of block - output_rstblock($texiblock); - next; - } - if ($reading_texi) { - # Accumulate the texi into a string - # but drop findex entries as they will confuse makeinfo - next if /^\@findex/; - $texiblock .= $_; - } -} - -die "Unexpectedly still in texi block at EOF" if $reading_texi; From 3304f5a8c97e2baea2882048141776168d7b93eb Mon Sep 17 00:00:00 2001 From: Yonggang Luo Date: Wed, 4 May 2022 04:05:23 +0800 Subject: [PATCH 181/935] cirrus/win32: upgrade mingw base packages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Yonggang Luo Reviewed-by: Marc-André Lureau Message-Id: <20220503200524.1868-2-luoyonggang@gmail.com> Signed-off-by: Thomas Huth --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index 7552d70974..20843a420c 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -12,7 +12,7 @@ windows_msys2_task: CIRRUS_SHELL: powershell MSYS: winsymlinks:nativestrict MSYSTEM: MINGW64 - MSYS2_URL: https://github.com/msys2/msys2-installer/releases/download/2021-04-19/msys2-base-x86_64-20210419.sfx.exe + MSYS2_URL: https://github.com/msys2/msys2-installer/releases/download/2022-05-03/msys2-base-x86_64-20220503.sfx.exe MSYS2_FINGERPRINT: 0 MSYS2_PACKAGES: " diffutils git grep make pkg-config sed From 5c570ef2f154ee8efe35ef939df00d2a33dee1fd Mon Sep 17 00:00:00 2001 From: Yonggang Luo Date: Wed, 4 May 2022 04:05:24 +0800 Subject: [PATCH 182/935] gitlab-ci: Upgrade mingw base package. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Yonggang Luo Reviewed-by: Marc-André Lureau Message-Id: <20220503200524.1868-3-luoyonggang@gmail.com> Signed-off-by: Thomas Huth --- .gitlab-ci.d/windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.d/windows.yml b/.gitlab-ci.d/windows.yml index 1df1630349..47f6073773 100644 --- a/.gitlab-ci.d/windows.yml +++ b/.gitlab-ci.d/windows.yml @@ -16,7 +16,7 @@ } - If ( !(Test-Path -Path msys64\var\cache\msys2.exe ) ) { Invoke-WebRequest - "https://github.com/msys2/msys2-installer/releases/download/2021-07-25/msys2-base-x86_64-20210725.sfx.exe" + "https://github.com/msys2/msys2-installer/releases/download/2022-05-03/msys2-base-x86_64-20220503.sfx.exe" -outfile "msys64\var\cache\msys2.exe" } - msys64\var\cache\msys2.exe -y From 26f0ee7ddb9e95b3bde1d1b51d98334bebce0e1f Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Thu, 5 May 2022 19:32:07 -0400 Subject: [PATCH 183/935] tests/vm: update openbsd to release 7.1 tests/vm/openbsd: Update to release 7.1 Signed-off-by: Brad Smith Tested-by: Thomas Huth Reviewed-by: Warner Losh Message-Id: Signed-off-by: Thomas Huth --- tests/vm/openbsd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/vm/openbsd b/tests/vm/openbsd index 337fe7c303..dc34b2718b 100755 --- a/tests/vm/openbsd +++ b/tests/vm/openbsd @@ -22,8 +22,8 @@ class OpenBSDVM(basevm.BaseVM): name = "openbsd" arch = "x86_64" - link = "https://cdn.openbsd.org/pub/OpenBSD/7.0/amd64/install70.iso" - csum = "1882f9a23c9800e5dba3dbd2cf0126f552605c915433ef4c5bb672610a4ca3a4" + link = "https://cdn.openbsd.org/pub/OpenBSD/7.1/amd64/install71.iso" + csum = "d3a7c5b9bf890bc404304a1c96f9ee72e1d9bbcf9cc849c1133bdb0d67843396" size = "20G" pkgs = [ # tools From f9bcb2d68496a8fa620443edacb27cad1acc1492 Mon Sep 17 00:00:00 2001 From: Gautam Agrawal Date: Sun, 1 May 2022 17:55:05 +0530 Subject: [PATCH 184/935] Warn user if the vga flag is passed but no vga device is created A global boolean variable "vga_interface_created"(declared in softmmu/globals.c) has been used to track the creation of vga interface. If the vga flag is passed in the command line "default_vga"(declared in softmmu/vl.c) variable is set to 0. To warn user, the condition checks if vga_interface_created is false and default_vga is equal to 0. If "-vga none" is passed, this patch will not warn the user regarding the creation of VGA device. The warning "A -vga option was passed but this machine type does not use that option; no VGA device has been created" is logged if vga flag is passed but no vga device is created. This patch has been tested for x86_64, i386, sparc, sparc64 and arm boards. Signed-off-by: Gautam Agrawal Reviewed-by: Peter Maydell Resolves: https://gitlab.com/qemu-project/qemu/-/issues/581 Message-Id: <20220501122505.29202-1-gautamnagrawal@gmail.com> [thuth: Fix wrong warning with "-device" in some cases as reported by Paolo] Signed-off-by: Thomas Huth --- hw/hppa/machine.c | 1 + hw/isa/isa-bus.c | 1 + hw/mips/fuloong2e.c | 1 + hw/pci/pci.c | 1 + hw/ppc/spapr.c | 1 + hw/sparc/sun4m.c | 2 ++ hw/sparc64/sun4u.c | 1 + hw/xenpv/xen_machine_pv.c | 1 + include/sysemu/sysemu.h | 1 + softmmu/globals.c | 1 + softmmu/vl.c | 7 +++++++ 11 files changed, 18 insertions(+) diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index ae0bc07e75..4d054ca869 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -265,6 +265,7 @@ static void machine_hppa_init(MachineState *machine) /* Graphics setup. */ if (machine->enable_graphics && vga_interface_type != VGA_NONE) { + vga_interface_created = true; dev = qdev_new("artist"); s = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(s, &error_fatal); diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index 0ad1c5fd65..cd5ad3687d 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -166,6 +166,7 @@ bool isa_realize_and_unref(ISADevice *dev, ISABus *bus, Error **errp) ISADevice *isa_vga_init(ISABus *bus) { + vga_interface_created = true; switch (vga_interface_type) { case VGA_CIRRUS: return isa_create_simple(bus, "isa-cirrus-vga"); diff --git a/hw/mips/fuloong2e.c b/hw/mips/fuloong2e.c index 7b13098f9b..5ee546f5f6 100644 --- a/hw/mips/fuloong2e.c +++ b/hw/mips/fuloong2e.c @@ -320,6 +320,7 @@ static void mips_fuloong2e_init(MachineState *machine) /* GPU */ if (vga_interface_type != VGA_NONE) { + vga_interface_created = true; pci_dev = pci_new(-1, "ati-vga"); dev = DEVICE(pci_dev); qdev_prop_set_uint32(dev, "vgamem_mb", 16); diff --git a/hw/pci/pci.c b/hw/pci/pci.c index e99417e501..9c58f02853 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2037,6 +2037,7 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus, PCIDevice *pci_vga_init(PCIBus *bus) { + vga_interface_created = true; switch (vga_interface_type) { case VGA_CIRRUS: return pci_create_simple(bus, -1, "cirrus-vga"); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index fe9937e811..8bbae68e1b 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1742,6 +1742,7 @@ static void spapr_rtc_create(SpaprMachineState *spapr) /* Returns whether we want to use VGA or not */ static bool spapr_vga_init(PCIBus *pci_bus, Error **errp) { + vga_interface_created = true; switch (vga_interface_type) { case VGA_NONE: return false; diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index fccaed1eb4..b693eea0e0 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -920,6 +920,7 @@ static void sun4m_hw_init(MachineState *machine) /* sbus irq 5 */ cg3_init(hwdef->tcx_base, slavio_irq[11], 0x00100000, graphic_width, graphic_height, graphic_depth); + vga_interface_created = true; } else { /* If no display specified, default to TCX */ if (graphic_depth != 8 && graphic_depth != 24) { @@ -935,6 +936,7 @@ static void sun4m_hw_init(MachineState *machine) tcx_init(hwdef->tcx_base, slavio_irq[11], 0x00100000, graphic_width, graphic_height, graphic_depth); + vga_interface_created = true; } } diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 6fd08e2298..7c461d194a 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -632,6 +632,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, switch (vga_interface_type) { case VGA_STD: pci_create_simple(pci_busA, PCI_DEVFN(2, 0), "VGA"); + vga_interface_created = true; break; case VGA_NONE: break; diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c index 8df575a457..20c9611d71 100644 --- a/hw/xenpv/xen_machine_pv.c +++ b/hw/xenpv/xen_machine_pv.c @@ -63,6 +63,7 @@ static void xen_init_pv(MachineState *machine) if (vga_interface_type == VGA_XENFB) { xen_config_dev_vfb(0, "vnc"); xen_config_dev_vkbd(0); + vga_interface_created = true; } /* configure disks */ diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 10e283c170..360a408edf 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -34,6 +34,7 @@ typedef enum { } VGAInterfaceType; extern int vga_interface_type; +extern bool vga_interface_created; extern int graphic_width; extern int graphic_height; diff --git a/softmmu/globals.c b/softmmu/globals.c index 3ebd718e35..98b64e0492 100644 --- a/softmmu/globals.c +++ b/softmmu/globals.c @@ -40,6 +40,7 @@ int nb_nics; NICInfo nd_table[MAX_NICS]; int autostart = 1; int vga_interface_type = VGA_NONE; +bool vga_interface_created; Chardev *parallel_hds[MAX_PARALLEL_PORTS]; int win2k_install_hack; int singlestep; diff --git a/softmmu/vl.c b/softmmu/vl.c index ad886fb878..488cc4d09e 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -1353,6 +1353,7 @@ static void qemu_disable_default_devices(void) if (!vga_model && !default_vga) { vga_interface_type = VGA_DEVICE; + vga_interface_created = true; } if (!has_defaults || machine_class->no_serial) { default_serial = 0; @@ -2736,6 +2737,12 @@ static void qemu_machine_creation_done(void) if (foreach_device_config(DEV_GDB, gdbserver_start) < 0) { exit(1); } + if (!vga_interface_created && !default_vga && + vga_interface_type != VGA_NONE) { + warn_report("A -vga option was passed but this machine " + "type does not use that option; " + "No VGA device has been created"); + } } void qmp_x_exit_preconfig(Error **errp) From ddc5a6cc70398ed7ec76220d59c123d8cb14b0ad Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 6 May 2022 17:01:46 +0200 Subject: [PATCH 185/935] docs/devel/writing-monitor-commands: Replace obsolete STEXI/ETEXI tags STEXI and ETEXI is not used anymore since we switched to Sphinx. Replace them in the example with SRST and ERST, too. Message-Id: <20220506150146.564244-1-thuth@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Thomas Huth --- docs/devel/writing-monitor-commands.rst | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/docs/devel/writing-monitor-commands.rst b/docs/devel/writing-monitor-commands.rst index 1693822f8f..4aa2bb904d 100644 --- a/docs/devel/writing-monitor-commands.rst +++ b/docs/devel/writing-monitor-commands.rst @@ -331,13 +331,10 @@ we should add it to the hmp-commands.hx file:: .cmd = hmp_hello_world, }, -:: - - STEXI - @item hello_world @var{message} - @findex hello_world - Print message to the standard output - ETEXI + SRST + ``hello_world`` *message* + Print message to the standard output + ERST To test this you have to open a user monitor and issue the "hello-world" command. It might be instructive to check the command's documentation with From 7d5983e3c8c40b1d0668faba31d79905c4fadd7d Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Mon, 25 Apr 2022 09:57:21 +0200 Subject: [PATCH 186/935] Introduce event-loop-base abstract class Introduce the 'event-loop-base' abstract class, it'll hold the properties common to all event loops and provide the necessary hooks for their creation and maintenance. Then have iothread inherit from it. EventLoopBaseClass is defined as user creatable and provides a hook for its children to attach themselves to the user creatable class 'complete' function. It also provides an update_params() callback to propagate property changes onto its children. The new 'event-loop-base' class will live in the root directory. It is built on its own using the 'link_whole' option (there are no direct function dependencies between the class and its children, it all happens trough 'constructor' magic). And also imposes new compilation dependencies: qom <- event-loop-base <- blockdev (iothread.c) And in subsequent patches: qom <- event-loop-base <- qemuutil (util/main-loop.c) All this forced some amount of reordering in meson.build: - Moved qom build definition before qemuutil. Doing it the other way around (i.e. moving qemuutil after qom) isn't possible as a lot of core libraries that live in between the two depend on it. - Process the 'hw' subdir earlier, as it introduces files into the 'qom' source set. No functional changes intended. Signed-off-by: Nicolas Saenz Julienne Reviewed-by: Stefan Hajnoczi Acked-by: Markus Armbruster Message-id: 20220425075723.20019-2-nsaenzju@redhat.com Signed-off-by: Stefan Hajnoczi --- event-loop-base.c | 104 +++++++++++++++++++++++++++++++ include/sysemu/event-loop-base.h | 36 +++++++++++ include/sysemu/iothread.h | 6 +- iothread.c | 65 ++++++------------- meson.build | 23 ++++--- qapi/qom.json | 22 +++++-- 6 files changed, 192 insertions(+), 64 deletions(-) create mode 100644 event-loop-base.c create mode 100644 include/sysemu/event-loop-base.h diff --git a/event-loop-base.c b/event-loop-base.c new file mode 100644 index 0000000000..a924c73a7c --- /dev/null +++ b/event-loop-base.c @@ -0,0 +1,104 @@ +/* + * QEMU event-loop base + * + * Copyright (C) 2022 Red Hat Inc + * + * Authors: + * Stefan Hajnoczi + * Nicolas Saenz Julienne + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qom/object_interfaces.h" +#include "qapi/error.h" +#include "sysemu/event-loop-base.h" + +typedef struct { + const char *name; + ptrdiff_t offset; /* field's byte offset in EventLoopBase struct */ +} EventLoopBaseParamInfo; + +static EventLoopBaseParamInfo aio_max_batch_info = { + "aio-max-batch", offsetof(EventLoopBase, aio_max_batch), +}; + +static void event_loop_base_get_param(Object *obj, Visitor *v, + const char *name, void *opaque, Error **errp) +{ + EventLoopBase *event_loop_base = EVENT_LOOP_BASE(obj); + EventLoopBaseParamInfo *info = opaque; + int64_t *field = (void *)event_loop_base + info->offset; + + visit_type_int64(v, name, field, errp); +} + +static void event_loop_base_set_param(Object *obj, Visitor *v, + const char *name, void *opaque, Error **errp) +{ + EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(obj); + EventLoopBase *base = EVENT_LOOP_BASE(obj); + EventLoopBaseParamInfo *info = opaque; + int64_t *field = (void *)base + info->offset; + int64_t value; + + if (!visit_type_int64(v, name, &value, errp)) { + return; + } + + if (value < 0) { + error_setg(errp, "%s value must be in range [0, %" PRId64 "]", + info->name, INT64_MAX); + return; + } + + *field = value; + + if (bc->update_params) { + bc->update_params(base, errp); + } + + return; +} + +static void event_loop_base_complete(UserCreatable *uc, Error **errp) +{ + EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(uc); + EventLoopBase *base = EVENT_LOOP_BASE(uc); + + if (bc->init) { + bc->init(base, errp); + } +} + +static void event_loop_base_class_init(ObjectClass *klass, void *class_data) +{ + UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass); + ucc->complete = event_loop_base_complete; + + object_class_property_add(klass, "aio-max-batch", "int", + event_loop_base_get_param, + event_loop_base_set_param, + NULL, &aio_max_batch_info); +} + +static const TypeInfo event_loop_base_info = { + .name = TYPE_EVENT_LOOP_BASE, + .parent = TYPE_OBJECT, + .instance_size = sizeof(EventLoopBase), + .class_size = sizeof(EventLoopBaseClass), + .class_init = event_loop_base_class_init, + .abstract = true, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static void register_types(void) +{ + type_register_static(&event_loop_base_info); +} +type_init(register_types); diff --git a/include/sysemu/event-loop-base.h b/include/sysemu/event-loop-base.h new file mode 100644 index 0000000000..8e77d8b69f --- /dev/null +++ b/include/sysemu/event-loop-base.h @@ -0,0 +1,36 @@ +/* + * QEMU event-loop backend + * + * Copyright (C) 2022 Red Hat Inc + * + * Authors: + * Nicolas Saenz Julienne + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef QEMU_EVENT_LOOP_BASE_H +#define QEMU_EVENT_LOOP_BASE_H + +#include "qom/object.h" +#include "block/aio.h" +#include "qemu/typedefs.h" + +#define TYPE_EVENT_LOOP_BASE "event-loop-base" +OBJECT_DECLARE_TYPE(EventLoopBase, EventLoopBaseClass, + EVENT_LOOP_BASE) + +struct EventLoopBaseClass { + ObjectClass parent_class; + + void (*init)(EventLoopBase *base, Error **errp); + void (*update_params)(EventLoopBase *base, Error **errp); +}; + +struct EventLoopBase { + Object parent; + + /* AioContext AIO engine parameters */ + int64_t aio_max_batch; +}; +#endif diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h index 7f714bd136..8f8601d6ab 100644 --- a/include/sysemu/iothread.h +++ b/include/sysemu/iothread.h @@ -17,11 +17,12 @@ #include "block/aio.h" #include "qemu/thread.h" #include "qom/object.h" +#include "sysemu/event-loop-base.h" #define TYPE_IOTHREAD "iothread" struct IOThread { - Object parent_obj; + EventLoopBase parent_obj; QemuThread thread; AioContext *ctx; @@ -37,9 +38,6 @@ struct IOThread { int64_t poll_max_ns; int64_t poll_grow; int64_t poll_shrink; - - /* AioContext AIO engine parameters */ - int64_t aio_max_batch; }; typedef struct IOThread IOThread; diff --git a/iothread.c b/iothread.c index 0f98af0f2a..8fa2f3bfb8 100644 --- a/iothread.c +++ b/iothread.c @@ -17,6 +17,7 @@ #include "qemu/module.h" #include "block/aio.h" #include "block/block.h" +#include "sysemu/event-loop-base.h" #include "sysemu/iothread.h" #include "qapi/error.h" #include "qapi/qapi-commands-misc.h" @@ -152,10 +153,15 @@ static void iothread_init_gcontext(IOThread *iothread) iothread->main_loop = g_main_loop_new(iothread->worker_context, TRUE); } -static void iothread_set_aio_context_params(IOThread *iothread, Error **errp) +static void iothread_set_aio_context_params(EventLoopBase *base, Error **errp) { + IOThread *iothread = IOTHREAD(base); ERRP_GUARD(); + if (!iothread->ctx) { + return; + } + aio_context_set_poll_params(iothread->ctx, iothread->poll_max_ns, iothread->poll_grow, @@ -166,14 +172,15 @@ static void iothread_set_aio_context_params(IOThread *iothread, Error **errp) } aio_context_set_aio_params(iothread->ctx, - iothread->aio_max_batch, + iothread->parent_obj.aio_max_batch, errp); } -static void iothread_complete(UserCreatable *obj, Error **errp) + +static void iothread_init(EventLoopBase *base, Error **errp) { Error *local_error = NULL; - IOThread *iothread = IOTHREAD(obj); + IOThread *iothread = IOTHREAD(base); char *thread_name; iothread->stopping = false; @@ -189,7 +196,7 @@ static void iothread_complete(UserCreatable *obj, Error **errp) */ iothread_init_gcontext(iothread); - iothread_set_aio_context_params(iothread, &local_error); + iothread_set_aio_context_params(base, &local_error); if (local_error) { error_propagate(errp, local_error); aio_context_unref(iothread->ctx); @@ -201,7 +208,7 @@ static void iothread_complete(UserCreatable *obj, Error **errp) * to inherit. */ thread_name = g_strdup_printf("IO %s", - object_get_canonical_path_component(OBJECT(obj))); + object_get_canonical_path_component(OBJECT(base))); qemu_thread_create(&iothread->thread, thread_name, iothread_run, iothread, QEMU_THREAD_JOINABLE); g_free(thread_name); @@ -226,9 +233,6 @@ static IOThreadParamInfo poll_grow_info = { static IOThreadParamInfo poll_shrink_info = { "poll-shrink", offsetof(IOThread, poll_shrink), }; -static IOThreadParamInfo aio_max_batch_info = { - "aio-max-batch", offsetof(IOThread, aio_max_batch), -}; static void iothread_get_param(Object *obj, Visitor *v, const char *name, IOThreadParamInfo *info, Error **errp) @@ -288,35 +292,12 @@ static void iothread_set_poll_param(Object *obj, Visitor *v, } } -static void iothread_get_aio_param(Object *obj, Visitor *v, - const char *name, void *opaque, Error **errp) -{ - IOThreadParamInfo *info = opaque; - - iothread_get_param(obj, v, name, info, errp); -} - -static void iothread_set_aio_param(Object *obj, Visitor *v, - const char *name, void *opaque, Error **errp) -{ - IOThread *iothread = IOTHREAD(obj); - IOThreadParamInfo *info = opaque; - - if (!iothread_set_param(obj, v, name, info, errp)) { - return; - } - - if (iothread->ctx) { - aio_context_set_aio_params(iothread->ctx, - iothread->aio_max_batch, - errp); - } -} - static void iothread_class_init(ObjectClass *klass, void *class_data) { - UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass); - ucc->complete = iothread_complete; + EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(klass); + + bc->init = iothread_init; + bc->update_params = iothread_set_aio_context_params; object_class_property_add(klass, "poll-max-ns", "int", iothread_get_poll_param, @@ -330,23 +311,15 @@ static void iothread_class_init(ObjectClass *klass, void *class_data) iothread_get_poll_param, iothread_set_poll_param, NULL, &poll_shrink_info); - object_class_property_add(klass, "aio-max-batch", "int", - iothread_get_aio_param, - iothread_set_aio_param, - NULL, &aio_max_batch_info); } static const TypeInfo iothread_info = { .name = TYPE_IOTHREAD, - .parent = TYPE_OBJECT, + .parent = TYPE_EVENT_LOOP_BASE, .class_init = iothread_class_init, .instance_size = sizeof(IOThread), .instance_init = iothread_instance_init, .instance_finalize = iothread_instance_finalize, - .interfaces = (InterfaceInfo[]) { - {TYPE_USER_CREATABLE}, - {} - }, }; static void iothread_register_types(void) @@ -383,7 +356,7 @@ static int query_one_iothread(Object *object, void *opaque) info->poll_max_ns = iothread->poll_max_ns; info->poll_grow = iothread->poll_grow; info->poll_shrink = iothread->poll_shrink; - info->aio_max_batch = iothread->aio_max_batch; + info->aio_max_batch = iothread->parent_obj.aio_max_batch; QAPI_LIST_APPEND(*tail, info); return 0; diff --git a/meson.build b/meson.build index fa672e57bc..85c151bf6c 100644 --- a/meson.build +++ b/meson.build @@ -3025,6 +3025,7 @@ subdir('qom') subdir('authz') subdir('crypto') subdir('ui') +subdir('hw') if enable_modules @@ -3032,6 +3033,18 @@ if enable_modules modulecommon = declare_dependency(link_whole: libmodulecommon, compile_args: '-DBUILD_DSO') endif +qom_ss = qom_ss.apply(config_host, strict: false) +libqom = static_library('qom', qom_ss.sources() + genh, + dependencies: [qom_ss.dependencies()], + name_suffix: 'fa') +qom = declare_dependency(link_whole: libqom) + +event_loop_base = files('event-loop-base.c') +event_loop_base = static_library('event-loop-base', sources: event_loop_base + genh, + build_by_default: true) +event_loop_base = declare_dependency(link_whole: event_loop_base, + dependencies: [qom]) + stub_ss = stub_ss.apply(config_all, strict: false) util_ss.add_all(trace_ss) @@ -3118,7 +3131,6 @@ subdir('monitor') subdir('net') subdir('replay') subdir('semihosting') -subdir('hw') subdir('tcg') subdir('fpu') subdir('accel') @@ -3243,13 +3255,6 @@ qemu_syms = custom_target('qemu.syms', output: 'qemu.syms', capture: true, command: [undefsym, nm, '@INPUT@']) -qom_ss = qom_ss.apply(config_host, strict: false) -libqom = static_library('qom', qom_ss.sources() + genh, - dependencies: [qom_ss.dependencies()], - name_suffix: 'fa') - -qom = declare_dependency(link_whole: libqom) - authz_ss = authz_ss.apply(config_host, strict: false) libauthz = static_library('authz', authz_ss.sources() + genh, dependencies: [authz_ss.dependencies()], @@ -3302,7 +3307,7 @@ libblockdev = static_library('blockdev', blockdev_ss.sources() + genh, build_by_default: false) blockdev = declare_dependency(link_whole: [libblockdev], - dependencies: [block]) + dependencies: [block, event_loop_base]) qmp_ss = qmp_ss.apply(config_host, strict: false) libqmp = static_library('qmp', qmp_ss.sources() + genh, diff --git a/qapi/qom.json b/qapi/qom.json index eeb5395ff3..a2439533c5 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -499,6 +499,20 @@ '*repeat': 'bool', '*grab-toggle': 'GrabToggleKeys' } } +## +# @EventLoopBaseProperties: +# +# Common properties for event loops +# +# @aio-max-batch: maximum number of requests in a batch for the AIO engine, +# 0 means that the engine will use its default. +# (default: 0) +# +# Since: 7.1 +## +{ 'struct': 'EventLoopBaseProperties', + 'data': { '*aio-max-batch': 'int' } } + ## # @IothreadProperties: # @@ -516,17 +530,15 @@ # algorithm detects it is spending too long polling without # encountering events. 0 selects a default behaviour (default: 0) # -# @aio-max-batch: maximum number of requests in a batch for the AIO engine, -# 0 means that the engine will use its default -# (default:0, since 6.1) +# The @aio-max-batch option is available since 6.1. # # Since: 2.0 ## { 'struct': 'IothreadProperties', + 'base': 'EventLoopBaseProperties', 'data': { '*poll-max-ns': 'int', '*poll-grow': 'int', - '*poll-shrink': 'int', - '*aio-max-batch': 'int' } } + '*poll-shrink': 'int' } } ## # @MemoryBackendProperties: From 70ac26b9e5ca8374bb3ef3f30b871726673c9f27 Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Mon, 25 Apr 2022 09:57:22 +0200 Subject: [PATCH 187/935] util/main-loop: Introduce the main loop into QOM 'event-loop-base' provides basic property handling for all 'AioContext' based event loops. So let's define a new 'MainLoopClass' that inherits from it. This will permit tweaking the main loop's properties through qapi as well as through the command line using the '-object' keyword[1]. Only one instance of 'MainLoopClass' might be created at any time. 'EventLoopBaseClass' learns a new callback, 'can_be_deleted()' so as to mark 'MainLoop' as non-deletable. [1] For example: -object main-loop,id=main-loop,aio-max-batch= Signed-off-by: Nicolas Saenz Julienne Reviewed-by: Stefan Hajnoczi Acked-by: Markus Armbruster Message-id: 20220425075723.20019-3-nsaenzju@redhat.com Signed-off-by: Stefan Hajnoczi --- event-loop-base.c | 13 ++++++++ include/qemu/main-loop.h | 10 ++++++ include/sysemu/event-loop-base.h | 1 + meson.build | 3 +- qapi/qom.json | 13 ++++++++ util/main-loop.c | 56 ++++++++++++++++++++++++++++++++ 6 files changed, 95 insertions(+), 1 deletion(-) diff --git a/event-loop-base.c b/event-loop-base.c index a924c73a7c..e7f99a6ec8 100644 --- a/event-loop-base.c +++ b/event-loop-base.c @@ -73,10 +73,23 @@ static void event_loop_base_complete(UserCreatable *uc, Error **errp) } } +static bool event_loop_base_can_be_deleted(UserCreatable *uc) +{ + EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(uc); + EventLoopBase *backend = EVENT_LOOP_BASE(uc); + + if (bc->can_be_deleted) { + return bc->can_be_deleted(backend); + } + + return true; +} + static void event_loop_base_class_init(ObjectClass *klass, void *class_data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass); ucc->complete = event_loop_base_complete; + ucc->can_be_deleted = event_loop_base_can_be_deleted; object_class_property_add(klass, "aio-max-batch", "int", event_loop_base_get_param, diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h index 89bd9edefb..5518845299 100644 --- a/include/qemu/main-loop.h +++ b/include/qemu/main-loop.h @@ -26,9 +26,19 @@ #define QEMU_MAIN_LOOP_H #include "block/aio.h" +#include "qom/object.h" +#include "sysemu/event-loop-base.h" #define SIG_IPI SIGUSR1 +#define TYPE_MAIN_LOOP "main-loop" +OBJECT_DECLARE_TYPE(MainLoop, MainLoopClass, MAIN_LOOP) + +struct MainLoop { + EventLoopBase parent_obj; +}; +typedef struct MainLoop MainLoop; + /** * qemu_init_main_loop: Set up the process so that it can run the main loop. * diff --git a/include/sysemu/event-loop-base.h b/include/sysemu/event-loop-base.h index 8e77d8b69f..fced4c9fea 100644 --- a/include/sysemu/event-loop-base.h +++ b/include/sysemu/event-loop-base.h @@ -25,6 +25,7 @@ struct EventLoopBaseClass { void (*init)(EventLoopBase *base, Error **errp); void (*update_params)(EventLoopBase *base, Error **errp); + bool (*can_be_deleted)(EventLoopBase *base); }; struct EventLoopBase { diff --git a/meson.build b/meson.build index 85c151bf6c..864e97945f 100644 --- a/meson.build +++ b/meson.build @@ -3053,7 +3053,8 @@ libqemuutil = static_library('qemuutil', sources: util_ss.sources() + stub_ss.sources() + genh, dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc, pixman]) qemuutil = declare_dependency(link_with: libqemuutil, - sources: genh + version_res) + sources: genh + version_res, + dependencies: [event_loop_base]) if have_system or have_user decodetree = generator(find_program('scripts/decodetree.py'), diff --git a/qapi/qom.json b/qapi/qom.json index a2439533c5..7d4a2ac1b9 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -540,6 +540,17 @@ '*poll-grow': 'int', '*poll-shrink': 'int' } } +## +# @MainLoopProperties: +# +# Properties for the main-loop object. +# +# Since: 7.1 +## +{ 'struct': 'MainLoopProperties', + 'base': 'EventLoopBaseProperties', + 'data': {} } + ## # @MemoryBackendProperties: # @@ -830,6 +841,7 @@ { 'name': 'input-linux', 'if': 'CONFIG_LINUX' }, 'iothread', + 'main-loop', { 'name': 'memory-backend-epc', 'if': 'CONFIG_LINUX' }, 'memory-backend-file', @@ -895,6 +907,7 @@ 'input-linux': { 'type': 'InputLinuxProperties', 'if': 'CONFIG_LINUX' }, 'iothread': 'IothreadProperties', + 'main-loop': 'MainLoopProperties', 'memory-backend-epc': { 'type': 'MemoryBackendEpcProperties', 'if': 'CONFIG_LINUX' }, 'memory-backend-file': 'MemoryBackendFileProperties', diff --git a/util/main-loop.c b/util/main-loop.c index 9afac10dff..e30f034815 100644 --- a/util/main-loop.c +++ b/util/main-loop.c @@ -33,6 +33,7 @@ #include "qemu/error-report.h" #include "qemu/queue.h" #include "qemu/compiler.h" +#include "qom/object.h" #ifndef _WIN32 #include @@ -184,6 +185,61 @@ int qemu_init_main_loop(Error **errp) return 0; } +static void main_loop_update_params(EventLoopBase *base, Error **errp) +{ + if (!qemu_aio_context) { + error_setg(errp, "qemu aio context not ready"); + return; + } + + aio_context_set_aio_params(qemu_aio_context, base->aio_max_batch, errp); +} + +MainLoop *mloop; + +static void main_loop_init(EventLoopBase *base, Error **errp) +{ + MainLoop *m = MAIN_LOOP(base); + + if (mloop) { + error_setg(errp, "only one main-loop instance allowed"); + return; + } + + main_loop_update_params(base, errp); + + mloop = m; + return; +} + +static bool main_loop_can_be_deleted(EventLoopBase *base) +{ + return false; +} + +static void main_loop_class_init(ObjectClass *oc, void *class_data) +{ + EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(oc); + + bc->init = main_loop_init; + bc->update_params = main_loop_update_params; + bc->can_be_deleted = main_loop_can_be_deleted; +} + +static const TypeInfo main_loop_info = { + .name = TYPE_MAIN_LOOP, + .parent = TYPE_EVENT_LOOP_BASE, + .class_init = main_loop_class_init, + .instance_size = sizeof(MainLoop), +}; + +static void main_loop_register_types(void) +{ + type_register_static(&main_loop_info); +} + +type_init(main_loop_register_types) + static int max_priority; #ifndef _WIN32 From 71ad4713cc1d7fca24388b828ef31ae6cb38a31c Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Mon, 25 Apr 2022 09:57:23 +0200 Subject: [PATCH 188/935] util/event-loop-base: Introduce options to set the thread pool size The thread pool regulates itself: when idle, it kills threads until empty, when in demand, it creates new threads until full. This behaviour doesn't play well with latency sensitive workloads where the price of creating a new thread is too high. For example, when paired with qemu's '-mlock', or using safety features like SafeStack, creating a new thread has been measured take multiple milliseconds. In order to mitigate this let's introduce a new 'EventLoopBase' property to set the thread pool size. The threads will be created during the pool's initialization or upon updating the property's value, remain available during its lifetime regardless of demand, and destroyed upon freeing it. A properly characterized workload will then be able to configure the pool to avoid any latency spikes. Signed-off-by: Nicolas Saenz Julienne Reviewed-by: Stefan Hajnoczi Acked-by: Markus Armbruster Message-id: 20220425075723.20019-4-nsaenzju@redhat.com Signed-off-by: Stefan Hajnoczi --- event-loop-base.c | 23 +++++++++++++ include/block/aio.h | 10 ++++++ include/block/thread-pool.h | 3 ++ include/sysemu/event-loop-base.h | 4 +++ iothread.c | 3 ++ qapi/qom.json | 10 +++++- util/aio-posix.c | 1 + util/async.c | 20 ++++++++++++ util/main-loop.c | 9 ++++++ util/thread-pool.c | 55 +++++++++++++++++++++++++++++--- 10 files changed, 133 insertions(+), 5 deletions(-) diff --git a/event-loop-base.c b/event-loop-base.c index e7f99a6ec8..d5be4dc6fc 100644 --- a/event-loop-base.c +++ b/event-loop-base.c @@ -14,6 +14,7 @@ #include "qemu/osdep.h" #include "qom/object_interfaces.h" #include "qapi/error.h" +#include "block/thread-pool.h" #include "sysemu/event-loop-base.h" typedef struct { @@ -21,9 +22,22 @@ typedef struct { ptrdiff_t offset; /* field's byte offset in EventLoopBase struct */ } EventLoopBaseParamInfo; +static void event_loop_base_instance_init(Object *obj) +{ + EventLoopBase *base = EVENT_LOOP_BASE(obj); + + base->thread_pool_max = THREAD_POOL_MAX_THREADS_DEFAULT; +} + static EventLoopBaseParamInfo aio_max_batch_info = { "aio-max-batch", offsetof(EventLoopBase, aio_max_batch), }; +static EventLoopBaseParamInfo thread_pool_min_info = { + "thread-pool-min", offsetof(EventLoopBase, thread_pool_min), +}; +static EventLoopBaseParamInfo thread_pool_max_info = { + "thread-pool-max", offsetof(EventLoopBase, thread_pool_max), +}; static void event_loop_base_get_param(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) @@ -95,12 +109,21 @@ static void event_loop_base_class_init(ObjectClass *klass, void *class_data) event_loop_base_get_param, event_loop_base_set_param, NULL, &aio_max_batch_info); + object_class_property_add(klass, "thread-pool-min", "int", + event_loop_base_get_param, + event_loop_base_set_param, + NULL, &thread_pool_min_info); + object_class_property_add(klass, "thread-pool-max", "int", + event_loop_base_get_param, + event_loop_base_set_param, + NULL, &thread_pool_max_info); } static const TypeInfo event_loop_base_info = { .name = TYPE_EVENT_LOOP_BASE, .parent = TYPE_OBJECT, .instance_size = sizeof(EventLoopBase), + .instance_init = event_loop_base_instance_init, .class_size = sizeof(EventLoopBaseClass), .class_init = event_loop_base_class_init, .abstract = true, diff --git a/include/block/aio.h b/include/block/aio.h index 5634173b12..d128558f1d 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -192,6 +192,8 @@ struct AioContext { QSLIST_HEAD(, Coroutine) scheduled_coroutines; QEMUBH *co_schedule_bh; + int thread_pool_min; + int thread_pool_max; /* Thread pool for performing work and receiving completion callbacks. * Has its own locking. */ @@ -769,4 +771,12 @@ void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns, void aio_context_set_aio_params(AioContext *ctx, int64_t max_batch, Error **errp); +/** + * aio_context_set_thread_pool_params: + * @ctx: the aio context + * @min: min number of threads to have readily available in the thread pool + * @min: max number of threads the thread pool can contain + */ +void aio_context_set_thread_pool_params(AioContext *ctx, int64_t min, + int64_t max, Error **errp); #endif diff --git a/include/block/thread-pool.h b/include/block/thread-pool.h index 7dd7d730a0..2020bcc92d 100644 --- a/include/block/thread-pool.h +++ b/include/block/thread-pool.h @@ -20,6 +20,8 @@ #include "block/block.h" +#define THREAD_POOL_MAX_THREADS_DEFAULT 64 + typedef int ThreadPoolFunc(void *opaque); typedef struct ThreadPool ThreadPool; @@ -33,5 +35,6 @@ BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool, int coroutine_fn thread_pool_submit_co(ThreadPool *pool, ThreadPoolFunc *func, void *arg); void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg); +void thread_pool_update_params(ThreadPool *pool, struct AioContext *ctx); #endif diff --git a/include/sysemu/event-loop-base.h b/include/sysemu/event-loop-base.h index fced4c9fea..2748bf6ae1 100644 --- a/include/sysemu/event-loop-base.h +++ b/include/sysemu/event-loop-base.h @@ -33,5 +33,9 @@ struct EventLoopBase { /* AioContext AIO engine parameters */ int64_t aio_max_batch; + + /* AioContext thread pool parameters */ + int64_t thread_pool_min; + int64_t thread_pool_max; }; #endif diff --git a/iothread.c b/iothread.c index 8fa2f3bfb8..529194a566 100644 --- a/iothread.c +++ b/iothread.c @@ -174,6 +174,9 @@ static void iothread_set_aio_context_params(EventLoopBase *base, Error **errp) aio_context_set_aio_params(iothread->ctx, iothread->parent_obj.aio_max_batch, errp); + + aio_context_set_thread_pool_params(iothread->ctx, base->thread_pool_min, + base->thread_pool_max, errp); } diff --git a/qapi/qom.json b/qapi/qom.json index 7d4a2ac1b9..6a653c6636 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -508,10 +508,18 @@ # 0 means that the engine will use its default. # (default: 0) # +# @thread-pool-min: minimum number of threads reserved in the thread pool +# (default:0) +# +# @thread-pool-max: maximum number of threads the thread pool can contain +# (default:64) +# # Since: 7.1 ## { 'struct': 'EventLoopBaseProperties', - 'data': { '*aio-max-batch': 'int' } } + 'data': { '*aio-max-batch': 'int', + '*thread-pool-min': 'int', + '*thread-pool-max': 'int' } } ## # @IothreadProperties: diff --git a/util/aio-posix.c b/util/aio-posix.c index be0182a3c6..731f3826c0 100644 --- a/util/aio-posix.c +++ b/util/aio-posix.c @@ -15,6 +15,7 @@ #include "qemu/osdep.h" #include "block/block.h" +#include "block/thread-pool.h" #include "qemu/main-loop.h" #include "qemu/rcu.h" #include "qemu/rcu_queue.h" diff --git a/util/async.c b/util/async.c index 2ea1172f3e..554ba70cca 100644 --- a/util/async.c +++ b/util/async.c @@ -563,6 +563,9 @@ AioContext *aio_context_new(Error **errp) ctx->aio_max_batch = 0; + ctx->thread_pool_min = 0; + ctx->thread_pool_max = THREAD_POOL_MAX_THREADS_DEFAULT; + return ctx; fail: g_source_destroy(&ctx->source); @@ -696,3 +699,20 @@ void qemu_set_current_aio_context(AioContext *ctx) assert(!get_my_aiocontext()); set_my_aiocontext(ctx); } + +void aio_context_set_thread_pool_params(AioContext *ctx, int64_t min, + int64_t max, Error **errp) +{ + + if (min > max || !max || min > INT_MAX || max > INT_MAX) { + error_setg(errp, "bad thread-pool-min/thread-pool-max values"); + return; + } + + ctx->thread_pool_min = min; + ctx->thread_pool_max = max; + + if (ctx->thread_pool) { + thread_pool_update_params(ctx->thread_pool, ctx); + } +} diff --git a/util/main-loop.c b/util/main-loop.c index e30f034815..f00a25451b 100644 --- a/util/main-loop.c +++ b/util/main-loop.c @@ -30,6 +30,7 @@ #include "sysemu/replay.h" #include "qemu/main-loop.h" #include "block/aio.h" +#include "block/thread-pool.h" #include "qemu/error-report.h" #include "qemu/queue.h" #include "qemu/compiler.h" @@ -187,12 +188,20 @@ int qemu_init_main_loop(Error **errp) static void main_loop_update_params(EventLoopBase *base, Error **errp) { + ERRP_GUARD(); + if (!qemu_aio_context) { error_setg(errp, "qemu aio context not ready"); return; } aio_context_set_aio_params(qemu_aio_context, base->aio_max_batch, errp); + if (*errp) { + return; + } + + aio_context_set_thread_pool_params(qemu_aio_context, base->thread_pool_min, + base->thread_pool_max, errp); } MainLoop *mloop; diff --git a/util/thread-pool.c b/util/thread-pool.c index d763cea505..196835b4d3 100644 --- a/util/thread-pool.c +++ b/util/thread-pool.c @@ -58,7 +58,6 @@ struct ThreadPool { QemuMutex lock; QemuCond worker_stopped; QemuSemaphore sem; - int max_threads; QEMUBH *new_thread_bh; /* The following variables are only accessed from one AioContext. */ @@ -71,8 +70,27 @@ struct ThreadPool { int new_threads; /* backlog of threads we need to create */ int pending_threads; /* threads created but not running yet */ bool stopping; + int min_threads; + int max_threads; }; +static inline bool back_to_sleep(ThreadPool *pool, int ret) +{ + /* + * The semaphore timed out, we should exit the loop except when: + * - There is work to do, we raced with the signal. + * - The max threads threshold just changed, we raced with the signal. + * - The thread pool forces a minimum number of readily available threads. + */ + if (ret == -1 && (!QTAILQ_EMPTY(&pool->request_list) || + pool->cur_threads > pool->max_threads || + pool->cur_threads <= pool->min_threads)) { + return true; + } + + return false; +} + static void *worker_thread(void *opaque) { ThreadPool *pool = opaque; @@ -91,8 +109,9 @@ static void *worker_thread(void *opaque) ret = qemu_sem_timedwait(&pool->sem, 10000); qemu_mutex_lock(&pool->lock); pool->idle_threads--; - } while (ret == -1 && !QTAILQ_EMPTY(&pool->request_list)); - if (ret == -1 || pool->stopping) { + } while (back_to_sleep(pool, ret)); + if (ret == -1 || pool->stopping || + pool->cur_threads > pool->max_threads) { break; } @@ -294,6 +313,33 @@ void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg) thread_pool_submit_aio(pool, func, arg, NULL, NULL); } +void thread_pool_update_params(ThreadPool *pool, AioContext *ctx) +{ + qemu_mutex_lock(&pool->lock); + + pool->min_threads = ctx->thread_pool_min; + pool->max_threads = ctx->thread_pool_max; + + /* + * We either have to: + * - Increase the number available of threads until over the min_threads + * threshold. + * - Decrease the number of available threads until under the max_threads + * threshold. + * - Do nothing. The current number of threads fall in between the min and + * max thresholds. We'll let the pool manage itself. + */ + for (int i = pool->cur_threads; i < pool->min_threads; i++) { + spawn_thread(pool); + } + + for (int i = pool->cur_threads; i > pool->max_threads; i--) { + qemu_sem_post(&pool->sem); + } + + qemu_mutex_unlock(&pool->lock); +} + static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx) { if (!ctx) { @@ -306,11 +352,12 @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx) qemu_mutex_init(&pool->lock); qemu_cond_init(&pool->worker_stopped); qemu_sem_init(&pool->sem, 0); - pool->max_threads = 64; pool->new_thread_bh = aio_bh_new(ctx, spawn_thread_bh_fn, pool); QLIST_INIT(&pool->head); QTAILQ_INIT(&pool->request_list); + + thread_pool_update_params(pool, ctx); } ThreadPool *thread_pool_new(AioContext *ctx) From 2f743ef6366c2df4ef51ef3ae318138cdc0125ab Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 27 Apr 2022 15:35:36 +0100 Subject: [PATCH 189/935] virtio-scsi: fix ctrl and event handler functions in dataplane mode Commit f34e8d8b8d48d73f36a67b6d5e492ef9784b5012 ("virtio-scsi: prepare virtio_scsi_handle_cmd for dataplane") prepared the virtio-scsi cmd virtqueue handler function to be used in both the dataplane and non-datpalane code paths. It failed to convert the ctrl and event virtqueue handler functions, which are not designed to be called from the dataplane code path but will be since the ioeventfd is set up for those virtqueues when dataplane starts. Convert the ctrl and event virtqueue handler functions now so they operate correctly when called from the dataplane code path. Avoid code duplication by extracting this code into a helper function. Fixes: f34e8d8b8d48d73f36a67b6d5e492ef9784b5012 ("virtio-scsi: prepare virtio_scsi_handle_cmd for dataplane") Signed-off-by: Stefan Hajnoczi Reviewed-by: Paolo Bonzini Message-id: 20220427143541.119567-2-stefanha@redhat.com [Fixed s/by used/be used/ typo pointed out by Michael Tokarev . --Stefan] Signed-off-by: Stefan Hajnoczi --- hw/scsi/virtio-scsi.c | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 34a968ecfb..417fbc71d6 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -472,16 +472,32 @@ bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq) return progress; } +/* + * If dataplane is configured but not yet started, do so now and return true on + * success. + * + * Dataplane is started by the core virtio code but virtqueue handler functions + * can also be invoked when a guest kicks before DRIVER_OK, so this helper + * function helps us deal with manually starting ioeventfd in that case. + */ +static bool virtio_scsi_defer_to_dataplane(VirtIOSCSI *s) +{ + if (!s->ctx || s->dataplane_started) { + return false; + } + + virtio_device_start_ioeventfd(&s->parent_obj.parent_obj); + return !s->dataplane_fenced; +} + static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) { VirtIOSCSI *s = (VirtIOSCSI *)vdev; - if (s->ctx) { - virtio_device_start_ioeventfd(vdev); - if (!s->dataplane_fenced) { - return; - } + if (virtio_scsi_defer_to_dataplane(s)) { + return; } + virtio_scsi_acquire(s); virtio_scsi_handle_ctrl_vq(s, vq); virtio_scsi_release(s); @@ -720,12 +736,10 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) /* use non-QOM casts in the data path */ VirtIOSCSI *s = (VirtIOSCSI *)vdev; - if (s->ctx && !s->dataplane_started) { - virtio_device_start_ioeventfd(vdev); - if (!s->dataplane_fenced) { - return; - } + if (virtio_scsi_defer_to_dataplane(s)) { + return; } + virtio_scsi_acquire(s); virtio_scsi_handle_cmd_vq(s, vq); virtio_scsi_release(s); @@ -855,12 +869,10 @@ static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq) { VirtIOSCSI *s = VIRTIO_SCSI(vdev); - if (s->ctx) { - virtio_device_start_ioeventfd(vdev); - if (!s->dataplane_fenced) { - return; - } + if (virtio_scsi_defer_to_dataplane(s)) { + return; } + virtio_scsi_acquire(s); virtio_scsi_handle_event_vq(s, vq); virtio_scsi_release(s); From 38738f7dbbda90fbc161757b7f4be35b52205552 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 27 Apr 2022 15:35:37 +0100 Subject: [PATCH 190/935] virtio-scsi: don't waste CPU polling the event virtqueue The virtio-scsi event virtqueue is not emptied by its handler function. This is typical for rx virtqueues where the device uses buffers when some event occurs (e.g. a packet is received, an error condition happens, etc). Polling non-empty virtqueues wastes CPU cycles. We are not waiting for new buffers to become available, we are waiting for an event to occur, so it's a misuse of CPU resources to poll for buffers. Introduce the new virtio_queue_aio_attach_host_notifier_no_poll() API, which is identical to virtio_queue_aio_attach_host_notifier() except that it does not poll the virtqueue. Before this patch the following command-line consumed 100% CPU in the IOThread polling and calling virtio_scsi_handle_event(): $ qemu-system-x86_64 -M accel=kvm -m 1G -cpu host \ --object iothread,id=iothread0 \ --device virtio-scsi-pci,iothread=iothread0 \ --blockdev file,filename=test.img,aio=native,cache.direct=on,node-name=drive0 \ --device scsi-hd,drive=drive0 After this patch CPU is no longer wasted. Reported-by: Nir Soffer Signed-off-by: Stefan Hajnoczi Tested-by: Nir Soffer Message-id: 20220427143541.119567-3-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/scsi/virtio-scsi-dataplane.c | 2 +- hw/virtio/virtio.c | 13 +++++++++++++ include/hw/virtio/virtio.h | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index 29575cbaf6..8bb6e6acfc 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -138,7 +138,7 @@ int virtio_scsi_dataplane_start(VirtIODevice *vdev) aio_context_acquire(s->ctx); virtio_queue_aio_attach_host_notifier(vs->ctrl_vq, s->ctx); - virtio_queue_aio_attach_host_notifier(vs->event_vq, s->ctx); + virtio_queue_aio_attach_host_notifier_no_poll(vs->event_vq, s->ctx); for (i = 0; i < vs->conf.num_queues; i++) { virtio_queue_aio_attach_host_notifier(vs->cmd_vqs[i], s->ctx); diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 9d637e043e..67a873f54a 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -3534,6 +3534,19 @@ void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx) virtio_queue_host_notifier_aio_poll_end); } +/* + * Same as virtio_queue_aio_attach_host_notifier() but without polling. Use + * this for rx virtqueues and similar cases where the virtqueue handler + * function does not pop all elements. When the virtqueue is left non-empty + * polling consumes CPU cycles and should not be used. + */ +void virtio_queue_aio_attach_host_notifier_no_poll(VirtQueue *vq, AioContext *ctx) +{ + aio_set_event_notifier(ctx, &vq->host_notifier, true, + virtio_queue_host_notifier_read, + NULL, NULL); +} + void virtio_queue_aio_detach_host_notifier(VirtQueue *vq, AioContext *ctx) { aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL, NULL, NULL); diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index b31c4507f5..b62a35fdca 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -317,6 +317,7 @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq); void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled); void virtio_queue_host_notifier_read(EventNotifier *n); void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx); +void virtio_queue_aio_attach_host_notifier_no_poll(VirtQueue *vq, AioContext *ctx); void virtio_queue_aio_detach_host_notifier(VirtQueue *vq, AioContext *ctx); VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector); VirtQueue *virtio_vector_next_queue(VirtQueue *vq); From 37ce2de95169dacab3fb53d11bd4509b9c2e3a4c Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 27 Apr 2022 15:35:38 +0100 Subject: [PATCH 191/935] virtio-scsi: clean up virtio_scsi_handle_event_vq() virtio_scsi_handle_event_vq() is only called from hw/scsi/virtio-scsi.c now and its return value is no longer used. Remove the function prototype from virtio-scsi.h and drop the return value. Signed-off-by: Stefan Hajnoczi Reviewed-by: Paolo Bonzini Message-id: 20220427143541.119567-4-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/scsi/virtio-scsi.c | 4 +--- include/hw/virtio/virtio-scsi.h | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 417fbc71d6..aa03a713d8 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -856,13 +856,11 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, virtio_scsi_complete_req(req); } -bool virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq) +static void virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq) { if (s->events_dropped) { virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0); - return true; } - return false; } static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq) diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 0997313f0a..85e69d0368 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -149,7 +149,6 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp); void virtio_scsi_common_unrealize(DeviceState *dev); -bool virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq); bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq); bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq); void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req); From 73b3b49f1880f236b4d0ffd7efb00280c05a5fab Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 27 Apr 2022 15:35:39 +0100 Subject: [PATCH 192/935] virtio-scsi: clean up virtio_scsi_handle_ctrl_vq() virtio_scsi_handle_ctrl_vq() is only called from hw/scsi/virtio-scsi.c now and its return value is no longer used. Remove the function prototype from virtio-scsi.h and drop the return value. Signed-off-by: Stefan Hajnoczi Reviewed-by: Paolo Bonzini Message-id: 20220427143541.119567-5-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/scsi/virtio-scsi.c | 5 +---- include/hw/virtio/virtio-scsi.h | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index aa03a713d8..eefda16e4b 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -460,16 +460,13 @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) } } -bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq) +static void virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq) { VirtIOSCSIReq *req; - bool progress = false; while ((req = virtio_scsi_pop_req(s, vq))) { - progress = true; virtio_scsi_handle_ctrl_req(s, req); } - return progress; } /* diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 85e69d0368..ac99800ee2 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -150,7 +150,6 @@ void virtio_scsi_common_realize(DeviceState *dev, void virtio_scsi_common_unrealize(DeviceState *dev); bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq); -bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq); void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req); void virtio_scsi_free_req(VirtIOSCSIReq *req); void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, From ad482b57ef841b2d4883c5079d20ba44ff5e4b3e Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 27 Apr 2022 15:35:40 +0100 Subject: [PATCH 193/935] virtio-scsi: clean up virtio_scsi_handle_cmd_vq() virtio_scsi_handle_cmd_vq() is only called from hw/scsi/virtio-scsi.c now and its return value is no longer used. Remove the function prototype from virtio-scsi.h and drop the return value. Signed-off-by: Stefan Hajnoczi Reviewed-by: Paolo Bonzini Message-id: 20220427143541.119567-6-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/scsi/virtio-scsi.c | 5 +---- include/hw/virtio/virtio-scsi.h | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index eefda16e4b..12c6a21202 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -685,12 +685,11 @@ static void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req) scsi_req_unref(sreq); } -bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq) +static void virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq) { VirtIOSCSIReq *req, *next; int ret = 0; bool suppress_notifications = virtio_queue_get_notification(vq); - bool progress = false; QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs); @@ -700,7 +699,6 @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq) } while ((req = virtio_scsi_pop_req(s, vq))) { - progress = true; ret = virtio_scsi_handle_cmd_req_prepare(s, req); if (!ret) { QTAILQ_INSERT_TAIL(&reqs, req, next); @@ -725,7 +723,6 @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq) QTAILQ_FOREACH_SAFE(req, &reqs, next, next) { virtio_scsi_handle_cmd_req_submit(s, req); } - return progress; } static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index ac99800ee2..2040352102 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -149,7 +149,6 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp); void virtio_scsi_common_unrealize(DeviceState *dev); -bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq); void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req); void virtio_scsi_free_req(VirtIOSCSIReq *req); void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, From 3dc584abeef0e1277c2de8c1c1974cb49444eb0a Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 27 Apr 2022 15:35:41 +0100 Subject: [PATCH 194/935] virtio-scsi: move request-related items from .h to .c There is no longer a need to expose the request and related APIs in virtio-scsi.h since there are no callers outside virtio-scsi.c. Note the block comment in VirtIOSCSIReq has been adjusted to meet the coding style. Signed-off-by: Stefan Hajnoczi Reviewed-by: Paolo Bonzini Message-id: 20220427143541.119567-7-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/scsi/virtio-scsi.c | 45 ++++++++++++++++++++++++++++++--- include/hw/virtio/virtio-scsi.h | 40 ----------------------------- 2 files changed, 41 insertions(+), 44 deletions(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 12c6a21202..db54d104be 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -29,6 +29,43 @@ #include "hw/virtio/virtio-access.h" #include "trace.h" +typedef struct VirtIOSCSIReq { + /* + * Note: + * - fields up to resp_iov are initialized by virtio_scsi_init_req; + * - fields starting at vring are zeroed by virtio_scsi_init_req. + */ + VirtQueueElement elem; + + VirtIOSCSI *dev; + VirtQueue *vq; + QEMUSGList qsgl; + QEMUIOVector resp_iov; + + union { + /* Used for two-stage request submission */ + QTAILQ_ENTRY(VirtIOSCSIReq) next; + + /* Used for cancellation of request during TMFs */ + int remaining; + }; + + SCSIRequest *sreq; + size_t resp_size; + enum SCSIXferMode mode; + union { + VirtIOSCSICmdResp cmd; + VirtIOSCSICtrlTMFResp tmf; + VirtIOSCSICtrlANResp an; + VirtIOSCSIEvent event; + } resp; + union { + VirtIOSCSICmdReq cmd; + VirtIOSCSICtrlTMFReq tmf; + VirtIOSCSICtrlANReq an; + } req; +} VirtIOSCSIReq; + static inline int virtio_scsi_get_lun(uint8_t *lun) { return ((lun[2] << 8) | lun[3]) & 0x3FFF; @@ -45,7 +82,7 @@ static inline SCSIDevice *virtio_scsi_device_get(VirtIOSCSI *s, uint8_t *lun) return scsi_device_get(&s->bus, 0, lun[1], virtio_scsi_get_lun(lun)); } -void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req) +static void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req) { VirtIODevice *vdev = VIRTIO_DEVICE(s); const size_t zero_skip = @@ -58,7 +95,7 @@ void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req) memset((uint8_t *)req + zero_skip, 0, sizeof(*req) - zero_skip); } -void virtio_scsi_free_req(VirtIOSCSIReq *req) +static void virtio_scsi_free_req(VirtIOSCSIReq *req) { qemu_iovec_destroy(&req->resp_iov); qemu_sglist_destroy(&req->qsgl); @@ -801,8 +838,8 @@ static void virtio_scsi_reset(VirtIODevice *vdev) s->events_dropped = false; } -void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, - uint32_t event, uint32_t reason) +static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, + uint32_t event, uint32_t reason) { VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); VirtIOSCSIReq *req; diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 2040352102..a36aad9c86 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -92,42 +92,6 @@ struct VirtIOSCSI { uint32_t host_features; }; -typedef struct VirtIOSCSIReq { - /* Note: - * - fields up to resp_iov are initialized by virtio_scsi_init_req; - * - fields starting at vring are zeroed by virtio_scsi_init_req. - * */ - VirtQueueElement elem; - - VirtIOSCSI *dev; - VirtQueue *vq; - QEMUSGList qsgl; - QEMUIOVector resp_iov; - - union { - /* Used for two-stage request submission */ - QTAILQ_ENTRY(VirtIOSCSIReq) next; - - /* Used for cancellation of request during TMFs */ - int remaining; - }; - - SCSIRequest *sreq; - size_t resp_size; - enum SCSIXferMode mode; - union { - VirtIOSCSICmdResp cmd; - VirtIOSCSICtrlTMFResp tmf; - VirtIOSCSICtrlANResp an; - VirtIOSCSIEvent event; - } resp; - union { - VirtIOSCSICmdReq cmd; - VirtIOSCSICtrlTMFReq tmf; - VirtIOSCSICtrlANReq an; - } req; -} VirtIOSCSIReq; - static inline void virtio_scsi_acquire(VirtIOSCSI *s) { if (s->ctx) { @@ -149,10 +113,6 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp); void virtio_scsi_common_unrealize(DeviceState *dev); -void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req); -void virtio_scsi_free_req(VirtIOSCSIReq *req); -void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, - uint32_t event, uint32_t reason); void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp); int virtio_scsi_dataplane_start(VirtIODevice *s); From 14d5addcaedae2e8666aeda71510e1d4be5bb50d Mon Sep 17 00:00:00 2001 From: Leif Lindholm Date: Thu, 5 May 2022 12:37:40 +0100 Subject: [PATCH 195/935] MAINTAINERS/.mailmap: update email for Leif Lindholm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NUVIA was acquired by Qualcomm in March 2021, but kept functioning on separate infrastructure for a transitional period. We've now switched over to contributing as Qualcomm Innovation Center (quicinc), so update my email address to reflect this. Signed-off-by: Leif Lindholm Message-id: 20220505113740.75565-1-quic_llindhol@quicinc.com Cc: Leif Lindholm Cc: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé [Fixed commit message typo] Signed-off-by: Peter Maydell --- .mailmap | 3 ++- MAINTAINERS | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.mailmap b/.mailmap index 2976a675ea..8c326709cf 100644 --- a/.mailmap +++ b/.mailmap @@ -62,7 +62,8 @@ Greg Kurz Huacai Chen Huacai Chen James Hogan -Leif Lindholm +Leif Lindholm +Leif Lindholm Radoslaw Biernacki Paul Burton Paul Burton diff --git a/MAINTAINERS b/MAINTAINERS index 662ec47246..42f67e2b93 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -889,7 +889,7 @@ F: include/hw/ssi/imx_spi.h SBSA-REF M: Radoslaw Biernacki M: Peter Maydell -R: Leif Lindholm +R: Leif Lindholm L: qemu-arm@nongnu.org S: Maintained F: hw/arm/sbsa-ref.c From 696ba3771894f7a0b233e634dc9d401330568e35 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:19 -0500 Subject: [PATCH 196/935] target/arm: Handle cpreg registration for missing EL More gracefully handle cpregs when EL2 and/or EL3 are missing. If the reg is entirely inaccessible, do not register it at all. If the reg is for EL2, and EL3 is present but EL2 is not, either discard, squash to res0, const, or keep unchanged. Per rule RJFFP, mark the 4 aarch32 hypervisor access registers with ARM_CP_EL3_NO_EL2_KEEP, and mark all of the EL2 address translation and tlb invalidation "regs" ARM_CP_EL3_NO_EL2_UNDEF. Mark the 2 virtualization processor id regs ARM_CP_EL3_NO_EL2_C_NZ. This will simplify cpreg registration for conditional arm features. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpregs.h | 11 +++ target/arm/helper.c | 178 ++++++++++++++++++++++++++++++-------------- 2 files changed, 133 insertions(+), 56 deletions(-) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 73984549d2..db03d6a7e1 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -102,6 +102,17 @@ enum { ARM_CP_SVE = 1 << 14, /* Flag: Do not expose in gdb sysreg xml. */ ARM_CP_NO_GDB = 1 << 15, + /* + * Flags: If EL3 but not EL2... + * - UNDEF: discard the cpreg, + * - KEEP: retain the cpreg as is, + * - C_NZ: set const on the cpreg, but retain resetvalue, + * - else: set const on the cpreg, zero resetvalue, aka RES0. + * See rule RJFFP in section D1.1.3 of DDI0487H.a. + */ + ARM_CP_EL3_NO_EL2_UNDEF = 1 << 16, + ARM_CP_EL3_NO_EL2_KEEP = 1 << 17, + ARM_CP_EL3_NO_EL2_C_NZ = 1 << 18, }; /* diff --git a/target/arm/helper.c b/target/arm/helper.c index b4daf4f076..9ab8b65e7b 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5056,16 +5056,17 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .access = PL1_RW, .readfn = spsel_read, .writefn = spsel_write }, { .name = "FPEXC32_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 3, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_ALIAS | ARM_CP_FPU, + .access = PL2_RW, + .type = ARM_CP_ALIAS | ARM_CP_FPU | ARM_CP_EL3_NO_EL2_KEEP, .fieldoffset = offsetof(CPUARMState, vfp.xregs[ARM_VFP_FPEXC]) }, { .name = "DACR32_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 3, .crm = 0, .opc2 = 0, - .access = PL2_RW, .resetvalue = 0, + .access = PL2_RW, .resetvalue = 0, .type = ARM_CP_EL3_NO_EL2_KEEP, .writefn = dacr_write, .raw_writefn = raw_write, .fieldoffset = offsetof(CPUARMState, cp15.dacr32_el2) }, { .name = "IFSR32_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 0, .opc2 = 1, - .access = PL2_RW, .resetvalue = 0, + .access = PL2_RW, .resetvalue = 0, .type = ARM_CP_EL3_NO_EL2_KEEP, .fieldoffset = offsetof(CPUARMState, cp15.ifsr32_el2) }, { .name = "SPSR_IRQ", .state = ARM_CP_STATE_AA64, .type = ARM_CP_ALIAS, @@ -5542,27 +5543,27 @@ static const ARMCPRegInfo el2_cp_reginfo[] = { .writefn = tlbimva_hyp_is_write }, { .name = "TLBI_ALLE2", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 0, - .type = ARM_CP_NO_RAW, .access = PL2_W, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_alle2_write }, { .name = "TLBI_VAE2", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 1, - .type = ARM_CP_NO_RAW, .access = PL2_W, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_vae2_write }, { .name = "TLBI_VALE2", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_vae2_write }, { .name = "TLBI_ALLE2IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 0, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_alle2is_write }, { .name = "TLBI_VAE2IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 1, - .type = ARM_CP_NO_RAW, .access = PL2_W, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_vae2is_write }, { .name = "TLBI_VALE2IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_vae2is_write }, #ifndef CONFIG_USER_ONLY /* Unlike the other EL2-related AT operations, these must @@ -5572,11 +5573,13 @@ static const ARMCPRegInfo el2_cp_reginfo[] = { { .name = "AT_S1E2R", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 0, .access = PL2_W, .accessfn = at_s1e2_access, - .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, .writefn = ats_write64 }, + .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC | ARM_CP_EL3_NO_EL2_UNDEF, + .writefn = ats_write64 }, { .name = "AT_S1E2W", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 1, .access = PL2_W, .accessfn = at_s1e2_access, - .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, .writefn = ats_write64 }, + .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC | ARM_CP_EL3_NO_EL2_UNDEF, + .writefn = ats_write64 }, /* The AArch32 ATS1H* operations are CONSTRAINED UNPREDICTABLE * if EL2 is not implemented; we choose to UNDEF. Behaviour at EL3 * with SCR.NS == 0 outside Monitor mode is UNPREDICTABLE; we choose @@ -6076,7 +6079,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { { .name = "DBGVCR32_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 2, .opc1 = 4, .crn = 0, .crm = 7, .opc2 = 0, .access = PL2_RW, .accessfn = access_tda, - .type = ARM_CP_NOP }, + .type = ARM_CP_NOP | ARM_CP_EL3_NO_EL2_KEEP }, /* Dummy MDCCINT_EL1, since we don't implement the Debug Communications * Channel but Linux may try to access this register. The 32-bit * alias is DBGDCCINT. @@ -6892,11 +6895,11 @@ static const ARMCPRegInfo tlbirange_reginfo[] = { .access = PL2_W, .type = ARM_CP_NOP }, { .name = "TLBI_RVAE2IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 2, .opc2 = 1, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_rvae2is_write }, { .name = "TLBI_RVALE2IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 2, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_rvae2is_write }, { .name = "TLBI_RIPAS2E1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 2, @@ -6906,19 +6909,19 @@ static const ARMCPRegInfo tlbirange_reginfo[] = { .access = PL2_W, .type = ARM_CP_NOP }, { .name = "TLBI_RVAE2OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 5, .opc2 = 1, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_rvae2is_write }, { .name = "TLBI_RVALE2OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 5, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_rvae2is_write }, { .name = "TLBI_RVAE2", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 6, .opc2 = 1, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_rvae2_write }, { .name = "TLBI_RVALE2", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 6, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_rvae2_write }, { .name = "TLBI_RVAE3IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 2, .opc2 = 1, @@ -6973,11 +6976,11 @@ static const ARMCPRegInfo tlbios_reginfo[] = { .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_ALLE2OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 0, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_alle2is_write }, { .name = "TLBI_VAE2OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 1, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_vae2is_write }, { .name = "TLBI_ALLE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 4, @@ -6985,7 +6988,7 @@ static const ARMCPRegInfo tlbios_reginfo[] = { .writefn = tlbi_aa64_alle1is_write }, { .name = "TLBI_VALE2OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF, .writefn = tlbi_aa64_vae2is_write }, { .name = "TLBI_VMALLS12E1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 6, @@ -7905,21 +7908,24 @@ void register_cp_regs_for_features(ARMCPU *cpu) { .name = "VPIDR", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 0, .access = PL2_RW, .accessfn = access_el3_aa32ns, - .resetvalue = cpu->midr, .type = ARM_CP_ALIAS, + .resetvalue = cpu->midr, + .type = ARM_CP_ALIAS | ARM_CP_EL3_NO_EL2_C_NZ, .fieldoffset = offsetoflow32(CPUARMState, cp15.vpidr_el2) }, { .name = "VPIDR_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 0, .access = PL2_RW, .resetvalue = cpu->midr, + .type = ARM_CP_EL3_NO_EL2_C_NZ, .fieldoffset = offsetof(CPUARMState, cp15.vpidr_el2) }, { .name = "VMPIDR", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5, .access = PL2_RW, .accessfn = access_el3_aa32ns, - .resetvalue = vmpidr_def, .type = ARM_CP_ALIAS, + .resetvalue = vmpidr_def, + .type = ARM_CP_ALIAS | ARM_CP_EL3_NO_EL2_C_NZ, .fieldoffset = offsetoflow32(CPUARMState, cp15.vmpidr_el2) }, { .name = "VMPIDR_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5, - .access = PL2_RW, - .resetvalue = vmpidr_def, + .access = PL2_RW, .resetvalue = vmpidr_def, + .type = ARM_CP_EL3_NO_EL2_C_NZ, .fieldoffset = offsetof(CPUARMState, cp15.vmpidr_el2) }, }; define_arm_cp_regs(cpu, vpidr_regs); @@ -8506,13 +8512,14 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, int crm, int opc1, int opc2, const char *name) { + CPUARMState *env = &cpu->env; uint32_t key; ARMCPRegInfo *r2; bool is64 = r->type & ARM_CP_64BIT; bool ns = secstate & ARM_CP_SECSTATE_NS; int cp = r->cp; - bool isbanked; size_t name_len; + bool make_const; switch (state) { case ARM_CP_STATE_AA32: @@ -8547,6 +8554,32 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, } } + /* + * Eliminate registers that are not present because the EL is missing. + * Doing this here makes it easier to put all registers for a given + * feature into the same ARMCPRegInfo array and define them all at once. + */ + make_const = false; + if (arm_feature(env, ARM_FEATURE_EL3)) { + /* + * An EL2 register without EL2 but with EL3 is (usually) RES0. + * See rule RJFFP in section D1.1.3 of DDI0487H.a. + */ + int min_el = ctz32(r->access) / 2; + if (min_el == 2 && !arm_feature(env, ARM_FEATURE_EL2)) { + if (r->type & ARM_CP_EL3_NO_EL2_UNDEF) { + return; + } + make_const = !(r->type & ARM_CP_EL3_NO_EL2_KEEP); + } + } else { + CPAccessRights max_el = (arm_feature(env, ARM_FEATURE_EL2) + ? PL2_RW : PL1_RW); + if ((r->access & max_el) == 0) { + return; + } + } + /* Combine cpreg and name into one allocation. */ name_len = strlen(name) + 1; r2 = g_malloc(sizeof(*r2) + name_len); @@ -8567,44 +8600,77 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, r2->opaque = opaque; } - isbanked = r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]; - if (isbanked) { + if (make_const) { + /* This should not have been a very special register to begin. */ + int old_special = r2->type & ARM_CP_SPECIAL_MASK; + assert(old_special == 0 || old_special == ARM_CP_NOP); /* - * Register is banked (using both entries in array). - * Overwriting fieldoffset as the array is only used to define - * banked registers but later only fieldoffset is used. + * Set the special function to CONST, retaining the other flags. + * This is important for e.g. ARM_CP_SVE so that we still + * take the SVE trap if CPTR_EL3.EZ == 0. */ - r2->fieldoffset = r->bank_fieldoffsets[ns]; - } + r2->type = (r2->type & ~ARM_CP_SPECIAL_MASK) | ARM_CP_CONST; + /* + * Usually, these registers become RES0, but there are a few + * special cases like VPIDR_EL2 which have a constant non-zero + * value with writes ignored. + */ + if (!(r->type & ARM_CP_EL3_NO_EL2_C_NZ)) { + r2->resetvalue = 0; + } + /* + * ARM_CP_CONST has precedence, so removing the callbacks and + * offsets are not strictly necessary, but it is potentially + * less confusing to debug later. + */ + r2->readfn = NULL; + r2->writefn = NULL; + r2->raw_readfn = NULL; + r2->raw_writefn = NULL; + r2->resetfn = NULL; + r2->fieldoffset = 0; + r2->bank_fieldoffsets[0] = 0; + r2->bank_fieldoffsets[1] = 0; + } else { + bool isbanked = r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]; - if (state == ARM_CP_STATE_AA32) { if (isbanked) { /* - * If the register is banked then we don't need to migrate or - * reset the 32-bit instance in certain cases: - * - * 1) If the register has both 32-bit and 64-bit instances then we - * can count on the 64-bit instance taking care of the - * non-secure bank. - * 2) If ARMv8 is enabled then we can count on a 64-bit version - * taking care of the secure bank. This requires that separate - * 32 and 64-bit definitions are provided. + * Register is banked (using both entries in array). + * Overwriting fieldoffset as the array is only used to define + * banked registers but later only fieldoffset is used. */ - if ((r->state == ARM_CP_STATE_BOTH && ns) || - (arm_feature(&cpu->env, ARM_FEATURE_V8) && !ns)) { + r2->fieldoffset = r->bank_fieldoffsets[ns]; + } + if (state == ARM_CP_STATE_AA32) { + if (isbanked) { + /* + * If the register is banked then we don't need to migrate or + * reset the 32-bit instance in certain cases: + * + * 1) If the register has both 32-bit and 64-bit instances + * then we can count on the 64-bit instance taking care + * of the non-secure bank. + * 2) If ARMv8 is enabled then we can count on a 64-bit + * version taking care of the secure bank. This requires + * that separate 32 and 64-bit definitions are provided. + */ + if ((r->state == ARM_CP_STATE_BOTH && ns) || + (arm_feature(env, ARM_FEATURE_V8) && !ns)) { + r2->type |= ARM_CP_ALIAS; + } + } else if ((secstate != r->secure) && !ns) { + /* + * The register is not banked so we only want to allow + * migration of the non-secure instance. + */ r2->type |= ARM_CP_ALIAS; } - } else if ((secstate != r->secure) && !ns) { - /* - * The register is not banked so we only want to allow migration - * of the non-secure instance. - */ - r2->type |= ARM_CP_ALIAS; - } - if (HOST_BIG_ENDIAN && - r->state == ARM_CP_STATE_BOTH && r2->fieldoffset) { - r2->fieldoffset += sizeof(uint32_t); + if (HOST_BIG_ENDIAN && + r->state == ARM_CP_STATE_BOTH && r2->fieldoffset) { + r2->fieldoffset += sizeof(uint32_t); + } } } @@ -8615,7 +8681,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, * multiple times. Special registers (ie NOP/WFI) are * never migratable and not even raw-accessible. */ - if (r->type & ARM_CP_SPECIAL_MASK) { + if (r2->type & ARM_CP_SPECIAL_MASK) { r2->type |= ARM_CP_NO_RAW; } if (((r->crm == CP_ANY) && crm != 0) || From 99a90811d09e58630c1c43c43b644501ce12ced0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:20 -0500 Subject: [PATCH 197/935] target/arm: Drop EL3 no EL2 fallbacks Drop el3_no_el2_cp_reginfo, el3_no_el2_v8_cp_reginfo, and the local vpidr_regs definition, and rely on the squashing to ARM_CP_CONST while registering for v8. This is a behavior change for v7 cpus with Security Extensions and without Virtualization Extensions, in that the virtualization cpregs are now correctly not present. This would be a migration compatibility break, except that we have an existing bug in which migration of 32-bit cpus with Security Extensions enabled does not work. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 158 ++++---------------------------------------- 1 file changed, 13 insertions(+), 145 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 9ab8b65e7b..ea2788b3d5 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5099,124 +5099,6 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .fieldoffset = offsetoflow32(CPUARMState, cp15.mdcr_el3) }, }; -/* Used to describe the behaviour of EL2 regs when EL2 does not exist. */ -static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = { - { .name = "VBAR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 0, .opc2 = 0, - .access = PL2_RW, - .readfn = arm_cp_read_zero, .writefn = arm_cp_write_ignore }, - { .name = "HCR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 0, - .access = PL2_RW, - .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "HACR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 7, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "ESR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 0, - .access = PL2_RW, - .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPTR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 2, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "MAIR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 10, .crm = 2, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "HMAIR1", .state = ARM_CP_STATE_AA32, - .cp = 15, .opc1 = 4, .crn = 10, .crm = 2, .opc2 = 1, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "AMAIR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 10, .crm = 3, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "HAMAIR1", .state = ARM_CP_STATE_AA32, - .cp = 15, .opc1 = 4, .crn = 10, .crm = 3, .opc2 = 1, - .access = PL2_RW, .type = ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "AFSR0_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 1, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "AFSR1_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 1, .opc2 = 1, - .access = PL2_RW, .type = ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "TCR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 2, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "VTCR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 2, - .access = PL2_RW, .accessfn = access_el3_aa32ns, - .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "VTTBR", .state = ARM_CP_STATE_AA32, - .cp = 15, .opc1 = 6, .crm = 2, - .access = PL2_RW, .accessfn = access_el3_aa32ns, - .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, - { .name = "VTTBR_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "SCTLR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "TPIDR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 2, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "TTBR0_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "HTTBR", .cp = 15, .opc1 = 4, .crm = 2, - .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "CNTHCTL_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 1, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CNTVOFF_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 3, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CNTVOFF", .cp = 15, .opc1 = 4, .crm = 14, - .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "CNTHP_CVAL_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 2, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CNTHP_CVAL", .cp = 15, .opc1 = 6, .crm = 14, - .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST, - .resetvalue = 0 }, - { .name = "CNTHP_TVAL_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CNTHP_CTL_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 1, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1, - .access = PL2_RW, .accessfn = access_tda, - .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "HPFAR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 4, - .access = PL2_RW, .accessfn = access_el3_aa32ns, - .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "HSTR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 3, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "FAR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "HIFAR", .state = ARM_CP_STATE_AA32, - .type = ARM_CP_CONST, - .cp = 15, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 2, - .access = PL2_RW, .resetvalue = 0 }, -}; - -/* Ditto, but for registers which exist in ARMv8 but not v7 */ -static const ARMCPRegInfo el3_no_el2_v8_cp_reginfo[] = { - { .name = "HCR2", .state = ARM_CP_STATE_AA32, - .cp = 15, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 4, - .access = PL2_RW, - .type = ARM_CP_CONST, .resetvalue = 0 }, -}; - static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) { ARMCPU *cpu = env_archcpu(env); @@ -7902,7 +7784,17 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_arm_cp_regs(cpu, v8_idregs); define_arm_cp_regs(cpu, v8_cp_reginfo); } - if (arm_feature(env, ARM_FEATURE_EL2)) { + + /* + * Register the base EL2 cpregs. + * Pre v8, these registers are implemented only as part of the + * Virtualization Extensions (EL2 present). Beginning with v8, + * if EL2 is missing but EL3 is enabled, mostly these become + * RES0 from EL3, with some specific exceptions. + */ + if (arm_feature(env, ARM_FEATURE_EL2) + || (arm_feature(env, ARM_FEATURE_EL3) + && arm_feature(env, ARM_FEATURE_V8))) { uint64_t vmpidr_def = mpidr_read_val(env); ARMCPRegInfo vpidr_regs[] = { { .name = "VPIDR", .state = ARM_CP_STATE_AA32, @@ -7946,33 +7838,9 @@ void register_cp_regs_for_features(ARMCPU *cpu) }; define_one_arm_cp_reg(cpu, &rvbar); } - } else { - /* If EL2 is missing but higher ELs are enabled, we need to - * register the no_el2 reginfos. - */ - if (arm_feature(env, ARM_FEATURE_EL3)) { - /* When EL3 exists but not EL2, VPIDR and VMPIDR take the value - * of MIDR_EL1 and MPIDR_EL1. - */ - ARMCPRegInfo vpidr_regs[] = { - { .name = "VPIDR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 0, - .access = PL2_RW, .accessfn = access_el3_aa32ns, - .type = ARM_CP_CONST, .resetvalue = cpu->midr, - .fieldoffset = offsetof(CPUARMState, cp15.vpidr_el2) }, - { .name = "VMPIDR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5, - .access = PL2_RW, .accessfn = access_el3_aa32ns, - .type = ARM_CP_NO_RAW, - .writefn = arm_cp_write_ignore, .readfn = mpidr_read }, - }; - define_arm_cp_regs(cpu, vpidr_regs); - define_arm_cp_regs(cpu, el3_no_el2_cp_reginfo); - if (arm_feature(env, ARM_FEATURE_V8)) { - define_arm_cp_regs(cpu, el3_no_el2_v8_cp_reginfo); - } - } } + + /* Register the base EL3 cpregs. */ if (arm_feature(env, ARM_FEATURE_EL3)) { define_arm_cp_regs(cpu, el3_cp_reginfo); ARMCPRegInfo el3_regs[] = { From 60360d82a1022f8db9cbe5ed312de14b490fa46e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:21 -0500 Subject: [PATCH 198/935] target/arm: Merge zcr reginfo Drop zcr_no_el2_reginfo and merge the 3 registers into one array, now that ZCR_EL2 can be squashed to RES0 and ZCR_EL3 dropped while registering. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-4-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 55 ++++++++++++++------------------------------- 1 file changed, 17 insertions(+), 38 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index ea2788b3d5..72d05070f0 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6122,35 +6122,22 @@ static void zcr_write(CPUARMState *env, const ARMCPRegInfo *ri, } } -static const ARMCPRegInfo zcr_el1_reginfo = { - .name = "ZCR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_SVE, - .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[1]), - .writefn = zcr_write, .raw_writefn = raw_write -}; - -static const ARMCPRegInfo zcr_el2_reginfo = { - .name = "ZCR_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_SVE, - .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[2]), - .writefn = zcr_write, .raw_writefn = raw_write -}; - -static const ARMCPRegInfo zcr_no_el2_reginfo = { - .name = "ZCR_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_SVE, - .readfn = arm_cp_read_zero, .writefn = arm_cp_write_ignore -}; - -static const ARMCPRegInfo zcr_el3_reginfo = { - .name = "ZCR_EL3", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 2, .opc2 = 0, - .access = PL3_RW, .type = ARM_CP_SVE, - .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[3]), - .writefn = zcr_write, .raw_writefn = raw_write +static const ARMCPRegInfo zcr_reginfo[] = { + { .name = "ZCR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_SVE, + .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[1]), + .writefn = zcr_write, .raw_writefn = raw_write }, + { .name = "ZCR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 0, + .access = PL2_RW, .type = ARM_CP_SVE, + .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[2]), + .writefn = zcr_write, .raw_writefn = raw_write }, + { .name = "ZCR_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 2, .opc2 = 0, + .access = PL3_RW, .type = ARM_CP_SVE, + .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[3]), + .writefn = zcr_write, .raw_writefn = raw_write }, }; void hw_watchpoint_update(ARMCPU *cpu, int n) @@ -8233,15 +8220,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) } if (cpu_isar_feature(aa64_sve, cpu)) { - define_one_arm_cp_reg(cpu, &zcr_el1_reginfo); - if (arm_feature(env, ARM_FEATURE_EL2)) { - define_one_arm_cp_reg(cpu, &zcr_el2_reginfo); - } else { - define_one_arm_cp_reg(cpu, &zcr_no_el2_reginfo); - } - if (arm_feature(env, ARM_FEATURE_EL3)) { - define_one_arm_cp_reg(cpu, &zcr_el3_reginfo); - } + define_arm_cp_regs(cpu, zcr_reginfo); } #ifdef TARGET_AARCH64 From 52d187275b3a306c6bc83c083885ae34e0939f0d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:22 -0500 Subject: [PATCH 199/935] target/arm: Adjust definition of CONTEXTIDR_EL2 This register is present for either VHE or Debugv8p2. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 72d05070f0..7b31c71980 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -7246,11 +7246,14 @@ static const ARMCPRegInfo jazelle_regs[] = { .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, }; +static const ARMCPRegInfo contextidr_el2 = { + .name = "CONTEXTIDR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 1, + .access = PL2_RW, + .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el[2]) +}; + static const ARMCPRegInfo vhe_reginfo[] = { - { .name = "CONTEXTIDR_EL2", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 1, - .access = PL2_RW, - .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el[2]) }, { .name = "TTBR1_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 1, .access = PL2_RW, .writefn = vmsa_tcr_ttbr_el2_write, @@ -8215,6 +8218,10 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_one_arm_cp_reg(cpu, &ssbs_reginfo); } + if (cpu_isar_feature(aa64_vh, cpu) || + cpu_isar_feature(aa64_debugv8p2, cpu)) { + define_one_arm_cp_reg(cpu, &contextidr_el2); + } if (arm_feature(env, ARM_FEATURE_EL2) && cpu_isar_feature(aa64_vh, cpu)) { define_arm_cp_regs(cpu, vhe_reginfo); } From 7c1aaf98ff6b06e96de1a25fa8e3214eb402bd77 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:23 -0500 Subject: [PATCH 200/935] target/arm: Move cortex impdef sysregs to cpu_tcg.c Previously we were defining some of these in user-only mode, but none of them are accessible from user-only, therefore define them only in system mode. This will shortly be used from cpu_tcg.c also. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-6-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu64.c | 64 +++--------------------------------------- target/arm/cpu_tcg.c | 59 ++++++++++++++++++++++++++++++++++++++ target/arm/internals.h | 6 ++++ 3 files changed, 69 insertions(+), 60 deletions(-) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index c841d55d0e..33a0a71900 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -34,65 +34,9 @@ #include "hvf_arm.h" #include "qapi/visitor.h" #include "hw/qdev-properties.h" -#include "cpregs.h" +#include "internals.h" -#ifndef CONFIG_USER_ONLY -static uint64_t a57_a53_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - ARMCPU *cpu = env_archcpu(env); - - /* Number of cores is in [25:24]; otherwise we RAZ */ - return (cpu->core_count - 1) << 24; -} -#endif - -static const ARMCPRegInfo cortex_a72_a57_a53_cp_reginfo[] = { -#ifndef CONFIG_USER_ONLY - { .name = "L2CTLR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 2, - .access = PL1_RW, .readfn = a57_a53_l2ctlr_read, - .writefn = arm_cp_write_ignore }, - { .name = "L2CTLR", - .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 2, - .access = PL1_RW, .readfn = a57_a53_l2ctlr_read, - .writefn = arm_cp_write_ignore }, -#endif - { .name = "L2ECTLR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 3, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "L2ECTLR", - .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 3, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "L2ACTLR", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUACTLR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUACTLR", - .cp = 15, .opc1 = 0, .crm = 15, - .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, - { .name = "CPUECTLR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 1, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUECTLR", - .cp = 15, .opc1 = 1, .crm = 15, - .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, - { .name = "CPUMERRSR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 2, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPUMERRSR", - .cp = 15, .opc1 = 2, .crm = 15, - .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, - { .name = "L2MERRSR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 3, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "L2MERRSR", - .cp = 15, .opc1 = 3, .crm = 15, - .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, -}; - static void aarch64_a57_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); @@ -143,7 +87,7 @@ static void aarch64_a57_initfn(Object *obj) cpu->gic_num_lrs = 4; cpu->gic_vpribits = 5; cpu->gic_vprebits = 5; - define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); + define_cortex_a72_a57_a53_cp_reginfo(cpu); } static void aarch64_a53_initfn(Object *obj) @@ -196,7 +140,7 @@ static void aarch64_a53_initfn(Object *obj) cpu->gic_num_lrs = 4; cpu->gic_vpribits = 5; cpu->gic_vprebits = 5; - define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); + define_cortex_a72_a57_a53_cp_reginfo(cpu); } static void aarch64_a72_initfn(Object *obj) @@ -247,7 +191,7 @@ static void aarch64_a72_initfn(Object *obj) cpu->gic_num_lrs = 4; cpu->gic_vpribits = 5; cpu->gic_vprebits = 5; - define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); + define_cortex_a72_a57_a53_cp_reginfo(cpu); } void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index 9338088b22..d078f06931 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -20,6 +20,65 @@ #endif #include "cpregs.h" +#ifndef CONFIG_USER_ONLY +static uint64_t l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + ARMCPU *cpu = env_archcpu(env); + + /* Number of cores is in [25:24]; otherwise we RAZ */ + return (cpu->core_count - 1) << 24; +} + +static const ARMCPRegInfo cortex_a72_a57_a53_cp_reginfo[] = { + { .name = "L2CTLR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 2, + .access = PL1_RW, .readfn = l2ctlr_read, + .writefn = arm_cp_write_ignore }, + { .name = "L2CTLR", + .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 2, + .access = PL1_RW, .readfn = l2ctlr_read, + .writefn = arm_cp_write_ignore }, + { .name = "L2ECTLR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 3, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "L2ECTLR", + .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 3, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "L2ACTLR", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 0, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUACTLR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUACTLR", + .cp = 15, .opc1 = 0, .crm = 15, + .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, + { .name = "CPUECTLR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 1, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUECTLR", + .cp = 15, .opc1 = 1, .crm = 15, + .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, + { .name = "CPUMERRSR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 2, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CPUMERRSR", + .cp = 15, .opc1 = 2, .crm = 15, + .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, + { .name = "L2MERRSR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 3, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "L2MERRSR", + .cp = 15, .opc1 = 3, .crm = 15, + .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, +}; + +void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu) +{ + define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); +} +#endif /* !CONFIG_USER_ONLY */ + /* CPU models. These are not needed for the AArch64 linux-user build. */ #if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) diff --git a/target/arm/internals.h b/target/arm/internals.h index 255833479d..343b465d51 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1307,4 +1307,10 @@ int aarch64_fpu_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg); int aarch64_fpu_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg); #endif +#ifdef CONFIG_USER_ONLY +static inline void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu) { } +#else +void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu); +#endif + #endif From 7e834daf0abe785041804a63f6b65b095ece8e6c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:24 -0500 Subject: [PATCH 201/935] target/arm: Update qemu-system-arm -cpu max to cortex-a57 Instead of starting with cortex-a15 and adding v8 features to a v7 cpu, begin with a v8 cpu stripped of its aarch64 features. This fixes the long-standing to-do where we only enabled v8 features for user-only. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-7-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu_tcg.c | 151 ++++++++++++++++++++++++++----------------- 1 file changed, 92 insertions(+), 59 deletions(-) diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index d078f06931..f9094c1752 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -994,71 +994,104 @@ static void arm_v7m_class_init(ObjectClass *oc, void *data) static void arm_max_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); + uint32_t t; - cortex_a15_initfn(obj); + /* aarch64_a57_initfn, advertising none of the aarch64 features */ + cpu->dtb_compatible = "arm,cortex-a57"; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + cpu->midr = 0x411fd070; + cpu->revidr = 0x00000000; + cpu->reset_fpsid = 0x41034070; + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x12111111; + cpu->isar.mvfr2 = 0x00000043; + cpu->ctr = 0x8444c004; + cpu->reset_sctlr = 0x00c50838; + cpu->isar.id_pfr0 = 0x00000131; + cpu->isar.id_pfr1 = 0x00011011; + cpu->isar.id_dfr0 = 0x03010066; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10101105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02102211; + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232042; + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00011142; + cpu->isar.id_isar5 = 0x00011121; + cpu->isar.id_isar6 = 0; + cpu->isar.dbgdidr = 0x3516d000; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ + cpu->ccsidr[2] = 0x70ffe07a; /* 2048KB L2 cache */ + define_cortex_a72_a57_a53_cp_reginfo(cpu); - /* old-style VFP short-vector support */ - cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); + /* Add additional features supported by QEMU */ + t = cpu->isar.id_isar5; + t = FIELD_DP32(t, ID_ISAR5, AES, 2); + t = FIELD_DP32(t, ID_ISAR5, SHA1, 1); + t = FIELD_DP32(t, ID_ISAR5, SHA2, 1); + t = FIELD_DP32(t, ID_ISAR5, CRC32, 1); + t = FIELD_DP32(t, ID_ISAR5, RDM, 1); + t = FIELD_DP32(t, ID_ISAR5, VCMA, 1); + cpu->isar.id_isar5 = t; + + t = cpu->isar.id_isar6; + t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); + t = FIELD_DP32(t, ID_ISAR6, DP, 1); + t = FIELD_DP32(t, ID_ISAR6, FHM, 1); + t = FIELD_DP32(t, ID_ISAR6, SB, 1); + t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); + t = FIELD_DP32(t, ID_ISAR6, BF16, 1); + t = FIELD_DP32(t, ID_ISAR6, I8MM, 1); + cpu->isar.id_isar6 = t; + + t = cpu->isar.mvfr1; + t = FIELD_DP32(t, MVFR1, FPHP, 3); /* v8.2-FP16 */ + t = FIELD_DP32(t, MVFR1, SIMDHP, 2); /* v8.2-FP16 */ + cpu->isar.mvfr1 = t; + + t = cpu->isar.mvfr2; + t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ + t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ + cpu->isar.mvfr2 = t; + + t = cpu->isar.id_mmfr3; + t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */ + cpu->isar.id_mmfr3 = t; + + t = cpu->isar.id_mmfr4; + t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ + t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ + t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* TTCNP */ + t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* TTS2UXN */ + cpu->isar.id_mmfr4 = t; + + t = cpu->isar.id_pfr0; + t = FIELD_DP32(t, ID_PFR0, DIT, 1); + cpu->isar.id_pfr0 = t; + + t = cpu->isar.id_pfr2; + t = FIELD_DP32(t, ID_PFR2, SSBS, 1); + cpu->isar.id_pfr2 = t; #ifdef CONFIG_USER_ONLY /* - * We don't set these in system emulation mode for the moment, - * since we don't correctly set (all of) the ID registers to - * advertise them. + * Break with true ARMv8 and add back old-style VFP short-vector support. + * Only do this for user-mode, where -cpu max is the default, so that + * older v6 and v7 programs are more likely to work without adjustment. */ - set_feature(&cpu->env, ARM_FEATURE_V8); - { - uint32_t t; - - t = cpu->isar.id_isar5; - t = FIELD_DP32(t, ID_ISAR5, AES, 2); - t = FIELD_DP32(t, ID_ISAR5, SHA1, 1); - t = FIELD_DP32(t, ID_ISAR5, SHA2, 1); - t = FIELD_DP32(t, ID_ISAR5, CRC32, 1); - t = FIELD_DP32(t, ID_ISAR5, RDM, 1); - t = FIELD_DP32(t, ID_ISAR5, VCMA, 1); - cpu->isar.id_isar5 = t; - - t = cpu->isar.id_isar6; - t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); - t = FIELD_DP32(t, ID_ISAR6, DP, 1); - t = FIELD_DP32(t, ID_ISAR6, FHM, 1); - t = FIELD_DP32(t, ID_ISAR6, SB, 1); - t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); - t = FIELD_DP32(t, ID_ISAR6, BF16, 1); - t = FIELD_DP32(t, ID_ISAR6, I8MM, 1); - cpu->isar.id_isar6 = t; - - t = cpu->isar.mvfr1; - t = FIELD_DP32(t, MVFR1, FPHP, 3); /* v8.2-FP16 */ - t = FIELD_DP32(t, MVFR1, SIMDHP, 2); /* v8.2-FP16 */ - cpu->isar.mvfr1 = t; - - t = cpu->isar.mvfr2; - t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ - t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ - cpu->isar.mvfr2 = t; - - t = cpu->isar.id_mmfr3; - t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */ - cpu->isar.id_mmfr3 = t; - - t = cpu->isar.id_mmfr4; - t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ - t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ - t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* TTCNP */ - t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* TTS2UXN */ - cpu->isar.id_mmfr4 = t; - - t = cpu->isar.id_pfr0; - t = FIELD_DP32(t, ID_PFR0, DIT, 1); - cpu->isar.id_pfr0 = t; - - t = cpu->isar.id_pfr2; - t = FIELD_DP32(t, ID_PFR2, SSBS, 1); - cpu->isar.id_pfr2 = t; - } -#endif /* CONFIG_USER_ONLY */ + cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); +#endif } #endif /* !TARGET_AARCH64 */ From e14cc941f109cb93fab28a2b3fe79c700c7b6eeb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:25 -0500 Subject: [PATCH 202/935] target/arm: Set ID_DFR0.PerfMon for qemu-system-arm -cpu max We set this for qemu-system-aarch64, but failed to do so for the strictly 32-bit emulation. Fixes: 3bec78447a9 ("target/arm: Provide ARMv8.4-PMU in '-cpu max'") Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-8-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu_tcg.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index f9094c1752..9aa2f737c1 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -1084,6 +1084,10 @@ static void arm_max_initfn(Object *obj) t = FIELD_DP32(t, ID_PFR2, SSBS, 1); cpu->isar.id_pfr2 = t; + t = cpu->isar.id_dfr0; + t = FIELD_DP32(t, ID_DFR0, PERFMON, 5); /* v8.4-PMU */ + cpu->isar.id_dfr0 = t; + #ifdef CONFIG_USER_ONLY /* * Break with true ARMv8 and add back old-style VFP short-vector support. From b6f8b358c2a2784433f51299279cd8e04fc981ac Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:26 -0500 Subject: [PATCH 203/935] target/arm: Split out aa32_max_features Share the code to set AArch32 max features so that we no longer have code drift between qemu{-system,}-{arm,aarch64}. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-9-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu64.c | 50 +----------------- target/arm/cpu_tcg.c | 114 ++++++++++++++++++++++------------------- target/arm/internals.h | 2 + 3 files changed, 65 insertions(+), 101 deletions(-) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 33a0a71900..6da42af56e 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -682,7 +682,6 @@ static void aarch64_max_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); uint64_t t; - uint32_t u; if (kvm_enabled() || hvf_enabled()) { /* With KVM or HVF, '-cpu max' is identical to '-cpu host' */ @@ -799,57 +798,12 @@ static void aarch64_max_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64ZFR0, F64MM, 1); cpu->isar.id_aa64zfr0 = t; - /* Replicate the same data to the 32-bit id registers. */ - u = cpu->isar.id_isar5; - u = FIELD_DP32(u, ID_ISAR5, AES, 2); /* AES + PMULL */ - u = FIELD_DP32(u, ID_ISAR5, SHA1, 1); - u = FIELD_DP32(u, ID_ISAR5, SHA2, 1); - u = FIELD_DP32(u, ID_ISAR5, CRC32, 1); - u = FIELD_DP32(u, ID_ISAR5, RDM, 1); - u = FIELD_DP32(u, ID_ISAR5, VCMA, 1); - cpu->isar.id_isar5 = u; - - u = cpu->isar.id_isar6; - u = FIELD_DP32(u, ID_ISAR6, JSCVT, 1); - u = FIELD_DP32(u, ID_ISAR6, DP, 1); - u = FIELD_DP32(u, ID_ISAR6, FHM, 1); - u = FIELD_DP32(u, ID_ISAR6, SB, 1); - u = FIELD_DP32(u, ID_ISAR6, SPECRES, 1); - u = FIELD_DP32(u, ID_ISAR6, BF16, 1); - u = FIELD_DP32(u, ID_ISAR6, I8MM, 1); - cpu->isar.id_isar6 = u; - - u = cpu->isar.id_pfr0; - u = FIELD_DP32(u, ID_PFR0, DIT, 1); - cpu->isar.id_pfr0 = u; - - u = cpu->isar.id_pfr2; - u = FIELD_DP32(u, ID_PFR2, SSBS, 1); - cpu->isar.id_pfr2 = u; - - u = cpu->isar.id_mmfr3; - u = FIELD_DP32(u, ID_MMFR3, PAN, 2); /* ATS1E1 */ - cpu->isar.id_mmfr3 = u; - - u = cpu->isar.id_mmfr4; - u = FIELD_DP32(u, ID_MMFR4, HPDS, 1); /* AA32HPD */ - u = FIELD_DP32(u, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ - u = FIELD_DP32(u, ID_MMFR4, CNP, 1); /* TTCNP */ - u = FIELD_DP32(u, ID_MMFR4, XNX, 1); /* TTS2UXN */ - cpu->isar.id_mmfr4 = u; - t = cpu->isar.id_aa64dfr0; t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 5); /* v8.4-PMU */ cpu->isar.id_aa64dfr0 = t; - u = cpu->isar.id_dfr0; - u = FIELD_DP32(u, ID_DFR0, PERFMON, 5); /* v8.4-PMU */ - cpu->isar.id_dfr0 = u; - - u = cpu->isar.mvfr1; - u = FIELD_DP32(u, MVFR1, FPHP, 3); /* v8.2-FP16 */ - u = FIELD_DP32(u, MVFR1, SIMDHP, 2); /* v8.2-FP16 */ - cpu->isar.mvfr1 = u; + /* Replicate the same data to the 32-bit id registers. */ + aa32_max_features(cpu); #ifdef CONFIG_USER_ONLY /* diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index 9aa2f737c1..b0dbf2c991 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -20,6 +20,66 @@ #endif #include "cpregs.h" + +/* Share AArch32 -cpu max features with AArch64. */ +void aa32_max_features(ARMCPU *cpu) +{ + uint32_t t; + + /* Add additional features supported by QEMU */ + t = cpu->isar.id_isar5; + t = FIELD_DP32(t, ID_ISAR5, AES, 2); + t = FIELD_DP32(t, ID_ISAR5, SHA1, 1); + t = FIELD_DP32(t, ID_ISAR5, SHA2, 1); + t = FIELD_DP32(t, ID_ISAR5, CRC32, 1); + t = FIELD_DP32(t, ID_ISAR5, RDM, 1); + t = FIELD_DP32(t, ID_ISAR5, VCMA, 1); + cpu->isar.id_isar5 = t; + + t = cpu->isar.id_isar6; + t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); + t = FIELD_DP32(t, ID_ISAR6, DP, 1); + t = FIELD_DP32(t, ID_ISAR6, FHM, 1); + t = FIELD_DP32(t, ID_ISAR6, SB, 1); + t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); + t = FIELD_DP32(t, ID_ISAR6, BF16, 1); + t = FIELD_DP32(t, ID_ISAR6, I8MM, 1); + cpu->isar.id_isar6 = t; + + t = cpu->isar.mvfr1; + t = FIELD_DP32(t, MVFR1, FPHP, 3); /* v8.2-FP16 */ + t = FIELD_DP32(t, MVFR1, SIMDHP, 2); /* v8.2-FP16 */ + cpu->isar.mvfr1 = t; + + t = cpu->isar.mvfr2; + t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ + t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ + cpu->isar.mvfr2 = t; + + t = cpu->isar.id_mmfr3; + t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */ + cpu->isar.id_mmfr3 = t; + + t = cpu->isar.id_mmfr4; + t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ + t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ + t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* TTCNP */ + t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* TTS2UXN */ + cpu->isar.id_mmfr4 = t; + + t = cpu->isar.id_pfr0; + t = FIELD_DP32(t, ID_PFR0, DIT, 1); + cpu->isar.id_pfr0 = t; + + t = cpu->isar.id_pfr2; + t = FIELD_DP32(t, ID_PFR2, SSBS, 1); + cpu->isar.id_pfr2 = t; + + t = cpu->isar.id_dfr0; + t = FIELD_DP32(t, ID_DFR0, PERFMON, 5); /* v8.4-PMU */ + cpu->isar.id_dfr0 = t; +} + #ifndef CONFIG_USER_ONLY static uint64_t l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) { @@ -994,7 +1054,6 @@ static void arm_v7m_class_init(ObjectClass *oc, void *data) static void arm_max_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); - uint32_t t; /* aarch64_a57_initfn, advertising none of the aarch64 features */ cpu->dtb_compatible = "arm,cortex-a57"; @@ -1035,58 +1094,7 @@ static void arm_max_initfn(Object *obj) cpu->ccsidr[2] = 0x70ffe07a; /* 2048KB L2 cache */ define_cortex_a72_a57_a53_cp_reginfo(cpu); - /* Add additional features supported by QEMU */ - t = cpu->isar.id_isar5; - t = FIELD_DP32(t, ID_ISAR5, AES, 2); - t = FIELD_DP32(t, ID_ISAR5, SHA1, 1); - t = FIELD_DP32(t, ID_ISAR5, SHA2, 1); - t = FIELD_DP32(t, ID_ISAR5, CRC32, 1); - t = FIELD_DP32(t, ID_ISAR5, RDM, 1); - t = FIELD_DP32(t, ID_ISAR5, VCMA, 1); - cpu->isar.id_isar5 = t; - - t = cpu->isar.id_isar6; - t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); - t = FIELD_DP32(t, ID_ISAR6, DP, 1); - t = FIELD_DP32(t, ID_ISAR6, FHM, 1); - t = FIELD_DP32(t, ID_ISAR6, SB, 1); - t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); - t = FIELD_DP32(t, ID_ISAR6, BF16, 1); - t = FIELD_DP32(t, ID_ISAR6, I8MM, 1); - cpu->isar.id_isar6 = t; - - t = cpu->isar.mvfr1; - t = FIELD_DP32(t, MVFR1, FPHP, 3); /* v8.2-FP16 */ - t = FIELD_DP32(t, MVFR1, SIMDHP, 2); /* v8.2-FP16 */ - cpu->isar.mvfr1 = t; - - t = cpu->isar.mvfr2; - t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ - t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ - cpu->isar.mvfr2 = t; - - t = cpu->isar.id_mmfr3; - t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */ - cpu->isar.id_mmfr3 = t; - - t = cpu->isar.id_mmfr4; - t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ - t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ - t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* TTCNP */ - t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* TTS2UXN */ - cpu->isar.id_mmfr4 = t; - - t = cpu->isar.id_pfr0; - t = FIELD_DP32(t, ID_PFR0, DIT, 1); - cpu->isar.id_pfr0 = t; - - t = cpu->isar.id_pfr2; - t = FIELD_DP32(t, ID_PFR2, SSBS, 1); - cpu->isar.id_pfr2 = t; - - t = cpu->isar.id_dfr0; - t = FIELD_DP32(t, ID_DFR0, PERFMON, 5); /* v8.4-PMU */ - cpu->isar.id_dfr0 = t; + aa32_max_features(cpu); #ifdef CONFIG_USER_ONLY /* diff --git a/target/arm/internals.h b/target/arm/internals.h index 343b465d51..c563b3735f 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1313,4 +1313,6 @@ static inline void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu) { } void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu); #endif +void aa32_max_features(ARMCPU *cpu); + #endif From ef696cfbae6290d448ca0b36f9e41e3e0ec3d50d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:27 -0500 Subject: [PATCH 204/935] target/arm: Annotate arm_max_initfn with FEAT identifiers Update the legacy feature names to the current names. Provide feature names for id changes that were not marked. Sort the field updates into increasing bitfield order. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-10-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu64.c | 100 +++++++++++++++++++++---------------------- target/arm/cpu_tcg.c | 48 ++++++++++----------- 2 files changed, 74 insertions(+), 74 deletions(-) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 6da42af56e..5fce40a6bc 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -713,51 +713,51 @@ static void aarch64_max_initfn(Object *obj) cpu->midr = t; t = cpu->isar.id_aa64isar0; - t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2); /* AES + PMULL */ - t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 2); /* SHA512 */ + t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2); /* FEAT_PMULL */ + t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); /* FEAT_SHA1 */ + t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 2); /* FEAT_SHA512 */ t = FIELD_DP64(t, ID_AA64ISAR0, CRC32, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, ATOMIC, 2); - t = FIELD_DP64(t, ID_AA64ISAR0, RDM, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, SHA3, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, DP, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, TS, 2); /* v8.5-CondM */ - t = FIELD_DP64(t, ID_AA64ISAR0, TLB, 2); /* FEAT_TLBIRANGE */ - t = FIELD_DP64(t, ID_AA64ISAR0, RNDR, 1); + t = FIELD_DP64(t, ID_AA64ISAR0, ATOMIC, 2); /* FEAT_LSE */ + t = FIELD_DP64(t, ID_AA64ISAR0, RDM, 1); /* FEAT_RDM */ + t = FIELD_DP64(t, ID_AA64ISAR0, SHA3, 1); /* FEAT_SHA3 */ + t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 1); /* FEAT_SM3 */ + t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 1); /* FEAT_SM4 */ + t = FIELD_DP64(t, ID_AA64ISAR0, DP, 1); /* FEAT_DotProd */ + t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 1); /* FEAT_FHM */ + t = FIELD_DP64(t, ID_AA64ISAR0, TS, 2); /* FEAT_FlagM2 */ + t = FIELD_DP64(t, ID_AA64ISAR0, TLB, 2); /* FEAT_TLBIRANGE */ + t = FIELD_DP64(t, ID_AA64ISAR0, RNDR, 1); /* FEAT_RNG */ cpu->isar.id_aa64isar0 = t; t = cpu->isar.id_aa64isar1; - t = FIELD_DP64(t, ID_AA64ISAR1, DPB, 2); - t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, LRCPC, 2); /* ARMv8.4-RCPC */ - t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 1); + t = FIELD_DP64(t, ID_AA64ISAR1, DPB, 2); /* FEAT_DPB2 */ + t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1); /* FEAT_JSCVT */ + t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1); /* FEAT_FCMA */ + t = FIELD_DP64(t, ID_AA64ISAR1, LRCPC, 2); /* FEAT_LRCPC2 */ + t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1); /* FEAT_FRINTTS */ + t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1); /* FEAT_SB */ + t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1); /* FEAT_SPECRES */ + t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 1); /* FEAT_BF16 */ + t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 1); /* FEAT_I8MM */ cpu->isar.id_aa64isar1 = t; t = cpu->isar.id_aa64pfr0; + t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); /* FEAT_FP16 */ + t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); /* FEAT_FP16 */ t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); - t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); - t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); - t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); - t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); + t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); /* FEAT_SEL2 */ + t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); /* FEAT_DIT */ cpu->isar.id_aa64pfr0 = t; t = cpu->isar.id_aa64pfr1; - t = FIELD_DP64(t, ID_AA64PFR1, BT, 1); - t = FIELD_DP64(t, ID_AA64PFR1, SSBS, 2); + t = FIELD_DP64(t, ID_AA64PFR1, BT, 1); /* FEAT_BTI */ + t = FIELD_DP64(t, ID_AA64PFR1, SSBS, 2); /* FEAT_SSBS2 */ /* * Begin with full support for MTE. This will be downgraded to MTE=0 * during realize if the board provides no tag memory, much like * we do for EL2 with the virtualization=on property. */ - t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); + t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); /* FEAT_MTE3 */ cpu->isar.id_aa64pfr1 = t; t = cpu->isar.id_aa64mmfr0; @@ -769,37 +769,37 @@ static void aarch64_max_initfn(Object *obj) cpu->isar.id_aa64mmfr0 = t; t = cpu->isar.id_aa64mmfr1; - t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 1); /* HPD */ - t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1); - t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1); - t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 2); /* ATS1E1 */ - t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* VMID16 */ - t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1); /* TTS2UXN */ + t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* FEAT_VMID16 */ + t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1); /* FEAT_VHE */ + t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 1); /* FEAT_HPDS */ + t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1); /* FEAT_LOR */ + t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 2); /* FEAT_PAN2 */ + t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1); /* FEAT_XNX */ cpu->isar.id_aa64mmfr1 = t; t = cpu->isar.id_aa64mmfr2; - t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1); - t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* TTCNP */ - t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* TTST */ - t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1); /* FEAT_LVA */ - t = FIELD_DP64(t, ID_AA64MMFR2, TTL, 1); /* FEAT_TTL */ - t = FIELD_DP64(t, ID_AA64MMFR2, BBM, 2); /* FEAT_BBM at level 2 */ + t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* FEAT_TTCNP */ + t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1); /* FEAT_UAO */ + t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1); /* FEAT_LVA */ + t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* FEAT_TTST */ + t = FIELD_DP64(t, ID_AA64MMFR2, TTL, 1); /* FEAT_TTL */ + t = FIELD_DP64(t, ID_AA64MMFR2, BBM, 2); /* FEAT_BBM at level 2 */ cpu->isar.id_aa64mmfr2 = t; t = cpu->isar.id_aa64zfr0; t = FIELD_DP64(t, ID_AA64ZFR0, SVEVER, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, AES, 2); /* PMULL */ - t = FIELD_DP64(t, ID_AA64ZFR0, BITPERM, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, BFLOAT16, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, SHA3, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, SM4, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, I8MM, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, F32MM, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, F64MM, 1); + t = FIELD_DP64(t, ID_AA64ZFR0, AES, 2); /* FEAT_SVE_PMULL128 */ + t = FIELD_DP64(t, ID_AA64ZFR0, BITPERM, 1); /* FEAT_SVE_BitPerm */ + t = FIELD_DP64(t, ID_AA64ZFR0, BFLOAT16, 1); /* FEAT_BF16 */ + t = FIELD_DP64(t, ID_AA64ZFR0, SHA3, 1); /* FEAT_SVE_SHA3 */ + t = FIELD_DP64(t, ID_AA64ZFR0, SM4, 1); /* FEAT_SVE_SM4 */ + t = FIELD_DP64(t, ID_AA64ZFR0, I8MM, 1); /* FEAT_I8MM */ + t = FIELD_DP64(t, ID_AA64ZFR0, F32MM, 1); /* FEAT_F32MM */ + t = FIELD_DP64(t, ID_AA64ZFR0, F64MM, 1); /* FEAT_F64MM */ cpu->isar.id_aa64zfr0 = t; t = cpu->isar.id_aa64dfr0; - t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 5); /* v8.4-PMU */ + t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 5); /* FEAT_PMUv3p4 */ cpu->isar.id_aa64dfr0 = t; /* Replicate the same data to the 32-bit id registers. */ diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index b0dbf2c991..bc8f9d0edf 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -28,55 +28,55 @@ void aa32_max_features(ARMCPU *cpu) /* Add additional features supported by QEMU */ t = cpu->isar.id_isar5; - t = FIELD_DP32(t, ID_ISAR5, AES, 2); - t = FIELD_DP32(t, ID_ISAR5, SHA1, 1); - t = FIELD_DP32(t, ID_ISAR5, SHA2, 1); + t = FIELD_DP32(t, ID_ISAR5, AES, 2); /* FEAT_PMULL */ + t = FIELD_DP32(t, ID_ISAR5, SHA1, 1); /* FEAT_SHA1 */ + t = FIELD_DP32(t, ID_ISAR5, SHA2, 1); /* FEAT_SHA256 */ t = FIELD_DP32(t, ID_ISAR5, CRC32, 1); - t = FIELD_DP32(t, ID_ISAR5, RDM, 1); - t = FIELD_DP32(t, ID_ISAR5, VCMA, 1); + t = FIELD_DP32(t, ID_ISAR5, RDM, 1); /* FEAT_RDM */ + t = FIELD_DP32(t, ID_ISAR5, VCMA, 1); /* FEAT_FCMA */ cpu->isar.id_isar5 = t; t = cpu->isar.id_isar6; - t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); - t = FIELD_DP32(t, ID_ISAR6, DP, 1); - t = FIELD_DP32(t, ID_ISAR6, FHM, 1); - t = FIELD_DP32(t, ID_ISAR6, SB, 1); - t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); - t = FIELD_DP32(t, ID_ISAR6, BF16, 1); - t = FIELD_DP32(t, ID_ISAR6, I8MM, 1); + t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); /* FEAT_JSCVT */ + t = FIELD_DP32(t, ID_ISAR6, DP, 1); /* Feat_DotProd */ + t = FIELD_DP32(t, ID_ISAR6, FHM, 1); /* FEAT_FHM */ + t = FIELD_DP32(t, ID_ISAR6, SB, 1); /* FEAT_SB */ + t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); /* FEAT_SPECRES */ + t = FIELD_DP32(t, ID_ISAR6, BF16, 1); /* FEAT_AA32BF16 */ + t = FIELD_DP32(t, ID_ISAR6, I8MM, 1); /* FEAT_AA32I8MM */ cpu->isar.id_isar6 = t; t = cpu->isar.mvfr1; - t = FIELD_DP32(t, MVFR1, FPHP, 3); /* v8.2-FP16 */ - t = FIELD_DP32(t, MVFR1, SIMDHP, 2); /* v8.2-FP16 */ + t = FIELD_DP32(t, MVFR1, FPHP, 3); /* FEAT_FP16 */ + t = FIELD_DP32(t, MVFR1, SIMDHP, 2); /* FEAT_FP16 */ cpu->isar.mvfr1 = t; t = cpu->isar.mvfr2; - t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ - t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ + t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ + t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ cpu->isar.mvfr2 = t; t = cpu->isar.id_mmfr3; - t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */ + t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* FEAT_PAN2 */ cpu->isar.id_mmfr3 = t; t = cpu->isar.id_mmfr4; - t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ - t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ - t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* TTCNP */ - t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* TTS2UXN */ + t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* FEAT_AA32HPD */ + t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ + t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* FEAT_TTCNP */ + t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* FEAT_XNX*/ cpu->isar.id_mmfr4 = t; t = cpu->isar.id_pfr0; - t = FIELD_DP32(t, ID_PFR0, DIT, 1); + t = FIELD_DP32(t, ID_PFR0, DIT, 1); /* FEAT_DIT */ cpu->isar.id_pfr0 = t; t = cpu->isar.id_pfr2; - t = FIELD_DP32(t, ID_PFR2, SSBS, 1); + t = FIELD_DP32(t, ID_PFR2, SSBS, 1); /* FEAT_SSBS */ cpu->isar.id_pfr2 = t; t = cpu->isar.id_dfr0; - t = FIELD_DP32(t, ID_DFR0, PERFMON, 5); /* v8.4-PMU */ + t = FIELD_DP32(t, ID_DFR0, PERFMON, 5); /* FEAT_PMUv3p4 */ cpu->isar.id_dfr0 = t; } From b13c91c04b15f5216de9df3878da7dc4c1395979 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:28 -0500 Subject: [PATCH 205/935] target/arm: Use field names for manipulating EL2 and EL3 modes Use FIELD_DP{32,64} to manipulate id_pfr1 and id_aa64pfr0 during arm_cpu_realizefn. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-11-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 01176b2569..7995ff2712 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1801,11 +1801,13 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) */ unset_feature(env, ARM_FEATURE_EL3); - /* Disable the security extension feature bits in the processor feature - * registers as well. These are id_pfr1[7:4] and id_aa64pfr0[15:12]. + /* + * Disable the security extension feature bits in the processor + * feature registers as well. */ - cpu->isar.id_pfr1 &= ~0xf0; - cpu->isar.id_aa64pfr0 &= ~0xf000; + cpu->isar.id_pfr1 = FIELD_DP32(cpu->isar.id_pfr1, ID_PFR1, SECURITY, 0); + cpu->isar.id_aa64pfr0 = FIELD_DP64(cpu->isar.id_aa64pfr0, + ID_AA64PFR0, EL3, 0); } if (!cpu->has_el2) { @@ -1836,12 +1838,14 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } if (!arm_feature(env, ARM_FEATURE_EL2)) { - /* Disable the hypervisor feature bits in the processor feature - * registers if we don't have EL2. These are id_pfr1[15:12] and - * id_aa64pfr0_el1[11:8]. + /* + * Disable the hypervisor feature bits in the processor feature + * registers if we don't have EL2. */ - cpu->isar.id_aa64pfr0 &= ~0xf00; - cpu->isar.id_pfr1 &= ~0xf000; + cpu->isar.id_aa64pfr0 = FIELD_DP64(cpu->isar.id_aa64pfr0, + ID_AA64PFR0, EL2, 0); + cpu->isar.id_pfr1 = FIELD_DP32(cpu->isar.id_pfr1, + ID_PFR1, VIRTUALIZATION, 0); } #ifndef CONFIG_USER_ONLY From 033a4f15336646c5dbc07587a7924d71c12a9525 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:29 -0500 Subject: [PATCH 206/935] target/arm: Enable FEAT_Debugv8p2 for -cpu max The only portion of FEAT_Debugv8p2 that is relevant to QEMU is CONTEXTIDR_EL2, which is also conditionally implemented with FEAT_VHE. The rest of the debug extension concerns the External debug interface, which is outside the scope of QEMU. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-12-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- docs/system/arm/emulation.rst | 1 + target/arm/cpu.c | 1 + target/arm/cpu64.c | 1 + target/arm/cpu_tcg.c | 2 ++ 4 files changed, 5 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index c3bd0676a8..965f35d8c9 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -14,6 +14,7 @@ the following architecture extensions: - FEAT_BTI (Branch Target Identification) - FEAT_DIT (Data Independent Timing instructions) - FEAT_DPB (DC CVAP instruction) +- FEAT_Debugv8p2 (Debug changes for v8.2) - FEAT_DotProd (Advanced SIMD dot product instructions) - FEAT_FCMA (Floating-point complex number instructions) - FEAT_FHM (Floating-point half-precision multiplication instructions) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 7995ff2712..2667aaf28b 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1806,6 +1806,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) * feature registers as well. */ cpu->isar.id_pfr1 = FIELD_DP32(cpu->isar.id_pfr1, ID_PFR1, SECURITY, 0); + cpu->isar.id_dfr0 = FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, COPSDBG, 0); cpu->isar.id_aa64pfr0 = FIELD_DP64(cpu->isar.id_aa64pfr0, ID_AA64PFR0, EL3, 0); } diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 5fce40a6bc..202fd5c46e 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -799,6 +799,7 @@ static void aarch64_max_initfn(Object *obj) cpu->isar.id_aa64zfr0 = t; t = cpu->isar.id_aa64dfr0; + t = FIELD_DP64(t, ID_AA64DFR0, DEBUGVER, 8); /* FEAT_Debugv8p2 */ t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 5); /* FEAT_PMUv3p4 */ cpu->isar.id_aa64dfr0 = t; diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index bc8f9d0edf..b6fc3752f2 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -76,6 +76,8 @@ void aa32_max_features(ARMCPU *cpu) cpu->isar.id_pfr2 = t; t = cpu->isar.id_dfr0; + t = FIELD_DP32(t, ID_DFR0, COPDBG, 8); /* FEAT_Debugv8p2 */ + t = FIELD_DP32(t, ID_DFR0, COPSDBG, 8); /* FEAT_Debugv8p2 */ t = FIELD_DP32(t, ID_DFR0, PERFMON, 5); /* FEAT_PMUv3p4 */ cpu->isar.id_dfr0 = t; } From 8fc756b6be0d0de777b2092d324907ced7365543 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:30 -0500 Subject: [PATCH 207/935] target/arm: Enable FEAT_Debugv8p4 for -cpu max This extension concerns changes to the External Debug interface, with Secure and Non-secure access to the debug registers, and all of it is outside the scope of QEMU. Indicating support for this is mandatory with FEAT_SEL2, which we do implement. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-13-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- docs/system/arm/emulation.rst | 1 + target/arm/cpu64.c | 2 +- target/arm/cpu_tcg.c | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index 965f35d8c9..0acac6347c 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -15,6 +15,7 @@ the following architecture extensions: - FEAT_DIT (Data Independent Timing instructions) - FEAT_DPB (DC CVAP instruction) - FEAT_Debugv8p2 (Debug changes for v8.2) +- FEAT_Debugv8p4 (Debug changes for v8.4) - FEAT_DotProd (Advanced SIMD dot product instructions) - FEAT_FCMA (Floating-point complex number instructions) - FEAT_FHM (Floating-point half-precision multiplication instructions) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 202fd5c46e..88d3cef93e 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -799,7 +799,7 @@ static void aarch64_max_initfn(Object *obj) cpu->isar.id_aa64zfr0 = t; t = cpu->isar.id_aa64dfr0; - t = FIELD_DP64(t, ID_AA64DFR0, DEBUGVER, 8); /* FEAT_Debugv8p2 */ + t = FIELD_DP64(t, ID_AA64DFR0, DEBUGVER, 9); /* FEAT_Debugv8p4 */ t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 5); /* FEAT_PMUv3p4 */ cpu->isar.id_aa64dfr0 = t; diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index b6fc3752f2..337598e949 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -76,8 +76,8 @@ void aa32_max_features(ARMCPU *cpu) cpu->isar.id_pfr2 = t; t = cpu->isar.id_dfr0; - t = FIELD_DP32(t, ID_DFR0, COPDBG, 8); /* FEAT_Debugv8p2 */ - t = FIELD_DP32(t, ID_DFR0, COPSDBG, 8); /* FEAT_Debugv8p2 */ + t = FIELD_DP32(t, ID_DFR0, COPDBG, 9); /* FEAT_Debugv8p4 */ + t = FIELD_DP32(t, ID_DFR0, COPSDBG, 9); /* FEAT_Debugv8p4 */ t = FIELD_DP32(t, ID_DFR0, PERFMON, 5); /* FEAT_PMUv3p4 */ cpu->isar.id_dfr0 = t; } From 58e93b48aa1b9f0e6de7e57f6f68b6dda7a8198a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:31 -0500 Subject: [PATCH 208/935] target/arm: Add minimal RAS registers Add only the system registers required to implement zero error records. This means that all values for ERRSELR are out of range, which means that it and all of the indexed error record registers need not be implemented. Add the EL2 registers required for injecting virtual SError. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-14-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 5 +++ target/arm/helper.c | 84 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index ca01f909a8..a55980d66d 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -525,6 +525,11 @@ typedef struct CPUArchState { uint64_t tfsr_el[4]; /* tfsre0_el1 is index 0. */ uint64_t gcr_el1; uint64_t rgsr_el1; + + /* Minimal RAS registers */ + uint64_t disr_el1; + uint64_t vdisr_el2; + uint64_t vsesr_el2; } cp15; struct { diff --git a/target/arm/helper.c b/target/arm/helper.c index 7b31c71980..37c5e42bc0 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5980,6 +5980,87 @@ static const ARMCPRegInfo debug_lpae_cp_reginfo[] = { .access = PL0_R, .type = ARM_CP_CONST|ARM_CP_64BIT, .resetvalue = 0 }, }; +/* + * Check for traps to RAS registers, which are controlled + * by HCR_EL2.TERR and SCR_EL3.TERR. + */ +static CPAccessResult access_terr(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + int el = arm_current_el(env); + + if (el < 2 && (arm_hcr_el2_eff(env) & HCR_TERR)) { + return CP_ACCESS_TRAP_EL2; + } + if (el < 3 && (env->cp15.scr_el3 & SCR_TERR)) { + return CP_ACCESS_TRAP_EL3; + } + return CP_ACCESS_OK; +} + +static uint64_t disr_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + int el = arm_current_el(env); + + if (el < 2 && (arm_hcr_el2_eff(env) & HCR_AMO)) { + return env->cp15.vdisr_el2; + } + if (el < 3 && (env->cp15.scr_el3 & SCR_EA)) { + return 0; /* RAZ/WI */ + } + return env->cp15.disr_el1; +} + +static void disr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t val) +{ + int el = arm_current_el(env); + + if (el < 2 && (arm_hcr_el2_eff(env) & HCR_AMO)) { + env->cp15.vdisr_el2 = val; + return; + } + if (el < 3 && (env->cp15.scr_el3 & SCR_EA)) { + return; /* RAZ/WI */ + } + env->cp15.disr_el1 = val; +} + +/* + * Minimal RAS implementation with no Error Records. + * Which means that all of the Error Record registers: + * ERXADDR_EL1 + * ERXCTLR_EL1 + * ERXFR_EL1 + * ERXMISC0_EL1 + * ERXMISC1_EL1 + * ERXMISC2_EL1 + * ERXMISC3_EL1 + * ERXPFGCDN_EL1 (RASv1p1) + * ERXPFGCTL_EL1 (RASv1p1) + * ERXPFGF_EL1 (RASv1p1) + * ERXSTATUS_EL1 + * and + * ERRSELR_EL1 + * may generate UNDEFINED, which is the effect we get by not + * listing them at all. + */ +static const ARMCPRegInfo minimal_ras_reginfo[] = { + { .name = "DISR_EL1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 1, .opc2 = 1, + .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.disr_el1), + .readfn = disr_read, .writefn = disr_write, .raw_writefn = raw_write }, + { .name = "ERRIDR_EL1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 3, .opc2 = 0, + .access = PL1_R, .accessfn = access_terr, + .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "VDISR_EL2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 1, .opc2 = 1, + .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.vdisr_el2) }, + { .name = "VSESR_EL2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 3, + .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.vsesr_el2) }, +}; + /* Return the exception level to which exceptions should be taken * via SVEAccessTrap. If an exception should be routed through * AArch64.AdvSIMDFPAccessTrap, return 0; fp_exception_el should @@ -8217,6 +8298,9 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (cpu_isar_feature(aa64_ssbs, cpu)) { define_one_arm_cp_reg(cpu, &ssbs_reginfo); } + if (cpu_isar_feature(any_ras, cpu)) { + define_arm_cp_regs(cpu, minimal_ras_reginfo); + } if (cpu_isar_feature(aa64_vh, cpu) || cpu_isar_feature(aa64_debugv8p2, cpu)) { From da3d8b13624246702f7b8b88e37ee525a2f39ad2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:32 -0500 Subject: [PATCH 209/935] target/arm: Enable SCR and HCR bits for RAS Enable writes to the TERR and TEA bits when RAS is enabled. These bits are otherwise RES0. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-15-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target/arm/helper.c b/target/arm/helper.c index 37c5e42bc0..b6faebf4a7 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -1755,6 +1755,9 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) } valid_mask &= ~SCR_NET; + if (cpu_isar_feature(aa64_ras, cpu)) { + valid_mask |= SCR_TERR; + } if (cpu_isar_feature(aa64_lor, cpu)) { valid_mask |= SCR_TLOR; } @@ -1769,6 +1772,9 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) } } else { valid_mask &= ~(SCR_RW | SCR_ST); + if (cpu_isar_feature(aa32_ras, cpu)) { + valid_mask |= SCR_TERR; + } } if (!arm_feature(env, ARM_FEATURE_EL2)) { @@ -5126,6 +5132,9 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) if (cpu_isar_feature(aa64_vh, cpu)) { valid_mask |= HCR_E2H; } + if (cpu_isar_feature(aa64_ras, cpu)) { + valid_mask |= HCR_TERR | HCR_TEA; + } if (cpu_isar_feature(aa64_lor, cpu)) { valid_mask |= HCR_TLOR; } From 3c29632feba7724be447b621f3527136e5c32744 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:33 -0500 Subject: [PATCH 210/935] target/arm: Implement virtual SError exceptions Virtual SError exceptions are raised by setting HCR_EL2.VSE, and are routed to EL1 just like other virtual exceptions. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-16-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 38 +++++++++++++++++++++++++++++++++++++- target/arm/cpu.h | 2 ++ target/arm/helper.c | 40 +++++++++++++++++++++++++++++++++++++++- target/arm/internals.h | 8 ++++++++ target/arm/syndrome.h | 5 +++++ 5 files changed, 91 insertions(+), 2 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 2667aaf28b..652a84cf84 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -85,7 +85,7 @@ static bool arm_cpu_has_work(CPUState *cs) return (cpu->power_state != PSCI_OFF) && cs->interrupt_request & (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD - | CPU_INTERRUPT_VFIQ | CPU_INTERRUPT_VIRQ + | CPU_INTERRUPT_VFIQ | CPU_INTERRUPT_VIRQ | CPU_INTERRUPT_VSERR | CPU_INTERRUPT_EXITTB); } @@ -511,6 +511,12 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx, return false; } return !(env->daif & PSTATE_I); + case EXCP_VSERR: + if (!(hcr_el2 & HCR_AMO) || (hcr_el2 & HCR_TGE)) { + /* VIRQs are only taken when hypervized. */ + return false; + } + return !(env->daif & PSTATE_A); default: g_assert_not_reached(); } @@ -632,6 +638,17 @@ static bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request) goto found; } } + if (interrupt_request & CPU_INTERRUPT_VSERR) { + excp_idx = EXCP_VSERR; + target_el = 1; + if (arm_excp_unmasked(cs, excp_idx, target_el, + cur_el, secure, hcr_el2)) { + /* Taking a virtual abort clears HCR_EL2.VSE */ + env->cp15.hcr_el2 &= ~HCR_VSE; + cpu_reset_interrupt(cs, CPU_INTERRUPT_VSERR); + goto found; + } + } return false; found: @@ -684,6 +701,25 @@ void arm_cpu_update_vfiq(ARMCPU *cpu) } } +void arm_cpu_update_vserr(ARMCPU *cpu) +{ + /* + * Update the interrupt level for VSERR, which is the HCR_EL2.VSE bit. + */ + CPUARMState *env = &cpu->env; + CPUState *cs = CPU(cpu); + + bool new_state = env->cp15.hcr_el2 & HCR_VSE; + + if (new_state != ((cs->interrupt_request & CPU_INTERRUPT_VSERR) != 0)) { + if (new_state) { + cpu_interrupt(cs, CPU_INTERRUPT_VSERR); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_VSERR); + } + } +} + #ifndef CONFIG_USER_ONLY static void arm_cpu_set_irq(void *opaque, int irq, int level) { diff --git a/target/arm/cpu.h b/target/arm/cpu.h index a55980d66d..aade9237bd 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -56,6 +56,7 @@ #define EXCP_LSERR 21 /* v8M LSERR SecureFault */ #define EXCP_UNALIGNED 22 /* v7M UNALIGNED UsageFault */ #define EXCP_DIVBYZERO 23 /* v7M DIVBYZERO UsageFault */ +#define EXCP_VSERR 24 /* NB: add new EXCP_ defines to the array in arm_log_exception() too */ #define ARMV7M_EXCP_RESET 1 @@ -89,6 +90,7 @@ enum { #define CPU_INTERRUPT_FIQ CPU_INTERRUPT_TGT_EXT_1 #define CPU_INTERRUPT_VIRQ CPU_INTERRUPT_TGT_EXT_2 #define CPU_INTERRUPT_VFIQ CPU_INTERRUPT_TGT_EXT_3 +#define CPU_INTERRUPT_VSERR CPU_INTERRUPT_TGT_INT_0 /* The usual mapping for an AArch64 system register to its AArch32 * counterpart is for the 32 bit world to have access to the lower diff --git a/target/arm/helper.c b/target/arm/helper.c index b6faebf4a7..4857d2dbb8 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -1863,7 +1863,12 @@ static uint64_t isr_read(CPUARMState *env, const ARMCPRegInfo *ri) } } - /* External aborts are not possible in QEMU so A bit is always clear */ + if (hcr_el2 & HCR_AMO) { + if (cs->interrupt_request & CPU_INTERRUPT_VSERR) { + ret |= CPSR_A; + } + } + return ret; } @@ -5175,6 +5180,7 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) g_assert(qemu_mutex_iothread_locked()); arm_cpu_update_virq(cpu); arm_cpu_update_vfiq(cpu); + arm_cpu_update_vserr(cpu); } static void hcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) @@ -9331,6 +9337,7 @@ void arm_log_exception(CPUState *cs) [EXCP_LSERR] = "v8M LSERR UsageFault", [EXCP_UNALIGNED] = "v7M UNALIGNED UsageFault", [EXCP_DIVBYZERO] = "v7M DIVBYZERO UsageFault", + [EXCP_VSERR] = "Virtual SERR", }; if (idx >= 0 && idx < ARRAY_SIZE(excnames)) { @@ -9843,6 +9850,31 @@ static void arm_cpu_do_interrupt_aarch32(CPUState *cs) mask = CPSR_A | CPSR_I | CPSR_F; offset = 4; break; + case EXCP_VSERR: + { + /* + * Note that this is reported as a data abort, but the DFAR + * has an UNKNOWN value. Construct the SError syndrome from + * AET and ExT fields. + */ + ARMMMUFaultInfo fi = { .type = ARMFault_AsyncExternal, }; + + if (extended_addresses_enabled(env)) { + env->exception.fsr = arm_fi_to_lfsc(&fi); + } else { + env->exception.fsr = arm_fi_to_sfsc(&fi); + } + env->exception.fsr |= env->cp15.vsesr_el2 & 0xd000; + A32_BANKED_CURRENT_REG_SET(env, dfsr, env->exception.fsr); + qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x\n", + env->exception.fsr); + + new_mode = ARM_CPU_MODE_ABT; + addr = 0x10; + mask = CPSR_A | CPSR_I; + offset = 8; + } + break; case EXCP_SMC: new_mode = ARM_CPU_MODE_MON; addr = 0x08; @@ -10063,6 +10095,12 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) case EXCP_VFIQ: addr += 0x100; break; + case EXCP_VSERR: + addr += 0x180; + /* Construct the SError syndrome from IDS and ISS fields. */ + env->exception.syndrome = syn_serror(env->cp15.vsesr_el2 & 0x1ffffff); + env->cp15.esr_el[new_el] = env->exception.syndrome; + break; default: cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index); } diff --git a/target/arm/internals.h b/target/arm/internals.h index c563b3735f..6ca0e95746 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -947,6 +947,14 @@ void arm_cpu_update_virq(ARMCPU *cpu); */ void arm_cpu_update_vfiq(ARMCPU *cpu); +/** + * arm_cpu_update_vserr: Update CPU_INTERRUPT_VSERR bit + * + * Update the CPU_INTERRUPT_VSERR bit in cs->interrupt_request, + * following a change to the HCR_EL2.VSE bit. + */ +void arm_cpu_update_vserr(ARMCPU *cpu); + /** * arm_mmu_idx_el: * @env: The cpu environment diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index 8cde8e7243..0cb26dde7d 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -287,4 +287,9 @@ static inline uint32_t syn_pcalignment(void) return (EC_PCALIGNMENT << ARM_EL_EC_SHIFT) | ARM_EL_IL; } +static inline uint32_t syn_serror(uint32_t extra) +{ + return (EC_SERROR << ARM_EL_EC_SHIFT) | ARM_EL_IL | extra; +} + #endif /* TARGET_ARM_SYNDROME_H */ From 13954587ea240c305d43cffd1adc8959146f43fd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:34 -0500 Subject: [PATCH 211/935] target/arm: Implement ESB instruction Check for and defer any pending virtual SError. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-17-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/a32.decode | 16 ++++++++------ target/arm/helper.h | 1 + target/arm/op_helper.c | 43 ++++++++++++++++++++++++++++++++++++++ target/arm/t32.decode | 18 ++++++++-------- target/arm/translate-a64.c | 17 +++++++++++++++ target/arm/translate.c | 23 ++++++++++++++++++++ 6 files changed, 103 insertions(+), 15 deletions(-) diff --git a/target/arm/a32.decode b/target/arm/a32.decode index fcd8cd4f7d..f2ca480949 100644 --- a/target/arm/a32.decode +++ b/target/arm/a32.decode @@ -187,13 +187,17 @@ SMULTT .... 0001 0110 .... 0000 .... 1110 .... @rd0mn { { - YIELD ---- 0011 0010 0000 1111 ---- 0000 0001 - WFE ---- 0011 0010 0000 1111 ---- 0000 0010 - WFI ---- 0011 0010 0000 1111 ---- 0000 0011 + [ + YIELD ---- 0011 0010 0000 1111 ---- 0000 0001 + WFE ---- 0011 0010 0000 1111 ---- 0000 0010 + WFI ---- 0011 0010 0000 1111 ---- 0000 0011 - # TODO: Implement SEV, SEVL; may help SMP performance. - # SEV ---- 0011 0010 0000 1111 ---- 0000 0100 - # SEVL ---- 0011 0010 0000 1111 ---- 0000 0101 + # TODO: Implement SEV, SEVL; may help SMP performance. + # SEV ---- 0011 0010 0000 1111 ---- 0000 0100 + # SEVL ---- 0011 0010 0000 1111 ---- 0000 0101 + + ESB ---- 0011 0010 0000 1111 ---- 0001 0000 + ] # The canonical nop ends in 00000000, but the whole of the # rest of the space executes as nop if otherwise unsupported. diff --git a/target/arm/helper.h b/target/arm/helper.h index b463d9343b..b1334e0c42 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -54,6 +54,7 @@ DEF_HELPER_1(wfe, void, env) DEF_HELPER_1(yield, void, env) DEF_HELPER_1(pre_hvc, void, env) DEF_HELPER_2(pre_smc, void, env, i32) +DEF_HELPER_1(vesb, void, env) DEF_HELPER_3(cpsr_write, void, env, i32, i32) DEF_HELPER_2(cpsr_write_eret, void, env, i32) diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index 76499ffa14..390b6578a8 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -960,3 +960,46 @@ void HELPER(probe_access)(CPUARMState *env, target_ulong ptr, access_type, mmu_idx, ra); } } + +/* + * This function corresponds to AArch64.vESBOperation(). + * Note that the AArch32 version is not functionally different. + */ +void HELPER(vesb)(CPUARMState *env) +{ + /* + * The EL2Enabled() check is done inside arm_hcr_el2_eff, + * and will return HCR_EL2.VSE == 0, so nothing happens. + */ + uint64_t hcr = arm_hcr_el2_eff(env); + bool enabled = !(hcr & HCR_TGE) && (hcr & HCR_AMO); + bool pending = enabled && (hcr & HCR_VSE); + bool masked = (env->daif & PSTATE_A); + + /* If VSE pending and masked, defer the exception. */ + if (pending && masked) { + uint32_t syndrome; + + if (arm_el_is_aa64(env, 1)) { + /* Copy across IDS and ISS from VSESR. */ + syndrome = env->cp15.vsesr_el2 & 0x1ffffff; + } else { + ARMMMUFaultInfo fi = { .type = ARMFault_AsyncExternal }; + + if (extended_addresses_enabled(env)) { + syndrome = arm_fi_to_lfsc(&fi); + } else { + syndrome = arm_fi_to_sfsc(&fi); + } + /* Copy across AET and ExT from VSESR. */ + syndrome |= env->cp15.vsesr_el2 & 0xd000; + } + + /* Set VDISR_EL2.A along with the syndrome. */ + env->cp15.vdisr_el2 = syndrome | (1u << 31); + + /* Clear pending virtual SError */ + env->cp15.hcr_el2 &= ~HCR_VSE; + cpu_reset_interrupt(env_cpu(env), CPU_INTERRUPT_VSERR); + } +} diff --git a/target/arm/t32.decode b/target/arm/t32.decode index 78fadef9d6..f21ad0167a 100644 --- a/target/arm/t32.decode +++ b/target/arm/t32.decode @@ -364,17 +364,17 @@ CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm [ # Hints, and CPS { - YIELD 1111 0011 1010 1111 1000 0000 0000 0001 - WFE 1111 0011 1010 1111 1000 0000 0000 0010 - WFI 1111 0011 1010 1111 1000 0000 0000 0011 + [ + YIELD 1111 0011 1010 1111 1000 0000 0000 0001 + WFE 1111 0011 1010 1111 1000 0000 0000 0010 + WFI 1111 0011 1010 1111 1000 0000 0000 0011 - # TODO: Implement SEV, SEVL; may help SMP performance. - # SEV 1111 0011 1010 1111 1000 0000 0000 0100 - # SEVL 1111 0011 1010 1111 1000 0000 0000 0101 + # TODO: Implement SEV, SEVL; may help SMP performance. + # SEV 1111 0011 1010 1111 1000 0000 0000 0100 + # SEVL 1111 0011 1010 1111 1000 0000 0000 0101 - # For M-profile minimal-RAS ESB can be a NOP, which is the - # default behaviour since it is in the hint space. - # ESB 1111 0011 1010 1111 1000 0000 0001 0000 + ESB 1111 0011 1010 1111 1000 0000 0001 0000 + ] # The canonical nop ends in 0000 0000, but the whole rest # of the space is "reserved hint, behaves as nop". diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index b80313670f..5a02e076b7 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1454,6 +1454,23 @@ static void handle_hint(DisasContext *s, uint32_t insn, gen_helper_autib(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]); } break; + case 0b10000: /* ESB */ + /* Without RAS, we must implement this as NOP. */ + if (dc_isar_feature(aa64_ras, s)) { + /* + * QEMU does not have a source of physical SErrors, + * so we are only concerned with virtual SErrors. + * The pseudocode in the ARM for this case is + * if PSTATE.EL IN {EL0, EL1} && EL2Enabled() then + * AArch64.vESBOperation(); + * Most of the condition can be evaluated at translation time. + * Test for EL2 present, and defer test for SEL2 to runtime. + */ + if (s->current_el <= 1 && arm_dc_feature(s, ARM_FEATURE_EL2)) { + gen_helper_vesb(cpu_env); + } + } + break; case 0b11000: /* PACIAZ */ if (s->pauth_active) { gen_helper_pacia(cpu_X[30], cpu_env, cpu_X[30], diff --git a/target/arm/translate.c b/target/arm/translate.c index 4e19191ed5..87a899d638 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -6239,6 +6239,29 @@ static bool trans_WFI(DisasContext *s, arg_WFI *a) return true; } +static bool trans_ESB(DisasContext *s, arg_ESB *a) +{ + /* + * For M-profile, minimal-RAS ESB can be a NOP. + * Without RAS, we must implement this as NOP. + */ + if (!arm_dc_feature(s, ARM_FEATURE_M) && dc_isar_feature(aa32_ras, s)) { + /* + * QEMU does not have a source of physical SErrors, + * so we are only concerned with virtual SErrors. + * The pseudocode in the ARM for this case is + * if PSTATE.EL IN {EL0, EL1} && EL2Enabled() then + * AArch32.vESBOperation(); + * Most of the condition can be evaluated at translation time. + * Test for EL2 present, and defer test for SEL2 to runtime. + */ + if (s->current_el <= 1 && arm_dc_feature(s, ARM_FEATURE_EL2)) { + gen_helper_vesb(cpu_env); + } + } + return true; +} + static bool trans_NOP(DisasContext *s, arg_NOP *a) { return true; From e95c74c5e5522f6270092b788c3a96dfd8a93671 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:35 -0500 Subject: [PATCH 212/935] target/arm: Enable FEAT_RAS for -cpu max Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-18-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- docs/system/arm/emulation.rst | 1 + target/arm/cpu64.c | 1 + target/arm/cpu_tcg.c | 1 + 3 files changed, 3 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index 0acac6347c..8110408000 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -42,6 +42,7 @@ the following architecture extensions: - FEAT_PMULL (PMULL, PMULL2 instructions) - FEAT_PMUv3p1 (PMU Extensions v3.1) - FEAT_PMUv3p4 (PMU Extensions v3.4) +- FEAT_RAS (Reliability, availability, and serviceability) - FEAT_RDM (Advanced SIMD rounding double multiply accumulate instructions) - FEAT_RNG (Random number generator) - FEAT_SB (Speculation Barrier) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 88d3cef93e..35881c74b2 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -744,6 +744,7 @@ static void aarch64_max_initfn(Object *obj) t = cpu->isar.id_aa64pfr0; t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); /* FEAT_FP16 */ t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); /* FEAT_FP16 */ + t = FIELD_DP64(t, ID_AA64PFR0, RAS, 1); /* FEAT_RAS */ t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); /* FEAT_SEL2 */ t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); /* FEAT_DIT */ diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index 337598e949..c5cf7efe95 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -69,6 +69,7 @@ void aa32_max_features(ARMCPU *cpu) t = cpu->isar.id_pfr0; t = FIELD_DP32(t, ID_PFR0, DIT, 1); /* FEAT_DIT */ + t = FIELD_DP32(t, ID_PFR0, RAS, 1); /* FEAT_RAS */ cpu->isar.id_pfr0 = t; t = cpu->isar.id_pfr2; From 880cd10e84775d3cca599bf872a9362b02322747 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:36 -0500 Subject: [PATCH 213/935] target/arm: Enable FEAT_IESB for -cpu max This feature is AArch64 only, and applies to physical SErrors, which QEMU does not implement, thus the feature is a nop. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-19-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- docs/system/arm/emulation.rst | 1 + target/arm/cpu64.c | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index 8110408000..b200012d89 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -25,6 +25,7 @@ the following architecture extensions: - FEAT_FlagM2 (Enhancements to flag manipulation instructions) - FEAT_HPDS (Hierarchical permission disables) - FEAT_I8MM (AArch64 Int8 matrix multiplication instructions) +- FEAT_IESB (Implicit error synchronization event) - FEAT_JSCVT (JavaScript conversion instructions) - FEAT_LOR (Limited ordering regions) - FEAT_LPA (Large Physical Address space) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 35881c74b2..10410619f9 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -781,6 +781,7 @@ static void aarch64_max_initfn(Object *obj) t = cpu->isar.id_aa64mmfr2; t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* FEAT_TTCNP */ t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1); /* FEAT_UAO */ + t = FIELD_DP64(t, ID_AA64MMFR2, IESB, 1); /* FEAT_IESB */ t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1); /* FEAT_LVA */ t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* FEAT_TTST */ t = FIELD_DP64(t, ID_AA64MMFR2, TTL, 1); /* FEAT_TTL */ From 74b17e16695b93261b1c3ffb73031d574aba2b8e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:37 -0500 Subject: [PATCH 214/935] target/arm: Enable FEAT_CSV2 for -cpu max This extension concerns branch speculation, which TCG does not implement. Thus we can trivially enable this feature. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-20-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- docs/system/arm/emulation.rst | 1 + target/arm/cpu64.c | 1 + target/arm/cpu_tcg.c | 1 + 3 files changed, 3 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index b200012d89..b2a3e2a437 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -12,6 +12,7 @@ the following architecture extensions: - FEAT_BBM at level 2 (Translation table break-before-make levels) - FEAT_BF16 (AArch64 BFloat16 instructions) - FEAT_BTI (Branch Target Identification) +- FEAT_CSV2 (Cache speculation variant 2) - FEAT_DIT (Data Independent Timing instructions) - FEAT_DPB (DC CVAP instruction) - FEAT_Debugv8p2 (Debug changes for v8.2) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 10410619f9..25fe74f928 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -748,6 +748,7 @@ static void aarch64_max_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); /* FEAT_SEL2 */ t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); /* FEAT_DIT */ + t = FIELD_DP64(t, ID_AA64PFR0, CSV2, 1); /* FEAT_CSV2 */ cpu->isar.id_aa64pfr0 = t; t = cpu->isar.id_aa64pfr1; diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index c5cf7efe95..762b961707 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -68,6 +68,7 @@ void aa32_max_features(ARMCPU *cpu) cpu->isar.id_mmfr4 = t; t = cpu->isar.id_pfr0; + t = FIELD_DP32(t, ID_PFR0, CSV2, 2); /* FEAT_CVS2 */ t = FIELD_DP32(t, ID_PFR0, DIT, 1); /* FEAT_DIT */ t = FIELD_DP32(t, ID_PFR0, RAS, 1); /* FEAT_RAS */ cpu->isar.id_pfr0 = t; From 7cb1e61851332ea661d4ef6c1d958e3cdbffe2d8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:38 -0500 Subject: [PATCH 215/935] target/arm: Enable FEAT_CSV2_2 for -cpu max There is no branch prediction in TCG, therefore there is no need to actually include the context number into the predictor. Therefore all we need to do is add the state for SCXTNUM_ELx. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-21-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- docs/system/arm/emulation.rst | 3 ++ target/arm/cpu.c | 5 +++ target/arm/cpu.h | 16 +++++++++ target/arm/cpu64.c | 3 +- target/arm/helper.c | 61 ++++++++++++++++++++++++++++++++++- 5 files changed, 86 insertions(+), 2 deletions(-) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index b2a3e2a437..9765ee3eaf 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -13,6 +13,9 @@ the following architecture extensions: - FEAT_BF16 (AArch64 BFloat16 instructions) - FEAT_BTI (Branch Target Identification) - FEAT_CSV2 (Cache speculation variant 2) +- FEAT_CSV2_1p1 (Cache speculation variant 2, version 1.1) +- FEAT_CSV2_1p2 (Cache speculation variant 2, version 1.2) +- FEAT_CSV2_2 (Cache speculation variant 2, version 2) - FEAT_DIT (Data Independent Timing instructions) - FEAT_DPB (DC CVAP instruction) - FEAT_Debugv8p2 (Debug changes for v8.2) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 652a84cf84..59df597e05 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -230,6 +230,11 @@ static void arm_cpu_reset(DeviceState *dev) */ env->cp15.gcr_el1 = 0x1ffff; } + /* + * Disable access to SCXTNUM_EL0 from CSV2_1p2. + * This is not yet exposed from the Linux kernel in any way. + */ + env->cp15.sctlr_el[1] |= SCTLR_TSCXT; #else /* Reset into the highest available EL */ if (arm_feature(env, ARM_FEATURE_EL3)) { diff --git a/target/arm/cpu.h b/target/arm/cpu.h index aade9237bd..18ca61e8e2 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -688,6 +688,8 @@ typedef struct CPUArchState { ARMPACKey apdb; ARMPACKey apga; } keys; + + uint64_t scxtnum_el[4]; #endif #if defined(CONFIG_USER_ONLY) @@ -1211,6 +1213,7 @@ void pmu_init(ARMCPU *cpu); #define SCTLR_WXN (1U << 19) #define SCTLR_ST (1U << 20) /* up to ??, RAZ in v6 */ #define SCTLR_UWXN (1U << 20) /* v7 onward, AArch32 only */ +#define SCTLR_TSCXT (1U << 20) /* FEAT_CSV2_1p2, AArch64 only */ #define SCTLR_FI (1U << 21) /* up to v7, v8 RES0 */ #define SCTLR_IESB (1U << 21) /* v8.2-IESB, AArch64 only */ #define SCTLR_U (1U << 22) /* up to v6, RAO in v7 */ @@ -4022,6 +4025,19 @@ static inline bool isar_feature_aa64_dit(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, DIT) != 0; } +static inline bool isar_feature_aa64_scxtnum(const ARMISARegisters *id) +{ + int key = FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, CSV2); + if (key >= 2) { + return true; /* FEAT_CSV2_2 */ + } + if (key == 1) { + key = FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, CSV2_FRAC); + return key >= 2; /* FEAT_CSV2_1p2 */ + } + return false; +} + static inline bool isar_feature_aa64_ssbs(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SSBS) != 0; diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 25fe74f928..07b44a62be 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -748,7 +748,7 @@ static void aarch64_max_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); /* FEAT_SEL2 */ t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); /* FEAT_DIT */ - t = FIELD_DP64(t, ID_AA64PFR0, CSV2, 1); /* FEAT_CSV2 */ + t = FIELD_DP64(t, ID_AA64PFR0, CSV2, 2); /* FEAT_CSV2_2 */ cpu->isar.id_aa64pfr0 = t; t = cpu->isar.id_aa64pfr1; @@ -760,6 +760,7 @@ static void aarch64_max_initfn(Object *obj) * we do for EL2 with the virtualization=on property. */ t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); /* FEAT_MTE3 */ + t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_2 */ cpu->isar.id_aa64pfr1 = t; t = cpu->isar.id_aa64mmfr0; diff --git a/target/arm/helper.c b/target/arm/helper.c index 4857d2dbb8..432bd81919 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -1770,6 +1770,9 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) if (cpu_isar_feature(aa64_mte, cpu)) { valid_mask |= SCR_ATA; } + if (cpu_isar_feature(aa64_scxtnum, cpu)) { + valid_mask |= SCR_ENSCXT; + } } else { valid_mask &= ~(SCR_RW | SCR_ST); if (cpu_isar_feature(aa32_ras, cpu)) { @@ -5149,6 +5152,9 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) if (cpu_isar_feature(aa64_mte, cpu)) { valid_mask |= HCR_ATA | HCR_DCT | HCR_TID5; } + if (cpu_isar_feature(aa64_scxtnum, cpu)) { + valid_mask |= HCR_ENSCXT; + } } /* Clear RES0 bits. */ @@ -5800,6 +5806,10 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) { K(3, 0, 5, 6, 0), K(3, 4, 5, 6, 0), K(3, 5, 5, 6, 0), "TFSR_EL1", "TFSR_EL2", "TFSR_EL12", isar_feature_aa64_mte }, + { K(3, 0, 13, 0, 7), K(3, 4, 13, 0, 7), K(3, 5, 13, 0, 7), + "SCXTNUM_EL1", "SCXTNUM_EL2", "SCXTNUM_EL12", + isar_feature_aa64_scxtnum }, + /* TODO: ARMv8.2-SPE -- PMSCR_EL2 */ /* TODO: ARMv8.4-Trace -- TRFCR_EL2 */ }; @@ -7223,7 +7233,52 @@ static const ARMCPRegInfo mte_el0_cacheop_reginfo[] = { }, }; -#endif +static CPAccessResult access_scxtnum(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + uint64_t hcr = arm_hcr_el2_eff(env); + int el = arm_current_el(env); + + if (el == 0 && !((hcr & HCR_E2H) && (hcr & HCR_TGE))) { + if (env->cp15.sctlr_el[1] & SCTLR_TSCXT) { + if (hcr & HCR_TGE) { + return CP_ACCESS_TRAP_EL2; + } + return CP_ACCESS_TRAP; + } + } else if (el < 2 && (env->cp15.sctlr_el[2] & SCTLR_TSCXT)) { + return CP_ACCESS_TRAP_EL2; + } + if (el < 2 && arm_is_el2_enabled(env) && !(hcr & HCR_ENSCXT)) { + return CP_ACCESS_TRAP_EL2; + } + if (el < 3 + && arm_feature(env, ARM_FEATURE_EL3) + && !(env->cp15.scr_el3 & SCR_ENSCXT)) { + return CP_ACCESS_TRAP_EL3; + } + return CP_ACCESS_OK; +} + +static const ARMCPRegInfo scxtnum_reginfo[] = { + { .name = "SCXTNUM_EL0", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 3, .crn = 13, .crm = 0, .opc2 = 7, + .access = PL0_RW, .accessfn = access_scxtnum, + .fieldoffset = offsetof(CPUARMState, scxtnum_el[0]) }, + { .name = "SCXTNUM_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 7, + .access = PL1_RW, .accessfn = access_scxtnum, + .fieldoffset = offsetof(CPUARMState, scxtnum_el[1]) }, + { .name = "SCXTNUM_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 7, + .access = PL2_RW, .accessfn = access_scxtnum, + .fieldoffset = offsetof(CPUARMState, scxtnum_el[2]) }, + { .name = "SCXTNUM_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 13, .crm = 0, .opc2 = 7, + .access = PL3_RW, + .fieldoffset = offsetof(CPUARMState, scxtnum_el[3]) }, +}; +#endif /* TARGET_AARCH64 */ static CPAccessResult access_predinv(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) @@ -8365,6 +8420,10 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_arm_cp_regs(cpu, mte_tco_ro_reginfo); define_arm_cp_regs(cpu, mte_el0_cacheop_reginfo); } + + if (cpu_isar_feature(aa64_scxtnum, cpu)) { + define_arm_cp_regs(cpu, scxtnum_reginfo); + } #endif if (cpu_isar_feature(any_predinv, cpu)) { From 3082b86b107ec7a26352bd18ada295ac1cc4faca Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:39 -0500 Subject: [PATCH 216/935] target/arm: Enable FEAT_CSV3 for -cpu max This extension concerns cache speculation, which TCG does not implement. Thus we can trivially enable this feature. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-22-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- docs/system/arm/emulation.rst | 1 + target/arm/cpu64.c | 1 + target/arm/cpu_tcg.c | 1 + 3 files changed, 3 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index 9765ee3eaf..48522b8e1c 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -16,6 +16,7 @@ the following architecture extensions: - FEAT_CSV2_1p1 (Cache speculation variant 2, version 1.1) - FEAT_CSV2_1p2 (Cache speculation variant 2, version 1.2) - FEAT_CSV2_2 (Cache speculation variant 2, version 2) +- FEAT_CSV3 (Cache speculation variant 3) - FEAT_DIT (Data Independent Timing instructions) - FEAT_DPB (DC CVAP instruction) - FEAT_Debugv8p2 (Debug changes for v8.2) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 07b44a62be..40f77defb5 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -749,6 +749,7 @@ static void aarch64_max_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); /* FEAT_SEL2 */ t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); /* FEAT_DIT */ t = FIELD_DP64(t, ID_AA64PFR0, CSV2, 2); /* FEAT_CSV2_2 */ + t = FIELD_DP64(t, ID_AA64PFR0, CSV3, 1); /* FEAT_CSV3 */ cpu->isar.id_aa64pfr0 = t; t = cpu->isar.id_aa64pfr1; diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index 762b961707..ea4eccddc3 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -74,6 +74,7 @@ void aa32_max_features(ARMCPU *cpu) cpu->isar.id_pfr0 = t; t = cpu->isar.id_pfr2; + t = FIELD_DP32(t, ID_PFR2, CSV3, 1); /* FEAT_CSV3 */ t = FIELD_DP32(t, ID_PFR2, SSBS, 1); /* FEAT_SSBS */ cpu->isar.id_pfr2 = t; From 6d9650191ae301dc545dd9fd0727c57ec935503e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:40 -0500 Subject: [PATCH 217/935] target/arm: Enable FEAT_DGH for -cpu max This extension concerns not merging memory access, which TCG does not implement. Thus we can trivially enable this feature. Add a comment to handle_hint for the DGH instruction, but no code. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-23-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- docs/system/arm/emulation.rst | 1 + target/arm/cpu64.c | 1 + target/arm/translate-a64.c | 1 + 3 files changed, 3 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index 48522b8e1c..8ed466bf68 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -17,6 +17,7 @@ the following architecture extensions: - FEAT_CSV2_1p2 (Cache speculation variant 2, version 1.2) - FEAT_CSV2_2 (Cache speculation variant 2, version 2) - FEAT_CSV3 (Cache speculation variant 3) +- FEAT_DGH (Data gathering hint) - FEAT_DIT (Data Independent Timing instructions) - FEAT_DPB (DC CVAP instruction) - FEAT_Debugv8p2 (Debug changes for v8.2) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 40f77defb5..f55121060d 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -738,6 +738,7 @@ static void aarch64_max_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1); /* FEAT_SB */ t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1); /* FEAT_SPECRES */ t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 1); /* FEAT_BF16 */ + t = FIELD_DP64(t, ID_AA64ISAR1, DGH, 1); /* FEAT_DGH */ t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 1); /* FEAT_I8MM */ cpu->isar.id_aa64isar1 = t; diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 5a02e076b7..6a27234a5c 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1427,6 +1427,7 @@ static void handle_hint(DisasContext *s, uint32_t insn, break; case 0b00100: /* SEV */ case 0b00101: /* SEVL */ + case 0b00110: /* DGH */ /* we treat all as NOP at least for now */ break; case 0b00111: /* XPACLRI */ From 2f6283fc8e5219ce5f82ba60216ed5145a246470 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:41 -0500 Subject: [PATCH 218/935] target/arm: Define cortex-a76 Enable the a76 for virt and sbsa board use. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-24-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- docs/system/arm/virt.rst | 1 + hw/arm/sbsa-ref.c | 1 + hw/arm/virt.c | 1 + target/arm/cpu64.c | 66 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+) diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst index 5fe045cbf0..3e264d85af 100644 --- a/docs/system/arm/virt.rst +++ b/docs/system/arm/virt.rst @@ -55,6 +55,7 @@ Supported guest CPU types: - ``cortex-a53`` (64-bit) - ``cortex-a57`` (64-bit) - ``cortex-a72`` (64-bit) +- ``cortex-a76`` (64-bit) - ``a64fx`` (64-bit) - ``host`` (with KVM only) - ``max`` (same as ``host`` for KVM; best possible emulation with TCG) diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index 2387401963..2ddde88f5e 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -145,6 +145,7 @@ static const int sbsa_ref_irqmap[] = { static const char * const valid_cpus[] = { ARM_CPU_TYPE_NAME("cortex-a57"), ARM_CPU_TYPE_NAME("cortex-a72"), + ARM_CPU_TYPE_NAME("cortex-a76"), ARM_CPU_TYPE_NAME("max"), }; diff --git a/hw/arm/virt.c b/hw/arm/virt.c index f94278935f..12bc2318ec 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -202,6 +202,7 @@ static const char *valid_cpus[] = { ARM_CPU_TYPE_NAME("cortex-a53"), ARM_CPU_TYPE_NAME("cortex-a57"), ARM_CPU_TYPE_NAME("cortex-a72"), + ARM_CPU_TYPE_NAME("cortex-a76"), ARM_CPU_TYPE_NAME("a64fx"), ARM_CPU_TYPE_NAME("host"), ARM_CPU_TYPE_NAME("max"), diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index f55121060d..adfe6b26be 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -194,6 +194,71 @@ static void aarch64_a72_initfn(Object *obj) define_cortex_a72_a57_a53_cp_reginfo(cpu); } +static void aarch64_a76_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a76"; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_AARCH64); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + + /* Ordered by B2.4 AArch64 registers by functional group */ + cpu->clidr = 0x82000023; + cpu->ctr = 0x8444C004; + cpu->dcz_blocksize = 4; + cpu->isar.id_aa64dfr0 = 0x0000000010305408ull; + cpu->isar.id_aa64isar0 = 0x0000100010211120ull; + cpu->isar.id_aa64isar1 = 0x0000000000100001ull; + cpu->isar.id_aa64mmfr0 = 0x0000000000101122ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; + cpu->isar.id_aa64pfr0 = 0x1100000010111112ull; /* GIC filled in later */ + cpu->isar.id_aa64pfr1 = 0x0000000000000010ull; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_dfr0 = 0x04010088; + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232042; + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00010142; + cpu->isar.id_isar5 = 0x01011121; + cpu->isar.id_isar6 = 0x00000010; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02122211; + cpu->isar.id_mmfr4 = 0x00021110; + cpu->isar.id_pfr0 = 0x10010131; + cpu->isar.id_pfr1 = 0x00010000; /* GIC filled in later */ + cpu->isar.id_pfr2 = 0x00000011; + cpu->midr = 0x414fd0b1; /* r4p1 */ + cpu->revidr = 0; + + /* From B2.18 CCSIDR_EL1 */ + cpu->ccsidr[0] = 0x701fe01a; /* 64KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe01a; /* 64KB L1 icache */ + cpu->ccsidr[2] = 0x707fe03a; /* 512KB L2 cache */ + + /* From B2.93 SCTLR_EL3 */ + cpu->reset_sctlr = 0x30c50838; + + /* From B4.23 ICH_VTR_EL2 */ + cpu->gic_num_lrs = 4; + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + + /* From B5.1 AdvSIMD AArch64 register summary */ + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x13211111; + cpu->isar.mvfr2 = 0x00000043; +} + void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) { /* @@ -881,6 +946,7 @@ static const ARMCPUInfo aarch64_cpus[] = { { .name = "cortex-a57", .initfn = aarch64_a57_initfn }, { .name = "cortex-a53", .initfn = aarch64_a53_initfn }, { .name = "cortex-a72", .initfn = aarch64_a72_initfn }, + { .name = "cortex-a76", .initfn = aarch64_a76_initfn }, { .name = "a64fx", .initfn = aarch64_a64fx_initfn }, { .name = "max", .initfn = aarch64_max_initfn }, #if defined(CONFIG_KVM) || defined(CONFIG_HVF) From 5db6de806ab6f6db457300fc527f9b367fd97f21 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 May 2022 13:02:42 -0500 Subject: [PATCH 219/935] target/arm: Define neoverse-n1 Enable the n1 for virt and sbsa board use. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220506180242.216785-25-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- docs/system/arm/virt.rst | 1 + hw/arm/sbsa-ref.c | 1 + hw/arm/virt.c | 1 + target/arm/cpu64.c | 66 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+) diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst index 3e264d85af..3d1058a80c 100644 --- a/docs/system/arm/virt.rst +++ b/docs/system/arm/virt.rst @@ -58,6 +58,7 @@ Supported guest CPU types: - ``cortex-a76`` (64-bit) - ``a64fx`` (64-bit) - ``host`` (with KVM only) +- ``neoverse-n1`` (64-bit) - ``max`` (same as ``host`` for KVM; best possible emulation with TCG) Note that the default is ``cortex-a15``, so for an AArch64 guest you must diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index 2ddde88f5e..dac8860f2d 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -146,6 +146,7 @@ static const char * const valid_cpus[] = { ARM_CPU_TYPE_NAME("cortex-a57"), ARM_CPU_TYPE_NAME("cortex-a72"), ARM_CPU_TYPE_NAME("cortex-a76"), + ARM_CPU_TYPE_NAME("neoverse-n1"), ARM_CPU_TYPE_NAME("max"), }; diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 12bc2318ec..da7e3ede56 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -204,6 +204,7 @@ static const char *valid_cpus[] = { ARM_CPU_TYPE_NAME("cortex-a72"), ARM_CPU_TYPE_NAME("cortex-a76"), ARM_CPU_TYPE_NAME("a64fx"), + ARM_CPU_TYPE_NAME("neoverse-n1"), ARM_CPU_TYPE_NAME("host"), ARM_CPU_TYPE_NAME("max"), }; diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index adfe6b26be..04427e073f 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -259,6 +259,71 @@ static void aarch64_a76_initfn(Object *obj) cpu->isar.mvfr2 = 0x00000043; } +static void aarch64_neoverse_n1_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,neoverse-n1"; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_AARCH64); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + + /* Ordered by B2.4 AArch64 registers by functional group */ + cpu->clidr = 0x82000023; + cpu->ctr = 0x8444c004; + cpu->dcz_blocksize = 4; + cpu->isar.id_aa64dfr0 = 0x0000000110305408ull; + cpu->isar.id_aa64isar0 = 0x0000100010211120ull; + cpu->isar.id_aa64isar1 = 0x0000000000100001ull; + cpu->isar.id_aa64mmfr0 = 0x0000000000101125ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; + cpu->isar.id_aa64pfr0 = 0x1100000010111112ull; /* GIC filled in later */ + cpu->isar.id_aa64pfr1 = 0x0000000000000020ull; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_dfr0 = 0x04010088; + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232042; + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00010142; + cpu->isar.id_isar5 = 0x01011121; + cpu->isar.id_isar6 = 0x00000010; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02122211; + cpu->isar.id_mmfr4 = 0x00021110; + cpu->isar.id_pfr0 = 0x10010131; + cpu->isar.id_pfr1 = 0x00010000; /* GIC filled in later */ + cpu->isar.id_pfr2 = 0x00000011; + cpu->midr = 0x414fd0c1; /* r4p1 */ + cpu->revidr = 0; + + /* From B2.23 CCSIDR_EL1 */ + cpu->ccsidr[0] = 0x701fe01a; /* 64KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe01a; /* 64KB L1 icache */ + cpu->ccsidr[2] = 0x70ffe03a; /* 1MB L2 cache */ + + /* From B2.98 SCTLR_EL3 */ + cpu->reset_sctlr = 0x30c50838; + + /* From B4.23 ICH_VTR_EL2 */ + cpu->gic_num_lrs = 4; + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + + /* From B5.1 AdvSIMD AArch64 register summary */ + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x13211111; + cpu->isar.mvfr2 = 0x00000043; +} + void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) { /* @@ -948,6 +1013,7 @@ static const ARMCPUInfo aarch64_cpus[] = { { .name = "cortex-a72", .initfn = aarch64_a72_initfn }, { .name = "cortex-a76", .initfn = aarch64_a76_initfn }, { .name = "a64fx", .initfn = aarch64_a64fx_initfn }, + { .name = "neoverse-n1", .initfn = aarch64_neoverse_n1_initfn }, { .name = "max", .initfn = aarch64_max_initfn }, #if defined(CONFIG_KVM) || defined(CONFIG_HVF) { .name = "host", .initfn = aarch64_host_initfn }, From 90ea2cceb286c66b8460725f5573d8a157e65bdf Mon Sep 17 00:00:00 2001 From: Leif Lindholm Date: Thu, 5 May 2022 12:39:47 +0100 Subject: [PATCH 220/935] hw/arm: add versioning to sbsa-ref machine DT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sbsa-ref machine is continuously evolving. Some of the changes we want to make in the near future, to align with real components (e.g. the GIC-700), will break compatibility for existing firmware. Introduce two new properties to the DT generated on machine generation: - machine-version-major To be incremented when a platform change makes the machine incompatible with existing firmware. - machine-version-minor To be incremented when functionality is added to the machine without causing incompatibility with existing firmware. to be reset to 0 when machine-version-major is incremented. This versioning scheme is *neither*: - A QEMU versioned machine type; a given version of QEMU will emulate a given version of the platform. - A reflection of level of SBSA (now SystemReady SR) support provided. The version will increment on guest-visible functional changes only, akin to a revision ID register found on a physical platform. These properties are both introduced with the value 0. (Hence, a machine where the DT is lacking these nodes is equivalent to version 0.0.) Signed-off-by: Leif Lindholm Message-id: 20220505113947.75714-1-quic_llindhol@quicinc.com Cc: Peter Maydell Cc: Radoslaw Biernacki Cc: Cédric Le Goater Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/sbsa-ref.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index dac8860f2d..4bb444684f 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -192,6 +192,20 @@ static void create_fdt(SBSAMachineState *sms) qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2); qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2); + /* + * This versioning scheme is for informing platform fw only. It is neither: + * - A QEMU versioned machine type; a given version of QEMU will emulate + * a given version of the platform. + * - A reflection of level of SBSA (now SystemReady SR) support provided. + * + * machine-version-major: updated when changes breaking fw compatibility + * are introduced. + * machine-version-minor: updated when features are added that don't break + * fw compatibility. + */ + qemu_fdt_setprop_cell(fdt, "/", "machine-version-major", 0); + qemu_fdt_setprop_cell(fdt, "/", "machine-version-minor", 0); + if (ms->numa_state->have_numa_distance) { int size = nb_numa_nodes * nb_numa_nodes * 3 * sizeof(uint32_t); uint32_t *matrix = g_malloc0(size); From 1dcf7001d4bae651129d46d5628b29e93a411d0b Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 3 May 2022 22:02:59 +0800 Subject: [PATCH 221/935] qapi/machine.json: Add cluster-id This adds cluster-id in CPU instance properties, which will be used by arm/virt machine. Besides, the cluster-id is also verified or dumped in various spots: * hw/core/machine.c::machine_set_cpu_numa_node() to associate CPU with its NUMA node. * hw/core/machine.c::machine_numa_finish_cpu_init() to record CPU slots with no NUMA mapping set. * hw/core/machine-hmp-cmds.c::hmp_hotpluggable_cpus() to dump cluster-id. Signed-off-by: Gavin Shan Reviewed-by: Yanan Wang Acked-by: Igor Mammedov Message-id: 20220503140304.855514-2-gshan@redhat.com Signed-off-by: Peter Maydell --- hw/core/machine-hmp-cmds.c | 4 ++++ hw/core/machine.c | 16 ++++++++++++++++ qapi/machine.json | 6 ++++-- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c index 4e2f319aeb..5cb5eecbfc 100644 --- a/hw/core/machine-hmp-cmds.c +++ b/hw/core/machine-hmp-cmds.c @@ -77,6 +77,10 @@ void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict) if (c->has_die_id) { monitor_printf(mon, " die-id: \"%" PRIu64 "\"\n", c->die_id); } + if (c->has_cluster_id) { + monitor_printf(mon, " cluster-id: \"%" PRIu64 "\"\n", + c->cluster_id); + } if (c->has_core_id) { monitor_printf(mon, " core-id: \"%" PRIu64 "\"\n", c->core_id); } diff --git a/hw/core/machine.c b/hw/core/machine.c index cb9bbc844d..700c1e76b8 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -682,6 +682,11 @@ void machine_set_cpu_numa_node(MachineState *machine, return; } + if (props->has_cluster_id && !slot->props.has_cluster_id) { + error_setg(errp, "cluster-id is not supported"); + return; + } + if (props->has_socket_id && !slot->props.has_socket_id) { error_setg(errp, "socket-id is not supported"); return; @@ -701,6 +706,11 @@ void machine_set_cpu_numa_node(MachineState *machine, continue; } + if (props->has_cluster_id && + props->cluster_id != slot->props.cluster_id) { + continue; + } + if (props->has_die_id && props->die_id != slot->props.die_id) { continue; } @@ -995,6 +1005,12 @@ static char *cpu_slot_to_string(const CPUArchId *cpu) } g_string_append_printf(s, "die-id: %"PRId64, cpu->props.die_id); } + if (cpu->props.has_cluster_id) { + if (s->len) { + g_string_append_printf(s, ", "); + } + g_string_append_printf(s, "cluster-id: %"PRId64, cpu->props.cluster_id); + } if (cpu->props.has_core_id) { if (s->len) { g_string_append_printf(s, ", "); diff --git a/qapi/machine.json b/qapi/machine.json index d25a481ce4..4c417e32a5 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -868,10 +868,11 @@ # @node-id: NUMA node ID the CPU belongs to # @socket-id: socket number within node/board the CPU belongs to # @die-id: die number within socket the CPU belongs to (since 4.1) -# @core-id: core number within die the CPU belongs to +# @cluster-id: cluster number within die the CPU belongs to (since 7.1) +# @core-id: core number within cluster the CPU belongs to # @thread-id: thread number within core the CPU belongs to # -# Note: currently there are 5 properties that could be present +# Note: currently there are 6 properties that could be present # but management should be prepared to pass through other # properties with device_add command to allow for future # interface extension. This also requires the filed names to be kept in @@ -883,6 +884,7 @@ 'data': { '*node-id': 'int', '*socket-id': 'int', '*die-id': 'int', + '*cluster-id': 'int', '*core-id': 'int', '*thread-id': 'int' } From ac7199a2523ce2ccf8e685087a5d177eeca89b09 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 3 May 2022 22:03:00 +0800 Subject: [PATCH 222/935] qtest/numa-test: Specify CPU topology in aarch64_numa_cpu() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CPU topology isn't enabled on arm/virt machine yet, but we're going to do it in next patch. After the CPU topology is enabled by next patch, "thread-id=1" becomes invalid because the CPU core is preferred on arm/virt machine. It means these two CPUs have 0/1 as their core IDs, but their thread IDs are all 0. It will trigger test failure as the following message indicates: [14/21 qemu:qtest+qtest-aarch64 / qtest-aarch64/numa-test ERROR 1.48s killed by signal 6 SIGABRT >>> G_TEST_DBUS_DAEMON=/home/gavin/sandbox/qemu.main/tests/dbus-vmstate-daemon.sh \ QTEST_QEMU_STORAGE_DAEMON_BINARY=./storage-daemon/qemu-storage-daemon \ QTEST_QEMU_BINARY=./qemu-system-aarch64 \ QTEST_QEMU_IMG=./qemu-img MALLOC_PERTURB_=83 \ /home/gavin/sandbox/qemu.main/build/tests/qtest/numa-test --tap -k ―――――――――――――――――――――――――――――――――――――――――――――― stderr: qemu-system-aarch64: -numa cpu,node-id=0,thread-id=1: no match found This fixes the issue by providing comprehensive SMP configurations in aarch64_numa_cpu(). The SMP configurations aren't used before the CPU topology is enabled in next patch. Signed-off-by: Gavin Shan Reviewed-by: Yanan Wang Message-id: 20220503140304.855514-3-gshan@redhat.com Signed-off-by: Peter Maydell --- tests/qtest/numa-test.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/qtest/numa-test.c b/tests/qtest/numa-test.c index 749429dd27..976526e527 100644 --- a/tests/qtest/numa-test.c +++ b/tests/qtest/numa-test.c @@ -223,7 +223,8 @@ static void aarch64_numa_cpu(const void *data) QTestState *qts; g_autofree char *cli = NULL; - cli = make_cli(data, "-machine smp.cpus=2 " + cli = make_cli(data, "-machine " + "smp.cpus=2,smp.sockets=1,smp.clusters=1,smp.cores=1,smp.threads=2 " "-numa node,nodeid=0,memdev=ram -numa node,nodeid=1 " "-numa cpu,node-id=1,thread-id=0 " "-numa cpu,node-id=0,thread-id=1"); From c9ec4cb5e4936f980889e717524e73896b0200ed Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 3 May 2022 22:03:01 +0800 Subject: [PATCH 223/935] hw/arm/virt: Consider SMP configuration in CPU topology Currently, the SMP configuration isn't considered when the CPU topology is populated. In this case, it's impossible to provide the default CPU-to-NUMA mapping or association based on the socket ID of the given CPU. This takes account of SMP configuration when the CPU topology is populated. The die ID for the given CPU isn't assigned since it's not supported on arm/virt machine. Besides, the used SMP configuration in qtest/numa-test/aarch64_numa_cpu() is corrcted to avoid testing failure Signed-off-by: Gavin Shan Reviewed-by: Yanan Wang Acked-by: Igor Mammedov Message-id: 20220503140304.855514-4-gshan@redhat.com Signed-off-by: Peter Maydell --- hw/arm/virt.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index da7e3ede56..c25023a083 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2562,6 +2562,7 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) int n; unsigned int max_cpus = ms->smp.max_cpus; VirtMachineState *vms = VIRT_MACHINE(ms); + MachineClass *mc = MACHINE_GET_CLASS(vms); if (ms->possible_cpus) { assert(ms->possible_cpus->len == max_cpus); @@ -2575,8 +2576,20 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) ms->possible_cpus->cpus[n].type = ms->cpu_type; ms->possible_cpus->cpus[n].arch_id = virt_cpu_mp_affinity(vms, n); + + assert(!mc->smp_props.dies_supported); + ms->possible_cpus->cpus[n].props.has_socket_id = true; + ms->possible_cpus->cpus[n].props.socket_id = + n / (ms->smp.clusters * ms->smp.cores * ms->smp.threads); + ms->possible_cpus->cpus[n].props.has_cluster_id = true; + ms->possible_cpus->cpus[n].props.cluster_id = + (n / (ms->smp.cores * ms->smp.threads)) % ms->smp.clusters; + ms->possible_cpus->cpus[n].props.has_core_id = true; + ms->possible_cpus->cpus[n].props.core_id = + (n / ms->smp.threads) % ms->smp.cores; ms->possible_cpus->cpus[n].props.has_thread_id = true; - ms->possible_cpus->cpus[n].props.thread_id = n; + ms->possible_cpus->cpus[n].props.thread_id = + n % ms->smp.threads; } return ms->possible_cpus; } From e280ecb39bc1629f74ea5479d464fd1608dc8f76 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 3 May 2022 22:03:02 +0800 Subject: [PATCH 224/935] qtest/numa-test: Correct CPU and NUMA association in aarch64_numa_cpu() In aarch64_numa_cpu(), the CPU and NUMA association is something like below. Two threads in the same core/cluster/socket are associated with two individual NUMA nodes, which is unreal as Igor Mammedov mentioned. We don't expect the association to break NUMA-to-socket boundary, which matches with the real world. NUMA-node socket cluster core thread ------------------------------------------ 0 0 0 0 0 1 0 0 0 1 This corrects the topology for CPUs and their association with NUMA nodes. After this patch is applied, the CPU and NUMA association becomes something like below, which looks real. Besides, socket/cluster/core/thread IDs are all checked when the NUMA node IDs are verified. It helps to check if the CPU topology is properly populated or not. NUMA-node socket cluster core thread ------------------------------------------ 0 1 0 0 0 1 0 0 0 0 Suggested-by: Igor Mammedov Signed-off-by: Gavin Shan Acked-by: Igor Mammedov Message-id: 20220503140304.855514-5-gshan@redhat.com Signed-off-by: Peter Maydell --- tests/qtest/numa-test.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/qtest/numa-test.c b/tests/qtest/numa-test.c index 976526e527..c5eb13f349 100644 --- a/tests/qtest/numa-test.c +++ b/tests/qtest/numa-test.c @@ -224,17 +224,17 @@ static void aarch64_numa_cpu(const void *data) g_autofree char *cli = NULL; cli = make_cli(data, "-machine " - "smp.cpus=2,smp.sockets=1,smp.clusters=1,smp.cores=1,smp.threads=2 " + "smp.cpus=2,smp.sockets=2,smp.clusters=1,smp.cores=1,smp.threads=1 " "-numa node,nodeid=0,memdev=ram -numa node,nodeid=1 " - "-numa cpu,node-id=1,thread-id=0 " - "-numa cpu,node-id=0,thread-id=1"); + "-numa cpu,node-id=0,socket-id=1,cluster-id=0,core-id=0,thread-id=0 " + "-numa cpu,node-id=1,socket-id=0,cluster-id=0,core-id=0,thread-id=0"); qts = qtest_init(cli); cpus = get_cpus(qts, &resp); g_assert(cpus); while ((e = qlist_pop(cpus))) { QDict *cpu, *props; - int64_t thread, node; + int64_t socket, cluster, core, thread, node; cpu = qobject_to(QDict, e); g_assert(qdict_haskey(cpu, "props")); @@ -242,12 +242,18 @@ static void aarch64_numa_cpu(const void *data) g_assert(qdict_haskey(props, "node-id")); node = qdict_get_int(props, "node-id"); + g_assert(qdict_haskey(props, "socket-id")); + socket = qdict_get_int(props, "socket-id"); + g_assert(qdict_haskey(props, "cluster-id")); + cluster = qdict_get_int(props, "cluster-id"); + g_assert(qdict_haskey(props, "core-id")); + core = qdict_get_int(props, "core-id"); g_assert(qdict_haskey(props, "thread-id")); thread = qdict_get_int(props, "thread-id"); - if (thread == 0) { + if (socket == 0 && cluster == 0 && core == 0 && thread == 0) { g_assert_cmpint(node, ==, 1); - } else if (thread == 1) { + } else if (socket == 1 && cluster == 0 && core == 0 && thread == 0) { g_assert_cmpint(node, ==, 0); } else { g_assert(false); From 4c18bc192386dfbca530e7f550e0992df657818a Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 3 May 2022 22:03:03 +0800 Subject: [PATCH 225/935] hw/arm/virt: Fix CPU's default NUMA node ID When CPU-to-NUMA association isn't explicitly provided by users, the default one is given by mc->get_default_cpu_node_id(). However, the CPU topology isn't fully considered in the default association and this causes CPU topology broken warnings on booting Linux guest. For example, the following warning messages are observed when the Linux guest is booted with the following command lines. /home/gavin/sandbox/qemu.main/build/qemu-system-aarch64 \ -accel kvm -machine virt,gic-version=host \ -cpu host \ -smp 6,sockets=2,cores=3,threads=1 \ -m 1024M,slots=16,maxmem=64G \ -object memory-backend-ram,id=mem0,size=128M \ -object memory-backend-ram,id=mem1,size=128M \ -object memory-backend-ram,id=mem2,size=128M \ -object memory-backend-ram,id=mem3,size=128M \ -object memory-backend-ram,id=mem4,size=128M \ -object memory-backend-ram,id=mem4,size=384M \ -numa node,nodeid=0,memdev=mem0 \ -numa node,nodeid=1,memdev=mem1 \ -numa node,nodeid=2,memdev=mem2 \ -numa node,nodeid=3,memdev=mem3 \ -numa node,nodeid=4,memdev=mem4 \ -numa node,nodeid=5,memdev=mem5 : alternatives: patching kernel code BUG: arch topology borken the CLS domain not a subset of the MC domain BUG: arch topology borken the DIE domain not a subset of the NODE domain With current implementation of mc->get_default_cpu_node_id(), CPU#0 to CPU#5 are associated with NODE#0 to NODE#5 separately. That's incorrect because CPU#0/1/2 should be associated with same NUMA node because they're seated in same socket. This fixes the issue by considering the socket ID when the default CPU-to-NUMA association is provided in virt_possible_cpu_arch_ids(). With this applied, no more CPU topology broken warnings are seen from the Linux guest. The 6 CPUs are associated with NODE#0/1, but there are no CPUs associated with NODE#2/3/4/5. Signed-off-by: Gavin Shan Reviewed-by: Igor Mammedov Reviewed-by: Yanan Wang Message-id: 20220503140304.855514-6-gshan@redhat.com Signed-off-by: Peter Maydell --- hw/arm/virt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index c25023a083..1a45f44435 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2554,7 +2554,9 @@ virt_cpu_index_to_props(MachineState *ms, unsigned cpu_index) static int64_t virt_get_default_cpu_node_id(const MachineState *ms, int idx) { - return idx % ms->numa_state->num_nodes; + int64_t socket_id = ms->possible_cpus->cpus[idx].props.socket_id; + + return socket_id % ms->numa_state->num_nodes; } static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) From ae9141d4a3265553503bf07d3574b40f84615a34 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 3 May 2022 22:03:04 +0800 Subject: [PATCH 226/935] hw/acpi/aml-build: Use existing CPU topology to build PPTT table When the PPTT table is built, the CPU topology is re-calculated, but it's unecessary because the CPU topology has been populated in virt_possible_cpu_arch_ids() on arm/virt machine. This reworks build_pptt() to avoid by reusing the existing IDs in ms->possible_cpus. Currently, the only user of build_pptt() is arm/virt machine. Signed-off-by: Gavin Shan Tested-by: Yanan Wang Reviewed-by: Yanan Wang Acked-by: Igor Mammedov Acked-by: Michael S. Tsirkin Message-id: 20220503140304.855514-7-gshan@redhat.com Signed-off-by: Peter Maydell --- hw/acpi/aml-build.c | 111 +++++++++++++++++++------------------------- 1 file changed, 48 insertions(+), 63 deletions(-) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 4086879ebf..e6bfac95c7 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -2002,86 +2002,71 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, const char *oem_id, const char *oem_table_id) { MachineClass *mc = MACHINE_GET_CLASS(ms); - GQueue *list = g_queue_new(); - guint pptt_start = table_data->len; - guint parent_offset; - guint length, i; - int uid = 0; - int socket; + CPUArchIdList *cpus = ms->possible_cpus; + int64_t socket_id = -1, cluster_id = -1, core_id = -1; + uint32_t socket_offset = 0, cluster_offset = 0, core_offset = 0; + uint32_t pptt_start = table_data->len; + int n; AcpiTable table = { .sig = "PPTT", .rev = 2, .oem_id = oem_id, .oem_table_id = oem_table_id }; acpi_table_begin(&table, table_data); - for (socket = 0; socket < ms->smp.sockets; socket++) { - g_queue_push_tail(list, - GUINT_TO_POINTER(table_data->len - pptt_start)); - build_processor_hierarchy_node( - table_data, - /* - * Physical package - represents the boundary - * of a physical package - */ - (1 << 0), - 0, socket, NULL, 0); - } - - if (mc->smp_props.clusters_supported) { - length = g_queue_get_length(list); - for (i = 0; i < length; i++) { - int cluster; - - parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list)); - for (cluster = 0; cluster < ms->smp.clusters; cluster++) { - g_queue_push_tail(list, - GUINT_TO_POINTER(table_data->len - pptt_start)); - build_processor_hierarchy_node( - table_data, - (0 << 0), /* not a physical package */ - parent_offset, cluster, NULL, 0); - } + /* + * This works with the assumption that cpus[n].props.*_id has been + * sorted from top to down levels in mc->possible_cpu_arch_ids(). + * Otherwise, the unexpected and duplicated containers will be + * created. + */ + for (n = 0; n < cpus->len; n++) { + if (cpus->cpus[n].props.socket_id != socket_id) { + assert(cpus->cpus[n].props.socket_id > socket_id); + socket_id = cpus->cpus[n].props.socket_id; + cluster_id = -1; + core_id = -1; + socket_offset = table_data->len - pptt_start; + build_processor_hierarchy_node(table_data, + (1 << 0), /* Physical package */ + 0, socket_id, NULL, 0); } - } - length = g_queue_get_length(list); - for (i = 0; i < length; i++) { - int core; - - parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list)); - for (core = 0; core < ms->smp.cores; core++) { - if (ms->smp.threads > 1) { - g_queue_push_tail(list, - GUINT_TO_POINTER(table_data->len - pptt_start)); - build_processor_hierarchy_node( - table_data, - (0 << 0), /* not a physical package */ - parent_offset, core, NULL, 0); - } else { - build_processor_hierarchy_node( - table_data, - (1 << 1) | /* ACPI Processor ID valid */ - (1 << 3), /* Node is a Leaf */ - parent_offset, uid++, NULL, 0); + if (mc->smp_props.clusters_supported) { + if (cpus->cpus[n].props.cluster_id != cluster_id) { + assert(cpus->cpus[n].props.cluster_id > cluster_id); + cluster_id = cpus->cpus[n].props.cluster_id; + core_id = -1; + cluster_offset = table_data->len - pptt_start; + build_processor_hierarchy_node(table_data, + (0 << 0), /* Not a physical package */ + socket_offset, cluster_id, NULL, 0); } + } else { + cluster_offset = socket_offset; } - } - length = g_queue_get_length(list); - for (i = 0; i < length; i++) { - int thread; + if (ms->smp.threads == 1) { + build_processor_hierarchy_node(table_data, + (1 << 1) | /* ACPI Processor ID valid */ + (1 << 3), /* Node is a Leaf */ + cluster_offset, n, NULL, 0); + } else { + if (cpus->cpus[n].props.core_id != core_id) { + assert(cpus->cpus[n].props.core_id > core_id); + core_id = cpus->cpus[n].props.core_id; + core_offset = table_data->len - pptt_start; + build_processor_hierarchy_node(table_data, + (0 << 0), /* Not a physical package */ + cluster_offset, core_id, NULL, 0); + } - parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list)); - for (thread = 0; thread < ms->smp.threads; thread++) { - build_processor_hierarchy_node( - table_data, + build_processor_hierarchy_node(table_data, (1 << 1) | /* ACPI Processor ID valid */ (1 << 2) | /* Processor is a Thread */ (1 << 3), /* Node is a Leaf */ - parent_offset, uid++, NULL, 0); + core_offset, n, NULL, 0); } } - g_queue_free(list); acpi_table_end(linker, &table); } From 52581c718c5cd55595ca032a56f1e194c5716456 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 6 May 2022 15:49:08 +0200 Subject: [PATCH 227/935] Clean up header guards that don't match their file name Header guard symbols should match their file name to make guard collisions less likely. Cleaned up with scripts/clean-header-guards.pl, followed by some renaming of new guard symbols picked by the script to better ones. Signed-off-by: Markus Armbruster Message-Id: <20220506134911.2856099-2-armbru@redhat.com> Reviewed-by: Richard Henderson [Change to generated file ebpf/rss.bpf.skeleton.h backed out] --- accel/tcg/tcg-accel-ops-icount.h | 6 +++--- accel/tcg/tcg-accel-ops-mttcg.h | 6 +++--- accel/tcg/tcg-accel-ops-rr.h | 6 +++--- accel/tcg/tcg-accel-ops.h | 6 +++--- block/coroutines.h | 6 +++--- bsd-user/arm/target_syscall.h | 6 +++--- bsd-user/i386/target.h | 7 +++---- bsd-user/i386/target_arch_sysarch.h | 6 +++--- bsd-user/x86_64/target_arch_sysarch.h | 6 +++--- hw/i386/e820_memory_layout.h | 4 ++-- hw/net/can/ctu_can_fd_frame.h | 4 ++-- hw/net/can/ctu_can_fd_regs.h | 4 ++-- hw/nvme/nvme.h | 6 +++--- hw/usb/hcd-dwc2.h | 4 ++-- include/block/block-hmp-cmds.h | 4 ++-- include/crypto/tls-cipher-suites.h | 6 +++--- include/hw/acpi/generic_event_device.h | 4 ++-- include/hw/i2c/arm_sbcon_i2c.h | 7 ++++--- include/hw/misc/bcm2835_cprman.h | 4 ++-- include/hw/misc/bcm2835_cprman_internals.h | 4 ++-- include/hw/misc/stm32f4xx_exti.h | 4 ++-- include/hw/misc/stm32f4xx_syscfg.h | 4 ++-- include/hw/misc/xlnx-versal-pmc-iou-slcr.h | 6 +++--- include/hw/net/mv88w8618_eth.h | 5 +++-- include/hw/nubus/mac-nubus-bridge.h | 4 ++-- include/hw/pci-host/remote.h | 4 ++-- include/hw/riscv/boot_opensbi.h | 5 +++-- include/hw/riscv/shakti_c.h | 4 ++-- include/hw/rtc/sun4v-rtc.h | 4 ++-- include/hw/rtc/xlnx-zynqmp-rtc.h | 4 ++-- include/hw/rx/rx62n.h | 4 ++-- include/hw/sensor/emc141x_regs.h | 4 ++-- include/hw/ssi/xlnx-versal-ospi.h | 6 +++--- include/hw/timer/bcm2835_systmr.h | 4 ++-- include/hw/tricore/tricore_testdevice.h | 5 ++--- include/hw/usb/dwc2-regs.h | 6 +++--- include/hw/usb/hcd-musb.h | 4 ++-- include/hw/usb/xlnx-usb-subsystem.h | 4 ++-- include/hw/usb/xlnx-versal-usb2-ctrl-regs.h | 4 ++-- include/hw/watchdog/wdt_imx2.h | 6 +++--- include/qemu/help-texts.h | 4 ++-- include/qemu/qemu-plugin.h | 7 ++++--- include/sysemu/block-backend-global-state.h | 6 +++--- plugins/plugin.h | 6 +++--- target/arm/translate-a32.h | 4 ++-- target/arm/vec_internal.h | 6 +++--- target/avr/cpu-qom.h | 6 +++--- target/hexagon/hex_arch_types.h | 4 ++-- target/hexagon/hex_regs.h | 4 ++-- target/i386/hax/hax-accel-ops.h | 6 +++--- target/i386/nvmm/nvmm-accel-ops.h | 6 +++--- target/i386/sev.h | 4 ++-- target/i386/whpx/whpx-accel-ops.h | 6 +++--- target/i386/whpx/whpx-internal.h | 6 +++--- target/xtensa/core-de233_fpu/core-isa.h | 7 +++---- target/xtensa/core-dsp3400/core-isa.h | 8 +++----- tests/qtest/fuzz/fuzz.h | 5 ++--- tools/virtiofsd/passthrough_seccomp.h | 7 +++---- 58 files changed, 148 insertions(+), 151 deletions(-) diff --git a/accel/tcg/tcg-accel-ops-icount.h b/accel/tcg/tcg-accel-ops-icount.h index d884aa2aaa..1b6fd9c607 100644 --- a/accel/tcg/tcg-accel-ops-icount.h +++ b/accel/tcg/tcg-accel-ops-icount.h @@ -7,8 +7,8 @@ * See the COPYING file in the top-level directory. */ -#ifndef TCG_CPUS_ICOUNT_H -#define TCG_CPUS_ICOUNT_H +#ifndef TCG_ACCEL_OPS_ICOUNT_H +#define TCG_ACCEL_OPS_ICOUNT_H void icount_handle_deadline(void); void icount_prepare_for_run(CPUState *cpu); @@ -16,4 +16,4 @@ void icount_process_data(CPUState *cpu); void icount_handle_interrupt(CPUState *cpu, int mask); -#endif /* TCG_CPUS_ICOUNT_H */ +#endif /* TCG_ACCEL_OPS_ICOUNT_H */ diff --git a/accel/tcg/tcg-accel-ops-mttcg.h b/accel/tcg/tcg-accel-ops-mttcg.h index 9fdc5a2ab5..8ffa7a9a9f 100644 --- a/accel/tcg/tcg-accel-ops-mttcg.h +++ b/accel/tcg/tcg-accel-ops-mttcg.h @@ -7,8 +7,8 @@ * See the COPYING file in the top-level directory. */ -#ifndef TCG_CPUS_MTTCG_H -#define TCG_CPUS_MTTCG_H +#ifndef TCG_ACCEL_OPS_MTTCG_H +#define TCG_ACCEL_OPS_MTTCG_H /* kick MTTCG vCPU thread */ void mttcg_kick_vcpu_thread(CPUState *cpu); @@ -16,4 +16,4 @@ void mttcg_kick_vcpu_thread(CPUState *cpu); /* start an mttcg vCPU thread */ void mttcg_start_vcpu_thread(CPUState *cpu); -#endif /* TCG_CPUS_MTTCG_H */ +#endif /* TCG_ACCEL_OPS_MTTCG_H */ diff --git a/accel/tcg/tcg-accel-ops-rr.h b/accel/tcg/tcg-accel-ops-rr.h index 54f6ae6e86..2a76a29612 100644 --- a/accel/tcg/tcg-accel-ops-rr.h +++ b/accel/tcg/tcg-accel-ops-rr.h @@ -7,8 +7,8 @@ * See the COPYING file in the top-level directory. */ -#ifndef TCG_CPUS_RR_H -#define TCG_CPUS_RR_H +#ifndef TCG_ACCEL_OPS_RR_H +#define TCG_ACCEL_OPS_RR_H #define TCG_KICK_PERIOD (NANOSECONDS_PER_SECOND / 10) @@ -18,4 +18,4 @@ void rr_kick_vcpu_thread(CPUState *unused); /* start the round robin vcpu thread */ void rr_start_vcpu_thread(CPUState *cpu); -#endif /* TCG_CPUS_RR_H */ +#endif /* TCG_ACCEL_OPS_RR_H */ diff --git a/accel/tcg/tcg-accel-ops.h b/accel/tcg/tcg-accel-ops.h index 6a5fcef889..f9bc6330e2 100644 --- a/accel/tcg/tcg-accel-ops.h +++ b/accel/tcg/tcg-accel-ops.h @@ -9,8 +9,8 @@ * See the COPYING file in the top-level directory. */ -#ifndef TCG_CPUS_H -#define TCG_CPUS_H +#ifndef TCG_ACCEL_OPS_H +#define TCG_ACCEL_OPS_H #include "sysemu/cpus.h" @@ -19,4 +19,4 @@ int tcg_cpus_exec(CPUState *cpu); void tcg_handle_interrupt(CPUState *cpu, int mask); void tcg_cpu_init_cflags(CPUState *cpu, bool parallel); -#endif /* TCG_CPUS_H */ +#endif /* TCG_ACCEL_OPS_H */ diff --git a/block/coroutines.h b/block/coroutines.h index 8ea70d45f9..830ecaa733 100644 --- a/block/coroutines.h +++ b/block/coroutines.h @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#ifndef BLOCK_COROUTINES_INT_H -#define BLOCK_COROUTINES_INT_H +#ifndef BLOCK_COROUTINES_H +#define BLOCK_COROUTINES_H #include "block/block_int.h" @@ -129,4 +129,4 @@ blk_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes); int generated_co_wrapper blk_do_flush(BlockBackend *blk); -#endif /* BLOCK_COROUTINES_INT_H */ +#endif /* BLOCK_COROUTINES_H */ diff --git a/bsd-user/arm/target_syscall.h b/bsd-user/arm/target_syscall.h index a5f2bb4e01..5804a53541 100644 --- a/bsd-user/arm/target_syscall.h +++ b/bsd-user/arm/target_syscall.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_SYSCALL_H_ -#define _TARGET_ARCH_SYSCALL_H_ +#ifndef ARM_TARGET_SYSCALL_H +#define ARM_TARGET_SYSCALL_H struct target_pt_regs { abi_long uregs[17]; @@ -52,4 +52,4 @@ struct target_pt_regs { #define TARGET_HW_MACHINE "arm" #define TARGET_HW_MACHINE_ARCH "armv7" -#endif /* !_TARGET_ARCH_SYSCALL_H_ */ +#endif /* ARM_TARGET_SYSCALL_H */ diff --git a/bsd-user/i386/target.h b/bsd-user/i386/target.h index 9b9df047a3..ddd3b8ec08 100644 --- a/bsd-user/i386/target.h +++ b/bsd-user/i386/target.h @@ -6,8 +6,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef TARGET_ARCH_H -#define TARGET_ARCH_H +#ifndef TARGET_H +#define TARGET_H /* * i386 doesn't 'lump' the registers for 64-bit args. @@ -17,5 +17,4 @@ static inline bool regpairs_aligned(void *cpu_env) return false; } -#endif /* ! TARGET_ARCH_H */ - +#endif /* TARGET_H */ diff --git a/bsd-user/i386/target_arch_sysarch.h b/bsd-user/i386/target_arch_sysarch.h index e9ab98ec32..db8fee6380 100644 --- a/bsd-user/i386/target_arch_sysarch.h +++ b/bsd-user/i386/target_arch_sysarch.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef BSD_USER_ARCH_SYSARCH_H_ -#define BSD_USER_ARCH_SYSARCH_H_ +#ifndef TARGET_ARCH_SYSARCH_H +#define TARGET_ARCH_SYSARCH_H #include "target_syscall.h" @@ -74,4 +74,4 @@ static inline void do_freebsd_arch_print_sysarch( TARGET_ABI_FMT_lx ")", name->name, (int)arg1, arg2, arg3, arg4); } -#endif /* !BSD_USER_ARCH_SYSARCH_H_ */ +#endif /* TARGET_ARCH_SYSARCH_H */ diff --git a/bsd-user/x86_64/target_arch_sysarch.h b/bsd-user/x86_64/target_arch_sysarch.h index 5c36fc0752..152cb8bcb8 100644 --- a/bsd-user/x86_64/target_arch_sysarch.h +++ b/bsd-user/x86_64/target_arch_sysarch.h @@ -16,8 +16,8 @@ * along with this program; if not, see . */ -#ifndef BSD_USER_ARCH_SYSARCH_H_ -#define BSD_USER_ARCH_SYSARCH_H_ +#ifndef TARGET_ARCH_SYSARCH_H +#define TARGET_ARCH_SYSARCH_H #include "target_syscall.h" @@ -73,4 +73,4 @@ static inline void do_freebsd_arch_print_sysarch( TARGET_ABI_FMT_lx ")", name->name, (int)arg1, arg2, arg3, arg4); } -#endif /*! BSD_USER_ARCH_SYSARCH_H_ */ +#endif /* TARGET_ARCH_SYSARCH_H */ diff --git a/hw/i386/e820_memory_layout.h b/hw/i386/e820_memory_layout.h index 2a0ceb8b9c..04f93780f9 100644 --- a/hw/i386/e820_memory_layout.h +++ b/hw/i386/e820_memory_layout.h @@ -6,8 +6,8 @@ * SPDX-License-Identifier: MIT */ -#ifndef HW_I386_E820_H -#define HW_I386_E820_H +#ifndef HW_I386_E820_MEMORY_LAYOUT_H +#define HW_I386_E820_MEMORY_LAYOUT_H /* e820 types */ #define E820_RAM 1 diff --git a/hw/net/can/ctu_can_fd_frame.h b/hw/net/can/ctu_can_fd_frame.h index 04d956c84e..459c4a0ada 100644 --- a/hw/net/can/ctu_can_fd_frame.h +++ b/hw/net/can/ctu_can_fd_frame.h @@ -29,8 +29,8 @@ /* This file is autogenerated, DO NOT EDIT! */ -#ifndef __CTU_CAN_FD_CAN_FD_FRAME_FORMAT__ -#define __CTU_CAN_FD_CAN_FD_FRAME_FORMAT__ +#ifndef HW_CAN_CTU_CAN_FD_FRAME_H +#define HW_CAN_CTU_CAN_FD_FRAME_H /* CAN_Frame_format memory map */ enum ctu_can_fd_can_frame_format { diff --git a/hw/net/can/ctu_can_fd_regs.h b/hw/net/can/ctu_can_fd_regs.h index 450f4b9fb3..57859b87bc 100644 --- a/hw/net/can/ctu_can_fd_regs.h +++ b/hw/net/can/ctu_can_fd_regs.h @@ -29,8 +29,8 @@ /* This file is autogenerated, DO NOT EDIT! */ -#ifndef __CTU_CAN_FD_CAN_FD_REGISTER_MAP__ -#define __CTU_CAN_FD_CAN_FD_REGISTER_MAP__ +#ifndef HW_CAN_CTU_CAN_FD_REGS_H +#define HW_CAN_CTU_CAN_FD_REGS_H /* CAN_Registers memory map */ enum ctu_can_fd_can_registers { diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h index 739c8b8f79..6773819325 100644 --- a/hw/nvme/nvme.h +++ b/hw/nvme/nvme.h @@ -15,8 +15,8 @@ * This code is licensed under the GNU GPL v2 or later. */ -#ifndef HW_NVME_INTERNAL_H -#define HW_NVME_INTERNAL_H +#ifndef HW_NVME_NVME_H +#define HW_NVME_NVME_H #include "qemu/uuid.h" #include "hw/pci/pci.h" @@ -519,4 +519,4 @@ void nvme_rw_complete_cb(void *opaque, int ret); uint16_t nvme_map_dptr(NvmeCtrl *n, NvmeSg *sg, size_t len, NvmeCmd *cmd); -#endif /* HW_NVME_INTERNAL_H */ +#endif /* HW_NVME_NVME_H */ diff --git a/hw/usb/hcd-dwc2.h b/hw/usb/hcd-dwc2.h index 6998b04706..9c3d88ea14 100644 --- a/hw/usb/hcd-dwc2.h +++ b/hw/usb/hcd-dwc2.h @@ -16,8 +16,8 @@ * GNU General Public License for more details. */ -#ifndef HW_USB_DWC2_H -#define HW_USB_DWC2_H +#ifndef HW_USB_HCD_DWC2_H +#define HW_USB_HCD_DWC2_H #include "qemu/timer.h" #include "hw/irq.h" diff --git a/include/block/block-hmp-cmds.h b/include/block/block-hmp-cmds.h index 3412e108ca..50ce0247c3 100644 --- a/include/block/block-hmp-cmds.h +++ b/include/block/block-hmp-cmds.h @@ -12,8 +12,8 @@ * the COPYING file in the top-level directory. */ -#ifndef BLOCK_HMP_COMMANDS_H -#define BLOCK_HMP_COMMANDS_H +#ifndef BLOCK_BLOCK_HMP_CMDS_H +#define BLOCK_BLOCK_HMP_CMDS_H void hmp_drive_add(Monitor *mon, const QDict *qdict); diff --git a/include/crypto/tls-cipher-suites.h b/include/crypto/tls-cipher-suites.h index 7eb1b76122..3bd2003f32 100644 --- a/include/crypto/tls-cipher-suites.h +++ b/include/crypto/tls-cipher-suites.h @@ -8,8 +8,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef QCRYPTO_TLSCIPHERSUITES_H -#define QCRYPTO_TLSCIPHERSUITES_H +#ifndef QCRYPTO_TLS_CIPHER_SUITES_H +#define QCRYPTO_TLS_CIPHER_SUITES_H #include "qom/object.h" #include "crypto/tlscreds.h" @@ -31,4 +31,4 @@ DECLARE_INSTANCE_CHECKER(QCryptoTLSCipherSuites, QCRYPTO_TLS_CIPHER_SUITES, GByteArray *qcrypto_tls_cipher_suites_get_data(QCryptoTLSCipherSuites *obj, Error **errp); -#endif /* QCRYPTO_TLSCIPHERSUITES_H */ +#endif /* QCRYPTO_TLS_CIPHER_SUITES_H */ diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h index d49217c445..d831bbd889 100644 --- a/include/hw/acpi/generic_event_device.h +++ b/include/hw/acpi/generic_event_device.h @@ -56,8 +56,8 @@ * */ -#ifndef HW_ACPI_GED_H -#define HW_ACPI_GED_H +#ifndef HW_ACPI_GENERIC_EVENT_DEVICE_H +#define HW_ACPI_GENERIC_EVENT_DEVICE_H #include "hw/sysbus.h" #include "hw/acpi/memory_hotplug.h" diff --git a/include/hw/i2c/arm_sbcon_i2c.h b/include/hw/i2c/arm_sbcon_i2c.h index ad96781e7a..f54d1e5413 100644 --- a/include/hw/i2c/arm_sbcon_i2c.h +++ b/include/hw/i2c/arm_sbcon_i2c.h @@ -9,8 +9,9 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef HW_I2C_ARM_SBCON_H -#define HW_I2C_ARM_SBCON_H + +#ifndef HW_I2C_ARM_SBCON_I2C_H +#define HW_I2C_ARM_SBCON_I2C_H #include "hw/sysbus.h" #include "hw/i2c/bitbang_i2c.h" @@ -34,4 +35,4 @@ struct ArmSbconI2CState { int in; }; -#endif /* HW_I2C_ARM_SBCON_H */ +#endif /* HW_I2C_ARM_SBCON_I2C_H */ diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h index 3df4ceedd2..0d38036728 100644 --- a/include/hw/misc/bcm2835_cprman.h +++ b/include/hw/misc/bcm2835_cprman.h @@ -6,8 +6,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef HW_MISC_CPRMAN_H -#define HW_MISC_CPRMAN_H +#ifndef HW_MISC_BCM2835_CPRMAN_H +#define HW_MISC_BCM2835_CPRMAN_H #include "hw/sysbus.h" #include "hw/qdev-clock.h" diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h index 339759b307..7617aff96f 100644 --- a/include/hw/misc/bcm2835_cprman_internals.h +++ b/include/hw/misc/bcm2835_cprman_internals.h @@ -6,8 +6,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef HW_MISC_CPRMAN_INTERNALS_H -#define HW_MISC_CPRMAN_INTERNALS_H +#ifndef HW_MISC_BCM2835_CPRMAN_INTERNALS_H +#define HW_MISC_BCM2835_CPRMAN_INTERNALS_H #include "hw/registerfields.h" #include "hw/misc/bcm2835_cprman.h" diff --git a/include/hw/misc/stm32f4xx_exti.h b/include/hw/misc/stm32f4xx_exti.h index ea6b0097b0..fc11c595fa 100644 --- a/include/hw/misc/stm32f4xx_exti.h +++ b/include/hw/misc/stm32f4xx_exti.h @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#ifndef HW_STM_EXTI_H -#define HW_STM_EXTI_H +#ifndef HW_STM32F4XX_EXTI_H +#define HW_STM32F4XX_EXTI_H #include "hw/sysbus.h" #include "qom/object.h" diff --git a/include/hw/misc/stm32f4xx_syscfg.h b/include/hw/misc/stm32f4xx_syscfg.h index 6f8ca49228..9fce67f4b4 100644 --- a/include/hw/misc/stm32f4xx_syscfg.h +++ b/include/hw/misc/stm32f4xx_syscfg.h @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#ifndef HW_STM_SYSCFG_H -#define HW_STM_SYSCFG_H +#ifndef HW_STM32F4XX_SYSCFG_H +#define HW_STM32F4XX_SYSCFG_H #include "hw/sysbus.h" #include "qom/object.h" diff --git a/include/hw/misc/xlnx-versal-pmc-iou-slcr.h b/include/hw/misc/xlnx-versal-pmc-iou-slcr.h index ab4e4b4f18..2170420f01 100644 --- a/include/hw/misc/xlnx-versal-pmc-iou-slcr.h +++ b/include/hw/misc/xlnx-versal-pmc-iou-slcr.h @@ -51,8 +51,8 @@ * 1: OSPI direct access mode. */ -#ifndef XILINX_VERSAL_PMC_IOU_SLCR_H -#define XILINX_VERSAL_PMC_IOU_SLCR_H +#ifndef XLNX_VERSAL_PMC_IOU_SLCR_H +#define XLNX_VERSAL_PMC_IOU_SLCR_H #include "hw/register.h" @@ -75,4 +75,4 @@ struct XlnxVersalPmcIouSlcr { RegisterInfo regs_info[XILINX_VERSAL_PMC_IOU_SLCR_R_MAX]; }; -#endif /* XILINX_VERSAL_PMC_IOU_SLCR_H */ +#endif /* XLNX_VERSAL_PMC_IOU_SLCR_H */ diff --git a/include/hw/net/mv88w8618_eth.h b/include/hw/net/mv88w8618_eth.h index 8f4c746092..41074940ec 100644 --- a/include/hw/net/mv88w8618_eth.h +++ b/include/hw/net/mv88w8618_eth.h @@ -4,8 +4,9 @@ * * Copyright (c) 2008-2021 QEMU contributors */ -#ifndef HW_NET_MV88W8618_H -#define HW_NET_MV88W8618_H + +#ifndef HW_NET_MV88W8618_ETH_H +#define HW_NET_MV88W8618_ETH_H #define TYPE_MV88W8618_ETH "mv88w8618_eth" diff --git a/include/hw/nubus/mac-nubus-bridge.h b/include/hw/nubus/mac-nubus-bridge.h index 70ab50ab2d..be4dd83530 100644 --- a/include/hw/nubus/mac-nubus-bridge.h +++ b/include/hw/nubus/mac-nubus-bridge.h @@ -6,8 +6,8 @@ * */ -#ifndef HW_NUBUS_MAC_H -#define HW_NUBUS_MAC_H +#ifndef HW_NUBUS_MAC_NUBUS_BRIDGE_H +#define HW_NUBUS_MAC_NUBUS_BRIDGE_H #include "hw/nubus/nubus.h" #include "qom/object.h" diff --git a/include/hw/pci-host/remote.h b/include/hw/pci-host/remote.h index 3dcf6aa51d..690a01f0fe 100644 --- a/include/hw/pci-host/remote.h +++ b/include/hw/pci-host/remote.h @@ -8,8 +8,8 @@ * */ -#ifndef REMOTE_PCIHOST_H -#define REMOTE_PCIHOST_H +#ifndef PCI_HOST_REMOTE_H +#define PCI_HOST_REMOTE_H #include "exec/memory.h" #include "hw/pci/pcie_host.h" diff --git a/include/hw/riscv/boot_opensbi.h b/include/hw/riscv/boot_opensbi.h index 0d5ddd6c3d..c19cad4818 100644 --- a/include/hw/riscv/boot_opensbi.h +++ b/include/hw/riscv/boot_opensbi.h @@ -4,8 +4,9 @@ * * Based on include/sbi/{fw_dynamic.h,sbi_scratch.h} from the OpenSBI project. */ -#ifndef OPENSBI_H -#define OPENSBI_H + +#ifndef RISCV_BOOT_OPENSBI_H +#define RISCV_BOOT_OPENSBI_H /** Expected value of info magic ('OSBI' ascii string in hex) */ #define FW_DYNAMIC_INFO_MAGIC_VALUE 0x4942534f diff --git a/include/hw/riscv/shakti_c.h b/include/hw/riscv/shakti_c.h index 50a2b79086..daf0aae13f 100644 --- a/include/hw/riscv/shakti_c.h +++ b/include/hw/riscv/shakti_c.h @@ -16,8 +16,8 @@ * this program. If not, see . */ -#ifndef HW_SHAKTI_H -#define HW_SHAKTI_H +#ifndef HW_SHAKTI_C_H +#define HW_SHAKTI_C_H #include "hw/riscv/riscv_hart.h" #include "hw/boards.h" diff --git a/include/hw/rtc/sun4v-rtc.h b/include/hw/rtc/sun4v-rtc.h index fd868f6ed2..fc54dfcba4 100644 --- a/include/hw/rtc/sun4v-rtc.h +++ b/include/hw/rtc/sun4v-rtc.h @@ -9,8 +9,8 @@ * version. */ -#ifndef HW_RTC_SUN4V -#define HW_RTC_SUN4V +#ifndef HW_RTC_SUN4V_RTC_H +#define HW_RTC_SUN4V_RTC_H #include "exec/hwaddr.h" diff --git a/include/hw/rtc/xlnx-zynqmp-rtc.h b/include/hw/rtc/xlnx-zynqmp-rtc.h index 5f1ad0a946..f0c6a2d78a 100644 --- a/include/hw/rtc/xlnx-zynqmp-rtc.h +++ b/include/hw/rtc/xlnx-zynqmp-rtc.h @@ -24,8 +24,8 @@ * THE SOFTWARE. */ -#ifndef HW_RTC_XLNX_ZYNQMP_H -#define HW_RTC_XLNX_ZYNQMP_H +#ifndef HW_RTC_XLNX_ZYNQMP_RTC_H +#define HW_RTC_XLNX_ZYNQMP_RTC_H #include "hw/register.h" #include "hw/sysbus.h" diff --git a/include/hw/rx/rx62n.h b/include/hw/rx/rx62n.h index 3ed80dba0d..73ceeb58e5 100644 --- a/include/hw/rx/rx62n.h +++ b/include/hw/rx/rx62n.h @@ -21,8 +21,8 @@ * this program. If not, see . */ -#ifndef HW_RX_RX62N_MCU_H -#define HW_RX_RX62N_MCU_H +#ifndef HW_RX_RX62N_H +#define HW_RX_RX62N_H #include "target/rx/cpu.h" #include "hw/intc/rx_icu.h" diff --git a/include/hw/sensor/emc141x_regs.h b/include/hw/sensor/emc141x_regs.h index 0560fb7c5c..e509a43d55 100644 --- a/include/hw/sensor/emc141x_regs.h +++ b/include/hw/sensor/emc141x_regs.h @@ -9,8 +9,8 @@ * later. See the COPYING file in the top-level directory. */ -#ifndef TMP105_REGS_H -#define TMP105_REGS_H +#ifndef EMC141X_REGS_H +#define EMC141X_REGS_H #define EMC1413_DEVICE_ID 0x21 #define EMC1414_DEVICE_ID 0x25 diff --git a/include/hw/ssi/xlnx-versal-ospi.h b/include/hw/ssi/xlnx-versal-ospi.h index 14d1263497..5d131d351d 100644 --- a/include/hw/ssi/xlnx-versal-ospi.h +++ b/include/hw/ssi/xlnx-versal-ospi.h @@ -49,8 +49,8 @@ * + Property "indac-write-disabled": Disable indirect access writes. */ -#ifndef XILINX_VERSAL_OSPI_H -#define XILINX_VERSAL_OSPI_H +#ifndef XLNX_VERSAL_OSPI_H +#define XLNX_VERSAL_OSPI_H #include "hw/register.h" #include "hw/ssi/ssi.h" @@ -108,4 +108,4 @@ struct XlnxVersalOspi { uint8_t stig_membank[512]; }; -#endif /* XILINX_VERSAL_OSPI_H */ +#endif /* XLNX_VERSAL_OSPI_H */ diff --git a/include/hw/timer/bcm2835_systmr.h b/include/hw/timer/bcm2835_systmr.h index bd3097d746..a8f605beeb 100644 --- a/include/hw/timer/bcm2835_systmr.h +++ b/include/hw/timer/bcm2835_systmr.h @@ -6,8 +6,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef BCM2835_SYSTIMER_H -#define BCM2835_SYSTIMER_H +#ifndef BCM2835_SYSTMR_H +#define BCM2835_SYSTMR_H #include "hw/sysbus.h" #include "hw/irq.h" diff --git a/include/hw/tricore/tricore_testdevice.h b/include/hw/tricore/tricore_testdevice.h index 2c56c51bcb..1e2b8942ac 100644 --- a/include/hw/tricore/tricore_testdevice.h +++ b/include/hw/tricore/tricore_testdevice.h @@ -15,9 +15,8 @@ * License along with this library; if not, see . */ - -#ifndef HW_TRICORE_TESTDEV_H -#define HW_TRICORE_TESTDEV_H +#ifndef HW_TRICORE_TESTDEVICE_H +#define HW_TRICORE_TESTDEVICE_H #include "hw/sysbus.h" #include "hw/hw.h" diff --git a/include/hw/usb/dwc2-regs.h b/include/hw/usb/dwc2-regs.h index a7eb531485..4015c1d691 100644 --- a/include/hw/usb/dwc2-regs.h +++ b/include/hw/usb/dwc2-regs.h @@ -39,8 +39,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DWC2_HW_H -#define DWC2_HW_H +#ifndef DWC2_REGS_H +#define DWC2_REGS_H #define HSOTG_REG(x) (x) @@ -896,4 +896,4 @@ struct dwc2_dma_desc { #define MAX_DMA_DESC_NUM_GENERIC 64 #define MAX_DMA_DESC_NUM_HS_ISOC 256 -#endif /* __DWC2_HW_H__ */ +#endif /* DWC2_REGS_H */ diff --git a/include/hw/usb/hcd-musb.h b/include/hw/usb/hcd-musb.h index c874b9f292..f30a26f7f4 100644 --- a/include/hw/usb/hcd-musb.h +++ b/include/hw/usb/hcd-musb.h @@ -10,8 +10,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef HW_USB_MUSB_H -#define HW_USB_MUSB_H +#ifndef HW_USB_HCD_MUSB_H +#define HW_USB_HCD_MUSB_H enum musb_irq_source_e { musb_irq_suspend = 0, diff --git a/include/hw/usb/xlnx-usb-subsystem.h b/include/hw/usb/xlnx-usb-subsystem.h index 999e423951..5b730abd84 100644 --- a/include/hw/usb/xlnx-usb-subsystem.h +++ b/include/hw/usb/xlnx-usb-subsystem.h @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#ifndef XLNX_VERSAL_USB_SUBSYSTEM_H -#define XLNX_VERSAL_USB_SUBSYSTEM_H +#ifndef XLNX_USB_SUBSYSTEM_H +#define XLNX_USB_SUBSYSTEM_H #include "hw/usb/xlnx-versal-usb2-ctrl-regs.h" #include "hw/usb/hcd-dwc3.h" diff --git a/include/hw/usb/xlnx-versal-usb2-ctrl-regs.h b/include/hw/usb/xlnx-versal-usb2-ctrl-regs.h index b76dce0419..633bf3013a 100644 --- a/include/hw/usb/xlnx-versal-usb2-ctrl-regs.h +++ b/include/hw/usb/xlnx-versal-usb2-ctrl-regs.h @@ -23,8 +23,8 @@ * THE SOFTWARE. */ -#ifndef XLNX_USB2_REGS_H -#define XLNX_USB2_REGS_H +#ifndef XLNX_VERSAL_USB2_CTRL_REGS_H +#define XLNX_VERSAL_USB2_CTRL_REGS_H #define TYPE_XILINX_VERSAL_USB2_CTRL_REGS "xlnx.versal-usb2-ctrl-regs" diff --git a/include/hw/watchdog/wdt_imx2.h b/include/hw/watchdog/wdt_imx2.h index 023d83f48f..600a552d2e 100644 --- a/include/hw/watchdog/wdt_imx2.h +++ b/include/hw/watchdog/wdt_imx2.h @@ -9,8 +9,8 @@ * See the COPYING file in the top-level directory. */ -#ifndef IMX2_WDT_H -#define IMX2_WDT_H +#ifndef WDT_IMX2_H +#define WDT_IMX2_H #include "qemu/bitops.h" #include "hw/sysbus.h" @@ -88,4 +88,4 @@ struct IMX2WdtState { bool wcr_wdt_locked; /* affects WDT (never cleared) */ }; -#endif /* IMX2_WDT_H */ +#endif /* WDT_IMX2_H */ diff --git a/include/qemu/help-texts.h b/include/qemu/help-texts.h index ba32cc8b1f..4f265fed8d 100644 --- a/include/qemu/help-texts.h +++ b/include/qemu/help-texts.h @@ -1,5 +1,5 @@ -#ifndef QEMU_COMMON_H -#define QEMU_COMMON_H +#ifndef QEMU_HELP_TEXTS_H +#define QEMU_HELP_TEXTS_H /* Copyright string for -version arguments, About dialogs, etc */ #define QEMU_COPYRIGHT "Copyright (c) 2003-2022 " \ diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h index 535ddbf0ae..d0e9d03adf 100644 --- a/include/qemu/qemu-plugin.h +++ b/include/qemu/qemu-plugin.h @@ -7,8 +7,9 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef QEMU_PLUGIN_API_H -#define QEMU_PLUGIN_API_H + +#ifndef QEMU_QEMU_PLUGIN_H +#define QEMU_QEMU_PLUGIN_H #include #include @@ -624,4 +625,4 @@ uint64_t qemu_plugin_end_code(void); */ uint64_t qemu_plugin_entry_code(void); -#endif /* QEMU_PLUGIN_API_H */ +#endif /* QEMU_QEMU_PLUGIN_H */ diff --git a/include/sysemu/block-backend-global-state.h b/include/sysemu/block-backend-global-state.h index 2e93a74679..415f0c91d7 100644 --- a/include/sysemu/block-backend-global-state.h +++ b/include/sysemu/block-backend-global-state.h @@ -10,8 +10,8 @@ * or later. See the COPYING.LIB file in the top-level directory. */ -#ifndef BLOCK_BACKEND_GS_H -#define BLOCK_BACKEND_GS_H +#ifndef BLOCK_BACKEND_GLOBAL_STATE_H +#define BLOCK_BACKEND_GLOBAL_STATE_H #include "block-backend-common.h" @@ -113,4 +113,4 @@ const BdrvChild *blk_root(BlockBackend *blk); int blk_make_empty(BlockBackend *blk, Error **errp); -#endif /* BLOCK_BACKEND_GS_H */ +#endif /* BLOCK_BACKEND_GLOBAL_STATE_H */ diff --git a/plugins/plugin.h b/plugins/plugin.h index b13677d0dc..5eb2fdbc85 100644 --- a/plugins/plugin.h +++ b/plugins/plugin.h @@ -9,8 +9,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef PLUGIN_INTERNAL_H -#define PLUGIN_INTERNAL_H +#ifndef PLUGIN_H +#define PLUGIN_H #include #include "qemu/qht.h" @@ -97,4 +97,4 @@ void plugin_register_vcpu_mem_cb(GArray **arr, void exec_inline_op(struct qemu_plugin_dyn_cb *cb); -#endif /* _PLUGIN_INTERNAL_H_ */ +#endif /* PLUGIN_H */ diff --git a/target/arm/translate-a32.h b/target/arm/translate-a32.h index 09010ad2da..78a84c1414 100644 --- a/target/arm/translate-a32.h +++ b/target/arm/translate-a32.h @@ -17,8 +17,8 @@ * License along with this library; if not, see . */ -#ifndef TARGET_ARM_TRANSLATE_A64_H -#define TARGET_ARM_TRANSLATE_A64_H +#ifndef TARGET_ARM_TRANSLATE_A32_H +#define TARGET_ARM_TRANSLATE_A32_H /* Prototypes for autogenerated disassembler functions */ bool disas_m_nocp(DisasContext *dc, uint32_t insn); diff --git a/target/arm/vec_internal.h b/target/arm/vec_internal.h index fb43a2380e..1d63402042 100644 --- a/target/arm/vec_internal.h +++ b/target/arm/vec_internal.h @@ -17,8 +17,8 @@ * License along with this library; if not, see . */ -#ifndef TARGET_ARM_VEC_INTERNALS_H -#define TARGET_ARM_VEC_INTERNALS_H +#ifndef TARGET_ARM_VEC_INTERNAL_H +#define TARGET_ARM_VEC_INTERNAL_H /* * Note that vector data is stored in host-endian 64-bit chunks, @@ -217,4 +217,4 @@ uint64_t pmull_h(uint64_t op1, uint64_t op2); */ uint64_t pmull_w(uint64_t op1, uint64_t op2); -#endif /* TARGET_ARM_VEC_INTERNALS_H */ +#endif /* TARGET_ARM_VEC_INTERNAL_H */ diff --git a/target/avr/cpu-qom.h b/target/avr/cpu-qom.h index 32a1c762e6..b5c3507d6d 100644 --- a/target/avr/cpu-qom.h +++ b/target/avr/cpu-qom.h @@ -18,8 +18,8 @@ * */ -#ifndef QEMU_AVR_QOM_H -#define QEMU_AVR_QOM_H +#ifndef TARGET_AVR_CPU_QOM_H +#define TARGET_AVR_CPU_QOM_H #include "hw/core/cpu.h" #include "qom/object.h" @@ -44,4 +44,4 @@ struct AVRCPUClass { }; -#endif /* !defined (QEMU_AVR_CPU_QOM_H) */ +#endif /* TARGET_AVR_CPU_QOM_H */ diff --git a/target/hexagon/hex_arch_types.h b/target/hexagon/hex_arch_types.h index 78ad607f53..885f68f760 100644 --- a/target/hexagon/hex_arch_types.h +++ b/target/hexagon/hex_arch_types.h @@ -15,8 +15,8 @@ * along with this program; if not, see . */ -#ifndef HEXAGON_ARCH_TYPES_H -#define HEXAGON_ARCH_TYPES_H +#ifndef HEXAGON_HEX_ARCH_TYPES_H +#define HEXAGON_HEX_ARCH_TYPES_H #include "qemu/osdep.h" #include "mmvec/mmvec.h" diff --git a/target/hexagon/hex_regs.h b/target/hexagon/hex_regs.h index e1b3149b07..a63c2c0fd5 100644 --- a/target/hexagon/hex_regs.h +++ b/target/hexagon/hex_regs.h @@ -15,8 +15,8 @@ * along with this program; if not, see . */ -#ifndef HEXAGON_REGS_H -#define HEXAGON_REGS_H +#ifndef HEXAGON_HEX_REGS_H +#define HEXAGON_HEX_REGS_H enum { HEX_REG_R00 = 0, diff --git a/target/i386/hax/hax-accel-ops.h b/target/i386/hax/hax-accel-ops.h index c7698519cd..9e357e7b40 100644 --- a/target/i386/hax/hax-accel-ops.h +++ b/target/i386/hax/hax-accel-ops.h @@ -7,8 +7,8 @@ * See the COPYING file in the top-level directory. */ -#ifndef HAX_CPUS_H -#define HAX_CPUS_H +#ifndef TARGET_I386_HAX_ACCEL_OPS_H +#define TARGET_I386_HAX_ACCEL_OPS_H #include "sysemu/cpus.h" @@ -28,4 +28,4 @@ int hax_vcpu_destroy(CPUState *cpu); void hax_raise_event(CPUState *cpu); void hax_reset_vcpu_state(void *opaque); -#endif /* HAX_CPUS_H */ +#endif /* TARGET_I386_HAX_ACCEL_OPS_H */ diff --git a/target/i386/nvmm/nvmm-accel-ops.h b/target/i386/nvmm/nvmm-accel-ops.h index 43e24adcaf..7c5461bd75 100644 --- a/target/i386/nvmm/nvmm-accel-ops.h +++ b/target/i386/nvmm/nvmm-accel-ops.h @@ -7,8 +7,8 @@ * See the COPYING file in the top-level directory. */ -#ifndef NVMM_CPUS_H -#define NVMM_CPUS_H +#ifndef TARGET_I386_NVMM_ACCEL_OPS_H +#define TARGET_I386_NVMM_ACCEL_OPS_H #include "sysemu/cpus.h" @@ -21,4 +21,4 @@ void nvmm_cpu_synchronize_post_reset(CPUState *cpu); void nvmm_cpu_synchronize_post_init(CPUState *cpu); void nvmm_cpu_synchronize_pre_loadvm(CPUState *cpu); -#endif /* NVMM_CPUS_H */ +#endif /* TARGET_I386_NVMM_ACCEL_OPS_H */ diff --git a/target/i386/sev.h b/target/i386/sev.h index 83e82aa42c..7b1528248a 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -11,8 +11,8 @@ * */ -#ifndef QEMU_SEV_I386_H -#define QEMU_SEV_I386_H +#ifndef I386_SEV_H +#define I386_SEV_H #ifndef CONFIG_USER_ONLY #include CONFIG_DEVICES /* CONFIG_SEV */ diff --git a/target/i386/whpx/whpx-accel-ops.h b/target/i386/whpx/whpx-accel-ops.h index b5102dd1ee..7a1bb1ab57 100644 --- a/target/i386/whpx/whpx-accel-ops.h +++ b/target/i386/whpx/whpx-accel-ops.h @@ -7,8 +7,8 @@ * See the COPYING file in the top-level directory. */ -#ifndef WHPX_CPUS_H -#define WHPX_CPUS_H +#ifndef TARGET_I386_WHPX_ACCEL_OPS_H +#define TARGET_I386_WHPX_ACCEL_OPS_H #include "sysemu/cpus.h" @@ -30,4 +30,4 @@ void whpx_cpu_synchronize_pre_resume(bool step_pending); /* full state set, modified during initialization or on vmload */ #define WHPX_SET_FULL_STATE 3 -#endif /* WHPX_CPUS_H */ +#endif /* TARGET_I386_WHPX_ACCEL_OPS_H */ diff --git a/target/i386/whpx/whpx-internal.h b/target/i386/whpx/whpx-internal.h index dbb7e7ba82..06429d8ccd 100644 --- a/target/i386/whpx/whpx-internal.h +++ b/target/i386/whpx/whpx-internal.h @@ -1,5 +1,5 @@ -#ifndef WHP_INTERNAL_H -#define WHP_INTERNAL_H +#ifndef TARGET_I386_WHPX_INTERNAL_H +#define TARGET_I386_WHPX_INTERNAL_H #include #include @@ -116,4 +116,4 @@ typedef enum WHPFunctionList { WINHV_PLATFORM_FNS_SUPPLEMENTAL } WHPFunctionList; -#endif /* WHP_INTERNAL_H */ +#endif /* TARGET_I386_WHPX_INTERNAL_H */ diff --git a/target/xtensa/core-de233_fpu/core-isa.h b/target/xtensa/core-de233_fpu/core-isa.h index f125619e8d..40543b2c5e 100644 --- a/target/xtensa/core-de233_fpu/core-isa.h +++ b/target/xtensa/core-de233_fpu/core-isa.h @@ -28,8 +28,8 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef XTENSA_CORE_CONFIGURATION_H_ -#define XTENSA_CORE_CONFIGURATION_H_ +#ifndef XTENSA_CORE_DE233_FPU_CORE_ISA_H +#define XTENSA_CORE_DE233_FPU_CORE_ISA_H //depot/dev/Homewood/Xtensa/SWConfig/hal/core-common.h.tph#24 - edit change 444323 (text+ko) @@ -723,5 +723,4 @@ #endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */ -#endif /* XTENSA_CORE_CONFIGURATION_H_ */ - +#endif /* XTENSA_CORE_DE233_FPU_CORE_ISA_H */ diff --git a/target/xtensa/core-dsp3400/core-isa.h b/target/xtensa/core-dsp3400/core-isa.h index 336b2467c6..1499ef2914 100644 --- a/target/xtensa/core-dsp3400/core-isa.h +++ b/target/xtensa/core-dsp3400/core-isa.h @@ -28,9 +28,8 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef _XTENSA_CORE_CONFIGURATION_H -#define _XTENSA_CORE_CONFIGURATION_H - +#ifndef XTENSA_CORE_DSP3400_CORE_ISA_H +#define XTENSA_CORE_DSP3400_CORE_ISA_H /**************************************************************************** Parameters Useful for Any Code, USER or PRIVILEGED @@ -448,5 +447,4 @@ #endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */ -#endif /* _XTENSA_CORE_CONFIGURATION_H */ - +#endif /* XTENSA_CORE_DSP3400_CORE_ISA_H */ diff --git a/tests/qtest/fuzz/fuzz.h b/tests/qtest/fuzz/fuzz.h index c5f0b7227a..327c1c5a55 100644 --- a/tests/qtest/fuzz/fuzz.h +++ b/tests/qtest/fuzz/fuzz.h @@ -11,8 +11,8 @@ * */ -#ifndef FUZZER_H_ -#define FUZZER_H_ +#ifndef QTEST_FUZZ_H +#define QTEST_FUZZ_H #include "qemu/units.h" #include "qapi/error.h" @@ -122,4 +122,3 @@ int LLVMFuzzerTestOneInput(const unsigned char *Data, size_t Size); int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp); #endif - diff --git a/tools/virtiofsd/passthrough_seccomp.h b/tools/virtiofsd/passthrough_seccomp.h index a3ab073f08..12674fc050 100644 --- a/tools/virtiofsd/passthrough_seccomp.h +++ b/tools/virtiofsd/passthrough_seccomp.h @@ -6,10 +6,9 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef VIRTIOFSD_SECCOMP_H -#define VIRTIOFSD_SECCOMP_H - +#ifndef VIRTIOFSD_PASSTHROUGH_SECCOMP_H +#define VIRTIOFSD_PASSTHROUGH_SECCOMP_H void setup_seccomp(bool enable_syslog); -#endif /* VIRTIOFSD_SECCOMP_H */ +#endif /* VIRTIOFSD_PASSTHROUGH_SECCOMP_H */ From 9c0928045ce4b97fc59cb285b7a4b559d21e5da0 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 6 May 2022 15:49:09 +0200 Subject: [PATCH 228/935] Clean up ill-advised or unusual header guards Leading underscores are ill-advised because such identifiers are reserved. Trailing underscores are merely ugly. Strip both. Our header guards commonly end in _H. Normalize the exceptions. Macros should be ALL_CAPS. Normalize the exception. Done with scripts/clean-header-guards.pl. include/hw/xen/interface/ and tools/virtiofsd/ left alone, because these were imported from Xen and libfuse respectively. Signed-off-by: Markus Armbruster Message-Id: <20220506134911.2856099-3-armbru@redhat.com> Reviewed-by: Richard Henderson --- block/copy-on-read.h | 6 +++--- bsd-user/arm/target_arch.h | 6 +++--- bsd-user/arm/target_arch_cpu.h | 6 +++--- bsd-user/arm/target_arch_elf.h | 7 ++++--- bsd-user/arm/target_arch_reg.h | 6 +++--- bsd-user/arm/target_arch_signal.h | 7 ++++--- bsd-user/arm/target_arch_sigtramp.h | 6 +++--- bsd-user/arm/target_arch_sysarch.h | 6 +++--- bsd-user/arm/target_arch_thread.h | 7 ++++--- bsd-user/arm/target_arch_vmparam.h | 7 ++++--- bsd-user/bsd-file.h | 6 +++--- bsd-user/errno_defs.h | 6 +++--- bsd-user/freebsd/host-os.h | 6 +++--- bsd-user/freebsd/target_os_elf.h | 7 ++++--- bsd-user/freebsd/target_os_siginfo.h | 7 ++++--- bsd-user/freebsd/target_os_signal.h | 6 +++--- bsd-user/freebsd/target_os_stack.h | 6 +++--- bsd-user/freebsd/target_os_thread.h | 6 +++--- bsd-user/freebsd/target_os_user.h | 6 +++--- bsd-user/freebsd/target_os_vmparam.h | 7 ++++--- bsd-user/i386/target_arch.h | 6 +++--- bsd-user/i386/target_arch_cpu.h | 6 +++--- bsd-user/i386/target_arch_elf.h | 7 ++++--- bsd-user/i386/target_arch_reg.h | 6 +++--- bsd-user/i386/target_arch_sigtramp.h | 6 +++--- bsd-user/i386/target_arch_thread.h | 7 ++++--- bsd-user/i386/target_arch_vmparam.h | 7 ++++--- bsd-user/netbsd/host-os.h | 6 +++--- bsd-user/netbsd/target_os_elf.h | 7 ++++--- bsd-user/netbsd/target_os_siginfo.h | 6 +++--- bsd-user/netbsd/target_os_signal.h | 6 +++--- bsd-user/netbsd/target_os_stack.h | 6 +++--- bsd-user/netbsd/target_os_thread.h | 6 +++--- bsd-user/openbsd/host-os.h | 6 +++--- bsd-user/openbsd/target_os_elf.h | 7 ++++--- bsd-user/openbsd/target_os_siginfo.h | 6 +++--- bsd-user/openbsd/target_os_signal.h | 6 +++--- bsd-user/openbsd/target_os_stack.h | 6 +++--- bsd-user/openbsd/target_os_thread.h | 6 +++--- bsd-user/syscall_defs.h | 6 +++--- bsd-user/x86_64/target_arch.h | 6 +++--- bsd-user/x86_64/target_arch_cpu.h | 6 +++--- bsd-user/x86_64/target_arch_elf.h | 7 ++++--- bsd-user/x86_64/target_arch_reg.h | 6 +++--- bsd-user/x86_64/target_arch_signal.h | 7 ++++--- bsd-user/x86_64/target_arch_sigtramp.h | 6 +++--- bsd-user/x86_64/target_arch_thread.h | 7 ++++--- bsd-user/x86_64/target_arch_vmparam.h | 7 ++++--- crypto/ivgen-plain.h | 6 +++--- include/chardev/char-socket.h | 7 ++++--- include/hw/i2c/i2c_mux_pca954x.h | 4 ++-- include/hw/input/lm832x.h | 4 ++-- include/hw/intc/exynos4210_combiner.h | 4 ++-- include/hw/intc/nios2_vic.h | 6 +++--- include/hw/ppc/pnv_pnor.h | 8 +++++--- include/hw/s390x/s390-pci-clp.h | 4 ++-- include/hw/tricore/tc27x_soc.h | 4 ++-- include/hw/virtio/vhost-user-fs.h | 6 +++--- include/hw/virtio/vhost-user-i2c.h | 6 +++--- include/hw/virtio/vhost-user-rng.h | 6 +++--- include/hw/virtio/vhost-user-vsock.h | 6 +++--- include/hw/virtio/vhost-vsock-common.h | 6 +++--- include/qemu/cpu-float.h | 6 +++--- include/qemu/crc-ccitt.h | 6 +++--- include/qemu/keyval.h | 7 ++++--- include/ui/dbus-display.h | 6 +++--- include/ui/dbus-module.h | 6 +++--- target/ppc/power8-pmu.h | 4 ++-- target/riscv/sbi_ecall_interface.h | 4 ++-- tests/qtest/libqmp.h | 7 ++++--- tests/qtest/migration-helpers.h | 7 ++++--- ui/dbus.h | 7 ++++--- 72 files changed, 232 insertions(+), 209 deletions(-) diff --git a/block/copy-on-read.h b/block/copy-on-read.h index 7bf405dccd..1d8ad38c74 100644 --- a/block/copy-on-read.h +++ b/block/copy-on-read.h @@ -22,11 +22,11 @@ * along with this program. If not, see . */ -#ifndef BLOCK_COPY_ON_READ -#define BLOCK_COPY_ON_READ +#ifndef BLOCK_COPY_ON_READ_H +#define BLOCK_COPY_ON_READ_H #include "block/block_int.h" void bdrv_cor_filter_drop(BlockDriverState *cor_filter_bs); -#endif /* BLOCK_COPY_ON_READ */ +#endif /* BLOCK_COPY_ON_READ_H */ diff --git a/bsd-user/arm/target_arch.h b/bsd-user/arm/target_arch.h index 93cfaea098..561934bbd2 100644 --- a/bsd-user/arm/target_arch.h +++ b/bsd-user/arm/target_arch.h @@ -17,12 +17,12 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_H_ -#define _TARGET_ARCH_H_ +#ifndef TARGET_ARCH_H +#define TARGET_ARCH_H #include "qemu.h" void target_cpu_set_tls(CPUARMState *env, target_ulong newtls); target_ulong target_cpu_get_tls(CPUARMState *env); -#endif /* !_TARGET_ARCH_H_ */ +#endif /* TARGET_ARCH_H */ diff --git a/bsd-user/arm/target_arch_cpu.h b/bsd-user/arm/target_arch_cpu.h index afb7814a8d..517d008764 100644 --- a/bsd-user/arm/target_arch_cpu.h +++ b/bsd-user/arm/target_arch_cpu.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_CPU_H_ -#define _TARGET_ARCH_CPU_H_ +#ifndef TARGET_ARCH_CPU_H +#define TARGET_ARCH_CPU_H #include "target_arch.h" #include "signal-common.h" @@ -210,4 +210,4 @@ static inline void target_cpu_reset(CPUArchState *env) { } -#endif /* !_TARGET_ARCH_CPU_H */ +#endif /* TARGET_ARCH_CPU_H */ diff --git a/bsd-user/arm/target_arch_elf.h b/bsd-user/arm/target_arch_elf.h index 4a0215d02e..935bce347f 100644 --- a/bsd-user/arm/target_arch_elf.h +++ b/bsd-user/arm/target_arch_elf.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_ELF_H_ -#define _TARGET_ARCH_ELF_H_ + +#ifndef TARGET_ARCH_ELF_H +#define TARGET_ARCH_ELF_H #define ELF_START_MMAP 0x80000000 #define ELF_ET_DYN_LOAD_ADDR 0x500000 @@ -125,4 +126,4 @@ static uint32_t get_elf_hwcap2(void) #undef GET_FEATURE #undef GET_FEATURE_ID -#endif /* _TARGET_ARCH_ELF_H_ */ +#endif /* TARGET_ARCH_ELF_H */ diff --git a/bsd-user/arm/target_arch_reg.h b/bsd-user/arm/target_arch_reg.h index ef5ed5154f..070fa24da1 100644 --- a/bsd-user/arm/target_arch_reg.h +++ b/bsd-user/arm/target_arch_reg.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_REG_H_ -#define _TARGET_ARCH_REG_H_ +#ifndef TARGET_ARCH_REG_H +#define TARGET_ARCH_REG_H /* See sys/arm/include/reg.h */ typedef struct target_reg { @@ -57,4 +57,4 @@ static inline void target_copy_regs(target_reg_t *regs, const CPUARMState *env) #undef tswapreg -#endif /* !_TARGET_ARCH_REG_H_ */ +#endif /* TARGET_ARCH_REG_H */ diff --git a/bsd-user/arm/target_arch_signal.h b/bsd-user/arm/target_arch_signal.h index f1844dbf22..02b2b33e07 100644 --- a/bsd-user/arm/target_arch_signal.h +++ b/bsd-user/arm/target_arch_signal.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_SIGNAL_H_ -#define _TARGET_ARCH_SIGNAL_H_ + +#ifndef TARGET_ARCH_SIGNAL_H +#define TARGET_ARCH_SIGNAL_H #include "cpu.h" @@ -85,4 +86,4 @@ struct target_sigframe { target_mcontext_vfp_t sf_vfp; /* actual saved VFP context */ }; -#endif /* !_TARGET_ARCH_SIGNAL_H_ */ +#endif /* TARGET_ARCH_SIGNAL_H */ diff --git a/bsd-user/arm/target_arch_sigtramp.h b/bsd-user/arm/target_arch_sigtramp.h index 5d434a9e7e..06198045ed 100644 --- a/bsd-user/arm/target_arch_sigtramp.h +++ b/bsd-user/arm/target_arch_sigtramp.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_SIGTRAMP_H_ -#define _TARGET_ARCH_SIGTRAMP_H_ +#ifndef TARGET_ARCH_SIGTRAMP_H +#define TARGET_ARCH_SIGTRAMP_H /* Compare to arm/arm/locore.S ENTRY_NP(sigcode) */ static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, @@ -46,4 +46,4 @@ static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE); } -#endif /* _TARGET_ARCH_SIGTRAMP_H_ */ +#endif /* TARGET_ARCH_SIGTRAMP_H */ diff --git a/bsd-user/arm/target_arch_sysarch.h b/bsd-user/arm/target_arch_sysarch.h index 8cc6bff207..5cb7864197 100644 --- a/bsd-user/arm/target_arch_sysarch.h +++ b/bsd-user/arm/target_arch_sysarch.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_SYSARCH_H_ -#define _TARGET_ARCH_SYSARCH_H_ +#ifndef TARGET_ARCH_SYSARCH_H +#define TARGET_ARCH_SYSARCH_H #include "target_syscall.h" #include "target_arch.h" @@ -75,4 +75,4 @@ static inline void do_freebsd_arch_print_sysarch( } } -#endif /*!_TARGET_ARCH_SYSARCH_H_ */ +#endif /* TARGET_ARCH_SYSARCH_H */ diff --git a/bsd-user/arm/target_arch_thread.h b/bsd-user/arm/target_arch_thread.h index fcafca2408..fd257f313d 100644 --- a/bsd-user/arm/target_arch_thread.h +++ b/bsd-user/arm/target_arch_thread.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_THREAD_H_ -#define _TARGET_ARCH_THREAD_H_ + +#ifndef TARGET_ARCH_THREAD_H +#define TARGET_ARCH_THREAD_H /* Compare to arm/arm/vm_machdep.c cpu_set_upcall_kse() */ static inline void target_thread_set_upcall(CPUARMState *env, abi_ulong entry, @@ -77,4 +78,4 @@ static inline void target_thread_init(struct target_pt_regs *regs, */ } -#endif /* !_TARGET_ARCH_THREAD_H_ */ +#endif /* TARGET_ARCH_THREAD_H */ diff --git a/bsd-user/arm/target_arch_vmparam.h b/bsd-user/arm/target_arch_vmparam.h index 4bbc04ddf5..3fb69aff51 100644 --- a/bsd-user/arm/target_arch_vmparam.h +++ b/bsd-user/arm/target_arch_vmparam.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_VMPARAM_H_ -#define _TARGET_ARCH_VMPARAM_H_ + +#ifndef TARGET_ARCH_VMPARAM_H +#define TARGET_ARCH_VMPARAM_H #include "cpu.h" @@ -45,4 +46,4 @@ static inline void set_second_rval(CPUARMState *state, abi_ulong retval2) state->regs[1] = retval2; } -#endif /* ! _TARGET_ARCH_VMPARAM_H_ */ +#endif /* TARGET_ARCH_VMPARAM_H */ diff --git a/bsd-user/bsd-file.h b/bsd-user/bsd-file.h index f0c3f347ec..a6bff3b8c2 100644 --- a/bsd-user/bsd-file.h +++ b/bsd-user/bsd-file.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef BSD_FILE_H_ -#define BSD_FILE_H_ +#ifndef BSD_FILE_H +#define BSD_FILE_H #include "qemu/path.h" @@ -27,4 +27,4 @@ extern struct iovec *lock_iovec(int type, abi_ulong target_addr, int count, extern void unlock_iovec(struct iovec *vec, abi_ulong target_addr, int count, int copy); -#endif /* !BSD_FILE_H_ */ +#endif /* BSD_FILE_H */ diff --git a/bsd-user/errno_defs.h b/bsd-user/errno_defs.h index 73cfa24b7f..f3e8ac3488 100644 --- a/bsd-user/errno_defs.h +++ b/bsd-user/errno_defs.h @@ -34,8 +34,8 @@ * @(#)errno.h 8.5 (Berkeley) 1/21/94 */ -#ifndef _ERRNO_DEFS_H_ -#define _ERRNO_DEFS_H_ +#ifndef ERRNO_DEFS_H +#define ERRNO_DEFS_H #define TARGET_EPERM 1 /* Operation not permitted */ #define TARGET_ENOENT 2 /* No such file or directory */ @@ -157,4 +157,4 @@ _Static_assert(TARGET_ERESTART == QEMU_ERESTARTSYS, "TARGET_ERESTART and QEMU_ERESTARTSYS expected to match"); -#endif /* ! _ERRNO_DEFS_H_ */ +#endif /* ERRNO_DEFS_H */ diff --git a/bsd-user/freebsd/host-os.h b/bsd-user/freebsd/host-os.h index dfb8344b7b..40cae72ec9 100644 --- a/bsd-user/freebsd/host-os.h +++ b/bsd-user/freebsd/host-os.h @@ -17,9 +17,9 @@ * along with this program; if not, see . */ -#ifndef _HOST_OS_H_ -#define _HOST_OS_H_ +#ifndef HOST_OS_H +#define HOST_OS_H #define HOST_DEFAULT_BSD_TYPE target_freebsd -#endif /*!_HOST_OS_H_ */ +#endif /* HOST_OS_H */ diff --git a/bsd-user/freebsd/target_os_elf.h b/bsd-user/freebsd/target_os_elf.h index e5ac8e8e50..9df17d56d8 100644 --- a/bsd-user/freebsd/target_os_elf.h +++ b/bsd-user/freebsd/target_os_elf.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_OS_ELF_H_ -#define _TARGET_OS_ELF_H_ + +#ifndef TARGET_OS_ELF_H +#define TARGET_OS_ELF_H #include "target_arch_elf.h" #include "elf.h" @@ -134,4 +135,4 @@ static abi_ulong target_create_elf_tables(abi_ulong p, int argc, int envc, return sp; } -#endif /* _TARGET_OS_ELF_H_ */ +#endif /* TARGET_OS_ELF_H */ diff --git a/bsd-user/freebsd/target_os_siginfo.h b/bsd-user/freebsd/target_os_siginfo.h index d50a3034a8..4573738752 100644 --- a/bsd-user/freebsd/target_os_siginfo.h +++ b/bsd-user/freebsd/target_os_siginfo.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_OS_SIGINFO_H_ -#define _TARGET_OS_SIGINFO_H_ + +#ifndef TARGET_OS_SIGINFO_H +#define TARGET_OS_SIGINFO_H #define TARGET_NSIG 128 #define TARGET_NSIG_BPW (sizeof(uint32_t) * 8) @@ -155,4 +156,4 @@ struct target_sigevent { #define TARGET_FPE_FLTINV (7) /* Invalid floating point operation. */ #define TARGET_FPE_FLTSUB (8) /* Subscript out of range. */ -#endif /* !_TARGET_OS_SIGINFO_H_ */ +#endif /* TARGET_OS_SIGINFO_H */ diff --git a/bsd-user/freebsd/target_os_signal.h b/bsd-user/freebsd/target_os_signal.h index 43700d08f7..5030abb52b 100644 --- a/bsd-user/freebsd/target_os_signal.h +++ b/bsd-user/freebsd/target_os_signal.h @@ -1,5 +1,5 @@ -#ifndef _TARGET_OS_SIGNAL_H_ -#define _TARGET_OS_SIGNAL_H_ +#ifndef TARGET_OS_SIGNAL_H +#define TARGET_OS_SIGNAL_H #include "target_os_siginfo.h" #include "target_arch_signal.h" @@ -78,4 +78,4 @@ abi_long setup_sigframe_arch(CPUArchState *env, abi_ulong frame_addr, #define TARGET_SS_ONSTACK 0x0001 /* take signals on alternate stack */ #define TARGET_SS_DISABLE 0x0004 /* disable taking signals on alternate stack*/ -#endif /* !_TARGET_OS_SIGNAL_H_ */ +#endif /* TARGET_OS_SIGNAL_H */ diff --git a/bsd-user/freebsd/target_os_stack.h b/bsd-user/freebsd/target_os_stack.h index 1bb1a2bf56..0590133291 100644 --- a/bsd-user/freebsd/target_os_stack.h +++ b/bsd-user/freebsd/target_os_stack.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_OS_STACK_H_ -#define _TARGET_OS_STACK_H_ +#ifndef TARGET_OS_STACK_H +#define TARGET_OS_STACK_H #include #include "target_arch_sigtramp.h" @@ -178,4 +178,4 @@ static inline int setup_initial_stack(struct bsd_binprm *bprm, return 0; } -#endif /* !_TARGET_OS_STACK_H_ */ +#endif /* TARGET_OS_STACK_H */ diff --git a/bsd-user/freebsd/target_os_thread.h b/bsd-user/freebsd/target_os_thread.h index 77433acdff..1b32cebd26 100644 --- a/bsd-user/freebsd/target_os_thread.h +++ b/bsd-user/freebsd/target_os_thread.h @@ -17,9 +17,9 @@ * along with this program; if not, see . */ -#ifndef _TARGET_OS_THREAD_H_ -#define _TARGET_OS_THREAD_H_ +#ifndef TARGET_OS_THREAD_H +#define TARGET_OS_THREAD_H #include "target_arch_thread.h" -#endif /* !_TARGET_OS_THREAD_H_ */ +#endif /* TARGET_OS_THREAD_H */ diff --git a/bsd-user/freebsd/target_os_user.h b/bsd-user/freebsd/target_os_user.h index 19892c5071..f036a32343 100644 --- a/bsd-user/freebsd/target_os_user.h +++ b/bsd-user/freebsd/target_os_user.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_OS_USER_H_ -#define _TARGET_OS_USER_H_ +#ifndef TARGET_OS_USER_H +#define TARGET_OS_USER_H /* * from sys/priority.h @@ -326,4 +326,4 @@ struct target_kinfo_vmentry { char kve_path[PATH_MAX]; /* Path to VM obj, if any. */ }; -#endif /* ! _TARGET_OS_USER_H_ */ +#endif /* TARGET_OS_USER_H */ diff --git a/bsd-user/freebsd/target_os_vmparam.h b/bsd-user/freebsd/target_os_vmparam.h index 990300c619..8457dd3913 100644 --- a/bsd-user/freebsd/target_os_vmparam.h +++ b/bsd-user/freebsd/target_os_vmparam.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_OS_VMPARAM_H_ -#define _TARGET_OS_VMPARAM_H_ + +#ifndef TARGET_OS_VMPARAM_H +#define TARGET_OS_VMPARAM_H #include "target_arch_vmparam.h" @@ -35,4 +36,4 @@ extern abi_ulong target_stksiz; #define TARGET_PS_STRINGS ((target_stkbas + target_stksiz) - \ sizeof(struct target_ps_strings)) -#endif /* !TARGET_OS_VMPARAM_H_ */ +#endif /* TARGET_OS_VMPARAM_H */ diff --git a/bsd-user/i386/target_arch.h b/bsd-user/i386/target_arch.h index 73e9a028fe..9595e60f09 100644 --- a/bsd-user/i386/target_arch.h +++ b/bsd-user/i386/target_arch.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_H_ -#define _TARGET_ARCH_H_ +#ifndef TARGET_ARCH_H +#define TARGET_ARCH_H /* target_arch_cpu.c */ void bsd_i386_write_dt(void *ptr, unsigned long addr, unsigned long limit, @@ -28,4 +28,4 @@ void bsd_i386_set_idt_base(uint64_t base); #define target_cpu_set_tls(env, newtls) -#endif /* ! _TARGET_ARCH_H_ */ +#endif /* TARGET_ARCH_H */ diff --git a/bsd-user/i386/target_arch_cpu.h b/bsd-user/i386/target_arch_cpu.h index 9da22202d4..d792dc720f 100644 --- a/bsd-user/i386/target_arch_cpu.h +++ b/bsd-user/i386/target_arch_cpu.h @@ -16,8 +16,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_CPU_H_ -#define _TARGET_ARCH_CPU_H_ +#ifndef TARGET_ARCH_CPU_H +#define TARGET_ARCH_CPU_H #include "target_arch.h" #include "signal-common.h" @@ -195,4 +195,4 @@ static inline void target_cpu_reset(CPUArchState *env) cpu_reset(env_cpu(env)); } -#endif /* ! _TARGET_ARCH_CPU_H_ */ +#endif /* TARGET_ARCH_CPU_H */ diff --git a/bsd-user/i386/target_arch_elf.h b/bsd-user/i386/target_arch_elf.h index eb760e07fa..cbcd1f08e2 100644 --- a/bsd-user/i386/target_arch_elf.h +++ b/bsd-user/i386/target_arch_elf.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_ELF_H_ -#define _TARGET_ARCH_ELF_H_ + +#ifndef TARGET_ARCH_ELF_H +#define TARGET_ARCH_ELF_H #define ELF_START_MMAP 0x80000000 #define ELF_ET_DYN_LOAD_ADDR 0x01001000 @@ -32,4 +33,4 @@ #define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 -#endif /* _TARGET_ARCH_ELF_H_ */ +#endif /* TARGET_ARCH_ELF_H */ diff --git a/bsd-user/i386/target_arch_reg.h b/bsd-user/i386/target_arch_reg.h index 1fce1daf01..8123109697 100644 --- a/bsd-user/i386/target_arch_reg.h +++ b/bsd-user/i386/target_arch_reg.h @@ -18,8 +18,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_REG_H_ -#define _TARGET_ARCH_REG_H_ +#ifndef TARGET_ARCH_REG_H +#define TARGET_ARCH_REG_H /* See sys/i386/include/reg.h */ typedef struct target_reg { @@ -79,4 +79,4 @@ static inline void target_copy_regs(target_reg_t *regs, const CPUX86State *env) regs->r_gs = env->segs[R_GS].selector & 0xffff; } -#endif /* !_TARGET_ARCH_REG_H_ */ +#endif /* TARGET_ARCH_REG_H */ diff --git a/bsd-user/i386/target_arch_sigtramp.h b/bsd-user/i386/target_arch_sigtramp.h index cb4e89b0b0..ef94cc864f 100644 --- a/bsd-user/i386/target_arch_sigtramp.h +++ b/bsd-user/i386/target_arch_sigtramp.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_SIGTRAMP_H_ -#define _TARGET_ARCH_SIGTRAMP_H_ +#ifndef TARGET_ARCH_SIGTRAMP_H +#define TARGET_ARCH_SIGTRAMP_H static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, unsigned sys_sigreturn) @@ -26,4 +26,4 @@ static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, return 0; } -#endif /* _TARGET_ARCH_SIGTRAMP_H_ */ +#endif /* TARGET_ARCH_SIGTRAMP_H */ diff --git a/bsd-user/i386/target_arch_thread.h b/bsd-user/i386/target_arch_thread.h index e65e476f75..cee2148d94 100644 --- a/bsd-user/i386/target_arch_thread.h +++ b/bsd-user/i386/target_arch_thread.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_THREAD_H_ -#define _TARGET_ARCH_THREAD_H_ + +#ifndef TARGET_ARCH_THREAD_H +#define TARGET_ARCH_THREAD_H /* Compare to vm_machdep.c cpu_set_upcall_kse() */ static inline void target_thread_set_upcall(CPUX86State *regs, abi_ulong entry, @@ -44,4 +45,4 @@ static inline void target_thread_init(struct target_pt_regs *regs, regs->edx = 0; } -#endif /* !_TARGET_ARCH_THREAD_H_ */ +#endif /* TARGET_ARCH_THREAD_H */ diff --git a/bsd-user/i386/target_arch_vmparam.h b/bsd-user/i386/target_arch_vmparam.h index bb7718265b..79db420e59 100644 --- a/bsd-user/i386/target_arch_vmparam.h +++ b/bsd-user/i386/target_arch_vmparam.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_VMPARAM_H_ -#define _TARGET_ARCH_VMPARAM_H_ + +#ifndef TARGET_ARCH_VMPARAM_H +#define TARGET_ARCH_VMPARAM_H #include "cpu.h" @@ -43,4 +44,4 @@ static inline void set_second_rval(CPUX86State *state, abi_ulong retval2) state->regs[R_EDX] = retval2; } -#endif /* !_TARGET_ARCH_VMPARAM_H_ */ +#endif /* TARGET_ARCH_VMPARAM_H */ diff --git a/bsd-user/netbsd/host-os.h b/bsd-user/netbsd/host-os.h index c0be51a7ef..7c14b1ea78 100644 --- a/bsd-user/netbsd/host-os.h +++ b/bsd-user/netbsd/host-os.h @@ -17,9 +17,9 @@ * along with this program; if not, see . */ -#ifndef _HOST_OS_H_ -#define _HOST_OS_H_ +#ifndef HOST_OS_H +#define HOST_OS_H #define HOST_DEFAULT_BSD_TYPE target_netbsd -#endif /*!_HOST_OS_H_ */ +#endif /* HOST_OS_H */ diff --git a/bsd-user/netbsd/target_os_elf.h b/bsd-user/netbsd/target_os_elf.h index 21b475f458..2f3cb20871 100644 --- a/bsd-user/netbsd/target_os_elf.h +++ b/bsd-user/netbsd/target_os_elf.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_OS_ELF_H_ -#define _TARGET_OS_ELF_H_ + +#ifndef TARGET_OS_ELF_H +#define TARGET_OS_ELF_H #include "target_arch_elf.h" #include "elf.h" @@ -143,4 +144,4 @@ static abi_ulong target_create_elf_tables(abi_ulong p, int argc, int envc, return sp; } -#endif /* _TARGET_OS_ELF_H_ */ +#endif /* TARGET_OS_ELF_H */ diff --git a/bsd-user/netbsd/target_os_siginfo.h b/bsd-user/netbsd/target_os_siginfo.h index 667c19cc7c..eb57e0a309 100644 --- a/bsd-user/netbsd/target_os_siginfo.h +++ b/bsd-user/netbsd/target_os_siginfo.h @@ -1,5 +1,5 @@ -#ifndef _TARGET_OS_SIGINFO_H_ -#define _TARGET_OS_SIGINFO_H_ +#ifndef TARGET_OS_SIGINFO_H +#define TARGET_OS_SIGINFO_H #define TARGET_NSIG 32 /* counting 0; could be 33 (mask is 1-32) */ #define TARGET_NSIG_BPW (sizeof(uint32_t) * 8) @@ -79,4 +79,4 @@ typedef union target_siginfo { #define TARGET_TRAP_TRACE 2 -#endif /* ! _TARGET_OS_SIGINFO_H_ */ +#endif /* TARGET_OS_SIGINFO_H */ diff --git a/bsd-user/netbsd/target_os_signal.h b/bsd-user/netbsd/target_os_signal.h index a373922f7e..4ee4f768e0 100644 --- a/bsd-user/netbsd/target_os_signal.h +++ b/bsd-user/netbsd/target_os_signal.h @@ -1,5 +1,5 @@ -#ifndef _TARGET_OS_SIGNAL_H_ -#define _TARGET_OS_SIGNAL_H_ +#ifndef TARGET_OS_SIGNAL_H +#define TARGET_OS_SIGNAL_H #include "target_os_siginfo.h" #include "target_arch_signal.h" @@ -66,4 +66,4 @@ #define TARGET_SS_ONSTACK 0x0001 /* take signals on alternate stack */ #define TARGET_SS_DISABLE 0x0004 /* disable taking signals on alternate stack */ -#endif /* !_TARGET_OS_SIGNAL_H_ */ +#endif /* TARGET_OS_SIGNAL_H */ diff --git a/bsd-user/netbsd/target_os_stack.h b/bsd-user/netbsd/target_os_stack.h index 503279c1a9..8349e9149b 100644 --- a/bsd-user/netbsd/target_os_stack.h +++ b/bsd-user/netbsd/target_os_stack.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_OS_STACK_H_ -#define _TARGET_OS_STACK_H_ +#ifndef TARGET_OS_STACK_H +#define TARGET_OS_STACK_H #include "target_arch_sigtramp.h" @@ -53,4 +53,4 @@ static inline int setup_initial_stack(struct bsd_binprm *bprm, abi_ulong *p, return 0; } -#endif /* !_TARGET_OS_STACK_H_ */ +#endif /* TARGET_OS_STACK_H */ diff --git a/bsd-user/netbsd/target_os_thread.h b/bsd-user/netbsd/target_os_thread.h index 904dd1bf78..8ccfa16e4b 100644 --- a/bsd-user/netbsd/target_os_thread.h +++ b/bsd-user/netbsd/target_os_thread.h @@ -17,9 +17,9 @@ * along with this program; if not, see . */ -#ifndef _TARGET_OS_THREAD_H_ -#define _TARGET_OS_THREAD_H_ +#ifndef TARGET_OS_THREAD_H +#define TARGET_OS_THREAD_H #include "target_arch_thread.h" -#endif /* !_TARGET_OS_THREAD_H_ */ +#endif /* TARGET_OS_THREAD_H */ diff --git a/bsd-user/openbsd/host-os.h b/bsd-user/openbsd/host-os.h index eb8fdf1567..b9222335d4 100644 --- a/bsd-user/openbsd/host-os.h +++ b/bsd-user/openbsd/host-os.h @@ -17,9 +17,9 @@ * along with this program; if not, see . */ -#ifndef _HOST_OS_H_ -#define _HOST_OS_H_ +#ifndef HOST_OS_H +#define HOST_OS_H #define HOST_DEFAULT_BSD_TYPE target_openbsd -#endif /*!_HOST_OS_H_ */ +#endif /* HOST_OS_H */ diff --git a/bsd-user/openbsd/target_os_elf.h b/bsd-user/openbsd/target_os_elf.h index a5cfcd3aff..6dca9c5a85 100644 --- a/bsd-user/openbsd/target_os_elf.h +++ b/bsd-user/openbsd/target_os_elf.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_OS_ELF_H_ -#define _TARGET_OS_ELF_H_ + +#ifndef TARGET_OS_ELF_H +#define TARGET_OS_ELF_H #include "target_arch_elf.h" #include "elf.h" @@ -143,4 +144,4 @@ static abi_ulong target_create_elf_tables(abi_ulong p, int argc, int envc, return sp; } -#endif /* _TARGET_OS_ELF_H_ */ +#endif /* TARGET_OS_ELF_H */ diff --git a/bsd-user/openbsd/target_os_siginfo.h b/bsd-user/openbsd/target_os_siginfo.h index baf646a5ab..732009a820 100644 --- a/bsd-user/openbsd/target_os_siginfo.h +++ b/bsd-user/openbsd/target_os_siginfo.h @@ -1,5 +1,5 @@ -#ifndef _TARGET_OS_SIGINFO_H_ -#define _TARGET_OS_SIGINFO_H_ +#ifndef TARGET_OS_SIGINFO_H +#define TARGET_OS_SIGINFO_H #define TARGET_NSIG 32 /* counting 0; could be 33 (mask is 1-32) */ #define TARGET_NSIG_BPW (sizeof(uint32_t) * 8) @@ -79,4 +79,4 @@ typedef union target_siginfo { #define TARGET_TRAP_TRACE 2 -#endif /* ! _TARGET_OS_SIGINFO_H_ */ +#endif /* TARGET_OS_SIGINFO_H */ diff --git a/bsd-user/openbsd/target_os_signal.h b/bsd-user/openbsd/target_os_signal.h index a373922f7e..4ee4f768e0 100644 --- a/bsd-user/openbsd/target_os_signal.h +++ b/bsd-user/openbsd/target_os_signal.h @@ -1,5 +1,5 @@ -#ifndef _TARGET_OS_SIGNAL_H_ -#define _TARGET_OS_SIGNAL_H_ +#ifndef TARGET_OS_SIGNAL_H +#define TARGET_OS_SIGNAL_H #include "target_os_siginfo.h" #include "target_arch_signal.h" @@ -66,4 +66,4 @@ #define TARGET_SS_ONSTACK 0x0001 /* take signals on alternate stack */ #define TARGET_SS_DISABLE 0x0004 /* disable taking signals on alternate stack */ -#endif /* !_TARGET_OS_SIGNAL_H_ */ +#endif /* TARGET_OS_SIGNAL_H */ diff --git a/bsd-user/openbsd/target_os_stack.h b/bsd-user/openbsd/target_os_stack.h index 4b37955d3b..264a658608 100644 --- a/bsd-user/openbsd/target_os_stack.h +++ b/bsd-user/openbsd/target_os_stack.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_OS_STACK_H_ -#define _TARGET_OS_STACK_H_ +#ifndef TARGET_OS_STACK_H +#define TARGET_OS_STACK_H #include "target_arch_sigtramp.h" @@ -53,4 +53,4 @@ static inline int setup_initial_stack(struct bsd_binprm *bprm, abi_ulong *p, return 0; } -#endif /* !_TARGET_OS_STACK_H_ */ +#endif /* TARGET_OS_STACK_H */ diff --git a/bsd-user/openbsd/target_os_thread.h b/bsd-user/openbsd/target_os_thread.h index 01ed0d9fc8..c3adc6712f 100644 --- a/bsd-user/openbsd/target_os_thread.h +++ b/bsd-user/openbsd/target_os_thread.h @@ -17,9 +17,9 @@ * along with this program; if not, see . */ -#ifndef _TARGET_OS_THREAD_H_ -#define _TARGET_OS_THREAD_H_ +#ifndef TARGET_OS_THREAD_H +#define TARGET_OS_THREAD_H #include "target_arch_thread.h" -#endif /* !_TARGET_OS_THREAD_H_ */ +#endif /* TARGET_OS_THREAD_H */ diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h index c3bf14f38f..f5797b28e3 100644 --- a/bsd-user/syscall_defs.h +++ b/bsd-user/syscall_defs.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _SYSCALL_DEFS_H_ -#define _SYSCALL_DEFS_H_ +#ifndef SYSCALL_DEFS_H +#define SYSCALL_DEFS_H #include #include @@ -226,4 +226,4 @@ type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ return safe_syscall(SYS_##name, arg1, arg2, arg3, arg4, arg5, arg6); \ } -#endif /* ! _SYSCALL_DEFS_H_ */ +#endif /* SYSCALL_DEFS_H */ diff --git a/bsd-user/x86_64/target_arch.h b/bsd-user/x86_64/target_arch.h index e558e1b956..09bd974889 100644 --- a/bsd-user/x86_64/target_arch.h +++ b/bsd-user/x86_64/target_arch.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_H_ -#define _TARGET_ARCH_H_ +#ifndef TARGET_ARCH_H +#define TARGET_ARCH_H /* target_arch_cpu.c */ void bsd_x86_64_write_dt(void *ptr, unsigned long addr, unsigned long limit, @@ -28,4 +28,4 @@ void bsd_x86_64_set_idt_base(uint64_t base); #define target_cpu_set_tls(env, newtls) -#endif /* !_TARGET_ARCH_H_ */ +#endif /* TARGET_ARCH_H */ diff --git a/bsd-user/x86_64/target_arch_cpu.h b/bsd-user/x86_64/target_arch_cpu.h index 5be2f02416..4094d61da1 100644 --- a/bsd-user/x86_64/target_arch_cpu.h +++ b/bsd-user/x86_64/target_arch_cpu.h @@ -16,8 +16,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_CPU_H_ -#define _TARGET_ARCH_CPU_H_ +#ifndef TARGET_ARCH_CPU_H +#define TARGET_ARCH_CPU_H #include "target_arch.h" #include "signal-common.h" @@ -174,4 +174,4 @@ static inline void target_cpu_reset(CPUArchState *env) cpu_reset(env_cpu(env)); } -#endif /* ! _TARGET_ARCH_CPU_H_ */ +#endif /* TARGET_ARCH_CPU_H */ diff --git a/bsd-user/x86_64/target_arch_elf.h b/bsd-user/x86_64/target_arch_elf.h index c2f8553962..b244711888 100644 --- a/bsd-user/x86_64/target_arch_elf.h +++ b/bsd-user/x86_64/target_arch_elf.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_ELF_H_ -#define _TARGET_ARCH_ELF_H_ + +#ifndef TARGET_ARCH_ELF_H +#define TARGET_ARCH_ELF_H #define ELF_START_MMAP 0x2aaaaab000ULL #define ELF_ET_DYN_LOAD_ADDR 0x01021000 @@ -32,4 +33,4 @@ #define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 -#endif /* _TARGET_ARCH_ELF_H_ */ +#endif /* TARGET_ARCH_ELF_H */ diff --git a/bsd-user/x86_64/target_arch_reg.h b/bsd-user/x86_64/target_arch_reg.h index 00e9624517..7a766de918 100644 --- a/bsd-user/x86_64/target_arch_reg.h +++ b/bsd-user/x86_64/target_arch_reg.h @@ -18,8 +18,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_REG_H_ -#define _TARGET_ARCH_REG_H_ +#ifndef TARGET_ARCH_REG_H +#define TARGET_ARCH_REG_H /* See sys/amd64/include/reg.h */ typedef struct target_reg { @@ -89,4 +89,4 @@ static inline void target_copy_regs(target_reg_t *regs, const CPUX86State *env) regs->r_ss = env->segs[R_SS].selector & 0xffff; } -#endif /* !_TARGET_ARCH_REG_H_ */ +#endif /* TARGET_ARCH_REG_H */ diff --git a/bsd-user/x86_64/target_arch_signal.h b/bsd-user/x86_64/target_arch_signal.h index b4a0ebf2bd..ca24bf1e7f 100644 --- a/bsd-user/x86_64/target_arch_signal.h +++ b/bsd-user/x86_64/target_arch_signal.h @@ -15,8 +15,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_SIGNAL_H_ -#define _TARGET_ARCH_SIGNAL_H_ + +#ifndef TARGET_ARCH_SIGNAL_H +#define TARGET_ARCH_SIGNAL_H #include "cpu.h" @@ -96,4 +97,4 @@ struct target_sigframe { uint32_t __spare__[2]; }; -#endif /* !TARGET_ARCH_SIGNAL_H_ */ +#endif /* TARGET_ARCH_SIGNAL_H */ diff --git a/bsd-user/x86_64/target_arch_sigtramp.h b/bsd-user/x86_64/target_arch_sigtramp.h index 29d4a8b55f..01da614098 100644 --- a/bsd-user/x86_64/target_arch_sigtramp.h +++ b/bsd-user/x86_64/target_arch_sigtramp.h @@ -17,8 +17,8 @@ * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_SIGTRAMP_H_ -#define _TARGET_ARCH_SIGTRAMP_H_ +#ifndef TARGET_ARCH_SIGTRAMP_H +#define TARGET_ARCH_SIGTRAMP_H static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, unsigned sys_sigreturn) @@ -26,4 +26,4 @@ static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, return 0; } -#endif /* _TARGET_ARCH_SIGTRAMP_H_ */ +#endif /* TARGET_ARCH_SIGTRAMP_H */ diff --git a/bsd-user/x86_64/target_arch_thread.h b/bsd-user/x86_64/target_arch_thread.h index b745d7ffeb..52c28906d6 100644 --- a/bsd-user/x86_64/target_arch_thread.h +++ b/bsd-user/x86_64/target_arch_thread.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_THREAD_H_ -#define _TARGET_ARCH_THREAD_H_ + +#ifndef TARGET_ARCH_THREAD_H +#define TARGET_ARCH_THREAD_H /* Compare to vm_machdep.c cpu_set_upcall_kse() */ static inline void target_thread_set_upcall(CPUX86State *regs, abi_ulong entry, @@ -35,4 +36,4 @@ static inline void target_thread_init(struct target_pt_regs *regs, regs->rdi = infop->start_stack; } -#endif /* !_TARGET_ARCH_THREAD_H_ */ +#endif /* TARGET_ARCH_THREAD_H */ diff --git a/bsd-user/x86_64/target_arch_vmparam.h b/bsd-user/x86_64/target_arch_vmparam.h index 81a915f2e5..6797623a6b 100644 --- a/bsd-user/x86_64/target_arch_vmparam.h +++ b/bsd-user/x86_64/target_arch_vmparam.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef _TARGET_ARCH_VMPARAM_H_ -#define _TARGET_ARCH_VMPARAM_H_ + +#ifndef TARGET_ARCH_VMPARAM_H +#define TARGET_ARCH_VMPARAM_H #include "cpu.h" @@ -43,4 +44,4 @@ static inline void set_second_rval(CPUX86State *state, abi_ulong retval2) state->regs[R_EDX] = retval2; } -#endif /* !_TARGET_ARCH_VMPARAM_H_ */ +#endif /* TARGET_ARCH_VMPARAM_H */ diff --git a/crypto/ivgen-plain.h b/crypto/ivgen-plain.h index 43db898809..ebae6acd04 100644 --- a/crypto/ivgen-plain.h +++ b/crypto/ivgen-plain.h @@ -17,11 +17,11 @@ * License along with this library; if not, see . */ -#ifndef QCRYPTO_IVGEN_PLAIN_H__ -#define QCRYPTO_IVGEN_PLAIN_H__ +#ifndef QCRYPTO_IVGEN_PLAIN_H +#define QCRYPTO_IVGEN_PLAIN_H #include "ivgenpriv.h" extern struct QCryptoIVGenDriver qcrypto_ivgen_plain; -#endif /* QCRYPTO_IVGEN_PLAIN_H__ */ +#endif /* QCRYPTO_IVGEN_PLAIN_H */ diff --git a/include/chardev/char-socket.h b/include/chardev/char-socket.h index 6b6e2ceba1..0708ca6fa9 100644 --- a/include/chardev/char-socket.h +++ b/include/chardev/char-socket.h @@ -21,8 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef CHAR_SOCKET_H_ -#define CHAR_SOCKET_H_ + +#ifndef CHAR_SOCKET_H +#define CHAR_SOCKET_H #include "io/channel-socket.h" #include "io/channel-tls.h" @@ -83,4 +84,4 @@ typedef struct SocketChardev SocketChardev; DECLARE_INSTANCE_CHECKER(SocketChardev, SOCKET_CHARDEV, TYPE_CHARDEV_SOCKET) -#endif /* CHAR_SOCKET_H_ */ +#endif /* CHAR_SOCKET_H */ diff --git a/include/hw/i2c/i2c_mux_pca954x.h b/include/hw/i2c/i2c_mux_pca954x.h index 8aaf9bbc39..3dd25ec983 100644 --- a/include/hw/i2c/i2c_mux_pca954x.h +++ b/include/hw/i2c/i2c_mux_pca954x.h @@ -1,5 +1,5 @@ -#ifndef QEMU_I2C_MUX_PCA954X -#define QEMU_I2C_MUX_PCA954X +#ifndef QEMU_I2C_MUX_PCA954X_H +#define QEMU_I2C_MUX_PCA954X_H #include "hw/i2c/i2c.h" diff --git a/include/hw/input/lm832x.h b/include/hw/input/lm832x.h index 2a58ccf891..e0e5d5ef20 100644 --- a/include/hw/input/lm832x.h +++ b/include/hw/input/lm832x.h @@ -18,8 +18,8 @@ * with this program; if not, see . */ -#ifndef HW_INPUT_LM832X -#define HW_INPUT_LM832X +#ifndef HW_INPUT_LM832X_H +#define HW_INPUT_LM832X_H #define TYPE_LM8323 "lm8323" diff --git a/include/hw/intc/exynos4210_combiner.h b/include/hw/intc/exynos4210_combiner.h index 429844fed4..bd207a7e6e 100644 --- a/include/hw/intc/exynos4210_combiner.h +++ b/include/hw/intc/exynos4210_combiner.h @@ -20,8 +20,8 @@ * with this program; if not, see . */ -#ifndef HW_INTC_EXYNOS4210_COMBINER -#define HW_INTC_EXYNOS4210_COMBINER +#ifndef HW_INTC_EXYNOS4210_COMBINER_H +#define HW_INTC_EXYNOS4210_COMBINER_H #include "hw/sysbus.h" diff --git a/include/hw/intc/nios2_vic.h b/include/hw/intc/nios2_vic.h index af1517a967..ac507b9d74 100644 --- a/include/hw/intc/nios2_vic.h +++ b/include/hw/intc/nios2_vic.h @@ -32,8 +32,8 @@ * THE SOFTWARE. */ -#ifndef HW_INTC_NIOS2_VIC -#define HW_INTC_NIOS2_VIC +#ifndef HW_INTC_NIOS2_VIC_H +#define HW_INTC_NIOS2_VIC_H #define TYPE_NIOS2_VIC "nios2-vic" OBJECT_DECLARE_SIMPLE_TYPE(Nios2VIC, NIOS2_VIC) @@ -61,4 +61,4 @@ struct Nios2VIC { uint32_t vec_tbl_addr; }; -#endif /* HW_INTC_NIOS2_VIC */ +#endif /* HW_INTC_NIOS2_VIC_H */ diff --git a/include/hw/ppc/pnv_pnor.h b/include/hw/ppc/pnv_pnor.h index 99f9a3adfb..bab2f79844 100644 --- a/include/hw/ppc/pnv_pnor.h +++ b/include/hw/ppc/pnv_pnor.h @@ -6,8 +6,10 @@ * This code is licensed under the GPL version 2 or later. See the * COPYING file in the top-level directory. */ -#ifndef _PPC_PNV_PNOR_H -#define _PPC_PNV_PNOR_H + +#ifndef PPC_PNV_PNOR_H +#define PPC_PNV_PNOR_H + #include "qom/object.h" /* @@ -28,4 +30,4 @@ struct PnvPnor { MemoryRegion mmio; }; -#endif /* _PPC_PNV_PNOR_H */ +#endif /* PPC_PNV_PNOR_H */ diff --git a/include/hw/s390x/s390-pci-clp.h b/include/hw/s390x/s390-pci-clp.h index cc8c8662b8..03b7f9ba5f 100644 --- a/include/hw/s390x/s390-pci-clp.h +++ b/include/hw/s390x/s390-pci-clp.h @@ -9,8 +9,8 @@ * directory. */ -#ifndef HW_S390_PCI_CLP -#define HW_S390_PCI_CLP +#ifndef HW_S390_PCI_CLP_H +#define HW_S390_PCI_CLP_H /* CLP common request & response block size */ #define CLP_BLK_SIZE 4096 diff --git a/include/hw/tricore/tc27x_soc.h b/include/hw/tricore/tc27x_soc.h index 6a7e5b54f5..dd3a7485c8 100644 --- a/include/hw/tricore/tc27x_soc.h +++ b/include/hw/tricore/tc27x_soc.h @@ -18,8 +18,8 @@ * License along with this library; if not, see . */ -#ifndef TC27X_SoC_H -#define TC27X_SoC_H +#ifndef TC27X_SOC_H +#define TC27X_SOC_H #include "hw/sysbus.h" #include "target/tricore/cpu.h" diff --git a/include/hw/virtio/vhost-user-fs.h b/include/hw/virtio/vhost-user-fs.h index 0d62834c25..94c3aaa84e 100644 --- a/include/hw/virtio/vhost-user-fs.h +++ b/include/hw/virtio/vhost-user-fs.h @@ -11,8 +11,8 @@ * top-level directory. */ -#ifndef _QEMU_VHOST_USER_FS_H -#define _QEMU_VHOST_USER_FS_H +#ifndef QEMU_VHOST_USER_FS_H +#define QEMU_VHOST_USER_FS_H #include "hw/virtio/virtio.h" #include "hw/virtio/vhost.h" @@ -44,4 +44,4 @@ struct VHostUserFS { /*< public >*/ }; -#endif /* _QEMU_VHOST_USER_FS_H */ +#endif /* QEMU_VHOST_USER_FS_H */ diff --git a/include/hw/virtio/vhost-user-i2c.h b/include/hw/virtio/vhost-user-i2c.h index d8372f3b43..0f7acd40e3 100644 --- a/include/hw/virtio/vhost-user-i2c.h +++ b/include/hw/virtio/vhost-user-i2c.h @@ -6,8 +6,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef _QEMU_VHOST_USER_I2C_H -#define _QEMU_VHOST_USER_I2C_H +#ifndef QEMU_VHOST_USER_I2C_H +#define QEMU_VHOST_USER_I2C_H #include "hw/virtio/vhost.h" #include "hw/virtio/vhost-user.h" @@ -28,4 +28,4 @@ struct VHostUserI2C { /* Virtio Feature bits */ #define VIRTIO_I2C_F_ZERO_LENGTH_REQUEST 0 -#endif /* _QEMU_VHOST_USER_I2C_H */ +#endif /* QEMU_VHOST_USER_I2C_H */ diff --git a/include/hw/virtio/vhost-user-rng.h b/include/hw/virtio/vhost-user-rng.h index 071539996d..ddd9f01eea 100644 --- a/include/hw/virtio/vhost-user-rng.h +++ b/include/hw/virtio/vhost-user-rng.h @@ -6,8 +6,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef _QEMU_VHOST_USER_RNG_H -#define _QEMU_VHOST_USER_RNG_H +#ifndef QEMU_VHOST_USER_RNG_H +#define QEMU_VHOST_USER_RNG_H #include "hw/virtio/virtio.h" #include "hw/virtio/vhost.h" @@ -30,4 +30,4 @@ struct VHostUserRNG { /*< public >*/ }; -#endif /* _QEMU_VHOST_USER_RNG_H */ +#endif /* QEMU_VHOST_USER_RNG_H */ diff --git a/include/hw/virtio/vhost-user-vsock.h b/include/hw/virtio/vhost-user-vsock.h index 4cfd558245..67aa46c952 100644 --- a/include/hw/virtio/vhost-user-vsock.h +++ b/include/hw/virtio/vhost-user-vsock.h @@ -8,8 +8,8 @@ * top-level directory. */ -#ifndef _QEMU_VHOST_USER_VSOCK_H -#define _QEMU_VHOST_USER_VSOCK_H +#ifndef QEMU_VHOST_USER_VSOCK_H +#define QEMU_VHOST_USER_VSOCK_H #include "hw/virtio/vhost-vsock-common.h" #include "hw/virtio/vhost-user.h" @@ -33,4 +33,4 @@ struct VHostUserVSock { /*< public >*/ }; -#endif /* _QEMU_VHOST_USER_VSOCK_H */ +#endif /* QEMU_VHOST_USER_VSOCK_H */ diff --git a/include/hw/virtio/vhost-vsock-common.h b/include/hw/virtio/vhost-vsock-common.h index d8b565b4da..456a9c2365 100644 --- a/include/hw/virtio/vhost-vsock-common.h +++ b/include/hw/virtio/vhost-vsock-common.h @@ -8,8 +8,8 @@ * top-level directory. */ -#ifndef _QEMU_VHOST_VSOCK_COMMON_H -#define _QEMU_VHOST_VSOCK_COMMON_H +#ifndef QEMU_VHOST_VSOCK_COMMON_H +#define QEMU_VHOST_VSOCK_COMMON_H #include "hw/virtio/virtio.h" #include "hw/virtio/vhost.h" @@ -49,4 +49,4 @@ void vhost_vsock_common_unrealize(VirtIODevice *vdev); uint64_t vhost_vsock_common_get_features(VirtIODevice *vdev, uint64_t features, Error **errp); -#endif /* _QEMU_VHOST_VSOCK_COMMON_H */ +#endif /* QEMU_VHOST_VSOCK_COMMON_H */ diff --git a/include/qemu/cpu-float.h b/include/qemu/cpu-float.h index 911099499f..a26b9faf68 100644 --- a/include/qemu/cpu-float.h +++ b/include/qemu/cpu-float.h @@ -1,5 +1,5 @@ -#ifndef QEMU_CPU_FLOAT_H_ -#define QEMU_CPU_FLOAT_H_ +#ifndef QEMU_CPU_FLOAT_H +#define QEMU_CPU_FLOAT_H #include "fpu/softfloat-types.h" @@ -61,4 +61,4 @@ typedef union { #endif } CPU_QuadU; -#endif /* QEMU_CPU_FLOAT_H_ */ +#endif /* QEMU_CPU_FLOAT_H */ diff --git a/include/qemu/crc-ccitt.h b/include/qemu/crc-ccitt.h index 06ee55b159..d6eb49146d 100644 --- a/include/qemu/crc-ccitt.h +++ b/include/qemu/crc-ccitt.h @@ -11,8 +11,8 @@ * SPDX-License-Identifier: GPL-2.0 */ -#ifndef _CRC_CCITT_H -#define _CRC_CCITT_H +#ifndef CRC_CCITT_H +#define CRC_CCITT_H extern uint16_t const crc_ccitt_table[256]; extern uint16_t const crc_ccitt_false_table[256]; @@ -30,4 +30,4 @@ static inline uint16_t crc_ccitt_false_byte(uint16_t crc, const uint8_t c) return (crc << 8) ^ crc_ccitt_false_table[(crc >> 8) ^ c]; } -#endif /* _CRC_CCITT_H */ +#endif /* CRC_CCITT_H */ diff --git a/include/qemu/keyval.h b/include/qemu/keyval.h index 2d263286d7..1187b68303 100644 --- a/include/qemu/keyval.h +++ b/include/qemu/keyval.h @@ -2,8 +2,9 @@ * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. */ -#ifndef KEYVAL_H_ -#define KEYVAL_H_ + +#ifndef KEYVAL_H +#define KEYVAL_H QDict *keyval_parse_into(QDict *qdict, const char *params, const char *implied_key, bool *p_help, Error **errp); @@ -11,4 +12,4 @@ QDict *keyval_parse(const char *params, const char *implied_key, bool *help, Error **errp); void keyval_merge(QDict *old, const QDict *new, Error **errp); -#endif /* KEYVAL_H_ */ +#endif /* KEYVAL_H */ diff --git a/include/ui/dbus-display.h b/include/ui/dbus-display.h index 88f153c237..7c9ec1a069 100644 --- a/include/ui/dbus-display.h +++ b/include/ui/dbus-display.h @@ -1,5 +1,5 @@ -#ifndef DBUS_DISPLAY_H_ -#define DBUS_DISPLAY_H_ +#ifndef DBUS_DISPLAY_H +#define DBUS_DISPLAY_H #include "qapi/error.h" #include "ui/dbus-module.h" @@ -14,4 +14,4 @@ static inline bool qemu_using_dbus_display(Error **errp) return true; } -#endif /* DBUS_DISPLAY_H_ */ +#endif /* DBUS_DISPLAY_H */ diff --git a/include/ui/dbus-module.h b/include/ui/dbus-module.h index ace4a17a5c..5442ee0bb6 100644 --- a/include/ui/dbus-module.h +++ b/include/ui/dbus-module.h @@ -1,5 +1,5 @@ -#ifndef DBUS_MODULE_H_ -#define DBUS_MODULE_H_ +#ifndef DBUS_MODULE_H +#define DBUS_MODULE_H struct QemuDBusDisplayOps { bool (*add_client)(int csock, Error **errp); @@ -8,4 +8,4 @@ struct QemuDBusDisplayOps { extern int using_dbus_display; extern struct QemuDBusDisplayOps qemu_dbus_display; -#endif /* DBUS_MODULE_H_*/ +#endif /* DBUS_MODULE_H */ diff --git a/target/ppc/power8-pmu.h b/target/ppc/power8-pmu.h index 256d90f523..9692dd765e 100644 --- a/target/ppc/power8-pmu.h +++ b/target/ppc/power8-pmu.h @@ -10,8 +10,8 @@ * See the COPYING file in the top-level directory. */ -#ifndef POWER8_PMU -#define POWER8_PMU +#ifndef POWER8_PMU_H +#define POWER8_PMU_H #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) void cpu_ppc_pmu_init(CPUPPCState *env); diff --git a/target/riscv/sbi_ecall_interface.h b/target/riscv/sbi_ecall_interface.h index fb1a3fa8f2..77574ed4cb 100644 --- a/target/riscv/sbi_ecall_interface.h +++ b/target/riscv/sbi_ecall_interface.h @@ -7,8 +7,8 @@ * Anup Patel */ -#ifndef __SBI_ECALL_INTERFACE_H__ -#define __SBI_ECALL_INTERFACE_H__ +#ifndef SBI_ECALL_INTERFACE_H +#define SBI_ECALL_INTERFACE_H /* clang-format off */ diff --git a/tests/qtest/libqmp.h b/tests/qtest/libqmp.h index 94aa97328a..5cb7eeaa18 100644 --- a/tests/qtest/libqmp.h +++ b/tests/qtest/libqmp.h @@ -14,8 +14,9 @@ * See the COPYING file in the top-level directory. * */ -#ifndef LIBQMP_H_ -#define LIBQMP_H_ + +#ifndef LIBQMP_H +#define LIBQMP_H #include "qapi/qmp/qdict.h" @@ -47,4 +48,4 @@ bool qmp_rsp_is_err(QDict *rsp); */ void qmp_expect_error_and_unref(QDict *rsp, const char *class); -#endif /* LIBQMP_H_ */ +#endif /* LIBQMP_H */ diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration-helpers.h index c7872e8442..2731399aaa 100644 --- a/tests/qtest/migration-helpers.h +++ b/tests/qtest/migration-helpers.h @@ -9,8 +9,9 @@ * See the COPYING file in the top-level directory. * */ -#ifndef MIGRATION_HELPERS_H_ -#define MIGRATION_HELPERS_H_ + +#ifndef MIGRATION_HELPERS_H +#define MIGRATION_HELPERS_H #include "libqtest.h" @@ -34,4 +35,4 @@ void wait_for_migration_complete(QTestState *who); void wait_for_migration_fail(QTestState *from, bool allow_active); -#endif /* MIGRATION_HELPERS_H_ */ +#endif /* MIGRATION_HELPERS_H */ diff --git a/ui/dbus.h b/ui/dbus.h index 5f5c1f759c..c001c11f70 100644 --- a/ui/dbus.h +++ b/ui/dbus.h @@ -21,8 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef UI_DBUS_H_ -#define UI_DBUS_H_ + +#ifndef UI_DBUS_H +#define UI_DBUS_H #include "chardev/char-socket.h" #include "qemu/dbus.h" @@ -144,4 +145,4 @@ void dbus_chardev_init(DBusDisplay *dpy); void dbus_clipboard_init(DBusDisplay *dpy); -#endif /* UI_DBUS_H_ */ +#endif /* UI_DBUS_H */ From 4f31b54bfe52c72be9c17c158b38924e6cefcd0f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 6 May 2022 15:49:10 +0200 Subject: [PATCH 229/935] Normalize header guard symbol definition We commonly define the header guard symbol without an explicit value. Normalize the exceptions. Done with scripts/clean-header-guards.pl. Signed-off-by: Markus Armbruster Message-Id: <20220506134911.2856099-4-armbru@redhat.com> Reviewed-by: Richard Henderson --- include/exec/memopidx.h | 2 +- include/tcg/tcg-ldst.h | 2 +- target/alpha/cpu-param.h | 2 +- target/arm/cpu-param.h | 2 +- target/cris/cpu-param.h | 2 +- target/hppa/cpu-param.h | 2 +- target/i386/cpu-param.h | 2 +- target/m68k/cpu-param.h | 2 +- target/microblaze/cpu-param.h | 2 +- target/mips/cpu-param.h | 2 +- target/nios2/cpu-param.h | 2 +- target/openrisc/cpu-param.h | 2 +- target/ppc/cpu-param.h | 2 +- target/riscv/cpu-param.h | 2 +- target/s390x/cpu-param.h | 2 +- target/sh4/cpu-param.h | 2 +- target/sparc/cpu-param.h | 2 +- target/tricore/cpu-param.h | 2 +- target/xtensa/cpu-param.h | 2 +- tcg/tcg-internal.h | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/include/exec/memopidx.h b/include/exec/memopidx.h index 83bce97874..eb7f1591a3 100644 --- a/include/exec/memopidx.h +++ b/include/exec/memopidx.h @@ -9,7 +9,7 @@ */ #ifndef EXEC_MEMOPIDX_H -#define EXEC_MEMOPIDX_H 1 +#define EXEC_MEMOPIDX_H #include "exec/memop.h" diff --git a/include/tcg/tcg-ldst.h b/include/tcg/tcg-ldst.h index 121a156933..2ba22bd5fe 100644 --- a/include/tcg/tcg-ldst.h +++ b/include/tcg/tcg-ldst.h @@ -23,7 +23,7 @@ */ #ifndef TCG_LDST_H -#define TCG_LDST_H 1 +#define TCG_LDST_H #ifdef CONFIG_SOFTMMU diff --git a/target/alpha/cpu-param.h b/target/alpha/cpu-param.h index 1153992e42..17cd14e590 100644 --- a/target/alpha/cpu-param.h +++ b/target/alpha/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef ALPHA_CPU_PARAM_H -#define ALPHA_CPU_PARAM_H 1 +#define ALPHA_CPU_PARAM_H #define TARGET_LONG_BITS 64 #define TARGET_PAGE_BITS 13 diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h index b59d505761..68ffb12427 100644 --- a/target/arm/cpu-param.h +++ b/target/arm/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef ARM_CPU_PARAM_H -#define ARM_CPU_PARAM_H 1 +#define ARM_CPU_PARAM_H #ifdef TARGET_AARCH64 # define TARGET_LONG_BITS 64 diff --git a/target/cris/cpu-param.h b/target/cris/cpu-param.h index 36a3058761..12ec22d8df 100644 --- a/target/cris/cpu-param.h +++ b/target/cris/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef CRIS_CPU_PARAM_H -#define CRIS_CPU_PARAM_H 1 +#define CRIS_CPU_PARAM_H #define TARGET_LONG_BITS 32 #define TARGET_PAGE_BITS 13 diff --git a/target/hppa/cpu-param.h b/target/hppa/cpu-param.h index a97d1428df..a48a2701ae 100644 --- a/target/hppa/cpu-param.h +++ b/target/hppa/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef HPPA_CPU_PARAM_H -#define HPPA_CPU_PARAM_H 1 +#define HPPA_CPU_PARAM_H #ifdef TARGET_HPPA64 # define TARGET_LONG_BITS 64 diff --git a/target/i386/cpu-param.h b/target/i386/cpu-param.h index 57abc64c0d..9740bd7abd 100644 --- a/target/i386/cpu-param.h +++ b/target/i386/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef I386_CPU_PARAM_H -#define I386_CPU_PARAM_H 1 +#define I386_CPU_PARAM_H #ifdef TARGET_X86_64 # define TARGET_LONG_BITS 64 diff --git a/target/m68k/cpu-param.h b/target/m68k/cpu-param.h index 06556dfbf3..44a8d193f0 100644 --- a/target/m68k/cpu-param.h +++ b/target/m68k/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef M68K_CPU_PARAM_H -#define M68K_CPU_PARAM_H 1 +#define M68K_CPU_PARAM_H #define TARGET_LONG_BITS 32 /* diff --git a/target/microblaze/cpu-param.h b/target/microblaze/cpu-param.h index 4d8297fa94..5e54ea0108 100644 --- a/target/microblaze/cpu-param.h +++ b/target/microblaze/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef MICROBLAZE_CPU_PARAM_H -#define MICROBLAZE_CPU_PARAM_H 1 +#define MICROBLAZE_CPU_PARAM_H /* * While system mode can address up to 64 bits of address space, diff --git a/target/mips/cpu-param.h b/target/mips/cpu-param.h index 1aebd01df9..f4c76994ea 100644 --- a/target/mips/cpu-param.h +++ b/target/mips/cpu-param.h @@ -5,7 +5,7 @@ */ #ifndef MIPS_CPU_PARAM_H -#define MIPS_CPU_PARAM_H 1 +#define MIPS_CPU_PARAM_H #ifdef TARGET_MIPS64 # define TARGET_LONG_BITS 64 diff --git a/target/nios2/cpu-param.h b/target/nios2/cpu-param.h index 38bedbfd61..177d720864 100644 --- a/target/nios2/cpu-param.h +++ b/target/nios2/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef NIOS2_CPU_PARAM_H -#define NIOS2_CPU_PARAM_H 1 +#define NIOS2_CPU_PARAM_H #define TARGET_LONG_BITS 32 #define TARGET_PAGE_BITS 12 diff --git a/target/openrisc/cpu-param.h b/target/openrisc/cpu-param.h index 06ee64d171..73be699f36 100644 --- a/target/openrisc/cpu-param.h +++ b/target/openrisc/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef OPENRISC_CPU_PARAM_H -#define OPENRISC_CPU_PARAM_H 1 +#define OPENRISC_CPU_PARAM_H #define TARGET_LONG_BITS 32 #define TARGET_PAGE_BITS 13 diff --git a/target/ppc/cpu-param.h b/target/ppc/cpu-param.h index 37b458d33d..ea377b7d06 100644 --- a/target/ppc/cpu-param.h +++ b/target/ppc/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef PPC_CPU_PARAM_H -#define PPC_CPU_PARAM_H 1 +#define PPC_CPU_PARAM_H #ifdef TARGET_PPC64 # define TARGET_LONG_BITS 64 diff --git a/target/riscv/cpu-param.h b/target/riscv/cpu-param.h index 80eb615f93..ebaf26d26d 100644 --- a/target/riscv/cpu-param.h +++ b/target/riscv/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef RISCV_CPU_PARAM_H -#define RISCV_CPU_PARAM_H 1 +#define RISCV_CPU_PARAM_H #if defined(TARGET_RISCV64) # define TARGET_LONG_BITS 64 diff --git a/target/s390x/cpu-param.h b/target/s390x/cpu-param.h index 472db648d7..bf951a002e 100644 --- a/target/s390x/cpu-param.h +++ b/target/s390x/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef S390_CPU_PARAM_H -#define S390_CPU_PARAM_H 1 +#define S390_CPU_PARAM_H #define TARGET_LONG_BITS 64 #define TARGET_PAGE_BITS 12 diff --git a/target/sh4/cpu-param.h b/target/sh4/cpu-param.h index 81ace3503b..98a02509bb 100644 --- a/target/sh4/cpu-param.h +++ b/target/sh4/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef SH4_CPU_PARAM_H -#define SH4_CPU_PARAM_H 1 +#define SH4_CPU_PARAM_H #define TARGET_LONG_BITS 32 #define TARGET_PAGE_BITS 12 /* 4k */ diff --git a/target/sparc/cpu-param.h b/target/sparc/cpu-param.h index 4746d89411..72ddc4a34f 100644 --- a/target/sparc/cpu-param.h +++ b/target/sparc/cpu-param.h @@ -5,7 +5,7 @@ */ #ifndef SPARC_CPU_PARAM_H -#define SPARC_CPU_PARAM_H 1 +#define SPARC_CPU_PARAM_H #ifdef TARGET_SPARC64 # define TARGET_LONG_BITS 64 diff --git a/target/tricore/cpu-param.h b/target/tricore/cpu-param.h index cf5d9af89d..2727913047 100644 --- a/target/tricore/cpu-param.h +++ b/target/tricore/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef TRICORE_CPU_PARAM_H -#define TRICORE_CPU_PARAM_H 1 +#define TRICORE_CPU_PARAM_H #define TARGET_LONG_BITS 32 #define TARGET_PAGE_BITS 14 diff --git a/target/xtensa/cpu-param.h b/target/xtensa/cpu-param.h index 4fde21b941..b53e9a3e08 100644 --- a/target/xtensa/cpu-param.h +++ b/target/xtensa/cpu-param.h @@ -6,7 +6,7 @@ */ #ifndef XTENSA_CPU_PARAM_H -#define XTENSA_CPU_PARAM_H 1 +#define XTENSA_CPU_PARAM_H #define TARGET_LONG_BITS 32 #define TARGET_PAGE_BITS 12 diff --git a/tcg/tcg-internal.h b/tcg/tcg-internal.h index 92c91dcde9..cc82088d52 100644 --- a/tcg/tcg-internal.h +++ b/tcg/tcg-internal.h @@ -23,7 +23,7 @@ */ #ifndef TCG_INTERNAL_H -#define TCG_INTERNAL_H 1 +#define TCG_INTERNAL_H #define TCG_HIGHWATER 1024 From ea9cea93c69d508a333dd1b0cb1a44f6daf80b63 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 6 May 2022 15:49:11 +0200 Subject: [PATCH 230/935] Clean up decorations and whitespace around header guards Cleaned up with scripts/clean-header-guards.pl. Signed-off-by: Markus Armbruster Message-Id: <20220506134911.2856099-5-armbru@redhat.com> Reviewed-by: Richard Henderson --- bsd-user/arm/target.h | 2 +- bsd-user/x86_64/target.h | 2 +- chardev/chardev-internal.h | 3 ++- include/block/block_int-global-state.h | 3 ++- include/exec/translator.h | 2 +- include/fpu/softfloat-helpers.h | 2 +- include/hw/gpio/aspeed_gpio.h | 2 +- include/hw/intc/rx_icu.h | 2 +- include/hw/misc/aspeed_hace.h | 2 +- include/hw/misc/aspeed_lpc.h | 2 +- include/hw/misc/aspeed_sbc.h | 2 +- include/hw/net/allwinner-sun8i-emac.h | 2 +- include/hw/rtc/m48t59.h | 2 +- include/hw/rtc/mc146818rtc.h | 2 +- include/qemu/plugin-memory.h | 2 +- include/qemu/selfmap.h | 2 +- include/user/syscall-trace.h | 2 +- linux-user/hexagon/target_signal.h | 2 +- target/avr/cpu.h | 2 +- target/hexagon/attribs.h | 2 +- target/xtensa/core-de233_fpu/core-matmap.h | 4 +--- target/xtensa/core-dsp3400/core-matmap.h | 4 +--- 22 files changed, 24 insertions(+), 26 deletions(-) diff --git a/bsd-user/arm/target.h b/bsd-user/arm/target.h index 419c039b68..7c423ec575 100644 --- a/bsd-user/arm/target.h +++ b/bsd-user/arm/target.h @@ -17,5 +17,5 @@ static inline bool regpairs_aligned(void *cpu_env) return true; } -#endif /* ! TARGET_H */ +#endif /* TARGET_H */ diff --git a/bsd-user/x86_64/target.h b/bsd-user/x86_64/target.h index 8956631db1..0cf0e2a14a 100644 --- a/bsd-user/x86_64/target.h +++ b/bsd-user/x86_64/target.h @@ -17,5 +17,5 @@ static inline bool regpairs_aligned(void *cpu_env) return false; } -#endif /* ! TARGET_H */ +#endif /* TARGET_H */ diff --git a/chardev/chardev-internal.h b/chardev/chardev-internal.h index aba0240759..4e03af3147 100644 --- a/chardev/chardev-internal.h +++ b/chardev/chardev-internal.h @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + #ifndef CHARDEV_INTERNAL_H #define CHARDEV_INTERNAL_H @@ -64,4 +65,4 @@ void mux_chr_send_all_event(Chardev *chr, QEMUChrEvent event); Object *get_chardevs_root(void); -#endif /* CHAR_MUX_H */ +#endif /* CHARDEV_INTERNAL_H */ diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h index 8b2e95f5ff..b49f4eb35b 100644 --- a/include/block/block_int-global-state.h +++ b/include/block/block_int-global-state.h @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + #ifndef BLOCK_INT_GLOBAL_STATE_H #define BLOCK_INT_GLOBAL_STATE_H @@ -326,4 +327,4 @@ static inline void assert_bdrv_graph_writable(BlockDriverState *bs) assert(qemu_in_main_thread()); } -#endif /* BLOCK_INT_GLOBAL_STATE */ +#endif /* BLOCK_INT_GLOBAL_STATE_H */ diff --git a/include/exec/translator.h b/include/exec/translator.h index 31d3fa76ff..7db6845535 100644 --- a/include/exec/translator.h +++ b/include/exec/translator.h @@ -187,4 +187,4 @@ FOR_EACH_TRANSLATOR_LD(GEN_TRANSLATOR_LD) #undef GEN_TRANSLATOR_LD -#endif /* EXEC__TRANSLATOR_H */ +#endif /* EXEC__TRANSLATOR_H */ diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h index a98d759cd3..94cbe073ec 100644 --- a/include/fpu/softfloat-helpers.h +++ b/include/fpu/softfloat-helpers.h @@ -141,4 +141,4 @@ static inline bool get_default_nan_mode(float_status *status) return status->default_nan_mode; } -#endif /* _SOFTFLOAT_HELPERS_H_ */ +#endif /* SOFTFLOAT_HELPERS_H */ diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h index 801846befb..6dee3cd438 100644 --- a/include/hw/gpio/aspeed_gpio.h +++ b/include/hw/gpio/aspeed_gpio.h @@ -93,4 +93,4 @@ struct AspeedGPIOState { } sets[ASPEED_GPIO_MAX_NR_SETS]; }; -#endif /* _ASPEED_GPIO_H_ */ +#endif /* ASPEED_GPIO_H */ diff --git a/include/hw/intc/rx_icu.h b/include/hw/intc/rx_icu.h index 7f5889b36f..b23504f3dd 100644 --- a/include/hw/intc/rx_icu.h +++ b/include/hw/intc/rx_icu.h @@ -73,4 +73,4 @@ struct RXICUState { #define TYPE_RX_ICU "rx-icu" OBJECT_DECLARE_SIMPLE_TYPE(RXICUState, RX_ICU) -#endif /* RX_ICU_H */ +#endif /* HW_INTC_RX_ICU_H */ diff --git a/include/hw/misc/aspeed_hace.h b/include/hw/misc/aspeed_hace.h index 4f9ce179bf..ecb1b67de8 100644 --- a/include/hw/misc/aspeed_hace.h +++ b/include/hw/misc/aspeed_hace.h @@ -47,4 +47,4 @@ struct AspeedHACEClass { uint32_t hash_mask; }; -#endif /* _ASPEED_HACE_H_ */ +#endif /* ASPEED_HACE_H */ diff --git a/include/hw/misc/aspeed_lpc.h b/include/hw/misc/aspeed_lpc.h index df418cfcd3..fd228731d2 100644 --- a/include/hw/misc/aspeed_lpc.h +++ b/include/hw/misc/aspeed_lpc.h @@ -44,4 +44,4 @@ typedef struct AspeedLPCState { uint32_t hicr7; } AspeedLPCState; -#endif /* _ASPEED_LPC_H_ */ +#endif /* ASPEED_LPC_H */ diff --git a/include/hw/misc/aspeed_sbc.h b/include/hw/misc/aspeed_sbc.h index 651747e28f..67e43b53ec 100644 --- a/include/hw/misc/aspeed_sbc.h +++ b/include/hw/misc/aspeed_sbc.h @@ -29,4 +29,4 @@ struct AspeedSBCClass { SysBusDeviceClass parent_class; }; -#endif /* _ASPEED_SBC_H_ */ +#endif /* ASPEED_SBC_H */ diff --git a/include/hw/net/allwinner-sun8i-emac.h b/include/hw/net/allwinner-sun8i-emac.h index 460a58f1ca..185895f4e1 100644 --- a/include/hw/net/allwinner-sun8i-emac.h +++ b/include/hw/net/allwinner-sun8i-emac.h @@ -101,4 +101,4 @@ struct AwSun8iEmacState { }; -#endif /* HW_NET_ALLWINNER_SUN8I_H */ +#endif /* HW_NET_ALLWINNER_SUN8I_EMAC_H */ diff --git a/include/hw/rtc/m48t59.h b/include/hw/rtc/m48t59.h index d9b45eb161..c14937476c 100644 --- a/include/hw/rtc/m48t59.h +++ b/include/hw/rtc/m48t59.h @@ -47,4 +47,4 @@ struct NvramClass { void (*toggle_lock)(Nvram *obj, int lock); }; -#endif /* HW_M48T59_H */ +#endif /* HW_RTC_M48T59_H */ diff --git a/include/hw/rtc/mc146818rtc.h b/include/hw/rtc/mc146818rtc.h index deef93f89a..33d85753c0 100644 --- a/include/hw/rtc/mc146818rtc.h +++ b/include/hw/rtc/mc146818rtc.h @@ -56,4 +56,4 @@ ISADevice *mc146818_rtc_init(ISABus *bus, int base_year, void rtc_set_memory(ISADevice *dev, int addr, int val); int rtc_get_memory(ISADevice *dev, int addr); -#endif /* MC146818RTC_H */ +#endif /* HW_RTC_MC146818RTC_H */ diff --git a/include/qemu/plugin-memory.h b/include/qemu/plugin-memory.h index 0f59226727..8ad13c110c 100644 --- a/include/qemu/plugin-memory.h +++ b/include/qemu/plugin-memory.h @@ -37,4 +37,4 @@ struct qemu_plugin_hwaddr { bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx, bool is_store, struct qemu_plugin_hwaddr *data); -#endif /* _PLUGIN_MEMORY_H_ */ +#endif /* PLUGIN_MEMORY_H */ diff --git a/include/qemu/selfmap.h b/include/qemu/selfmap.h index 80cf920fba..3479a2a618 100644 --- a/include/qemu/selfmap.h +++ b/include/qemu/selfmap.h @@ -41,4 +41,4 @@ GSList *read_self_maps(void); */ void free_self_maps(GSList *info); -#endif /* _SELFMAP_H_ */ +#endif /* SELFMAP_H */ diff --git a/include/user/syscall-trace.h b/include/user/syscall-trace.h index 614cfacfa5..b4e53d3870 100644 --- a/include/user/syscall-trace.h +++ b/include/user/syscall-trace.h @@ -39,4 +39,4 @@ static inline void record_syscall_return(void *cpu, int num, abi_long ret) } -#endif /* _SYSCALL_TRACE_H_ */ +#endif /* SYSCALL_TRACE_H */ diff --git a/linux-user/hexagon/target_signal.h b/linux-user/hexagon/target_signal.h index 193abac340..68fb71312e 100644 --- a/linux-user/hexagon/target_signal.h +++ b/linux-user/hexagon/target_signal.h @@ -22,4 +22,4 @@ #define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1 -#endif /* TARGET_SIGNAL_H */ +#endif /* HEXAGON_TARGET_SIGNAL_H */ diff --git a/target/avr/cpu.h b/target/avr/cpu.h index 55497f851d..d304f33301 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -247,4 +247,4 @@ bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, #include "exec/cpu-all.h" -#endif /* !defined (QEMU_AVR_CPU_H) */ +#endif /* QEMU_AVR_CPU_H */ diff --git a/target/hexagon/attribs.h b/target/hexagon/attribs.h index 54576f4143..d51bb4f732 100644 --- a/target/hexagon/attribs.h +++ b/target/hexagon/attribs.h @@ -32,4 +32,4 @@ extern DECLARE_BITMAP(opcode_attribs[XX_LAST_OPCODE], A_ZZ_LASTATTRIB); #define GET_ATTRIB(opcode, attrib) \ test_bit(attrib, opcode_attribs[opcode]) -#endif /* ATTRIBS_H */ +#endif /* HEXAGON_ATTRIBS_H */ diff --git a/target/xtensa/core-de233_fpu/core-matmap.h b/target/xtensa/core-de233_fpu/core-matmap.h index cca51c7af1..e99e7d3123 100644 --- a/target/xtensa/core-de233_fpu/core-matmap.h +++ b/target/xtensa/core-de233_fpu/core-matmap.h @@ -43,11 +43,9 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - #ifndef XTENSA_CONFIG_CORE_MATMAP_H #define XTENSA_CONFIG_CORE_MATMAP_H - /*---------------------------------------------------------------------- CACHE (MEMORY ACCESS) ATTRIBUTES ----------------------------------------------------------------------*/ @@ -713,5 +711,5 @@ -#endif /*XTENSA_CONFIG_CORE_MATMAP_H*/ +#endif /* XTENSA_CONFIG_CORE_MATMAP_H */ diff --git a/target/xtensa/core-dsp3400/core-matmap.h b/target/xtensa/core-dsp3400/core-matmap.h index 8d1aa8336e..692012f9f4 100644 --- a/target/xtensa/core-dsp3400/core-matmap.h +++ b/target/xtensa/core-dsp3400/core-matmap.h @@ -43,11 +43,9 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - #ifndef XTENSA_CONFIG_CORE_MATMAP_H #define XTENSA_CONFIG_CORE_MATMAP_H - /*---------------------------------------------------------------------- CACHE (MEMORY ACCESS) ATTRIBUTES ----------------------------------------------------------------------*/ @@ -308,5 +306,5 @@ -#endif /*XTENSA_CONFIG_CORE_MATMAP_H*/ +#endif /* XTENSA_CONFIG_CORE_MATMAP_H */ From 43924d1e53fd77c63b6f995556545e12f9fb11b6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 29 Mar 2022 13:01:58 +0200 Subject: [PATCH 231/935] pc-bios/optionrom: detect -fno-pie Do not rely on the detection that was done in the configure script, since in the future we may want to cross-compile this file. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- configure | 1 - pc-bios/optionrom/Makefile | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index e77b29b093..c8b5b99532 100755 --- a/configure +++ b/configure @@ -2038,7 +2038,6 @@ echo "CCAS=$ccas" >> $config_host_mak echo "CPP=$cpp" >> $config_host_mak echo "OBJCOPY=$objcopy" >> $config_host_mak echo "LD=$ld" >> $config_host_mak -echo "CFLAGS_NOPIE=$CFLAGS_NOPIE" >> $config_host_mak echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak echo "QEMU_CXXFLAGS=$QEMU_CXXFLAGS" >> $config_host_mak echo "QEMU_OBJCFLAGS=$QEMU_OBJCFLAGS" >> $config_host_mak diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile index f1ef898073..8de5a9461c 100644 --- a/pc-bios/optionrom/Makefile +++ b/pc-bios/optionrom/Makefile @@ -22,7 +22,8 @@ override CFLAGS += $(call cc-option, -fcf-protection=none) override CPPFLAGS += -MMD -MP -MT $@ -MF $(@D)/$(*F).d override CFLAGS += $(filter -W%, $(QEMU_CFLAGS)) -override CFLAGS += $(CFLAGS_NOPIE) -ffreestanding -I$(TOPSRC_DIR)/include +override CFLAGS += $(call cc-option, -fno-pie) +override CFLAGS += -ffreestanding -I$(TOPSRC_DIR)/include override CFLAGS += $(call cc-option, -fno-stack-protector) override CFLAGS += $(call cc-option, -m16) From 236d15222e06750d6b889030ed04c849b1dc279e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 13 Apr 2022 14:22:12 +0200 Subject: [PATCH 232/935] pc-bios/optionrom: compile with -Wno-array-bounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoids the following bogus warning: pvh_main.c: In function ‘pvh_load_kernel’: pvh_main.c:101:42: warning: array subscript 0 is outside array bounds of ‘uint16_t[0]’ {aka ‘short unsigned int[]’} [-Warray-bounds] 101 | uint32_t ebda_paddr = ((uint32_t)*((uint16_t *)EBDA_BASE_ADDR)) << 4; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Cc: qemu-stable@nongnu.org Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- pc-bios/optionrom/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile index 8de5a9461c..2494ad9c25 100644 --- a/pc-bios/optionrom/Makefile +++ b/pc-bios/optionrom/Makefile @@ -26,6 +26,7 @@ override CFLAGS += $(call cc-option, -fno-pie) override CFLAGS += -ffreestanding -I$(TOPSRC_DIR)/include override CFLAGS += $(call cc-option, -fno-stack-protector) override CFLAGS += $(call cc-option, -m16) +override CFLAGS += $(call cc-option, -Wno-array-bounds) ifeq ($(filter -m16, $(CFLAGS)),) # Attempt to work around compilers that lack -m16 (GCC <= 4.8, clang <= ??) From 798d8ec0dacd4cc0034298d94f430c14f23e2919 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 29 Apr 2022 21:16:28 +0200 Subject: [PATCH 233/935] target/i386: do not consult nonexistent host leaves When cache_info_passthrough is requested, QEMU passes the host values of the cache information CPUID leaves down to the guest. However, it blindly assumes that the CPUID leaf exists on the host, and this cannot be guaranteed: for example, KVM has recently started to synthesize AMD leaves up to 0x80000021 in order to provide accurate CPU bug information to guests. Querying a nonexistent host leaf fills the output arguments of host_cpuid with data that (albeit deterministic) is nonsensical as cache information, namely the data in the highest Intel CPUID leaf. If said highest leaf is not ECX-dependent, this can even cause an infinite loop when kvm_arch_init_vcpu prepares the input to KVM_SET_CPUID2. The infinite loop is only terminated by an abort() when the array gets full. Reported-by: Maxim Levitsky Reviewed-by: Maxim Levitsky Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 62c240fa91..c4a17c93f6 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5022,6 +5022,37 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, return r; } +static void x86_cpu_get_cache_cpuid(uint32_t func, uint32_t index, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + uint32_t level, unused; + + /* Only return valid host leaves. */ + switch (func) { + case 2: + case 4: + host_cpuid(0, 0, &level, &unused, &unused, &unused); + break; + case 0x80000005: + case 0x80000006: + case 0x8000001d: + host_cpuid(0x80000000, 0, &level, &unused, &unused, &unused); + break; + default: + return; + } + + if (func > level) { + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; + } else { + host_cpuid(func, index, eax, ebx, ecx, edx); + } +} + /* * Only for builtin_x86_defs models initialized with x86_register_cpudef_types. */ @@ -5280,7 +5311,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, case 2: /* cache info: needed for Pentium Pro compatibility */ if (cpu->cache_info_passthrough) { - host_cpuid(index, 0, eax, ebx, ecx, edx); + x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx); break; } else if (cpu->vendor_cpuid_only && IS_AMD_CPU(env)) { *eax = *ebx = *ecx = *edx = 0; @@ -5300,7 +5331,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, case 4: /* cache info: needed for Core compatibility */ if (cpu->cache_info_passthrough) { - host_cpuid(index, count, eax, ebx, ecx, edx); + x86_cpu_get_cache_cpuid(index, count, eax, ebx, ecx, edx); /* QEMU gives out its own APIC IDs, never pass down bits 31..26. */ *eax &= ~0xFC000000; if ((*eax & 31) && cs->nr_cores > 1) { @@ -5702,7 +5733,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, case 0x80000005: /* cache info (L1 cache) */ if (cpu->cache_info_passthrough) { - host_cpuid(index, 0, eax, ebx, ecx, edx); + x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx); break; } *eax = (L1_DTLB_2M_ASSOC << 24) | (L1_DTLB_2M_ENTRIES << 16) | @@ -5715,7 +5746,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, case 0x80000006: /* cache info (L2 cache) */ if (cpu->cache_info_passthrough) { - host_cpuid(index, 0, eax, ebx, ecx, edx); + x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx); break; } *eax = (AMD_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) | @@ -5775,7 +5806,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, case 0x8000001D: *eax = 0; if (cpu->cache_info_passthrough) { - host_cpuid(index, count, eax, ebx, ecx, edx); + x86_cpu_get_cache_cpuid(index, count, eax, ebx, ecx, edx); break; } switch (count) { From dfdb4f3c28737879685398c4a610a220e1ecf9c2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 6 Apr 2022 14:27:52 +0200 Subject: [PATCH 234/935] checkpatch: fix g_malloc check Use the string equality operator "eq", and ensure that $1 is defined by using "(try|)" instead of "(try)?". The alternative "((?:try)?)" is longer and less readable. Signed-off-by: Paolo Bonzini --- scripts/checkpatch.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 4763d02ae7..d900d18048 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2831,8 +2831,8 @@ sub process { } # check for pointless casting of g_malloc return - if ($line =~ /\*\s*\)\s*g_(try)?(m|re)alloc(0?)(_n)?\b/) { - if ($2 == 'm') { + if ($line =~ /\*\s*\)\s*g_(try|)(m|re)alloc(0?)(_n)?\b/) { + if ($2 eq 'm') { ERROR("unnecessary cast may hide bugs, use g_$1new$3 instead\n" . $herecurr); } else { ERROR("unnecessary cast may hide bugs, use g_$1renew$3 instead\n" . $herecurr); From 354d2d9b87658bab5da58b4251aeb612fa7dc6e4 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 2 May 2022 15:11:19 +0200 Subject: [PATCH 235/935] meson: Make mremap() detecting works correctly Without this (at least in Fedora 35) it don't detect mremap() correctly. Signed-off-by: Juan Quintela Message-Id: <20220502131119.2345-1-quintela@redhat.com> [Also switch the LEGACY_RDMA_REG_MR test to cc.links, otherwise Debian fails to build. - Paolo] Signed-off-by: Paolo Bonzini --- meson.build | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 864e97945f..03f63e95e2 100644 --- a/meson.build +++ b/meson.build @@ -2179,7 +2179,8 @@ config_host_data.set('CONFIG_AVX512F_OPT', get_option('avx512f') \ have_pvrdma = get_option('pvrdma') \ .require(rdma.found(), error_message: 'PVRDMA requires OpenFabrics libraries') \ - .require(cc.compiles(''' + .require(cc.compiles(gnu_source_prefix + ''' + #include int main(void) { char buf = 0; @@ -2190,7 +2191,7 @@ have_pvrdma = get_option('pvrdma') \ }'''), error_message: 'PVRDMA requires mremap').allowed() if have_pvrdma - config_host_data.set('LEGACY_RDMA_REG_MR', not cc.compiles(''' + config_host_data.set('LEGACY_RDMA_REG_MR', not cc.links(''' #include int main(void) { From 4a8027363e9680d00786622ee786fc3ccd6b970b Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 26 Mar 2022 17:58:23 +0100 Subject: [PATCH 236/935] hw/xen/xen_pt: Confine igd-passthrough-isa-bridge to XEN igd-passthrough-isa-bridge is only requested in xen_pt but was implemented in pc_piix.c. This caused xen_pt to dependend on i386/pc which is hereby resolved. Signed-off-by: Bernhard Beschow Acked-by: Anthony PERARD Message-Id: <20220326165825.30794-2-shentey@gmail.com> Signed-off-by: Paolo Bonzini --- hw/i386/pc_piix.c | 118 -------------------------------------- hw/xen/xen_pt.c | 1 - hw/xen/xen_pt.h | 1 + hw/xen/xen_pt_graphics.c | 119 +++++++++++++++++++++++++++++++++++++++ include/hw/i386/pc.h | 1 - 5 files changed, 120 insertions(+), 120 deletions(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 4c185c72d0..f843dd906f 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -813,124 +813,6 @@ static void pc_i440fx_1_4_machine_options(MachineClass *m) DEFINE_I440FX_MACHINE(v1_4, "pc-i440fx-1.4", pc_compat_1_4_fn, pc_i440fx_1_4_machine_options); -typedef struct { - uint16_t gpu_device_id; - uint16_t pch_device_id; - uint8_t pch_revision_id; -} IGDDeviceIDInfo; - -/* In real world different GPU should have different PCH. But actually - * the different PCH DIDs likely map to different PCH SKUs. We do the - * same thing for the GPU. For PCH, the different SKUs are going to be - * all the same silicon design and implementation, just different - * features turn on and off with fuses. The SW interfaces should be - * consistent across all SKUs in a given family (eg LPT). But just same - * features may not be supported. - * - * Most of these different PCH features probably don't matter to the - * Gfx driver, but obviously any difference in display port connections - * will so it should be fine with any PCH in case of passthrough. - * - * So currently use one PCH version, 0x8c4e, to cover all HSW(Haswell) - * scenarios, 0x9cc3 for BDW(Broadwell). - */ -static const IGDDeviceIDInfo igd_combo_id_infos[] = { - /* HSW Classic */ - {0x0402, 0x8c4e, 0x04}, /* HSWGT1D, HSWD_w7 */ - {0x0406, 0x8c4e, 0x04}, /* HSWGT1M, HSWM_w7 */ - {0x0412, 0x8c4e, 0x04}, /* HSWGT2D, HSWD_w7 */ - {0x0416, 0x8c4e, 0x04}, /* HSWGT2M, HSWM_w7 */ - {0x041E, 0x8c4e, 0x04}, /* HSWGT15D, HSWD_w7 */ - /* HSW ULT */ - {0x0A06, 0x8c4e, 0x04}, /* HSWGT1UT, HSWM_w7 */ - {0x0A16, 0x8c4e, 0x04}, /* HSWGT2UT, HSWM_w7 */ - {0x0A26, 0x8c4e, 0x06}, /* HSWGT3UT, HSWM_w7 */ - {0x0A2E, 0x8c4e, 0x04}, /* HSWGT3UT28W, HSWM_w7 */ - {0x0A1E, 0x8c4e, 0x04}, /* HSWGT2UX, HSWM_w7 */ - {0x0A0E, 0x8c4e, 0x04}, /* HSWGT1ULX, HSWM_w7 */ - /* HSW CRW */ - {0x0D26, 0x8c4e, 0x04}, /* HSWGT3CW, HSWM_w7 */ - {0x0D22, 0x8c4e, 0x04}, /* HSWGT3CWDT, HSWD_w7 */ - /* HSW Server */ - {0x041A, 0x8c4e, 0x04}, /* HSWSVGT2, HSWD_w7 */ - /* HSW SRVR */ - {0x040A, 0x8c4e, 0x04}, /* HSWSVGT1, HSWD_w7 */ - /* BSW */ - {0x1606, 0x9cc3, 0x03}, /* BDWULTGT1, BDWM_w7 */ - {0x1616, 0x9cc3, 0x03}, /* BDWULTGT2, BDWM_w7 */ - {0x1626, 0x9cc3, 0x03}, /* BDWULTGT3, BDWM_w7 */ - {0x160E, 0x9cc3, 0x03}, /* BDWULXGT1, BDWM_w7 */ - {0x161E, 0x9cc3, 0x03}, /* BDWULXGT2, BDWM_w7 */ - {0x1602, 0x9cc3, 0x03}, /* BDWHALOGT1, BDWM_w7 */ - {0x1612, 0x9cc3, 0x03}, /* BDWHALOGT2, BDWM_w7 */ - {0x1622, 0x9cc3, 0x03}, /* BDWHALOGT3, BDWM_w7 */ - {0x162B, 0x9cc3, 0x03}, /* BDWHALO28W, BDWM_w7 */ - {0x162A, 0x9cc3, 0x03}, /* BDWGT3WRKS, BDWM_w7 */ - {0x162D, 0x9cc3, 0x03}, /* BDWGT3SRVR, BDWM_w7 */ -}; - -static void isa_bridge_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - dc->desc = "ISA bridge faked to support IGD PT"; - set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->class_id = PCI_CLASS_BRIDGE_ISA; -}; - -static const TypeInfo isa_bridge_info = { - .name = "igd-passthrough-isa-bridge", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIDevice), - .class_init = isa_bridge_class_init, - .interfaces = (InterfaceInfo[]) { - { INTERFACE_CONVENTIONAL_PCI_DEVICE }, - { }, - }, -}; - -static void pt_graphics_register_types(void) -{ - type_register_static(&isa_bridge_info); -} -type_init(pt_graphics_register_types) - -void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id) -{ - struct PCIDevice *bridge_dev; - int i, num; - uint16_t pch_dev_id = 0xffff; - uint8_t pch_rev_id = 0; - - num = ARRAY_SIZE(igd_combo_id_infos); - for (i = 0; i < num; i++) { - if (gpu_dev_id == igd_combo_id_infos[i].gpu_device_id) { - pch_dev_id = igd_combo_id_infos[i].pch_device_id; - pch_rev_id = igd_combo_id_infos[i].pch_revision_id; - } - } - - if (pch_dev_id == 0xffff) { - return; - } - - /* Currently IGD drivers always need to access PCH by 1f.0. */ - bridge_dev = pci_create_simple(bus, PCI_DEVFN(0x1f, 0), - "igd-passthrough-isa-bridge"); - - /* - * Note that vendor id is always PCI_VENDOR_ID_INTEL. - */ - if (!bridge_dev) { - fprintf(stderr, "set igd-passthrough-isa-bridge failed!\n"); - return; - } - pci_config_set_device_id(bridge_dev->config, pch_dev_id); - pci_config_set_revision(bridge_dev->config, pch_rev_id); -} - #ifdef CONFIG_ISAPC static void isapc_machine_options(MachineClass *m) { diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index 027190fa44..829ea9985f 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -60,7 +60,6 @@ #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" #include "hw/xen/xen.h" -#include "hw/i386/pc.h" #include "hw/xen/xen-legacy-backend.h" #include "xen_pt.h" #include "qemu/range.h" diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h index 6b8e13cdee..806d832c94 100644 --- a/hw/xen/xen_pt.h +++ b/hw/xen/xen_pt.h @@ -43,6 +43,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(XenPCIPassthroughState, XEN_PT_DEVICE) uint32_t igd_read_opregion(XenPCIPassthroughState *s); void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val); +void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); /* function type for config reg */ typedef int (*xen_pt_conf_reg_init) diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c index a3bc7e3921..f1fbb98912 100644 --- a/hw/xen/xen_pt_graphics.c +++ b/hw/xen/xen_pt_graphics.c @@ -289,3 +289,122 @@ void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val) (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT), (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT)); } + +typedef struct { + uint16_t gpu_device_id; + uint16_t pch_device_id; + uint8_t pch_revision_id; +} IGDDeviceIDInfo; + +/* + * In real world different GPU should have different PCH. But actually + * the different PCH DIDs likely map to different PCH SKUs. We do the + * same thing for the GPU. For PCH, the different SKUs are going to be + * all the same silicon design and implementation, just different + * features turn on and off with fuses. The SW interfaces should be + * consistent across all SKUs in a given family (eg LPT). But just same + * features may not be supported. + * + * Most of these different PCH features probably don't matter to the + * Gfx driver, but obviously any difference in display port connections + * will so it should be fine with any PCH in case of passthrough. + * + * So currently use one PCH version, 0x8c4e, to cover all HSW(Haswell) + * scenarios, 0x9cc3 for BDW(Broadwell). + */ +static const IGDDeviceIDInfo igd_combo_id_infos[] = { + /* HSW Classic */ + {0x0402, 0x8c4e, 0x04}, /* HSWGT1D, HSWD_w7 */ + {0x0406, 0x8c4e, 0x04}, /* HSWGT1M, HSWM_w7 */ + {0x0412, 0x8c4e, 0x04}, /* HSWGT2D, HSWD_w7 */ + {0x0416, 0x8c4e, 0x04}, /* HSWGT2M, HSWM_w7 */ + {0x041E, 0x8c4e, 0x04}, /* HSWGT15D, HSWD_w7 */ + /* HSW ULT */ + {0x0A06, 0x8c4e, 0x04}, /* HSWGT1UT, HSWM_w7 */ + {0x0A16, 0x8c4e, 0x04}, /* HSWGT2UT, HSWM_w7 */ + {0x0A26, 0x8c4e, 0x06}, /* HSWGT3UT, HSWM_w7 */ + {0x0A2E, 0x8c4e, 0x04}, /* HSWGT3UT28W, HSWM_w7 */ + {0x0A1E, 0x8c4e, 0x04}, /* HSWGT2UX, HSWM_w7 */ + {0x0A0E, 0x8c4e, 0x04}, /* HSWGT1ULX, HSWM_w7 */ + /* HSW CRW */ + {0x0D26, 0x8c4e, 0x04}, /* HSWGT3CW, HSWM_w7 */ + {0x0D22, 0x8c4e, 0x04}, /* HSWGT3CWDT, HSWD_w7 */ + /* HSW Server */ + {0x041A, 0x8c4e, 0x04}, /* HSWSVGT2, HSWD_w7 */ + /* HSW SRVR */ + {0x040A, 0x8c4e, 0x04}, /* HSWSVGT1, HSWD_w7 */ + /* BSW */ + {0x1606, 0x9cc3, 0x03}, /* BDWULTGT1, BDWM_w7 */ + {0x1616, 0x9cc3, 0x03}, /* BDWULTGT2, BDWM_w7 */ + {0x1626, 0x9cc3, 0x03}, /* BDWULTGT3, BDWM_w7 */ + {0x160E, 0x9cc3, 0x03}, /* BDWULXGT1, BDWM_w7 */ + {0x161E, 0x9cc3, 0x03}, /* BDWULXGT2, BDWM_w7 */ + {0x1602, 0x9cc3, 0x03}, /* BDWHALOGT1, BDWM_w7 */ + {0x1612, 0x9cc3, 0x03}, /* BDWHALOGT2, BDWM_w7 */ + {0x1622, 0x9cc3, 0x03}, /* BDWHALOGT3, BDWM_w7 */ + {0x162B, 0x9cc3, 0x03}, /* BDWHALO28W, BDWM_w7 */ + {0x162A, 0x9cc3, 0x03}, /* BDWGT3WRKS, BDWM_w7 */ + {0x162D, 0x9cc3, 0x03}, /* BDWGT3SRVR, BDWM_w7 */ +}; + +static void isa_bridge_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + dc->desc = "ISA bridge faked to support IGD PT"; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->class_id = PCI_CLASS_BRIDGE_ISA; +}; + +static const TypeInfo isa_bridge_info = { + .name = "igd-passthrough-isa-bridge", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = isa_bridge_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, +}; + +static void pt_graphics_register_types(void) +{ + type_register_static(&isa_bridge_info); +} +type_init(pt_graphics_register_types) + +void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id) +{ + struct PCIDevice *bridge_dev; + int i, num; + uint16_t pch_dev_id = 0xffff; + uint8_t pch_rev_id = 0; + + num = ARRAY_SIZE(igd_combo_id_infos); + for (i = 0; i < num; i++) { + if (gpu_dev_id == igd_combo_id_infos[i].gpu_device_id) { + pch_dev_id = igd_combo_id_infos[i].pch_device_id; + pch_rev_id = igd_combo_id_infos[i].pch_revision_id; + } + } + + if (pch_dev_id == 0xffff) { + return; + } + + /* Currently IGD drivers always need to access PCH by 1f.0. */ + bridge_dev = pci_create_simple(bus, PCI_DEVFN(0x1f, 0), + "igd-passthrough-isa-bridge"); + + /* + * Note that vendor id is always PCI_VENDOR_ID_INTEL. + */ + if (!bridge_dev) { + fprintf(stderr, "set igd-passthrough-isa-bridge failed!\n"); + return; + } + pci_config_set_device_id(bridge_dev->config, pch_dev_id); + pci_config_set_revision(bridge_dev->config, pch_rev_id); +} diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 637367dc5f..aff8add155 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -315,5 +315,4 @@ extern const size_t pc_compat_1_4_len; } \ type_init(pc_machine_init_##suffix) -extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); #endif From 76acef2b735729c642c54385b7566de509506d9a Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 26 Mar 2022 17:58:24 +0100 Subject: [PATCH 237/935] hw/xen/xen_pt: Resolve igd_passthrough_isa_bridge_create() indirection Now that igd_passthrough_isa_bridge_create() is implemented within the xen context it may use Xen* data types directly and become xen_igd_passthrough_isa_bridge_create(). This resolves an indirection. Signed-off-by: Bernhard Beschow Acked-by: Anthony PERARD Message-Id: <20220326165825.30794-3-shentey@gmail.com> Signed-off-by: Paolo Bonzini --- hw/xen/xen_pt.c | 11 ----------- hw/xen/xen_pt.h | 3 ++- hw/xen/xen_pt_graphics.c | 5 ++++- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index 829ea9985f..0ec7e52183 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -701,17 +701,6 @@ static const MemoryListener xen_pt_io_listener = { .priority = 10, }; -static void -xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s, - XenHostPCIDevice *dev) -{ - uint16_t gpu_dev_id; - PCIDevice *d = &s->dev; - - gpu_dev_id = dev->device_id; - igd_passthrough_isa_bridge_create(pci_get_bus(d), gpu_dev_id); -} - /* destroy. */ static void xen_pt_destroy(PCIDevice *d) { diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h index 806d832c94..e7c4316a7d 100644 --- a/hw/xen/xen_pt.h +++ b/hw/xen/xen_pt.h @@ -43,7 +43,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(XenPCIPassthroughState, XEN_PT_DEVICE) uint32_t igd_read_opregion(XenPCIPassthroughState *s); void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val); -void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); +void xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s, + XenHostPCIDevice *dev); /* function type for config reg */ typedef int (*xen_pt_conf_reg_init) diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c index f1fbb98912..f303f67c9c 100644 --- a/hw/xen/xen_pt_graphics.c +++ b/hw/xen/xen_pt_graphics.c @@ -375,10 +375,13 @@ static void pt_graphics_register_types(void) } type_init(pt_graphics_register_types) -void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id) +void xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s, + XenHostPCIDevice *dev) { + PCIBus *bus = pci_get_bus(&s->dev); struct PCIDevice *bridge_dev; int i, num; + const uint16_t gpu_dev_id = dev->device_id; uint16_t pch_dev_id = 0xffff; uint8_t pch_rev_id = 0; From 3df72d1c5500347eac0b5b6d9894713dc443a079 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Wed, 4 May 2022 17:20:23 +0200 Subject: [PATCH 238/935] tests/qtest/libqos/pci: Introduce pio_limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the moment the IO space limit is hardcoded to QPCI_PIO_LIMIT = 0x10000. When accesses are performed to a bar, the base address of this latter is compared against the limit to decide whether we perform an IO or a memory access. On ARM, we cannot keep this PIO limit as the arm-virt machine uses [0x3eff0000, 0x3f000000 ] for the IO space map and we are mandated to allocate at 0x0. Add a new flag in QPCIBar indicating whether it is an IO bar or a memory bar. This flag is set on QPCIBar allocation and provisionned based on the BAR configuration. Then the new flag is used in access functions and in iomap() function. Signed-off-by: Eric Auger Reviewed-by: Thomas Huth Reviewed-by: Alex Bennée Message-Id: <20220504152025.1785704-2-eric.auger@redhat.com> Signed-off-by: Paolo Bonzini --- tests/qtest/libqos/pci-pc.c | 1 + tests/qtest/libqos/pci-spapr.c | 1 + tests/qtest/libqos/pci.c | 78 ++++++++++++++++++++++------------ tests/qtest/libqos/pci.h | 5 +-- 4 files changed, 54 insertions(+), 31 deletions(-) diff --git a/tests/qtest/libqos/pci-pc.c b/tests/qtest/libqos/pci-pc.c index e9dd5a57ec..81c2c055ca 100644 --- a/tests/qtest/libqos/pci-pc.c +++ b/tests/qtest/libqos/pci-pc.c @@ -150,6 +150,7 @@ void qpci_init_pc(QPCIBusPC *qpci, QTestState *qts, QGuestAllocator *alloc) qpci->bus.qts = qts; qpci->bus.pio_alloc_ptr = 0xc000; + qpci->bus.pio_limit = 0x10000; qpci->bus.mmio_alloc_ptr = 0xE0000000; qpci->bus.mmio_limit = 0x100000000ULL; diff --git a/tests/qtest/libqos/pci-spapr.c b/tests/qtest/libqos/pci-spapr.c index 76bf9a855d..0f1023e4a7 100644 --- a/tests/qtest/libqos/pci-spapr.c +++ b/tests/qtest/libqos/pci-spapr.c @@ -197,6 +197,7 @@ void qpci_init_spapr(QPCIBusSPAPR *qpci, QTestState *qts, qpci->bus.qts = qts; qpci->bus.pio_alloc_ptr = 0xc000; + qpci->bus.pio_limit = 0x10000; qpci->bus.mmio_alloc_ptr = qpci->mmio32.pci_base; qpci->bus.mmio_limit = qpci->mmio32.pci_base + qpci->mmio32.size; diff --git a/tests/qtest/libqos/pci.c b/tests/qtest/libqos/pci.c index 3a9076ae58..b23d72346b 100644 --- a/tests/qtest/libqos/pci.c +++ b/tests/qtest/libqos/pci.c @@ -398,44 +398,56 @@ void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value) uint8_t qpci_io_readb(QPCIDevice *dev, QPCIBar token, uint64_t off) { - if (token.addr < QPCI_PIO_LIMIT) { - return dev->bus->pio_readb(dev->bus, token.addr + off); + QPCIBus *bus = dev->bus; + + if (token.is_io) { + return bus->pio_readb(bus, token.addr + off); } else { uint8_t val; - dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); + + bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); return val; } } uint16_t qpci_io_readw(QPCIDevice *dev, QPCIBar token, uint64_t off) { - if (token.addr < QPCI_PIO_LIMIT) { - return dev->bus->pio_readw(dev->bus, token.addr + off); + QPCIBus *bus = dev->bus; + + if (token.is_io) { + return bus->pio_readw(bus, token.addr + off); } else { uint16_t val; - dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); + + bus->memread(bus, token.addr + off, &val, sizeof(val)); return le16_to_cpu(val); } } uint32_t qpci_io_readl(QPCIDevice *dev, QPCIBar token, uint64_t off) { - if (token.addr < QPCI_PIO_LIMIT) { - return dev->bus->pio_readl(dev->bus, token.addr + off); + QPCIBus *bus = dev->bus; + + if (token.is_io) { + return bus->pio_readl(bus, token.addr + off); } else { uint32_t val; - dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); + + bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); return le32_to_cpu(val); } } uint64_t qpci_io_readq(QPCIDevice *dev, QPCIBar token, uint64_t off) { - if (token.addr < QPCI_PIO_LIMIT) { - return dev->bus->pio_readq(dev->bus, token.addr + off); + QPCIBus *bus = dev->bus; + + if (token.is_io) { + return bus->pio_readq(bus, token.addr + off); } else { uint64_t val; - dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); + + bus->memread(bus, token.addr + off, &val, sizeof(val)); return le64_to_cpu(val); } } @@ -443,57 +455,65 @@ uint64_t qpci_io_readq(QPCIDevice *dev, QPCIBar token, uint64_t off) void qpci_io_writeb(QPCIDevice *dev, QPCIBar token, uint64_t off, uint8_t value) { - if (token.addr < QPCI_PIO_LIMIT) { - dev->bus->pio_writeb(dev->bus, token.addr + off, value); + QPCIBus *bus = dev->bus; + + if (token.is_io) { + bus->pio_writeb(bus, token.addr + off, value); } else { - dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value)); + bus->memwrite(bus, token.addr + off, &value, sizeof(value)); } } void qpci_io_writew(QPCIDevice *dev, QPCIBar token, uint64_t off, uint16_t value) { - if (token.addr < QPCI_PIO_LIMIT) { - dev->bus->pio_writew(dev->bus, token.addr + off, value); + QPCIBus *bus = dev->bus; + + if (token.is_io) { + bus->pio_writew(bus, token.addr + off, value); } else { value = cpu_to_le16(value); - dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value)); + bus->memwrite(bus, token.addr + off, &value, sizeof(value)); } } void qpci_io_writel(QPCIDevice *dev, QPCIBar token, uint64_t off, uint32_t value) { - if (token.addr < QPCI_PIO_LIMIT) { - dev->bus->pio_writel(dev->bus, token.addr + off, value); + QPCIBus *bus = dev->bus; + + if (token.is_io) { + bus->pio_writel(bus, token.addr + off, value); } else { value = cpu_to_le32(value); - dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value)); + bus->memwrite(bus, token.addr + off, &value, sizeof(value)); } } void qpci_io_writeq(QPCIDevice *dev, QPCIBar token, uint64_t off, uint64_t value) { - if (token.addr < QPCI_PIO_LIMIT) { - dev->bus->pio_writeq(dev->bus, token.addr + off, value); + QPCIBus *bus = dev->bus; + + if (token.is_io) { + bus->pio_writeq(bus, token.addr + off, value); } else { value = cpu_to_le64(value); - dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value)); + bus->memwrite(bus, token.addr + off, &value, sizeof(value)); } } void qpci_memread(QPCIDevice *dev, QPCIBar token, uint64_t off, void *buf, size_t len) { - g_assert(token.addr >= QPCI_PIO_LIMIT); + g_assert(!token.is_io); dev->bus->memread(dev->bus, token.addr + off, buf, len); } void qpci_memwrite(QPCIDevice *dev, QPCIBar token, uint64_t off, const void *buf, size_t len) { - g_assert(token.addr >= QPCI_PIO_LIMIT); + g_assert(!token.is_io); dev->bus->memwrite(dev->bus, token.addr + off, buf, len); } @@ -534,9 +554,10 @@ QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr) loc = QEMU_ALIGN_UP(bus->pio_alloc_ptr, size); g_assert(loc >= bus->pio_alloc_ptr); - g_assert(loc + size <= QPCI_PIO_LIMIT); /* Keep PIO below 64kiB */ + g_assert(loc + size <= bus->pio_limit); bus->pio_alloc_ptr = loc + size; + bar.is_io = true; qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO); } else { @@ -547,6 +568,7 @@ QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr) g_assert(loc + size <= bus->mmio_limit); bus->mmio_alloc_ptr = loc + size; + bar.is_io = false; qpci_config_writel(dev, bar_reg, loc); } @@ -562,7 +584,7 @@ void qpci_iounmap(QPCIDevice *dev, QPCIBar bar) QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr) { - QPCIBar bar = { .addr = addr }; + QPCIBar bar = { .addr = addr, .is_io = true }; return bar; } diff --git a/tests/qtest/libqos/pci.h b/tests/qtest/libqos/pci.h index e705e06598..a3c657d962 100644 --- a/tests/qtest/libqos/pci.h +++ b/tests/qtest/libqos/pci.h @@ -16,8 +16,6 @@ #include "../libqtest.h" #include "qgraph.h" -#define QPCI_PIO_LIMIT 0x10000 - #define QPCI_DEVFN(dev, fn) (((dev) << 3) | (fn)) typedef struct QPCIDevice QPCIDevice; @@ -51,7 +49,7 @@ struct QPCIBus { uint8_t offset, uint32_t value); QTestState *qts; - uint16_t pio_alloc_ptr; + uint64_t pio_alloc_ptr, pio_limit; uint64_t mmio_alloc_ptr, mmio_limit; bool has_buggy_msi; /* TRUE for spapr, FALSE for pci */ @@ -59,6 +57,7 @@ struct QPCIBus { struct QPCIBar { uint64_t addr; + bool is_io; }; struct QPCIDevice From 02ee7a8a97d3ddeda887b596005b462f680dc89c Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Wed, 4 May 2022 17:20:24 +0200 Subject: [PATCH 239/935] tests/qtest/libqos: Skip hotplug tests if pci root bus is not hotpluggable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ARM does not not support hotplug on pcie.0. Add a flag on the bus which tells if devices can be hotplugged and skip hotplug tests if the bus cannot be hotplugged. This is a temporary solution to enable the other pci tests on aarch64. Signed-off-by: Eric Auger Acked-by: Thomas Huth Reviewed-by: Alex Bennée Message-Id: <20220504152025.1785704-3-eric.auger@redhat.com> Signed-off-by: Paolo Bonzini --- tests/qtest/e1000e-test.c | 6 ++++++ tests/qtest/libqos/pci.h | 1 + tests/qtest/vhost-user-blk-test.c | 10 ++++++++++ tests/qtest/virtio-blk-test.c | 5 +++++ tests/qtest/virtio-net-test.c | 5 +++++ tests/qtest/virtio-rng-test.c | 5 +++++ 6 files changed, 32 insertions(+) diff --git a/tests/qtest/e1000e-test.c b/tests/qtest/e1000e-test.c index ddd6983ede..c98779c7c0 100644 --- a/tests/qtest/e1000e-test.c +++ b/tests/qtest/e1000e-test.c @@ -233,6 +233,12 @@ static void test_e1000e_multiple_transfers(void *obj, void *data, static void test_e1000e_hotplug(void *obj, void *data, QGuestAllocator * alloc) { QTestState *qts = global_qtest; /* TODO: get rid of global_qtest here */ + QE1000E_PCI *dev = obj; + + if (dev->pci_dev.bus->not_hotpluggable) { + g_test_skip("pci bus does not support hotplug"); + return; + } qtest_qmp_device_add(qts, "e1000e", "e1000e_net", "{'addr': '0x06'}"); qpci_unplug_acpi_device_test(qts, "e1000e_net", 0x06); diff --git a/tests/qtest/libqos/pci.h b/tests/qtest/libqos/pci.h index a3c657d962..8389614523 100644 --- a/tests/qtest/libqos/pci.h +++ b/tests/qtest/libqos/pci.h @@ -52,6 +52,7 @@ struct QPCIBus { uint64_t pio_alloc_ptr, pio_limit; uint64_t mmio_alloc_ptr, mmio_limit; bool has_buggy_msi; /* TRUE for spapr, FALSE for pci */ + bool not_hotpluggable; /* TRUE if devices cannot be hotplugged */ }; diff --git a/tests/qtest/vhost-user-blk-test.c b/tests/qtest/vhost-user-blk-test.c index 659b5050d8..a81c2a2715 100644 --- a/tests/qtest/vhost-user-blk-test.c +++ b/tests/qtest/vhost-user-blk-test.c @@ -676,6 +676,11 @@ static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc) QVirtioPCIDevice *dev; QTestState *qts = dev1->pdev->bus->qts; + if (dev1->pdev->bus->not_hotpluggable) { + g_test_skip("pci bus does not support hotplug"); + return; + } + /* plug secondary disk */ qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1", "{'addr': %s, 'chardev': 'char2'}", @@ -703,6 +708,11 @@ static void multiqueue(void *obj, void *data, QGuestAllocator *t_alloc) uint64_t features; uint16_t num_queues; + if (pdev1->pdev->bus->not_hotpluggable) { + g_test_skip("bus pci.0 does not support hotplug"); + return; + } + /* * The primary device has 1 queue and VIRTIO_BLK_F_MQ is not enabled. The * VIRTIO specification allows VIRTIO_BLK_F_MQ to be enabled when there is diff --git a/tests/qtest/virtio-blk-test.c b/tests/qtest/virtio-blk-test.c index f22594a1a8..dc5eed31c8 100644 --- a/tests/qtest/virtio-blk-test.c +++ b/tests/qtest/virtio-blk-test.c @@ -701,6 +701,11 @@ static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc) QVirtioPCIDevice *dev; QTestState *qts = dev1->pdev->bus->qts; + if (dev1->pdev->bus->not_hotpluggable) { + g_test_skip("pci bus does not support hotplug"); + return; + } + /* plug secondary disk */ qtest_qmp_device_add(qts, "virtio-blk-pci", "drv1", "{'addr': %s, 'drive': 'drive1'}", diff --git a/tests/qtest/virtio-net-test.c b/tests/qtest/virtio-net-test.c index fc9f2b9498..6ded252901 100644 --- a/tests/qtest/virtio-net-test.c +++ b/tests/qtest/virtio-net-test.c @@ -173,6 +173,11 @@ static void hotplug(void *obj, void *data, QGuestAllocator *t_alloc) QTestState *qts = dev->pdev->bus->qts; const char *arch = qtest_get_arch(); + if (dev->pdev->bus->not_hotpluggable) { + g_test_skip("pci bus does not support hotplug"); + return; + } + qtest_qmp_device_add(qts, "virtio-net-pci", "net1", "{'addr': %s}", stringify(PCI_SLOT_HP)); diff --git a/tests/qtest/virtio-rng-test.c b/tests/qtest/virtio-rng-test.c index 092ba13068..64e131cd8c 100644 --- a/tests/qtest/virtio-rng-test.c +++ b/tests/qtest/virtio-rng-test.c @@ -20,6 +20,11 @@ static void rng_hotplug(void *obj, void *data, QGuestAllocator *alloc) QVirtioPCIDevice *dev = obj; QTestState *qts = dev->pdev->bus->qts; + if (dev->pdev->bus->not_hotpluggable) { + g_test_skip("pci bus does not support hotplug"); + return; + } + const char *arch = qtest_get_arch(); qtest_qmp_device_add(qts, "virtio-rng-pci", "rng1", From 70be1d93f9c2dbf6793830d482e91bb33f921348 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Wed, 4 May 2022 17:20:25 +0200 Subject: [PATCH 240/935] tests/qtest/libqos: Add generic pci host bridge in arm-virt machine Up to now the virt-machine node contains a virtio-mmio node. However no driver produces any PCI interface node. Hence, PCI tests cannot be run with aarch64 binary. Add a GPEX driver node that produces a pci interface node. This latter then can be consumed by all the pci tests. One of the first motivation was to be able to run the virtio-iommu-pci tests. We still face an issue with pci hotplug tests as hotplug cannot happen on the pcie root bus and require a generic root port. This will be addressed later on. We force cpu=max along with aarch64/virt machine as some PCI tests require high MMIO regions to be available. Signed-off-by: Eric Auger Message-Id: <20220504152025.1785704-4-eric.auger@redhat.com> Signed-off-by: Paolo Bonzini --- tests/qtest/libqos/arm-virt-machine.c | 19 ++- tests/qtest/libqos/generic-pcihost.c | 231 ++++++++++++++++++++++++++ tests/qtest/libqos/generic-pcihost.h | 54 ++++++ tests/qtest/libqos/meson.build | 1 + 4 files changed, 301 insertions(+), 4 deletions(-) create mode 100644 tests/qtest/libqos/generic-pcihost.c create mode 100644 tests/qtest/libqos/generic-pcihost.h diff --git a/tests/qtest/libqos/arm-virt-machine.c b/tests/qtest/libqos/arm-virt-machine.c index 2e0beaefb8..139eaba142 100644 --- a/tests/qtest/libqos/arm-virt-machine.c +++ b/tests/qtest/libqos/arm-virt-machine.c @@ -22,6 +22,8 @@ #include "malloc.h" #include "qgraph.h" #include "virtio-mmio.h" +#include "generic-pcihost.h" +#include "hw/pci/pci_regs.h" #define ARM_PAGE_SIZE 4096 #define VIRTIO_MMIO_BASE_ADDR 0x0A003E00 @@ -35,6 +37,7 @@ struct QVirtMachine { QOSGraphObject obj; QGuestAllocator alloc; QVirtioMMIODevice virtio_mmio; + QGenericPCIHost bridge; }; static void virt_destructor(QOSGraphObject *obj) @@ -57,11 +60,13 @@ static void *virt_get_driver(void *object, const char *interface) static QOSGraphObject *virt_get_device(void *obj, const char *device) { QVirtMachine *machine = obj; - if (!g_strcmp0(device, "virtio-mmio")) { + if (!g_strcmp0(device, "generic-pcihost")) { + return &machine->bridge.obj; + } else if (!g_strcmp0(device, "virtio-mmio")) { return &machine->virtio_mmio.obj; } - fprintf(stderr, "%s not present in arm/virtio\n", device); + fprintf(stderr, "%s not present in arm/virt\n", device); g_assert_not_reached(); } @@ -76,16 +81,22 @@ static void *qos_create_machine_arm_virt(QTestState *qts) qvirtio_mmio_init_device(&machine->virtio_mmio, qts, VIRTIO_MMIO_BASE_ADDR, VIRTIO_MMIO_SIZE); + qos_create_generic_pcihost(&machine->bridge, qts, &machine->alloc); + machine->obj.get_device = virt_get_device; machine->obj.get_driver = virt_get_driver; machine->obj.destructor = virt_destructor; return machine; } -static void virtio_mmio_register_nodes(void) +static void virt_machine_register_nodes(void) { qos_node_create_machine("arm/virt", qos_create_machine_arm_virt); qos_node_contains("arm/virt", "virtio-mmio", NULL); + + qos_node_create_machine_args("aarch64/virt", qos_create_machine_arm_virt, + " -cpu max"); + qos_node_contains("aarch64/virt", "generic-pcihost", NULL); } -libqos_init(virtio_mmio_register_nodes); +libqos_init(virt_machine_register_nodes); diff --git a/tests/qtest/libqos/generic-pcihost.c b/tests/qtest/libqos/generic-pcihost.c new file mode 100644 index 0000000000..3124b0e46b --- /dev/null +++ b/tests/qtest/libqos/generic-pcihost.c @@ -0,0 +1,231 @@ +/* + * libqos PCI bindings for generic PCI + * + * Copyright Red Hat Inc., 2022 + * + * Authors: + * Eric Auger + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "../libqtest.h" +#include "generic-pcihost.h" +#include "qapi/qmp/qdict.h" +#include "hw/pci/pci_regs.h" +#include "qemu/host-utils.h" + +#include "qemu/module.h" + +/* QGenericPCIHost */ + +QOSGraphObject *generic_pcihost_get_device(void *obj, const char *device) +{ + QGenericPCIHost *host = obj; + if (!g_strcmp0(device, "pci-bus-generic")) { + return &host->pci.obj; + } + fprintf(stderr, "%s not present in generic-pcihost\n", device); + g_assert_not_reached(); +} + +void qos_create_generic_pcihost(QGenericPCIHost *host, + QTestState *qts, + QGuestAllocator *alloc) +{ + host->obj.get_device = generic_pcihost_get_device; + qpci_init_generic(&host->pci, qts, alloc, false); +} + +static uint8_t qpci_generic_pio_readb(QPCIBus *bus, uint32_t addr) +{ + QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); + + return qtest_readb(bus->qts, s->gpex_pio_base + addr); +} + +static void qpci_generic_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) +{ + QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); + + qtest_writeb(bus->qts, s->gpex_pio_base + addr, val); +} + +static uint16_t qpci_generic_pio_readw(QPCIBus *bus, uint32_t addr) +{ + QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); + + return qtest_readw(bus->qts, s->gpex_pio_base + addr); +} + +static void qpci_generic_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val) +{ + QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); + + qtest_writew(bus->qts, s->gpex_pio_base + addr, val); +} + +static uint32_t qpci_generic_pio_readl(QPCIBus *bus, uint32_t addr) +{ + QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); + + return qtest_readl(bus->qts, s->gpex_pio_base + addr); +} + +static void qpci_generic_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) +{ + QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); + + qtest_writel(bus->qts, s->gpex_pio_base + addr, val); +} + +static uint64_t qpci_generic_pio_readq(QPCIBus *bus, uint32_t addr) +{ + QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); + + return qtest_readq(bus->qts, s->gpex_pio_base + addr); +} + +static void qpci_generic_pio_writeq(QPCIBus *bus, uint32_t addr, uint64_t val) +{ + QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); + + qtest_writeq(bus->qts, s->gpex_pio_base + addr, val); +} + +static void qpci_generic_memread(QPCIBus *bus, uint32_t addr, void *buf, size_t len) +{ + qtest_memread(bus->qts, addr, buf, len); +} + +static void qpci_generic_memwrite(QPCIBus *bus, uint32_t addr, + const void *buf, size_t len) +{ + qtest_memwrite(bus->qts, addr, buf, len); +} + +static uint8_t qpci_generic_config_readb(QPCIBus *bus, int devfn, uint8_t offset) +{ + QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus); + uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset); + uint8_t val; + + qtest_memread(bus->qts, addr, &val, 1); + return val; +} + +static uint16_t qpci_generic_config_readw(QPCIBus *bus, int devfn, uint8_t offset) +{ + QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus); + uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset); + uint16_t val; + + qtest_memread(bus->qts, addr, &val, 2); + return le16_to_cpu(val); +} + +static uint32_t qpci_generic_config_readl(QPCIBus *bus, int devfn, uint8_t offset) +{ + QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus); + uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset); + uint32_t val; + + qtest_memread(bus->qts, addr, &val, 4); + return le32_to_cpu(val); +} + +static void +qpci_generic_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, uint8_t value) +{ + QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus); + uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset); + + qtest_memwrite(bus->qts, addr, &value, 1); +} + +static void +qpci_generic_config_writew(QPCIBus *bus, int devfn, uint8_t offset, uint16_t value) +{ + QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus); + uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset); + uint16_t val = cpu_to_le16(value); + + qtest_memwrite(bus->qts, addr, &val, 2); +} + +static void +qpci_generic_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint32_t value) +{ + QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus); + uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset); + uint32_t val = cpu_to_le32(value); + + qtest_memwrite(bus->qts, addr, &val, 4); +} + +static void *qpci_generic_get_driver(void *obj, const char *interface) +{ + QGenericPCIBus *qpci = obj; + if (!g_strcmp0(interface, "pci-bus")) { + return &qpci->bus; + } + fprintf(stderr, "%s not present in pci-bus-generic\n", interface); + g_assert_not_reached(); +} + +void qpci_init_generic(QGenericPCIBus *qpci, QTestState *qts, + QGuestAllocator *alloc, bool hotpluggable) +{ + assert(qts); + + qpci->gpex_pio_base = 0x3eff0000; + qpci->bus.not_hotpluggable = !hotpluggable; + qpci->bus.has_buggy_msi = false; + + qpci->bus.pio_readb = qpci_generic_pio_readb; + qpci->bus.pio_readw = qpci_generic_pio_readw; + qpci->bus.pio_readl = qpci_generic_pio_readl; + qpci->bus.pio_readq = qpci_generic_pio_readq; + + qpci->bus.pio_writeb = qpci_generic_pio_writeb; + qpci->bus.pio_writew = qpci_generic_pio_writew; + qpci->bus.pio_writel = qpci_generic_pio_writel; + qpci->bus.pio_writeq = qpci_generic_pio_writeq; + + qpci->bus.memread = qpci_generic_memread; + qpci->bus.memwrite = qpci_generic_memwrite; + + qpci->bus.config_readb = qpci_generic_config_readb; + qpci->bus.config_readw = qpci_generic_config_readw; + qpci->bus.config_readl = qpci_generic_config_readl; + + qpci->bus.config_writeb = qpci_generic_config_writeb; + qpci->bus.config_writew = qpci_generic_config_writew; + qpci->bus.config_writel = qpci_generic_config_writel; + + qpci->bus.qts = qts; + qpci->bus.pio_alloc_ptr = 0x0000; + qpci->bus.pio_limit = 0x10000; + qpci->bus.mmio_alloc_ptr = 0x10000000; + qpci->bus.mmio_limit = 0x2eff0000; + qpci->ecam_alloc_ptr = 0x4010000000; + + qpci->obj.get_driver = qpci_generic_get_driver; +} + +static void qpci_generic_register_nodes(void) +{ + qos_node_create_driver("pci-bus-generic", NULL); + qos_node_produces("pci-bus-generic", "pci-bus"); +} + +static void qpci_generic_pci_register_nodes(void) +{ + qos_node_create_driver("generic-pcihost", NULL); + qos_node_contains("generic-pcihost", "pci-bus-generic", NULL); +} + +libqos_init(qpci_generic_register_nodes); +libqos_init(qpci_generic_pci_register_nodes); diff --git a/tests/qtest/libqos/generic-pcihost.h b/tests/qtest/libqos/generic-pcihost.h new file mode 100644 index 0000000000..c693c769df --- /dev/null +++ b/tests/qtest/libqos/generic-pcihost.h @@ -0,0 +1,54 @@ +/* + * libqos Generic PCI bindings and generic pci host bridge + * + * Copyright Red Hat Inc., 2022 + * + * Authors: + * Eric Auger + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef LIBQOS_GENERIC_PCIHOST_H +#define LIBQOS_GENERIC_PCIHOST_H + +#include "pci.h" +#include "malloc.h" +#include "qgraph.h" + +typedef struct QGenericPCIBus { + QOSGraphObject obj; + QPCIBus bus; + uint64_t gpex_pio_base; + uint64_t ecam_alloc_ptr; +} QGenericPCIBus; + +/* + * qpci_init_generic(): + * @ret: A valid QGenericPCIBus * pointer + * @qts: The %QTestState + * @alloc: A previously initialized @alloc providing memory for @qts + * @bool: devices can be hotplugged on this bus + * + * This function initializes an already allocated + * QGenericPCIBus object. + */ +void qpci_init_generic(QGenericPCIBus *ret, QTestState *qts, + QGuestAllocator *alloc, bool hotpluggable); + +/* QGenericPCIHost */ + +typedef struct QGenericPCIHost QGenericPCIHost; + +struct QGenericPCIHost { + QOSGraphObject obj; + QGenericPCIBus pci; +}; + +QOSGraphObject *generic_pcihost_get_device(void *obj, const char *device); +void qos_create_generic_pcihost(QGenericPCIHost *host, + QTestState *qts, + QGuestAllocator *alloc); + +#endif diff --git a/tests/qtest/libqos/meson.build b/tests/qtest/libqos/meson.build index 9f292339f9..fd5d6e5ae1 100644 --- a/tests/qtest/libqos/meson.build +++ b/tests/qtest/libqos/meson.build @@ -45,6 +45,7 @@ libqos_srcs = files( 'virtio-scsi.c', 'virtio-serial.c', 'virtio-iommu.c', + 'generic-pcihost.c', # qgraph machines: 'aarch64-xlnx-zcu102-machine.c', From 98e3ab35054b946f7c2aba5408822532b0920b53 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 10 May 2022 17:10:19 +0200 Subject: [PATCH 241/935] coroutine: Rename qemu_coroutine_inc/dec_pool_size() It's true that these functions currently affect the batch size in which coroutines are reused (i.e. moved from the global release pool to the allocation pool of a specific thread), but this is a bug and will be fixed in a separate patch. In fact, the comment in the header file already just promises that it influences the pool size, so reflect this in the name of the functions. As a nice side effect, the shorter function name makes some line wrapping unnecessary. Cc: qemu-stable@nongnu.org Signed-off-by: Kevin Wolf Message-Id: <20220510151020.105528-2-kwolf@redhat.com> Signed-off-by: Kevin Wolf --- hw/block/virtio-blk.c | 6 ++---- include/qemu/coroutine.h | 6 +++--- util/qemu-coroutine.c | 4 ++-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 540c38f829..6a1cc41877 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -1215,8 +1215,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) for (i = 0; i < conf->num_queues; i++) { virtio_add_queue(vdev, conf->queue_size, virtio_blk_handle_output); } - qemu_coroutine_increase_pool_batch_size(conf->num_queues * conf->queue_size - / 2); + qemu_coroutine_inc_pool_size(conf->num_queues * conf->queue_size / 2); virtio_blk_data_plane_create(vdev, conf, &s->dataplane, &err); if (err != NULL) { error_propagate(errp, err); @@ -1253,8 +1252,7 @@ static void virtio_blk_device_unrealize(DeviceState *dev) for (i = 0; i < conf->num_queues; i++) { virtio_del_queue(vdev, i); } - qemu_coroutine_decrease_pool_batch_size(conf->num_queues * conf->queue_size - / 2); + qemu_coroutine_dec_pool_size(conf->num_queues * conf->queue_size / 2); qemu_del_vm_change_state_handler(s->change); blockdev_mark_auto_del(s->blk); virtio_cleanup(vdev); diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index 284571badb..031cf23711 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -334,12 +334,12 @@ void coroutine_fn yield_until_fd_readable(int fd); /** * Increase coroutine pool size */ -void qemu_coroutine_increase_pool_batch_size(unsigned int additional_pool_size); +void qemu_coroutine_inc_pool_size(unsigned int additional_pool_size); /** - * Devcrease coroutine pool size + * Decrease coroutine pool size */ -void qemu_coroutine_decrease_pool_batch_size(unsigned int additional_pool_size); +void qemu_coroutine_dec_pool_size(unsigned int additional_pool_size); #include "qemu/lockable.h" diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c index f3e8300c8d..ea23929a74 100644 --- a/util/qemu-coroutine.c +++ b/util/qemu-coroutine.c @@ -212,12 +212,12 @@ AioContext *coroutine_fn qemu_coroutine_get_aio_context(Coroutine *co) return co->ctx; } -void qemu_coroutine_increase_pool_batch_size(unsigned int additional_pool_size) +void qemu_coroutine_inc_pool_size(unsigned int additional_pool_size) { qatomic_add(&pool_batch_size, additional_pool_size); } -void qemu_coroutine_decrease_pool_batch_size(unsigned int removing_pool_size) +void qemu_coroutine_dec_pool_size(unsigned int removing_pool_size) { qatomic_sub(&pool_batch_size, removing_pool_size); } From 9ec7a59b5aad4b736871c378d30f5ef5ec51cb52 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 10 May 2022 17:10:20 +0200 Subject: [PATCH 242/935] coroutine: Revert to constant batch size Commit 4c41c69e changed the way the coroutine pool is sized because for virtio-blk devices with a large queue size and heavy I/O, it was just too small and caused coroutines to be deleted and reallocated soon afterwards. The change made the size dynamic based on the number of queues and the queue size of virtio-blk devices. There are two important numbers here: Slightly simplified, when a coroutine terminates, it is generally stored in the global release pool up to a certain pool size, and if the pool is full, it is freed. Conversely, when allocating a new coroutine, the coroutines in the release pool are reused if the pool already has reached a certain minimum size (the batch size), otherwise we allocate new coroutines. The problem after commit 4c41c69e is that it not only increases the maximum pool size (which is the intended effect), but also the batch size for reusing coroutines (which is a bug). It means that in cases with many devices and/or a large queue size (which defaults to the number of vcpus for virtio-blk-pci), many thousand coroutines could be sitting in the release pool without being reused. This is not only a waste of memory and allocations, but it actually makes the QEMU process likely to hit the vm.max_map_count limit on Linux because each coroutine requires two mappings (its stack and the guard page for the stack), causing it to abort() in qemu_alloc_stack() because when the limit is hit, mprotect() starts to fail with ENOMEM. In order to fix the problem, change the batch size back to 64 to avoid uselessly accumulating coroutines in the release pool, but keep the dynamic maximum pool size so that coroutines aren't freed too early in heavy I/O scenarios. Note that this fix doesn't strictly make it impossible to hit the limit, but this would only happen if most of the coroutines are actually in use at the same time, not just sitting in a pool. This is the same behaviour as we already had before commit 4c41c69e. Fully preventing this would require allowing qemu_coroutine_create() to return an error, but it doesn't seem to be a scenario that people hit in practice. Cc: qemu-stable@nongnu.org Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2079938 Fixes: 4c41c69e05fe28c0f95f8abd2ebf407e95a4f04b Signed-off-by: Kevin Wolf Message-Id: <20220510151020.105528-3-kwolf@redhat.com> Tested-by: Hiroki Narukawa Signed-off-by: Kevin Wolf --- util/qemu-coroutine.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c index ea23929a74..4a8bd63ef0 100644 --- a/util/qemu-coroutine.c +++ b/util/qemu-coroutine.c @@ -21,14 +21,20 @@ #include "qemu/coroutine-tls.h" #include "block/aio.h" -/** Initial batch size is 64, and is increased on demand */ +/** + * The minimal batch size is always 64, coroutines from the release_pool are + * reused as soon as there are 64 coroutines in it. The maximum pool size starts + * with 64 and is increased on demand so that coroutines are not deleted even if + * they are not immediately reused. + */ enum { - POOL_INITIAL_BATCH_SIZE = 64, + POOL_MIN_BATCH_SIZE = 64, + POOL_INITIAL_MAX_SIZE = 64, }; /** Free list to speed up creation */ static QSLIST_HEAD(, Coroutine) release_pool = QSLIST_HEAD_INITIALIZER(pool); -static unsigned int pool_batch_size = POOL_INITIAL_BATCH_SIZE; +static unsigned int pool_max_size = POOL_INITIAL_MAX_SIZE; static unsigned int release_pool_size; typedef QSLIST_HEAD(, Coroutine) CoroutineQSList; @@ -57,7 +63,7 @@ Coroutine *qemu_coroutine_create(CoroutineEntry *entry, void *opaque) co = QSLIST_FIRST(alloc_pool); if (!co) { - if (release_pool_size > qatomic_read(&pool_batch_size)) { + if (release_pool_size > POOL_MIN_BATCH_SIZE) { /* Slow path; a good place to register the destructor, too. */ Notifier *notifier = get_ptr_coroutine_pool_cleanup_notifier(); if (!notifier->notify) { @@ -95,12 +101,12 @@ static void coroutine_delete(Coroutine *co) co->caller = NULL; if (CONFIG_COROUTINE_POOL) { - if (release_pool_size < qatomic_read(&pool_batch_size) * 2) { + if (release_pool_size < qatomic_read(&pool_max_size) * 2) { QSLIST_INSERT_HEAD_ATOMIC(&release_pool, co, pool_next); qatomic_inc(&release_pool_size); return; } - if (get_alloc_pool_size() < qatomic_read(&pool_batch_size)) { + if (get_alloc_pool_size() < qatomic_read(&pool_max_size)) { QSLIST_INSERT_HEAD(get_ptr_alloc_pool(), co, pool_next); set_alloc_pool_size(get_alloc_pool_size() + 1); return; @@ -214,10 +220,10 @@ AioContext *coroutine_fn qemu_coroutine_get_aio_context(Coroutine *co) void qemu_coroutine_inc_pool_size(unsigned int additional_pool_size) { - qatomic_add(&pool_batch_size, additional_pool_size); + qatomic_add(&pool_max_size, additional_pool_size); } void qemu_coroutine_dec_pool_size(unsigned int removing_pool_size) { - qatomic_sub(&pool_batch_size, removing_pool_size); + qatomic_sub(&pool_max_size, removing_pool_size); } From 22d92e71c77c8690995315c9ef5a1136c6300047 Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Fri, 6 May 2022 15:42:15 +0200 Subject: [PATCH 243/935] iotests/testrunner: Flush after run_test() When stdout is not a terminal, the buffer may not be flushed at each end of line, so we should flush after each test is done. This is especially apparent when run by check-block, in two ways: First, when running make check-block -jX with X > 1, progress indication was missing, even though testrunner.py does theoretically print each test's status once it has been run, even in multi-processing mode. Flushing after each test restores this progress indication. Second, sometimes make check-block failed altogether, with an error message that "too few tests [were] run". I presume that's because one worker process in the job pool did not get to flush its stdout before the main process exited, and so meson did not get to see that worker's test results. In any case, by flushing at the end of run_test(), the problem has disappeared for me. Signed-off-by: Hanna Reitz Message-Id: <20220506134215.10086-1-hreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- tests/qemu-iotests/testrunner.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py index aae70a8341..10d9e8ef27 100644 --- a/tests/qemu-iotests/testrunner.py +++ b/tests/qemu-iotests/testrunner.py @@ -378,6 +378,7 @@ class TestRunner(ContextManager['TestRunner']): else: print(res.casenotrun) + sys.stdout.flush() return res def run_tests(self, tests: List[str], jobs: int = 1) -> bool: From 5e781c700a6ebf089cb01eb4f612479bfcfe186d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Mon, 9 May 2022 13:41:33 +0100 Subject: [PATCH 244/935] tests/qemu-iotests: print intent to run a test in TAP mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When running I/O tests using TAP output mode, we get a single TAP test with a sub-test reported for each I/O test that is run. The output looks something like this: 1..123 ok qcow2 011 ok qcow2 012 ok qcow2 013 ok qcow2 217 ... If everything runs or fails normally this is fine, but periodically we have been seeing the test harness abort early before all 123 tests have been run, just leaving a fairly useless message like TAP parsing error: Too few tests run (expected 123, got 107) we have no idea which tests were running at the time the test harness abruptly exited. This change causes us to print a message about our intent to run each test, so we have a record of what is active at the time the harness exits abnormally. 1..123 # running qcow2 011 ok qcow2 011 # running qcow2 012 ok qcow2 012 # running qcow2 013 ok qcow2 013 # running qcow2 217 ok qcow2 217 ... Signed-off-by: Daniel P. Berrangé Message-Id: <20220509124134.867431-2-berrange@redhat.com> Reviewed-by: Thomas Huth Signed-off-by: Kevin Wolf --- tests/qemu-iotests/testrunner.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py index 10d9e8ef27..5a771da86e 100644 --- a/tests/qemu-iotests/testrunner.py +++ b/tests/qemu-iotests/testrunner.py @@ -361,6 +361,9 @@ class TestRunner(ContextManager['TestRunner']): starttime=start, lasttime=last_el, end = '\n' if mp else '\r') + else: + testname = os.path.basename(test) + print(f'# running {self.env.imgfmt} {testname}') res = self.do_run_test(test, mp) From 29a493765ecd63e2b8c1593c777877ee1f8f1cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Mon, 9 May 2022 13:41:34 +0100 Subject: [PATCH 245/935] .gitlab-ci.d: export meson testlog.txt as an artifact MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When running 'make check' we only get a summary of progress on the console. Fortunately meson/ninja have saved the raw test output to a logfile. Exposing this log will make it easier to debug failures that happen in CI. Signed-off-by: Daniel P. Berrangé Message-Id: <20220509124134.867431-3-berrange@redhat.com> Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Kevin Wolf --- .gitlab-ci.d/buildtest-template.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.d/buildtest-template.yml b/.gitlab-ci.d/buildtest-template.yml index 2c7980a4f6..dc6d67aacf 100644 --- a/.gitlab-ci.d/buildtest-template.yml +++ b/.gitlab-ci.d/buildtest-template.yml @@ -26,7 +26,7 @@ make -j"$JOBS" $MAKE_CHECK_ARGS ; fi -.native_test_job_template: +.common_test_job_template: stage: test image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest script: @@ -37,8 +37,16 @@ # Avoid recompiling by hiding ninja with NINJA=":" - make NINJA=":" $MAKE_CHECK_ARGS +.native_test_job_template: + extends: .common_test_job_template + artifacts: + name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG" + expire_in: 7 days + paths: + - build/meson-logs/testlog.txt + .avocado_test_job_template: - extends: .native_test_job_template + extends: .common_test_job_template cache: key: "${CI_JOB_NAME}-cache" paths: From 97ec4d21e09b5e4a59f00c471a7f76533b08ce56 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 14 Apr 2022 12:52:56 -0400 Subject: [PATCH 246/935] machine: use QAPI struct for boot configuration As part of converting -boot to a property with a QAPI type, define the struct and use it throughout QEMU to access boot configuration. machine_boot_parse takes care of doing the QemuOpts->QAPI conversion by hand, for now. Signed-off-by: Paolo Bonzini Message-Id: <20220414165300.555321-2-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- hw/arm/nseries.c | 2 +- hw/core/machine.c | 68 +++++++++++++++++++++++++++++++++++++++-- hw/hppa/machine.c | 6 ++-- hw/i386/pc.c | 2 +- hw/nvram/fw_cfg.c | 27 +++++----------- hw/ppc/mac_newworld.c | 2 +- hw/ppc/mac_oldworld.c | 2 +- hw/ppc/prep.c | 2 +- hw/ppc/spapr.c | 4 +-- hw/s390x/ipl.c | 20 ++++-------- hw/sparc/sun4m.c | 4 +-- hw/sparc64/sun4u.c | 4 +-- include/hw/boards.h | 4 +-- include/sysemu/sysemu.h | 2 -- qapi/machine.json | 30 ++++++++++++++++++ softmmu/bootdevice.c | 3 +- softmmu/globals.c | 2 -- softmmu/vl.c | 25 +-------------- 18 files changed, 127 insertions(+), 82 deletions(-) diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c index 9c1cafae86..692c94ceb4 100644 --- a/hw/arm/nseries.c +++ b/hw/arm/nseries.c @@ -1365,7 +1365,7 @@ static void n8x0_init(MachineState *machine, } if (option_rom[0].name && - (machine->boot_order[0] == 'n' || !machine->kernel_filename)) { + (machine->boot_config.order[0] == 'n' || !machine->kernel_filename)) { uint8_t *nolo_tags = g_new(uint8_t, 0x10000); /* No, wait, better start at the ROM. */ s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000; diff --git a/hw/core/machine.c b/hw/core/machine.c index 700c1e76b8..b3deb8146f 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -784,6 +784,68 @@ static void machine_set_smp(Object *obj, Visitor *v, const char *name, machine_parse_smp_config(ms, config, errp); } +void machine_boot_parse(MachineState *ms, QemuOpts *opts, Error **errp) +{ + MachineClass *machine_class = MACHINE_GET_CLASS(ms); + const char *s; + ERRP_GUARD(); + + ms->boot_config = (BootConfiguration) { + .has_order = true, + .order = (char *)machine_class->default_boot_order, + .has_strict = true, + .strict = false, + }; + if (!opts) { + return; + } + + s = qemu_opt_get(opts, "order"); + if (s) { + validate_bootdevices(s, errp); + if (*errp) { + return; + } + ms->boot_config.order = (char *)s; + } + + s = qemu_opt_get(opts, "once"); + if (s) { + validate_bootdevices(s, errp); + if (*errp) { + return; + } + ms->boot_config.has_once = true; + ms->boot_config.once = (char *)s; + } + + s = qemu_opt_get(opts, "splash"); + if (s) { + ms->boot_config.has_splash = true; + ms->boot_config.splash = (char *)s; + } + + s = qemu_opt_get(opts, "splash-time"); + if (s) { + ms->boot_config.has_splash_time = true; + ms->boot_config.splash_time = qemu_opt_get_number(opts, "splash-time", -1); + } + + s = qemu_opt_get(opts, "reboot-timeout"); + if (s) { + ms->boot_config.has_reboot_timeout = true; + ms->boot_config.reboot_timeout = qemu_opt_get_number(opts, "reboot-timeout", -1); + } + + s = qemu_opt_get(opts, "menu"); + if (s) { + ms->boot_config.has_menu = true; + ms->boot_config.menu = qemu_opt_get_bool(opts, "menu", false); + } + + ms->boot_config.strict = qemu_opt_get_bool(opts, "strict", false); +} + static void machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -1229,9 +1291,9 @@ void qdev_machine_creation_done(void) { cpu_synchronize_all_post_init(); - if (current_machine->boot_once) { - qemu_boot_set(current_machine->boot_once, &error_fatal); - qemu_register_reset(restore_boot_order, g_strdup(current_machine->boot_order)); + if (current_machine->boot_config.has_once) { + qemu_boot_set(current_machine->boot_config.once, &error_fatal); + qemu_register_reset(restore_boot_order, g_strdup(current_machine->boot_config.order)); } /* diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 4d054ca869..d1e174b1f4 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -147,7 +147,7 @@ static FWCfgState *create_fw_cfg(MachineState *ms) fw_cfg_add_file(fw_cfg, "/etc/power-button-addr", g_memdup(&val, sizeof(val)), sizeof(val)); - fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, ms->boot_order[0]); + fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, ms->boot_config.order[0]); qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); return fw_cfg; @@ -391,8 +391,8 @@ static void machine_hppa_init(MachineState *machine) * mode (kernel_entry=1), and to boot from CD (gr[24]='d') * or hard disc * (gr[24]='c'). */ - kernel_entry = boot_menu ? 1 : 0; - cpu[0]->env.gr[24] = machine->boot_order[0]; + kernel_entry = machine->boot_config.has_menu ? machine->boot_config.menu : 0; + cpu[0]->env.gr[24] = machine->boot_config.order[0]; } /* We jump to the firmware entry routine and pass the diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 23bba9d82c..305d2c0820 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -675,7 +675,7 @@ void pc_cmos_init(PCMachineState *pcms, object_property_set_link(OBJECT(pcms), "rtc_state", OBJECT(s), &error_abort); - set_boot_dev(s, MACHINE(pcms)->boot_order, &error_fatal); + set_boot_dev(s, MACHINE(pcms)->boot_config.order, &error_fatal); val = 0; val |= 0x02; /* FPU is there */ diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 4125cbebcd..d605f3f45a 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -178,21 +178,13 @@ error: static void fw_cfg_bootsplash(FWCfgState *s) { - const char *boot_splash_filename = NULL; - const char *boot_splash_time = NULL; char *filename, *file_data; gsize file_size; int file_type; - /* get user configuration */ - QemuOptsList *plist = qemu_find_opts("boot-opts"); - QemuOpts *opts = QTAILQ_FIRST(&plist->head); - boot_splash_filename = qemu_opt_get(opts, "splash"); - boot_splash_time = qemu_opt_get(opts, "splash-time"); - /* insert splash time if user configurated */ - if (boot_splash_time) { - int64_t bst_val = qemu_opt_get_number(opts, "splash-time", -1); + if (current_machine->boot_config.has_splash_time) { + int64_t bst_val = current_machine->boot_config.splash_time; uint16_t bst_le16; /* validate the input */ @@ -208,7 +200,8 @@ static void fw_cfg_bootsplash(FWCfgState *s) } /* insert splash file if user configurated */ - if (boot_splash_filename) { + if (current_machine->boot_config.has_splash) { + const char *boot_splash_filename = current_machine->boot_config.splash; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, boot_splash_filename); if (filename == NULL) { error_report("failed to find file '%s'", boot_splash_filename); @@ -238,17 +231,11 @@ static void fw_cfg_bootsplash(FWCfgState *s) static void fw_cfg_reboot(FWCfgState *s) { - const char *reboot_timeout = NULL; uint64_t rt_val = -1; uint32_t rt_le32; - /* get user configuration */ - QemuOptsList *plist = qemu_find_opts("boot-opts"); - QemuOpts *opts = QTAILQ_FIRST(&plist->head); - reboot_timeout = qemu_opt_get(opts, "reboot-timeout"); - - if (reboot_timeout) { - rt_val = qemu_opt_get_number(opts, "reboot-timeout", -1); + if (current_machine->boot_config.has_reboot_timeout) { + rt_val = current_machine->boot_config.reboot_timeout; /* validate the input */ if (rt_val > 0xffff && rt_val != (uint64_t)-1) { @@ -1133,7 +1120,7 @@ static void fw_cfg_common_realize(DeviceState *dev, Error **errp) fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4); fw_cfg_add_bytes(s, FW_CFG_UUID, &qemu_uuid, 16); fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)!machine->enable_graphics); - fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu); + fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)(machine->boot_config.has_menu && machine->boot_config.menu)); fw_cfg_bootsplash(s); fw_cfg_reboot(s); diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index e8ef1a9e5d..c865921bdc 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -111,7 +111,7 @@ static void ppc_core99_init(MachineState *machine) const char *kernel_filename = machine->kernel_filename; const char *kernel_cmdline = machine->kernel_cmdline; const char *initrd_filename = machine->initrd_filename; - const char *boot_device = machine->boot_order; + const char *boot_device = machine->boot_config.order; Core99MachineState *core99_machine = CORE99_MACHINE(machine); PowerPCCPU *cpu = NULL; CPUPPCState *env = NULL; diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index fe2adb057b..d62fdf0db3 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -82,7 +82,7 @@ static void ppc_heathrow_init(MachineState *machine) { ram_addr_t ram_size = machine->ram_size; const char *bios_name = machine->firmware ?: PROM_FILENAME; - const char *boot_device = machine->boot_order; + const char *boot_device = machine->boot_config.order; PowerPCCPU *cpu = NULL; CPUPPCState *env = NULL; char *filename; diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index bf622aa38f..a1cd4505cc 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -381,7 +381,7 @@ static void ibm_40p_init(MachineState *machine) } boot_device = 'm'; } else { - boot_device = machine->boot_order[0]; + boot_device = machine->boot_config.order[0]; } fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)machine->smp.max_cpus); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 8bbae68e1b..6de800524a 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1044,8 +1044,8 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset) _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel-le", NULL, 0)); } } - if (boot_menu) { - _FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", boot_menu))); + if (machine->boot_config.has_menu && machine->boot_config.menu) { + _FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", true))); } _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-width", graphic_width)); _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-height", graphic_height)); diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index 4b5eb77afd..8612684d48 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -290,13 +290,10 @@ static Property s390_ipl_properties[] = { static void s390_ipl_set_boot_menu(S390IPLState *ipl) { - QemuOptsList *plist = qemu_find_opts("boot-opts"); - QemuOpts *opts = QTAILQ_FIRST(&plist->head); - const char *tmp; unsigned long splash_time = 0; if (!get_boot_device(0)) { - if (boot_menu) { + if (current_machine->boot_config.has_menu && current_machine->boot_config.menu) { error_report("boot menu requires a bootindex to be specified for " "the IPL device"); } @@ -306,7 +303,7 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl) switch (ipl->iplb.pbt) { case S390_IPL_TYPE_CCW: /* In the absence of -boot menu, use zipl parameters */ - if (!qemu_opt_get(opts, "menu")) { + if (!current_machine->boot_config.has_menu) { ipl->qipl.qipl_flags |= QIPL_FLAG_BM_OPTS_ZIPL; return; } @@ -314,26 +311,21 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl) case S390_IPL_TYPE_QEMU_SCSI: break; default: - if (boot_menu) { + if (current_machine->boot_config.has_menu && current_machine->boot_config.menu) { error_report("boot menu is not supported for this device type"); } return; } - if (!boot_menu) { + if (!current_machine->boot_config.has_menu || !current_machine->boot_config.menu) { return; } ipl->qipl.qipl_flags |= QIPL_FLAG_BM_OPTS_CMD; - tmp = qemu_opt_get(opts, "splash-time"); - - if (tmp && qemu_strtoul(tmp, NULL, 10, &splash_time)) { - error_report("splash-time is invalid, forcing it to 0"); - ipl->qipl.boot_menu_timeout = 0; - return; + if (current_machine->boot_config.has_splash_time) { + splash_time = current_machine->boot_config.splash_time; } - if (splash_time > 0xffffffff) { error_report("splash-time is too large, forcing it to max value"); ipl->qipl.boot_menu_timeout = 0xffffffff; diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index b693eea0e0..9d57491f68 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -1050,7 +1050,7 @@ static void sun4m_hw_init(MachineState *machine) machine->ram_size, &initrd_size); nvram_init(nvram, (uint8_t *)&nd->macaddr, machine->kernel_cmdline, - machine->boot_order, machine->ram_size, kernel_size, + machine->boot_config.order, machine->ram_size, kernel_size, graphic_width, graphic_height, graphic_depth, hwdef->nvram_machine_id, "Sun4m"); @@ -1091,7 +1091,7 @@ static void sun4m_hw_init(MachineState *machine) } fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR); fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); - fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, machine->boot_order[0]); + fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, machine->boot_config.order[0]); qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); } diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 7c461d194a..d1bc77d27e 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -695,7 +695,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, &kernel_addr, &kernel_entry); sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", machine->ram_size, - machine->boot_order, + machine->boot_config.order, kernel_addr, kernel_size, machine->kernel_cmdline, initrd_addr, initrd_size, @@ -727,7 +727,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, } fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr); fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); - fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, machine->boot_order[0]); + fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, machine->boot_config.order[0]); fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH, graphic_width); fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_HEIGHT, graphic_height); diff --git a/include/hw/boards.h b/include/hw/boards.h index d64b5481e8..6cda7e4308 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -26,6 +26,7 @@ OBJECT_DECLARE_TYPE(MachineState, MachineClass, MACHINE) extern MachineState *current_machine; void machine_run_board_init(MachineState *machine); +void machine_boot_parse(MachineState *ms, QemuOpts *opts, Error **errp); bool machine_usb(MachineState *machine); int machine_phandle_start(MachineState *machine); bool machine_dump_guest_core(MachineState *machine); @@ -350,8 +351,7 @@ struct MachineState { ram_addr_t ram_size; ram_addr_t maxram_size; uint64_t ram_slots; - const char *boot_order; - const char *boot_once; + BootConfiguration boot_config; char *kernel_filename; char *kernel_cmdline; char *initrd_filename; diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 360a408edf..b4030acd74 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -46,8 +46,6 @@ extern int alt_grab; extern int ctrl_grab; extern int graphic_rotate; extern int old_param; -extern int boot_menu; -extern bool boot_strict; extern uint8_t *boot_splash_filedata; extern bool enable_mlock; extern bool enable_cpu_pm; diff --git a/qapi/machine.json b/qapi/machine.json index 4c417e32a5..e3dcf5a119 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -1395,6 +1395,36 @@ 'data': { 'device': 'str', 'msg': 'str' }, 'features': ['deprecated'] } +## +# @BootConfiguration: +# +# Schema for virtual machine boot configuration. +# +# @order: Boot order (a=floppy, c=hard disk, d=CD-ROM, n=network) +# +# @once: Boot order to apply on first boot +# +# @menu: Whether to show a boot menu +# +# @splash: The name of the file to be passed to the firmware as logo picture, if @menu is true. +# +# @splash-time: How long to show the logo picture, in milliseconds +# +# @reboot-timeout: Timeout before guest reboots after boot fails +# +# @strict: Whether to attempt booting from devices not included in the boot order +# +# Since: 7.1 +## +{ 'struct': 'BootConfiguration', 'data': { + '*order': 'str', + '*once': 'str', + '*menu': 'bool', + '*splash': 'str', + '*splash-time': 'int', + '*reboot-timeout': 'int', + '*strict': 'bool' } } + ## # @SMPConfiguration: # diff --git a/softmmu/bootdevice.c b/softmmu/bootdevice.c index c0713bfa9f..2106f1026f 100644 --- a/softmmu/bootdevice.c +++ b/softmmu/bootdevice.c @@ -268,7 +268,8 @@ char *get_boot_devices_list(size_t *size) *size = total; - if (boot_strict && *size > 0) { + if (current_machine->boot_config.has_strict && + current_machine->boot_config.strict && *size > 0) { list[total-1] = '\n'; list = g_realloc(list, total + 5); memcpy(&list[total], "HALT", 5); diff --git a/softmmu/globals.c b/softmmu/globals.c index 98b64e0492..916bc12e2b 100644 --- a/softmmu/globals.c +++ b/softmmu/globals.c @@ -54,8 +54,6 @@ int alt_grab; int ctrl_grab; unsigned int nb_prom_envs; const char *prom_envs[MAX_PROM_ENVS]; -int boot_menu; -bool boot_strict; uint8_t *boot_splash_filedata; int only_migratable; /* turn it off unless user states otherwise */ int icount_align_option; diff --git a/softmmu/vl.c b/softmmu/vl.c index 488cc4d09e..dd90df3ed1 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -1884,9 +1884,6 @@ static bool object_create_early(const char *type) static void qemu_apply_machine_options(QDict *qdict) { - MachineClass *machine_class = MACHINE_GET_CLASS(current_machine); - const char *boot_order = NULL; - const char *boot_once = NULL; QemuOpts *opts; object_set_properties_from_keyval(OBJECT(current_machine), qdict, false, &error_fatal); @@ -1895,27 +1892,7 @@ static void qemu_apply_machine_options(QDict *qdict) current_machine->ram_slots = ram_slots; opts = qemu_opts_find(qemu_find_opts("boot-opts"), NULL); - if (opts) { - boot_order = qemu_opt_get(opts, "order"); - if (boot_order) { - validate_bootdevices(boot_order, &error_fatal); - } - - boot_once = qemu_opt_get(opts, "once"); - if (boot_once) { - validate_bootdevices(boot_once, &error_fatal); - } - - boot_menu = qemu_opt_get_bool(opts, "menu", boot_menu); - boot_strict = qemu_opt_get_bool(opts, "strict", false); - } - - if (!boot_order) { - boot_order = machine_class->default_boot_order; - } - - current_machine->boot_order = boot_order; - current_machine->boot_once = boot_once; + machine_boot_parse(current_machine, opts, &error_fatal); if (semihosting_enabled() && !semihosting_get_argc()) { /* fall back to the -kernel/-append */ From 8c4da4b52186e9d0c7233b0ffc796e78fdf3e7b3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 14 Apr 2022 12:52:57 -0400 Subject: [PATCH 247/935] machine: add boot compound property Make -boot syntactic sugar for a compound property "-machine boot.{order,menu,...}". machine_boot_parse is replaced by the setter for the property. Signed-off-by: Paolo Bonzini Message-Id: <20220414165300.555321-3-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- hw/core/machine.c | 100 +++++++++++++++++++++++--------------------- include/hw/boards.h | 1 - softmmu/vl.c | 16 +++---- 3 files changed, 58 insertions(+), 59 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index b3deb8146f..8cea94537d 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -784,66 +784,63 @@ static void machine_set_smp(Object *obj, Visitor *v, const char *name, machine_parse_smp_config(ms, config, errp); } -void machine_boot_parse(MachineState *ms, QemuOpts *opts, Error **errp) +static void machine_get_boot(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + MachineState *ms = MACHINE(obj); + BootConfiguration *config = &ms->boot_config; + visit_type_BootConfiguration(v, name, &config, &error_abort); +} + +static void machine_free_boot_config(MachineState *ms) +{ + g_free(ms->boot_config.order); + g_free(ms->boot_config.once); + g_free(ms->boot_config.splash); +} + +static void machine_copy_boot_config(MachineState *ms, BootConfiguration *config) { MachineClass *machine_class = MACHINE_GET_CLASS(ms); - const char *s; - ERRP_GUARD(); - ms->boot_config = (BootConfiguration) { - .has_order = true, - .order = (char *)machine_class->default_boot_order, - .has_strict = true, - .strict = false, - }; - if (!opts) { + machine_free_boot_config(ms); + ms->boot_config = *config; + if (!config->has_order) { + ms->boot_config.has_order = true; + ms->boot_config.order = g_strdup(machine_class->default_boot_order); + } +} + +static void machine_set_boot(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + ERRP_GUARD(); + MachineState *ms = MACHINE(obj); + BootConfiguration *config = NULL; + + if (!visit_type_BootConfiguration(v, name, &config, errp)) { return; } - - s = qemu_opt_get(opts, "order"); - if (s) { - validate_bootdevices(s, errp); + if (config->has_order) { + validate_bootdevices(config->order, errp); if (*errp) { - return; + goto out_free; } - ms->boot_config.order = (char *)s; } - - s = qemu_opt_get(opts, "once"); - if (s) { - validate_bootdevices(s, errp); + if (config->has_once) { + validate_bootdevices(config->once, errp); if (*errp) { - return; + goto out_free; } - ms->boot_config.has_once = true; - ms->boot_config.once = (char *)s; } - s = qemu_opt_get(opts, "splash"); - if (s) { - ms->boot_config.has_splash = true; - ms->boot_config.splash = (char *)s; - } + machine_copy_boot_config(ms, config); + /* Strings live in ms->boot_config. */ + free(config); + return; - s = qemu_opt_get(opts, "splash-time"); - if (s) { - ms->boot_config.has_splash_time = true; - ms->boot_config.splash_time = qemu_opt_get_number(opts, "splash-time", -1); - } - - s = qemu_opt_get(opts, "reboot-timeout"); - if (s) { - ms->boot_config.has_reboot_timeout = true; - ms->boot_config.reboot_timeout = qemu_opt_get_number(opts, "reboot-timeout", -1); - } - - s = qemu_opt_get(opts, "menu"); - if (s) { - ms->boot_config.has_menu = true; - ms->boot_config.menu = qemu_opt_get_bool(opts, "menu", false); - } - - ms->boot_config.strict = qemu_opt_get_bool(opts, "strict", false); +out_free: + qapi_free_BootConfiguration(config); } static void machine_class_init(ObjectClass *oc, void *data) @@ -884,6 +881,12 @@ static void machine_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, "dumpdtb", "Dump current dtb to a file and quit"); + object_class_property_add(oc, "boot", "BootConfiguration", + machine_get_boot, machine_set_boot, + NULL, NULL); + object_class_property_set_description(oc, "boot", + "Boot configuration"); + object_class_property_add(oc, "smp", "SMPConfiguration", machine_get_smp, machine_set_smp, NULL, NULL); @@ -1017,12 +1020,15 @@ static void machine_initfn(Object *obj) ms->smp.clusters = 1; ms->smp.cores = 1; ms->smp.threads = 1; + + machine_copy_boot_config(ms, &(BootConfiguration){ 0 }); } static void machine_finalize(Object *obj) { MachineState *ms = MACHINE(obj); + machine_free_boot_config(ms); g_free(ms->kernel_filename); g_free(ms->initrd_filename); g_free(ms->kernel_cmdline); diff --git a/include/hw/boards.h b/include/hw/boards.h index 6cda7e4308..910c3ffde2 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -26,7 +26,6 @@ OBJECT_DECLARE_TYPE(MachineState, MachineClass, MACHINE) extern MachineState *current_machine; void machine_run_board_init(MachineState *machine); -void machine_boot_parse(MachineState *ms, QemuOpts *opts, Error **errp); bool machine_usb(MachineState *machine); int machine_phandle_start(MachineState *machine); bool machine_dump_guest_core(MachineState *machine); diff --git a/softmmu/vl.c b/softmmu/vl.c index dd90df3ed1..13ae31e92f 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -1884,16 +1884,11 @@ static bool object_create_early(const char *type) static void qemu_apply_machine_options(QDict *qdict) { - QemuOpts *opts; - object_set_properties_from_keyval(OBJECT(current_machine), qdict, false, &error_fatal); current_machine->ram_size = ram_size; current_machine->maxram_size = maxram_size; current_machine->ram_slots = ram_slots; - opts = qemu_opts_find(qemu_find_opts("boot-opts"), NULL); - machine_boot_parse(current_machine, opts, &error_fatal); - if (semihosting_enabled() && !semihosting_get_argc()) { /* fall back to the -kernel/-append */ semihosting_arg_fallback(current_machine->kernel_filename, current_machine->kernel_cmdline); @@ -2189,7 +2184,8 @@ static bool is_qemuopts_group(const char *group) { if (g_str_equal(group, "object") || g_str_equal(group, "machine") || - g_str_equal(group, "smp-opts")) { + g_str_equal(group, "smp-opts") || + g_str_equal(group, "boot-opts")) { return false; } return true; @@ -2211,6 +2207,8 @@ static void qemu_record_config_group(const char *group, QDict *dict, keyval_merge(machine_opts_dict, dict, errp); } else if (g_str_equal(group, "smp-opts")) { machine_merge_property("smp", dict, &error_fatal); + } else if (g_str_equal(group, "boot-opts")) { + machine_merge_property("boot", dict, &error_fatal); } else { abort(); } @@ -2956,11 +2954,7 @@ void qemu_init(int argc, char **argv, char **envp) drive_add(IF_DEFAULT, 2, optarg, CDROM_OPTS); break; case QEMU_OPTION_boot: - opts = qemu_opts_parse_noisily(qemu_find_opts("boot-opts"), - optarg, true); - if (!opts) { - exit(1); - } + machine_parse_property_opt(qemu_find_opts("boot-opts"), "boot", optarg); break; case QEMU_OPTION_fda: case QEMU_OPTION_fdb: From ce9d03fb3f7a87f46a1a2fc3597f2f44541a0c9c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 14 Apr 2022 12:52:58 -0400 Subject: [PATCH 248/935] machine: add mem compound property Make -m syntactic sugar for a compound property "-machine mem.{size,max-size,slots}". The new property does not have the magic conversion to megabytes of unsuffixed arguments, and also does not understand that "0" means the default size (you have to leave it out to get the default). This means that we need to convert the QemuOpts by hand to a QDict. Signed-off-by: Paolo Bonzini Message-Id: <20220414165300.555321-4-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- hw/core/machine.c | 80 ++++++++++++++++++++++++++++++ qapi/machine.json | 18 +++++++ softmmu/vl.c | 123 +++++++++++++++------------------------------- 3 files changed, 138 insertions(+), 83 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index 8cea94537d..46b8d0effa 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -523,6 +523,78 @@ static void machine_set_hmat(Object *obj, bool value, Error **errp) ms->numa_state->hmat_enabled = value; } +static void machine_get_mem(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + MachineState *ms = MACHINE(obj); + MemorySizeConfiguration mem = { + .has_size = true, + .size = ms->ram_size, + .has_max_size = !!ms->ram_slots, + .max_size = ms->maxram_size, + .has_slots = !!ms->ram_slots, + .slots = ms->ram_slots, + }; + MemorySizeConfiguration *p_mem = &mem; + + visit_type_MemorySizeConfiguration(v, name, &p_mem, &error_abort); +} + +static void machine_set_mem(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + MachineState *ms = MACHINE(obj); + MachineClass *mc = MACHINE_GET_CLASS(obj); + MemorySizeConfiguration *mem; + + ERRP_GUARD(); + + if (!visit_type_MemorySizeConfiguration(v, name, &mem, errp)) { + return; + } + + if (!mem->has_size) { + mem->has_size = true; + mem->size = mc->default_ram_size; + } + mem->size = QEMU_ALIGN_UP(mem->size, 8192); + if (mc->fixup_ram_size) { + mem->size = mc->fixup_ram_size(mem->size); + } + if ((ram_addr_t)mem->size != mem->size) { + error_setg(errp, "ram size too large"); + goto out_free; + } + + if (mem->has_max_size) { + if (mem->max_size < mem->size) { + error_setg(errp, "invalid value of maxmem: " + "maximum memory size (0x%" PRIx64 ") must be at least " + "the initial memory size (0x%" PRIx64 ")", + mem->max_size, mem->size); + goto out_free; + } + if (mem->has_slots && mem->slots && mem->max_size == mem->size) { + error_setg(errp, "invalid value of maxmem: " + "memory slots were specified but maximum memory size " + "(0x%" PRIx64 ") is equal to the initial memory size " + "(0x%" PRIx64 ")", mem->max_size, mem->size); + goto out_free; + } + ms->maxram_size = mem->max_size; + } else { + if (mem->has_slots) { + error_setg(errp, "slots specified but no max-size"); + goto out_free; + } + ms->maxram_size = mem->size; + } + ms->ram_size = mem->size; + ms->ram_slots = mem->has_slots ? mem->slots : 0; +out_free: + qapi_free_MemorySizeConfiguration(mem); +} + static char *machine_get_nvdimm_persistence(Object *obj, Error **errp) { MachineState *ms = MACHINE(obj); @@ -953,6 +1025,12 @@ static void machine_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, "memory-backend", "Set RAM backend" "Valid value is ID of hostmem based backend"); + + object_class_property_add(oc, "memory", "MemorySizeConfiguration", + machine_get_mem, machine_set_mem, + NULL, NULL); + object_class_property_set_description(oc, "memory", + "Memory size configuration"); } static void machine_class_base_init(ObjectClass *oc, void *data) @@ -983,6 +1061,8 @@ static void machine_initfn(Object *obj) ms->mem_merge = true; ms->enable_graphics = true; ms->kernel_cmdline = g_strdup(""); + ms->ram_size = mc->default_ram_size; + ms->maxram_size = mc->default_ram_size; if (mc->nvdimm_supported) { Object *obj = OBJECT(ms); diff --git a/qapi/machine.json b/qapi/machine.json index e3dcf5a119..92480d4044 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -1614,3 +1614,21 @@ ## { 'enum': 'SmbiosEntryPointType', 'data': [ '32', '64' ] } + +## +# @MemorySizeConfiguration: +# +# Schema for memory size configuration. +# +# @size: memory size in bytes +# +# @max-size: maximum hotpluggable memory size in bytes +# +# @slots: number of available memory slots for hotplug +# +# Since: 7.1 +## +{ 'struct': 'MemorySizeConfiguration', 'data': { + '*size': 'size', + '*max-size': 'size', + '*slots': 'uint64' } } diff --git a/softmmu/vl.c b/softmmu/vl.c index 13ae31e92f..65a665e0bc 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -159,11 +159,10 @@ static const char *mem_path; static const char *incoming; static const char *loadvm; static const char *accelerators; +static bool have_custom_ram_size; static QDict *machine_opts_dict; static QTAILQ_HEAD(, ObjectOption) object_opts = QTAILQ_HEAD_INITIALIZER(object_opts); static QTAILQ_HEAD(, DeviceOption) device_opts = QTAILQ_HEAD_INITIALIZER(device_opts); -static ram_addr_t maxram_size; -static uint64_t ram_slots; static int display_remote; static int snapshot; static bool preconfig_requested; @@ -171,7 +170,6 @@ static QemuPluginList plugin_list = QTAILQ_HEAD_INITIALIZER(plugin_list); static BlockdevOptionsQueue bdo_queue = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue); static bool nographic = false; static int mem_prealloc; /* force preallocation of physical target memory */ -static ram_addr_t ram_size; static const char *vga_model = NULL; static DisplayOptions dpy; static int num_serial_hds; @@ -1736,6 +1734,7 @@ static void keyval_dashify(QDict *qdict, Error **errp) static void qemu_apply_legacy_machine_options(QDict *qdict) { const char *value; + QObject *prop; keyval_dashify(qdict, &error_fatal); @@ -1768,6 +1767,13 @@ static void qemu_apply_legacy_machine_options(QDict *qdict) false); qdict_del(qdict, "kernel-irqchip"); } + + prop = qdict_get(qdict, "memory"); + if (prop) { + have_custom_ram_size = + qobject_type(prop) == QTYPE_QDICT && + qdict_haskey(qobject_to(QDict, prop), "size"); + } } static void object_option_foreach_add(bool (*type_opt_predicate)(const char *)) @@ -1885,9 +1891,6 @@ static bool object_create_early(const char *type) static void qemu_apply_machine_options(QDict *qdict) { object_set_properties_from_keyval(OBJECT(current_machine), qdict, false, &error_fatal); - current_machine->ram_size = ram_size; - current_machine->maxram_size = maxram_size; - current_machine->ram_slots = ram_slots; if (semihosting_enabled() && !semihosting_get_argc()) { /* fall back to the -kernel/-append */ @@ -1998,12 +2001,6 @@ static void qemu_create_late_backends(void) qemu_semihosting_console_init(); } -static bool have_custom_ram_size(void) -{ - QemuOpts *opts = qemu_find_opts_singleton("memory"); - return !!qemu_opt_get_size(opts, "size", 0); -} - static void qemu_resolve_machine_memdev(void) { if (current_machine->ram_memdev_id) { @@ -2018,7 +2015,7 @@ static void qemu_resolve_machine_memdev(void) exit(EXIT_FAILURE); } backend_size = object_property_get_uint(backend, "size", &error_abort); - if (have_custom_ram_size() && backend_size != ram_size) { + if (have_custom_ram_size && backend_size != current_machine->ram_size) { error_report("Size specified by -m option must match size of " "explicitly specified 'memory-backend' property"); exit(EXIT_FAILURE); @@ -2028,95 +2025,58 @@ static void qemu_resolve_machine_memdev(void) "'-machine memory-backend'"); exit(EXIT_FAILURE); } - ram_size = backend_size; + current_machine->ram_size = backend_size; } if (!xen_enabled()) { /* On 32-bit hosts, QEMU is limited by virtual address space */ - if (ram_size > (2047 << 20) && HOST_LONG_BITS == 32) { + if (current_machine->ram_size > (2047 << 20) && HOST_LONG_BITS == 32) { error_report("at most 2047 MB RAM can be simulated"); exit(1); } } } -static void set_memory_options(MachineClass *mc) +static void parse_memory_options(const char *arg) { - uint64_t sz; + QemuOpts *opts; + QDict *dict, *prop; const char *mem_str; - const ram_addr_t default_ram_size = mc->default_ram_size; - QemuOpts *opts = qemu_find_opts_singleton("memory"); - Location loc; - loc_push_none(&loc); - qemu_opts_loc_restore(opts); + opts = qemu_opts_parse_noisily(qemu_find_opts("memory"), arg, true); + if (!opts) { + exit(EXIT_FAILURE); + } - sz = 0; - mem_str = qemu_opt_get(opts, "size"); - if (mem_str) { + prop = qdict_new(); + + if (qemu_opt_get_size(opts, "size", 0) != 0) { + mem_str = qemu_opt_get(opts, "size"); if (!*mem_str) { error_report("missing 'size' option value"); exit(EXIT_FAILURE); } - sz = qemu_opt_get_size(opts, "size", ram_size); - /* Fix up legacy suffix-less format */ if (g_ascii_isdigit(mem_str[strlen(mem_str) - 1])) { - uint64_t overflow_check = sz; - - sz *= MiB; - if (sz / MiB != overflow_check) { - error_report("too large 'size' option value"); - exit(EXIT_FAILURE); - } + g_autofree char *mib_str = g_strdup_printf("%sM", mem_str); + qdict_put_str(prop, "size", mib_str); + } else { + qdict_put_str(prop, "size", mem_str); } } - /* backward compatibility behaviour for case "-m 0" */ - if (sz == 0) { - sz = default_ram_size; - } - - sz = QEMU_ALIGN_UP(sz, 8192); - if (mc->fixup_ram_size) { - sz = mc->fixup_ram_size(sz); - } - ram_size = sz; - if (ram_size != sz) { - error_report("ram size too large"); - exit(EXIT_FAILURE); - } - - maxram_size = ram_size; - if (qemu_opt_get(opts, "maxmem")) { - uint64_t slots; - - sz = qemu_opt_get_size(opts, "maxmem", 0); - slots = qemu_opt_get_number(opts, "slots", 0); - if (sz < ram_size) { - error_report("invalid value of -m option maxmem: " - "maximum memory size (0x%" PRIx64 ") must be at least " - "the initial memory size (0x" RAM_ADDR_FMT ")", - sz, ram_size); - exit(EXIT_FAILURE); - } else if (slots && sz == ram_size) { - error_report("invalid value of -m option maxmem: " - "memory slots were specified but maximum memory size " - "(0x%" PRIx64 ") is equal to the initial memory size " - "(0x" RAM_ADDR_FMT ")", sz, ram_size); - exit(EXIT_FAILURE); - } - - maxram_size = sz; - ram_slots = slots; - } else if (qemu_opt_get(opts, "slots")) { - error_report("invalid -m option value: missing 'maxmem' option"); - exit(EXIT_FAILURE); + qdict_put_str(prop, "max-size", qemu_opt_get(opts, "maxmem")); + } + if (qemu_opt_get(opts, "slots")) { + qdict_put_str(prop, "slots", qemu_opt_get(opts, "slots")); } - loc_pop(&loc); + dict = qdict_new(); + qdict_put(dict, "memory", prop); + keyval_merge(machine_opts_dict, dict, &error_fatal); + qobject_unref(dict); } static void qemu_create_machine(QDict *qdict) @@ -2124,8 +2084,6 @@ static void qemu_create_machine(QDict *qdict) MachineClass *machine_class = select_machine(qdict, &error_fatal); object_set_machine_compat_props(machine_class->compat_props); - set_memory_options(machine_class); - current_machine = MACHINE(object_new_with_class(OBJECT_CLASS(machine_class))); object_property_add_child(object_get_root(), "machine", OBJECT(current_machine)); @@ -2185,7 +2143,8 @@ static bool is_qemuopts_group(const char *group) if (g_str_equal(group, "object") || g_str_equal(group, "machine") || g_str_equal(group, "smp-opts") || - g_str_equal(group, "boot-opts")) { + g_str_equal(group, "boot-opts") || + g_str_equal(group, "memory")) { return false; } return true; @@ -2209,6 +2168,8 @@ static void qemu_record_config_group(const char *group, QDict *dict, machine_merge_property("smp", dict, &error_fatal); } else if (g_str_equal(group, "boot-opts")) { machine_merge_property("boot", dict, &error_fatal); + } else if (g_str_equal(group, "memory")) { + machine_merge_property("memory", dict, &error_fatal); } else { abort(); } @@ -3009,11 +2970,7 @@ void qemu_init(int argc, char **argv, char **envp) exit(0); break; case QEMU_OPTION_m: - opts = qemu_opts_parse_noisily(qemu_find_opts("memory"), - optarg, true); - if (!opts) { - exit(EXIT_FAILURE); - } + parse_memory_options(optarg); break; #ifdef CONFIG_TPM case QEMU_OPTION_tpmdev: From 26f88d84dab62e6eb3ec72737ccb155d06049e3a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 14 Apr 2022 12:52:59 -0400 Subject: [PATCH 249/935] machine: make memory-backend a link property Handle HostMemoryBackend creation and setting of ms->ram entirely in machine_run_board_init. Signed-off-by: Paolo Bonzini Message-Id: <20220414165300.555321-5-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- hw/core/machine.c | 70 ++++++++++++++++++++++++++++++--------------- hw/core/numa.c | 2 +- hw/sparc/sun4m.c | 5 ++-- include/hw/boards.h | 4 +-- softmmu/vl.c | 62 ++++++++++++++------------------------- 5 files changed, 74 insertions(+), 69 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index 46b8d0effa..8aab5416dd 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -36,6 +36,7 @@ #include "exec/confidential-guest-support.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-pci.h" +#include "qom/object_interfaces.h" GlobalProperty hw_compat_7_0[] = {}; const size_t hw_compat_7_0_len = G_N_ELEMENTS(hw_compat_7_0); @@ -653,21 +654,6 @@ bool device_type_is_dynamic_sysbus(MachineClass *mc, const char *type) return allowed; } -static char *machine_get_memdev(Object *obj, Error **errp) -{ - MachineState *ms = MACHINE(obj); - - return g_strdup(ms->ram_memdev_id); -} - -static void machine_set_memdev(Object *obj, const char *value, Error **errp) -{ - MachineState *ms = MACHINE(obj); - - g_free(ms->ram_memdev_id); - ms->ram_memdev_id = g_strdup(value); -} - HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine) { int i; @@ -1020,8 +1006,9 @@ static void machine_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, "memory-encryption", "Set memory encryption object to use"); - object_class_property_add_str(oc, "memory-backend", - machine_get_memdev, machine_set_memdev); + object_class_property_add_link(oc, "memory-backend", TYPE_MEMORY_BACKEND, + offsetof(MachineState, memdev), object_property_allow_set_link, + OBJ_PROP_LINK_STRONG); object_class_property_set_description(oc, "memory-backend", "Set RAM backend" "Valid value is ID of hostmem based backend"); @@ -1270,7 +1257,40 @@ MemoryRegion *machine_consume_memdev(MachineState *machine, return ret; } -void machine_run_board_init(MachineState *machine) +static bool create_default_memdev(MachineState *ms, const char *path, Error **errp) +{ + Object *obj; + MachineClass *mc = MACHINE_GET_CLASS(ms); + bool r = false; + + obj = object_new(path ? TYPE_MEMORY_BACKEND_FILE : TYPE_MEMORY_BACKEND_RAM); + if (path) { + if (!object_property_set_str(obj, "mem-path", path, errp)) { + goto out; + } + } + if (!object_property_set_int(obj, "size", ms->ram_size, errp)) { + goto out; + } + object_property_add_child(object_get_objects_root(), mc->default_ram_id, + obj); + /* Ensure backend's memory region name is equal to mc->default_ram_id */ + if (!object_property_set_bool(obj, "x-use-canonical-path-for-ramblock-id", + false, errp)) { + goto out; + } + if (!user_creatable_complete(USER_CREATABLE(obj), errp)) { + goto out; + } + r = object_property_set_link(OBJECT(ms), "memory-backend", obj, errp); + +out: + object_unref(obj); + return r; +} + + +void machine_run_board_init(MachineState *machine, const char *mem_path, Error **errp) { MachineClass *machine_class = MACHINE_GET_CLASS(machine); ObjectClass *oc = object_class_by_name(machine->cpu_type); @@ -1281,11 +1301,11 @@ void machine_run_board_init(MachineState *machine) clock values from the log. */ replay_checkpoint(CHECKPOINT_INIT); - if (machine->ram_memdev_id) { - Object *o; - o = object_resolve_path_type(machine->ram_memdev_id, - TYPE_MEMORY_BACKEND, NULL); - machine->ram = machine_consume_memdev(machine, MEMORY_BACKEND(o)); + if (machine_class->default_ram_id && machine->ram_size && + numa_uses_legacy_mem() && !machine->memdev) { + if (!create_default_memdev(current_machine, mem_path, errp)) { + return; + } } if (machine->numa_state) { @@ -1295,6 +1315,10 @@ void machine_run_board_init(MachineState *machine) } } + if (!machine->ram && machine->memdev) { + machine->ram = machine_consume_memdev(machine, machine->memdev); + } + /* If the machine supports the valid_cpu_types check and the user * specified a CPU with -cpu check here that the user CPU is supported. */ diff --git a/hw/core/numa.c b/hw/core/numa.c index 1aa05dcf42..26d8e5f616 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -695,7 +695,7 @@ void numa_complete_configuration(MachineState *ms) } if (!numa_uses_legacy_mem() && mc->default_ram_id) { - if (ms->ram_memdev_id) { + if (ms->memdev) { error_report("'-machine memory-backend' and '-numa memdev'" " properties are mutually exclusive"); exit(1); diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 9d57491f68..d9288326d6 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -831,8 +831,7 @@ static void sun4m_hw_init(MachineState *machine) SysBusDevice *s; unsigned int smp_cpus = machine->smp.cpus; unsigned int max_cpus = machine->smp.max_cpus; - Object *ram_memdev = object_resolve_path_type(machine->ram_memdev_id, - TYPE_MEMORY_BACKEND, NULL); + HostMemoryBackend *ram_memdev = machine->memdev; NICInfo *nd = &nd_table[0]; if (machine->ram_size > hwdef->max_mem) { @@ -852,7 +851,7 @@ static void sun4m_hw_init(MachineState *machine) /* Create and map RAM frontend */ dev = qdev_new("memory"); - object_property_set_link(OBJECT(dev), "memdev", ram_memdev, &error_fatal); + object_property_set_link(OBJECT(dev), "memdev", OBJECT(ram_memdev), &error_fatal); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0); diff --git a/include/hw/boards.h b/include/hw/boards.h index 910c3ffde2..7b416c9787 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -25,7 +25,7 @@ OBJECT_DECLARE_TYPE(MachineState, MachineClass, MACHINE) extern MachineState *current_machine; -void machine_run_board_init(MachineState *machine); +void machine_run_board_init(MachineState *machine, const char *mem_path, Error **errp); bool machine_usb(MachineState *machine); int machine_phandle_start(MachineState *machine); bool machine_dump_guest_core(MachineState *machine); @@ -339,7 +339,7 @@ struct MachineState { bool suppress_vmdesc; bool enable_graphics; ConfidentialGuestSupport *cgs; - char *ram_memdev_id; + HostMemoryBackend *memdev; /* * convenience alias to ram_memdev_id backend memory region * or to numa container memory region diff --git a/softmmu/vl.c b/softmmu/vl.c index 65a665e0bc..f6deec9380 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -160,6 +160,7 @@ static const char *incoming; static const char *loadvm; static const char *accelerators; static bool have_custom_ram_size; +static const char *ram_memdev_id; static QDict *machine_opts_dict; static QTAILQ_HEAD(, ObjectOption) object_opts = QTAILQ_HEAD_INITIALIZER(object_opts); static QTAILQ_HEAD(, DeviceOption) device_opts = QTAILQ_HEAD_INITIALIZER(device_opts); @@ -1768,6 +1769,19 @@ static void qemu_apply_legacy_machine_options(QDict *qdict) qdict_del(qdict, "kernel-irqchip"); } + value = qdict_get_try_str(qdict, "memory-backend"); + if (value) { + if (mem_path) { + error_report("'-mem-path' can't be used together with" + "'-machine memory-backend'"); + exit(EXIT_FAILURE); + } + + /* Resolved later. */ + ram_memdev_id = g_strdup(value); + qdict_del(qdict, "memory-backend"); + } + prop = qdict_get(qdict, "memory"); if (prop) { have_custom_ram_size = @@ -2003,29 +2017,25 @@ static void qemu_create_late_backends(void) static void qemu_resolve_machine_memdev(void) { - if (current_machine->ram_memdev_id) { + if (ram_memdev_id) { Object *backend; ram_addr_t backend_size; - backend = object_resolve_path_type(current_machine->ram_memdev_id, + backend = object_resolve_path_type(ram_memdev_id, TYPE_MEMORY_BACKEND, NULL); if (!backend) { - error_report("Memory backend '%s' not found", - current_machine->ram_memdev_id); + error_report("Memory backend '%s' not found", ram_memdev_id); exit(EXIT_FAILURE); } backend_size = object_property_get_uint(backend, "size", &error_abort); if (have_custom_ram_size && backend_size != current_machine->ram_size) { - error_report("Size specified by -m option must match size of " - "explicitly specified 'memory-backend' property"); - exit(EXIT_FAILURE); - } - if (mem_path) { - error_report("'-mem-path' can't be used together with" - "'-machine memory-backend'"); + error_report("Size specified by -m option must match size of " + "explicitly specified 'memory-backend' property"); exit(EXIT_FAILURE); } current_machine->ram_size = backend_size; + object_property_set_link(OBJECT(current_machine), + "memory-backend", backend, &error_fatal); } if (!xen_enabled()) { @@ -2376,27 +2386,6 @@ static void configure_accelerators(const char *progname) } } -static void create_default_memdev(MachineState *ms, const char *path) -{ - Object *obj; - MachineClass *mc = MACHINE_GET_CLASS(ms); - - obj = object_new(path ? TYPE_MEMORY_BACKEND_FILE : TYPE_MEMORY_BACKEND_RAM); - if (path) { - object_property_set_str(obj, "mem-path", path, &error_fatal); - } - object_property_set_int(obj, "size", ms->ram_size, &error_fatal); - object_property_add_child(object_get_objects_root(), mc->default_ram_id, - obj); - /* Ensure backend's memory region name is equal to mc->default_ram_id */ - object_property_set_bool(obj, "x-use-canonical-path-for-ramblock-id", - false, &error_fatal); - user_creatable_complete(USER_CREATABLE(obj), &error_fatal); - object_unref(obj); - object_property_set_str(OBJECT(ms), "memory-backend", mc->default_ram_id, - &error_fatal); -} - static void qemu_validate_options(const QDict *machine_opts) { const char *kernel_filename = qdict_get_try_str(machine_opts, "kernel"); @@ -2581,18 +2570,11 @@ static void qemu_init_displays(void) static void qemu_init_board(void) { - MachineClass *machine_class = MACHINE_GET_CLASS(current_machine); - - if (machine_class->default_ram_id && current_machine->ram_size && - numa_uses_legacy_mem() && !current_machine->ram_memdev_id) { - create_default_memdev(current_machine, mem_path); - } - /* process plugin before CPUs are created, but once -smp has been parsed */ qemu_plugin_load_list(&plugin_list, &error_fatal); /* From here on we enter MACHINE_PHASE_INITIALIZED. */ - machine_run_board_init(current_machine); + machine_run_board_init(current_machine, mem_path, &error_fatal); drive_check_orphaned(); From fb56b7a052e1443409334c579e617e287a7250d3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 14 Apr 2022 12:53:00 -0400 Subject: [PATCH 250/935] machine: move more memory validation to Machine object This allows setting memory properties without going through vl.c, and have them validated just the same. Signed-off-by: Paolo Bonzini Message-Id: <20220414165300.555321-6-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- hw/core/machine.c | 21 +++++++++++++++++++-- softmmu/vl.c | 17 +++-------------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index 8aab5416dd..3264c1e11d 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -21,12 +21,14 @@ #include "qapi/qapi-visit-common.h" #include "qapi/qapi-visit-machine.h" #include "qapi/visitor.h" +#include "qom/object_interfaces.h" #include "hw/sysbus.h" #include "sysemu/cpus.h" #include "sysemu/sysemu.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" #include "sysemu/numa.h" +#include "sysemu/xen.h" #include "qemu/error-report.h" #include "sysemu/qtest.h" #include "hw/pci/pci.h" @@ -1301,8 +1303,23 @@ void machine_run_board_init(MachineState *machine, const char *mem_path, Error * clock values from the log. */ replay_checkpoint(CHECKPOINT_INIT); - if (machine_class->default_ram_id && machine->ram_size && - numa_uses_legacy_mem() && !machine->memdev) { + if (!xen_enabled()) { + /* On 32-bit hosts, QEMU is limited by virtual address space */ + if (machine->ram_size > (2047 << 20) && HOST_LONG_BITS == 32) { + error_setg(errp, "at most 2047 MB RAM can be simulated"); + return; + } + } + + if (machine->memdev) { + ram_addr_t backend_size = object_property_get_uint(OBJECT(machine->memdev), + "size", &error_abort); + if (backend_size != machine->ram_size) { + error_setg(errp, "Machine memory size does not match the size of the memory backend"); + return; + } + } else if (machine_class->default_ram_id && machine->ram_size && + numa_uses_legacy_mem()) { if (!create_default_memdev(current_machine, mem_path, errp)) { return; } diff --git a/softmmu/vl.c b/softmmu/vl.c index f6deec9380..edba74f075 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2027,24 +2027,13 @@ static void qemu_resolve_machine_memdev(void) error_report("Memory backend '%s' not found", ram_memdev_id); exit(EXIT_FAILURE); } - backend_size = object_property_get_uint(backend, "size", &error_abort); - if (have_custom_ram_size && backend_size != current_machine->ram_size) { - error_report("Size specified by -m option must match size of " - "explicitly specified 'memory-backend' property"); - exit(EXIT_FAILURE); + if (!have_custom_ram_size) { + backend_size = object_property_get_uint(backend, "size", &error_abort); + current_machine->ram_size = backend_size; } - current_machine->ram_size = backend_size; object_property_set_link(OBJECT(current_machine), "memory-backend", backend, &error_fatal); } - - if (!xen_enabled()) { - /* On 32-bit hosts, QEMU is limited by virtual address space */ - if (current_machine->ram_size > (2047 << 20) && HOST_LONG_BITS == 32) { - error_report("at most 2047 MB RAM can be simulated"); - exit(1); - } - } } static void parse_memory_options(const char *arg) From 0c1450e2045e1a046854c34f34ed9f03dcdab0fb Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 4 May 2022 22:15:14 +0200 Subject: [PATCH 251/935] slirp: bump submodule past 4.7 release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Version 4.7 of slirp provides a new timer API that works better with CFI, together with several other improvements: * Allow disabling the internal DHCP server !22 * Support Unix sockets in hostfwd !103 * IPv6 DNS proxying support !110 * bootp: add support for UEFI HTTP boot !111 and bugfixes. The submodule update also includes 2 commits to fix warnings in the Win32 build. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- slirp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slirp b/slirp index a88d9ace23..9d59bb775d 160000 --- a/slirp +++ b/slirp @@ -1 +1 @@ -Subproject commit a88d9ace234a24ce1c17189642ef9104799425e0 +Subproject commit 9d59bb775d6294c8b447a88512f7bb43f12a25a8 From ad2e5b87d7d070cb4c0a3ba1c20a4ec5e6429301 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 11 Apr 2022 09:26:06 +0200 Subject: [PATCH 252/935] net: slirp: introduce a wrapper struct for QemuTimer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This struct will be extended in the next few patches to support the new slirp_handle_timer() call. For that we need to store an additional "int" for each SLIRP timer, in addition to the cb_opaque. Reviewed-by: Samuel Thibault Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- net/slirp.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/net/slirp.c b/net/slirp.c index bc5e9e4f77..f1e25d741f 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -184,23 +184,32 @@ static int64_t net_slirp_clock_get_ns(void *opaque) return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } +struct SlirpTimer { + QEMUTimer timer; +} + static void *net_slirp_timer_new(SlirpTimerCb cb, void *cb_opaque, void *opaque) { - return timer_new_full(NULL, QEMU_CLOCK_VIRTUAL, - SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL, - cb, cb_opaque); + SlirpTimer *t = g_new(SlirpTimer, 1); + timer_init_full(&t->timer, NULL, QEMU_CLOCK_VIRTUAL, + SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL, + cb, cb_opaque); + return t; } static void net_slirp_timer_free(void *timer, void *opaque) { - timer_free(timer); + SlirpTimer *t = timer; + timer_del(&t->timer); + g_free(t); } static void net_slirp_timer_mod(void *timer, int64_t expire_timer, void *opaque) { - timer_mod(timer, expire_timer); + SlirpTimer *t = timer; + timer_mod(&t->timer, expire_timer); } static void net_slirp_register_poll_fd(int fd, void *opaque) From bce63ded2066a21cc1f5922d0bf667123123d6f6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 11 Apr 2022 10:16:36 +0200 Subject: [PATCH 253/935] net: slirp: switch to slirp_new Replace slirp_init with slirp_new, so that a more recent cfg.version can be specified. The function appeared in version 4.1.0. Signed-off-by: Paolo Bonzini --- meson.build | 2 +- net/slirp.c | 27 +++++++++++++++++++++------ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index 03f63e95e2..ea72ba7c2f 100644 --- a/meson.build +++ b/meson.build @@ -2638,7 +2638,7 @@ if have_system if slirp_opt in ['enabled', 'auto', 'system'] have_internal = fs.exists(meson.current_source_dir() / 'slirp/meson.build') slirp = dependency('slirp', kwargs: static_kwargs, - method: 'pkg-config', + method: 'pkg-config', version: '>=4.1.0', required: slirp_opt == 'system' or slirp_opt == 'enabled' and not have_internal) if slirp.found() diff --git a/net/slirp.c b/net/slirp.c index f1e25d741f..b7464be86b 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -389,6 +389,7 @@ static int net_slirp_init(NetClientState *peer, const char *model, #if defined(CONFIG_SMBD_COMMAND) struct in_addr smbsrv = { .s_addr = 0 }; #endif + SlirpConfig cfg = { 0 }; NetClientState *nc; SlirpState *s; char buf[20]; @@ -577,12 +578,26 @@ static int net_slirp_init(NetClientState *peer, const char *model, s = DO_UPCAST(SlirpState, nc, nc); - s->slirp = slirp_init(restricted, ipv4, net, mask, host, - ipv6, ip6_prefix, vprefix6_len, ip6_host, - vhostname, tftp_server_name, - tftp_export, bootfile, dhcp, - dns, ip6_dns, dnssearch, vdomainname, - &slirp_cb, s); + cfg.version = 1; + cfg.restricted = restricted; + cfg.in_enabled = ipv4; + cfg.vnetwork = net; + cfg.vnetmask = mask; + cfg.vhost = host; + cfg.in6_enabled = ipv6; + cfg.vprefix_addr6 = ip6_prefix; + cfg.vprefix_len = vprefix6_len; + cfg.vhost6 = ip6_host; + cfg.vhostname = vhostname; + cfg.tftp_server_name = tftp_server_name; + cfg.tftp_path = tftp_export; + cfg.bootfile = bootfile; + cfg.vdhcp_start = dhcp; + cfg.vnameserver = dns; + cfg.vnameserver6 = ip6_dns; + cfg.vdnssearch = dnssearch; + cfg.vdomainname = vdomainname; + s->slirp = slirp_new(&cfg, &slirp_cb, s); QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry); /* From 6222e55d134162e87062326a773eb7c9f9d13834 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 11 Apr 2022 09:39:16 +0200 Subject: [PATCH 254/935] net: slirp: add support for CFI-friendly timer API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit libslirp 4.7 introduces a CFI-friendly version of the .timer_new callback. The new callback replaces the function pointer with an enum; invoking the callback is done with a new function slirp_handle_timer. Support the new API so that CFI can be made compatible with using a system libslirp. Reviewed-by: Samuel Thibault Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- net/slirp.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/net/slirp.c b/net/slirp.c index b7464be86b..8679be6444 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -184,10 +184,43 @@ static int64_t net_slirp_clock_get_ns(void *opaque) return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } +typedef struct SlirpTimer SlirpTimer; struct SlirpTimer { QEMUTimer timer; +#if SLIRP_CHECK_VERSION(4,7,0) + Slirp *slirp; + SlirpTimerId id; + void *cb_opaque; +#endif +}; + +#if SLIRP_CHECK_VERSION(4,7,0) +static void net_slirp_init_completed(Slirp *slirp, void *opaque) +{ + SlirpState *s = opaque; + s->slirp = slirp; } +static void net_slirp_timer_cb(void *opaque) +{ + SlirpTimer *t = opaque; + slirp_handle_timer(t->slirp, t->id, t->cb_opaque); +} + +static void *net_slirp_timer_new_opaque(SlirpTimerId id, + void *cb_opaque, void *opaque) +{ + SlirpState *s = opaque; + SlirpTimer *t = g_new(SlirpTimer, 1); + t->slirp = s->slirp; + t->id = id; + t->cb_opaque = cb_opaque; + timer_init_full(&t->timer, NULL, QEMU_CLOCK_VIRTUAL, + SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL, + net_slirp_timer_cb, t); + return t; +} +#else static void *net_slirp_timer_new(SlirpTimerCb cb, void *cb_opaque, void *opaque) { @@ -197,6 +230,7 @@ static void *net_slirp_timer_new(SlirpTimerCb cb, cb, cb_opaque); return t; } +#endif static void net_slirp_timer_free(void *timer, void *opaque) { @@ -231,7 +265,12 @@ static const SlirpCb slirp_cb = { .send_packet = net_slirp_send_packet, .guest_error = net_slirp_guest_error, .clock_get_ns = net_slirp_clock_get_ns, +#if SLIRP_CHECK_VERSION(4,7,0) + .init_completed = net_slirp_init_completed, + .timer_new_opaque = net_slirp_timer_new_opaque, +#else .timer_new = net_slirp_timer_new, +#endif .timer_free = net_slirp_timer_free, .timer_mod = net_slirp_timer_mod, .register_poll_fd = net_slirp_register_poll_fd, @@ -578,7 +617,7 @@ static int net_slirp_init(NetClientState *peer, const char *model, s = DO_UPCAST(SlirpState, nc, nc); - cfg.version = 1; + cfg.version = SLIRP_CHECK_VERSION(4,7,0) ? 4 : 1; cfg.restricted = restricted; cfg.in_enabled = ipv4; cfg.vnetwork = net; From bf2f69d08bf158bfdbbe251357452f9576489b6d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 11 Apr 2022 09:41:27 +0200 Subject: [PATCH 255/935] net: slirp: allow CFI with libslirp >= 4.7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit slirp 4.7 introduces a new CFI-friendly timer callback that does not pass function pointers within libslirp as callbacks for timers. Check the version number and, if it is new enough, allow using CFI even with a system libslirp. Reviewed-by: Samuel Thibault Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- meson.build | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/meson.build b/meson.build index ea72ba7c2f..9b20dcd143 100644 --- a/meson.build +++ b/meson.build @@ -2637,10 +2637,25 @@ if have_system slirp_opt = get_option('slirp') if slirp_opt in ['enabled', 'auto', 'system'] have_internal = fs.exists(meson.current_source_dir() / 'slirp/meson.build') + slirp_dep_required = (slirp_opt == 'system' or + slirp_opt == 'enabled' and not have_internal) slirp = dependency('slirp', kwargs: static_kwargs, method: 'pkg-config', version: '>=4.1.0', - required: slirp_opt == 'system' or - slirp_opt == 'enabled' and not have_internal) + required: slirp_dep_required) + # slirp <4.7 is incompatible with CFI support in QEMU. This is because + # it passes function pointers within libslirp as callbacks for timers. + # When using a system-wide shared libslirp, the type information for the + # callback is missing and the timer call produces a false positive with CFI. + # Do not use the "version" keyword argument to produce a better error. + # with control-flow integrity. + if get_option('cfi') and slirp.found() and slirp.version().version_compare('<4.7') + if slirp_dep_required + error('Control-Flow Integrity requires libslirp 4.7.') + else + warning('Control-Flow Integrity requires libslirp 4.7, not using system-wide libslirp.') + slirp = not_found + endif + endif if slirp.found() slirp_opt = 'system' elif have_internal @@ -2713,18 +2728,6 @@ if have_system endif endif -# For CFI, we need to compile slirp as a static library together with qemu. -# This is because we register slirp functions as callbacks for QEMU Timers. -# When using a system-wide shared libslirp, the type information for the -# callback is missing and the timer call produces a false positive with CFI. -# -# Now that slirp_opt has been defined, check if the selected slirp is compatible -# with control-flow integrity. -if get_option('cfi') and slirp_opt == 'system' - error('Control-Flow Integrity is not compatible with system-wide slirp.' \ - + ' Please configure with --enable-slirp=git') -endif - fdt = not_found if have_system fdt_opt = get_option('fdt') From 248af9e80a04c5ab4ffec789aa24345d3d86b42b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 27 Apr 2022 15:08:28 +0200 Subject: [PATCH 256/935] coroutine-lock: qemu_co_queue_next is a coroutine-only qemu_co_enter_next qemu_co_queue_next is basically the same as qemu_co_enter_next but without a QemuLockable argument. That's perfectly fine, but only as long as the function is marked coroutine_fn. If used outside coroutine context, qemu_co_queue_wait will attempt to take the lock and that is just broken: if you are calling qemu_co_queue_next outside coroutine context, the lock is going to be a QemuMutex which cannot be taken twice by the same thread. The patch adds the marker and reimplements qemu_co_queue_next in terms of qemu_co_enter_next_impl, to remove duplicated code and to clarify that the latter also works in coroutine context. Signed-off-by: Paolo Bonzini Reviewed-by: Eric Blake Message-Id: <20220427130830.150180-2-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- include/qemu/coroutine.h | 7 ++++--- util/qemu-coroutine-lock.c | 21 +++++++-------------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index 284571badb..c23d41e1ff 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -208,11 +208,12 @@ void qemu_co_queue_init(CoQueue *queue); void coroutine_fn qemu_co_queue_wait_impl(CoQueue *queue, QemuLockable *lock); /** - * Removes the next coroutine from the CoQueue, and wake it up. + * Removes the next coroutine from the CoQueue, and queue it to run after + * the currently-running coroutine yields. * Returns true if a coroutine was removed, false if the queue is empty. - * OK to run from coroutine and non-coroutine context. + * Used from coroutine context, use qemu_co_enter_next outside. */ -bool qemu_co_queue_next(CoQueue *queue); +bool coroutine_fn qemu_co_queue_next(CoQueue *queue); /** * Empties the CoQueue; all coroutines are woken up. diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c index 2669403839..5705cfea2e 100644 --- a/util/qemu-coroutine-lock.c +++ b/util/qemu-coroutine-lock.c @@ -67,7 +67,7 @@ void coroutine_fn qemu_co_queue_wait_impl(CoQueue *queue, QemuLockable *lock) } } -static bool qemu_co_queue_do_restart(CoQueue *queue, bool single) +void qemu_co_queue_restart_all(CoQueue *queue) { Coroutine *next; @@ -78,23 +78,10 @@ static bool qemu_co_queue_do_restart(CoQueue *queue, bool single) while ((next = QSIMPLEQ_FIRST(&queue->entries)) != NULL) { QSIMPLEQ_REMOVE_HEAD(&queue->entries, co_queue_next); aio_co_wake(next); - if (single) { - break; - } } return true; } -bool qemu_co_queue_next(CoQueue *queue) -{ - return qemu_co_queue_do_restart(queue, true); -} - -void qemu_co_queue_restart_all(CoQueue *queue) -{ - qemu_co_queue_do_restart(queue, false); -} - bool qemu_co_enter_next_impl(CoQueue *queue, QemuLockable *lock) { Coroutine *next; @@ -115,6 +102,12 @@ bool qemu_co_enter_next_impl(CoQueue *queue, QemuLockable *lock) return true; } +bool coroutine_fn qemu_co_queue_next(CoQueue *queue) +{ + /* No unlock/lock needed in coroutine context. */ + return qemu_co_enter_next_impl(queue, NULL); +} + bool qemu_co_queue_empty(CoQueue *queue) { return QSIMPLEQ_FIRST(&queue->entries) == NULL; From d6ee15adec5a2345e88c680cd15ed48796c89c14 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 27 Apr 2022 15:08:29 +0200 Subject: [PATCH 257/935] coroutine-lock: introduce qemu_co_queue_enter_all Because qemu_co_queue_restart_all does not release the lock, it should be used only in coroutine context. Introduce a new function that, like qemu_co_enter_next, does release the lock, and use it whenever qemu_co_queue_restart_all was used outside coroutine context. Signed-off-by: Paolo Bonzini Reviewed-by: Eric Blake Message-Id: <20220427130830.150180-3-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- include/qemu/coroutine.h | 13 +++++++++++++ ui/console.c | 2 +- util/qemu-coroutine-lock.c | 7 +++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index c23d41e1ff..e5954635f6 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -234,6 +234,19 @@ void qemu_co_queue_restart_all(CoQueue *queue); qemu_co_enter_next_impl(queue, QEMU_MAKE_LOCKABLE(lock)) bool qemu_co_enter_next_impl(CoQueue *queue, QemuLockable *lock); +/** + * Empties the CoQueue, waking the waiting coroutine one at a time. Unlike + * qemu_co_queue_all, this function releases the lock during aio_co_wake + * because it is meant to be used outside coroutine context; in that case, the + * coroutine is entered immediately, before qemu_co_enter_all returns. + * + * If used in coroutine context, qemu_co_enter_all is equivalent to + * qemu_co_queue_all. + */ +#define qemu_co_enter_all(queue, lock) \ + qemu_co_enter_all_impl(queue, QEMU_MAKE_LOCKABLE(lock)) +void qemu_co_enter_all_impl(CoQueue *queue, QemuLockable *lock); + /** * Checks if the CoQueue is empty. */ diff --git a/ui/console.c b/ui/console.c index 15d0f6affd..36c80cd1de 100644 --- a/ui/console.c +++ b/ui/console.c @@ -221,7 +221,7 @@ static void gui_setup_refresh(DisplayState *ds) void graphic_hw_update_done(QemuConsole *con) { if (con) { - qemu_co_queue_restart_all(&con->dump_queue); + qemu_co_enter_all(&con->dump_queue, NULL); } } diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c index 5705cfea2e..5b0342faed 100644 --- a/util/qemu-coroutine-lock.c +++ b/util/qemu-coroutine-lock.c @@ -108,6 +108,13 @@ bool coroutine_fn qemu_co_queue_next(CoQueue *queue) return qemu_co_enter_next_impl(queue, NULL); } +void qemu_co_enter_all_impl(CoQueue *queue, QemuLockable *lock) +{ + while (qemu_co_enter_next_impl(queue, lock)) { + /* just loop */ + } +} + bool qemu_co_queue_empty(CoQueue *queue) { return QSIMPLEQ_FIRST(&queue->entries) == NULL; From f0d43b1ecef04105e0d0f55658182510b4e0f58e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 27 Apr 2022 15:08:30 +0200 Subject: [PATCH 258/935] coroutine-lock: qemu_co_queue_restart_all is a coroutine-only qemu_co_enter_all qemu_co_queue_restart_all is basically the same as qemu_co_enter_all but without a QemuLockable argument. That's perfectly fine, but only as long as the function is marked coroutine_fn. If used outside coroutine context, qemu_co_queue_wait will attempt to take the lock and that is just broken: if you are calling qemu_co_queue_restart_all outside coroutine context, the lock is going to be a QemuMutex which cannot be taken twice by the same thread. The patch adds the marker to qemu_co_queue_restart_all and to its sole non-coroutine_fn caller; it then reimplements the function in terms of qemu_co_enter_all_impl, to remove duplicated code and to clarify that the latter also works in coroutine context. Signed-off-by: Paolo Bonzini Reviewed-by: Eric Blake Message-Id: <20220427130830.150180-4-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- block/io.c | 2 +- include/qemu/coroutine.h | 7 ++++--- util/qemu-coroutine-lock.c | 21 ++++++--------------- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/block/io.c b/block/io.c index 9769ec53b0..789e6373d5 100644 --- a/block/io.c +++ b/block/io.c @@ -751,7 +751,7 @@ void bdrv_drain_all(void) * * This function should be called when a tracked request is completing. */ -static void tracked_request_end(BdrvTrackedRequest *req) +static void coroutine_fn tracked_request_end(BdrvTrackedRequest *req) { if (req->serialising) { qatomic_dec(&req->bs->serialising_in_flight); diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index e5954635f6..43df7a7e66 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -216,10 +216,11 @@ void coroutine_fn qemu_co_queue_wait_impl(CoQueue *queue, QemuLockable *lock); bool coroutine_fn qemu_co_queue_next(CoQueue *queue); /** - * Empties the CoQueue; all coroutines are woken up. - * OK to run from coroutine and non-coroutine context. + * Empties the CoQueue and queues the coroutine to run after + * the currently-running coroutine yields. + * Used from coroutine context, use qemu_co_enter_all outside. */ -void qemu_co_queue_restart_all(CoQueue *queue); +void coroutine_fn qemu_co_queue_restart_all(CoQueue *queue); /** * Removes the next coroutine from the CoQueue, and wake it up. Unlike diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c index 5b0342faed..9ad24ab1af 100644 --- a/util/qemu-coroutine-lock.c +++ b/util/qemu-coroutine-lock.c @@ -67,21 +67,6 @@ void coroutine_fn qemu_co_queue_wait_impl(CoQueue *queue, QemuLockable *lock) } } -void qemu_co_queue_restart_all(CoQueue *queue) -{ - Coroutine *next; - - if (QSIMPLEQ_EMPTY(&queue->entries)) { - return false; - } - - while ((next = QSIMPLEQ_FIRST(&queue->entries)) != NULL) { - QSIMPLEQ_REMOVE_HEAD(&queue->entries, co_queue_next); - aio_co_wake(next); - } - return true; -} - bool qemu_co_enter_next_impl(CoQueue *queue, QemuLockable *lock) { Coroutine *next; @@ -115,6 +100,12 @@ void qemu_co_enter_all_impl(CoQueue *queue, QemuLockable *lock) } } +void coroutine_fn qemu_co_queue_restart_all(CoQueue *queue) +{ + /* No unlock/lock needed in coroutine context. */ + qemu_co_enter_all_impl(queue, NULL); +} + bool qemu_co_queue_empty(CoQueue *queue) { return QSIMPLEQ_FIRST(&queue->entries) == NULL; From d93e839ccd26ac95650fe31e45c91394936ddc27 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 11 May 2022 09:40:35 +0200 Subject: [PATCH 259/935] vhost-backend: do not depend on CONFIG_VHOST_VSOCK The vsock callbacks .vhost_vsock_set_guest_cid and .vhost_vsock_set_running are the only ones to be conditional on #ifdef CONFIG_VHOST_VSOCK. This is different from any other device-dependent callbacks like .vhost_scsi_set_endpoint, and it also broke when CONFIG_VHOST_VSOCK was changed to a per-target symbol. It would be possible to also use the CONFIG_DEVICES include, but really there is no reason for most virtio files to be per-target so just remove the #ifdef to fix the issue. Reported-by: Dov Murik Fixes: 9972ae314f ("build: move vhost-vsock configuration to Kconfig") Signed-off-by: Paolo Bonzini --- hw/virtio/vhost-backend.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c index e409a865ae..4de8b6b3b0 100644 --- a/hw/virtio/vhost-backend.c +++ b/hw/virtio/vhost-backend.c @@ -203,7 +203,6 @@ static int vhost_kernel_get_vq_index(struct vhost_dev *dev, int idx) return idx - dev->vq_index; } -#ifdef CONFIG_VHOST_VSOCK static int vhost_kernel_vsock_set_guest_cid(struct vhost_dev *dev, uint64_t guest_cid) { @@ -214,7 +213,6 @@ static int vhost_kernel_vsock_set_running(struct vhost_dev *dev, int start) { return vhost_kernel_call(dev, VHOST_VSOCK_SET_RUNNING, &start); } -#endif /* CONFIG_VHOST_VSOCK */ static void vhost_kernel_iotlb_read(void *opaque) { @@ -319,10 +317,8 @@ const VhostOps kernel_ops = { .vhost_set_owner = vhost_kernel_set_owner, .vhost_reset_device = vhost_kernel_reset_device, .vhost_get_vq_index = vhost_kernel_get_vq_index, -#ifdef CONFIG_VHOST_VSOCK .vhost_vsock_set_guest_cid = vhost_kernel_vsock_set_guest_cid, .vhost_vsock_set_running = vhost_kernel_vsock_set_running, -#endif /* CONFIG_VHOST_VSOCK */ .vhost_set_iotlb_callback = vhost_kernel_set_iotlb_callback, .vhost_send_device_iotlb_msg = vhost_kernel_send_device_iotlb_msg, }; From e23a13c0426774443543d78eef84ec8404534f0b Mon Sep 17 00:00:00 2001 From: Kshitij Suri Date: Tue, 10 May 2022 16:19:32 +0000 Subject: [PATCH 260/935] meson: link libpng independent of vnc Currently png support is dependent on vnc for linking object file to libpng. This commit makes the parameter independent of vnc as it breaks system emulator with --disable-vnc unless --disable-png is added. Fixes: 9a0a119a38 ("Added parameter to take screenshot with screendump as PNG", 2022-04-27) Signed-off-by: Kshitij Suri Message-Id: <20220510161932.228481-1-kshitij.suri@nutanix.com> Signed-off-by: Paolo Bonzini --- ui/meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/meson.build b/ui/meson.build index eba93b41e3..e9f48c5315 100644 --- a/ui/meson.build +++ b/ui/meson.build @@ -2,6 +2,7 @@ softmmu_ss.add(pixman) specific_ss.add(when: ['CONFIG_SOFTMMU'], if_true: pixman) # for the include path specific_ss.add(when: ['CONFIG_SOFTMMU'], if_true: opengl) # for the include path +softmmu_ss.add(png) softmmu_ss.add(files( 'clipboard.c', 'console.c', @@ -40,7 +41,7 @@ vnc_ss.add(files( 'vnc-jobs.c', 'vnc-clipboard.c', )) -vnc_ss.add(zlib, png, jpeg, gnutls) +vnc_ss.add(zlib, jpeg, gnutls) vnc_ss.add(when: sasl, if_true: files('vnc-auth-sasl.c')) softmmu_ss.add_all(when: vnc, if_true: vnc_ss) softmmu_ss.add(when: vnc, if_false: files('vnc-stubs.c')) From defac5e2fbddf8423a354ff0454283a2115e1367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 18 Nov 2021 12:57:32 +0100 Subject: [PATCH 261/935] hw/block/fdc: Prevent end-of-track overrun (CVE-2021-3507) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per the 82078 datasheet, if the end-of-track (EOT byte in the FIFO) is more than the number of sectors per side, the command is terminated unsuccessfully: * 5.2.5 DATA TRANSFER TERMINATION The 82078 supports terminal count explicitly through the TC pin and implicitly through the underrun/over- run and end-of-track (EOT) functions. For full sector transfers, the EOT parameter can define the last sector to be transferred in a single or multisector transfer. If the last sector to be transferred is a par- tial sector, the host can stop transferring the data in mid-sector, and the 82078 will continue to complete the sector as if a hardware TC was received. The only difference between these implicit functions and TC is that they return "abnormal termination" result status. Such status indications can be ignored if they were expected. * 6.1.3 READ TRACK This command terminates when the EOT specified number of sectors have been read. If the 82078 does not find an I D Address Mark on the diskette after the second· occurrence of a pulse on the INDX# pin, then it sets the IC code in Status Regis- ter 0 to "01" (Abnormal termination), sets the MA bit in Status Register 1 to "1", and terminates the com- mand. * 6.1.6 VERIFY Refer to Table 6-6 and Table 6-7 for information concerning the values of MT and EC versus SC and EOT value. * Table 6·6. Result Phase Table * Table 6-7. Verify Command Result Phase Table Fix by aborting the transfer when EOT > # Sectors Per Side. Cc: qemu-stable@nongnu.org Cc: Hervé Poussineau Fixes: baca51faff0 ("floppy driver: disk geometry auto detect") Reported-by: Alexander Bulekov Resolves: https://gitlab.com/qemu-project/qemu/-/issues/339 Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20211118115733.4038610-2-philmd@redhat.com> Reviewed-by: Hanna Reitz Signed-off-by: Kevin Wolf --- hw/block/fdc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 347875a0cd..57bb355794 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -1530,6 +1530,14 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) int tmp; fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]); tmp = (fdctrl->fifo[6] - ks + 1); + if (tmp < 0) { + FLOPPY_DPRINTF("invalid EOT: %d\n", tmp); + fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00); + fdctrl->fifo[3] = kt; + fdctrl->fifo[4] = kh; + fdctrl->fifo[5] = ks; + return; + } if (fdctrl->fifo[0] & 0x80) tmp += fdctrl->fifo[6]; fdctrl->data_len *= tmp; From 46609b90d9e3a6304def11038a76b58ff43f77bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 18 Nov 2021 12:57:33 +0100 Subject: [PATCH 262/935] tests/qtest/fdc-test: Add a regression test for CVE-2021-3507 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the reproducer from https://gitlab.com/qemu-project/qemu/-/issues/339 Without the previous commit, when running 'make check-qtest-i386' with QEMU configured with '--enable-sanitizers' we get: ==4028352==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x619000062a00 at pc 0x5626d03c491a bp 0x7ffdb4199410 sp 0x7ffdb4198bc0 READ of size 786432 at 0x619000062a00 thread T0 #0 0x5626d03c4919 in __asan_memcpy (qemu-system-i386+0x1e65919) #1 0x5626d1c023cc in flatview_write_continue softmmu/physmem.c:2787:13 #2 0x5626d1bf0c0f in flatview_write softmmu/physmem.c:2822:14 #3 0x5626d1bf0798 in address_space_write softmmu/physmem.c:2914:18 #4 0x5626d1bf0f37 in address_space_rw softmmu/physmem.c:2924:16 #5 0x5626d1bf14c8 in cpu_physical_memory_rw softmmu/physmem.c:2933:5 #6 0x5626d0bd5649 in cpu_physical_memory_write include/exec/cpu-common.h:82:5 #7 0x5626d0bd0a07 in i8257_dma_write_memory hw/dma/i8257.c:452:9 #8 0x5626d09f825d in fdctrl_transfer_handler hw/block/fdc.c:1616:13 #9 0x5626d0a048b4 in fdctrl_start_transfer hw/block/fdc.c:1539:13 #10 0x5626d09f4c3e in fdctrl_write_data hw/block/fdc.c:2266:13 #11 0x5626d09f22f7 in fdctrl_write hw/block/fdc.c:829:9 #12 0x5626d1c20bc5 in portio_write softmmu/ioport.c:207:17 0x619000062a00 is located 0 bytes to the right of 512-byte region [0x619000062800,0x619000062a00) allocated by thread T0 here: #0 0x5626d03c66ec in posix_memalign (qemu-system-i386+0x1e676ec) #1 0x5626d2b988d4 in qemu_try_memalign util/oslib-posix.c:210:11 #2 0x5626d2b98b0c in qemu_memalign util/oslib-posix.c:226:27 #3 0x5626d09fbaf0 in fdctrl_realize_common hw/block/fdc.c:2341:20 #4 0x5626d0a150ed in isabus_fdc_realize hw/block/fdc-isa.c:113:5 #5 0x5626d2367935 in device_set_realized hw/core/qdev.c:531:13 SUMMARY: AddressSanitizer: heap-buffer-overflow (qemu-system-i386+0x1e65919) in __asan_memcpy Shadow bytes around the buggy address: 0x0c32800044f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c3280004500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c3280004510: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c3280004520: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c3280004530: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0c3280004540:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c3280004550: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c3280004560: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c3280004570: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c3280004580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c3280004590: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Heap left redzone: fa Freed heap region: fd ==4028352==ABORTING [ kwolf: Added snapshot=on to prevent write file lock failure ] Reported-by: Alexander Bulekov Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alexander Bulekov Signed-off-by: Kevin Wolf --- tests/qtest/fdc-test.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/qtest/fdc-test.c b/tests/qtest/fdc-test.c index 0b3c2c0d52..52ade90a7d 100644 --- a/tests/qtest/fdc-test.c +++ b/tests/qtest/fdc-test.c @@ -582,6 +582,26 @@ static void test_cve_2021_20196(void) qtest_quit(s); } +static void test_cve_2021_3507(void) +{ + QTestState *s; + + s = qtest_initf("-nographic -m 32M -nodefaults " + "-drive file=%s,format=raw,if=floppy,snapshot=on", + test_image); + qtest_outl(s, 0x9, 0x0a0206); + qtest_outw(s, 0x3f4, 0x1600); + qtest_outw(s, 0x3f4, 0x0000); + qtest_outw(s, 0x3f4, 0x0000); + qtest_outw(s, 0x3f4, 0x0000); + qtest_outw(s, 0x3f4, 0x0200); + qtest_outw(s, 0x3f4, 0x0200); + qtest_outw(s, 0x3f4, 0x0000); + qtest_outw(s, 0x3f4, 0x0000); + qtest_outw(s, 0x3f4, 0x0000); + qtest_quit(s); +} + int main(int argc, char **argv) { int fd; @@ -613,6 +633,7 @@ int main(int argc, char **argv) qtest_add_func("/fdc/read_no_dma_19", test_read_no_dma_19); qtest_add_func("/fdc/fuzz-registers", fuzz_registers); qtest_add_func("/fdc/fuzz/cve_2021_20196", test_cve_2021_20196); + qtest_add_func("/fdc/fuzz/cve_2021_3507", test_cve_2021_3507); ret = g_test_run(); From a5fced40212ed73c715ca298a2929dd4d99c9999 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 11 May 2022 19:49:23 -0500 Subject: [PATCH 263/935] qemu-nbd: Pass max connections to blockdev layer The next patch wants to adjust whether the NBD server code advertises MULTI_CONN based on whether it is known if the server limits to exactly one client. For a server started by QMP, this information is obtained through nbd_server_start (which can support more than one export); but for qemu-nbd (which supports exactly one export), it is controlled only by the command-line option -e/--shared. Since we already have a hook function used by qemu-nbd, it's easiest to just alter its signature to fit our needs. Signed-off-by: Eric Blake Message-Id: <20220512004924.417153-2-eblake@redhat.com> Signed-off-by: Kevin Wolf --- blockdev-nbd.c | 8 ++++---- include/block/nbd.h | 2 +- qemu-nbd.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/blockdev-nbd.c b/blockdev-nbd.c index 7f6531cba0..711e0e72bd 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -30,18 +30,18 @@ typedef struct NBDServerData { } NBDServerData; static NBDServerData *nbd_server; -static bool is_qemu_nbd; +static int qemu_nbd_connections = -1; /* Non-negative if this is qemu-nbd */ static void nbd_update_server_watch(NBDServerData *s); -void nbd_server_is_qemu_nbd(bool value) +void nbd_server_is_qemu_nbd(int max_connections) { - is_qemu_nbd = value; + qemu_nbd_connections = max_connections; } bool nbd_server_is_running(void) { - return nbd_server || is_qemu_nbd; + return nbd_server || qemu_nbd_connections >= 0; } static void nbd_blockdev_client_closed(NBDClient *client, bool ignored) diff --git a/include/block/nbd.h b/include/block/nbd.h index a98eb665da..c5a29ce1c6 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -344,7 +344,7 @@ void nbd_client_new(QIOChannelSocket *sioc, void nbd_client_get(NBDClient *client); void nbd_client_put(NBDClient *client); -void nbd_server_is_qemu_nbd(bool value); +void nbd_server_is_qemu_nbd(int max_connections); bool nbd_server_is_running(void); void nbd_server_start(SocketAddress *addr, const char *tls_creds, const char *tls_authz, uint32_t max_connections, diff --git a/qemu-nbd.c b/qemu-nbd.c index 2382b5042a..0cd5aa6f02 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -1095,7 +1095,7 @@ int main(int argc, char **argv) bs->detect_zeroes = detect_zeroes; - nbd_server_is_qemu_nbd(true); + nbd_server_is_qemu_nbd(shared); export_opts = g_new(BlockExportOptions, 1); *export_opts = (BlockExportOptions) { From 58a6fdcc9efb2a7c1ef4893dca4aa5e8020ca3dc Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 11 May 2022 19:49:24 -0500 Subject: [PATCH 264/935] nbd/server: Allow MULTI_CONN for shared writable exports According to the NBD spec, a server that advertises NBD_FLAG_CAN_MULTI_CONN promises that multiple client connections will not see any cache inconsistencies: when properly separated by a single flush, actions performed by one client will be visible to another client, regardless of which client did the flush. We always satisfy these conditions in qemu - even when we support multiple clients, ALL clients go through a single point of reference into the block layer, with no local caching. The effect of one client is instantly visible to the next client. Even if our backend were a network device, we argue that any multi-path caching effects that would cause inconsistencies in back-to-back actions not seeing the effect of previous actions would be a bug in that backend, and not the fault of caching in qemu. As such, it is safe to unconditionally advertise CAN_MULTI_CONN for any qemu NBD server situation that supports parallel clients. Note, however, that we don't want to advertise CAN_MULTI_CONN when we know that a second client cannot connect (for historical reasons, qemu-nbd defaults to a single connection while nbd-server-add and QMP commands default to unlimited connections; but we already have existing means to let either style of NBD server creation alter those defaults). This is visible by no longer advertising MULTI_CONN for 'qemu-nbd -r' without -e, as in the iotest nbd-qemu-allocation. The harder part of this patch is setting up an iotest to demonstrate behavior of multiple NBD clients to a single server. It might be possible with parallel qemu-io processes, but I found it easier to do in python with the help of libnbd, and help from Nir and Vladimir in writing the test. Signed-off-by: Eric Blake Suggested-by: Nir Soffer Suggested-by: Vladimir Sementsov-Ogievskiy Message-Id: <20220512004924.417153-3-eblake@redhat.com> Signed-off-by: Kevin Wolf --- MAINTAINERS | 1 + blockdev-nbd.c | 5 + docs/interop/nbd.txt | 1 + docs/tools/qemu-nbd.rst | 3 +- include/block/nbd.h | 3 +- nbd/server.c | 10 +- qapi/block-export.json | 8 +- tests/qemu-iotests/tests/nbd-multiconn | 145 ++++++++++++++++++ tests/qemu-iotests/tests/nbd-multiconn.out | 5 + .../tests/nbd-qemu-allocation.out | 2 +- 10 files changed, 172 insertions(+), 11 deletions(-) create mode 100755 tests/qemu-iotests/tests/nbd-multiconn create mode 100644 tests/qemu-iotests/tests/nbd-multiconn.out diff --git a/MAINTAINERS b/MAINTAINERS index 571556d279..fbc0662627 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3367,6 +3367,7 @@ F: qemu-nbd.* F: blockdev-nbd.c F: docs/interop/nbd.txt F: docs/tools/qemu-nbd.rst +F: tests/qemu-iotests/tests/*nbd* T: git https://repo.or.cz/qemu/ericb.git nbd T: git https://src.openvz.org/scm/~vsementsov/qemu.git nbd diff --git a/blockdev-nbd.c b/blockdev-nbd.c index 711e0e72bd..012256bb02 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -44,6 +44,11 @@ bool nbd_server_is_running(void) return nbd_server || qemu_nbd_connections >= 0; } +int nbd_server_max_connections(void) +{ + return nbd_server ? nbd_server->max_connections : qemu_nbd_connections; +} + static void nbd_blockdev_client_closed(NBDClient *client, bool ignored) { nbd_client_put(client); diff --git a/docs/interop/nbd.txt b/docs/interop/nbd.txt index bdb0f2a41a..f5ca25174a 100644 --- a/docs/interop/nbd.txt +++ b/docs/interop/nbd.txt @@ -68,3 +68,4 @@ NBD_CMD_BLOCK_STATUS for "qemu:dirty-bitmap:", NBD_CMD_CACHE * 4.2: NBD_FLAG_CAN_MULTI_CONN for shareable read-only exports, NBD_CMD_FLAG_FAST_ZERO * 5.2: NBD_CMD_BLOCK_STATUS for "qemu:allocation-depth" +* 7.1: NBD_FLAG_CAN_MULTI_CONN for shareable writable exports diff --git a/docs/tools/qemu-nbd.rst b/docs/tools/qemu-nbd.rst index 4c950f6199..8e08a29e89 100644 --- a/docs/tools/qemu-nbd.rst +++ b/docs/tools/qemu-nbd.rst @@ -139,8 +139,7 @@ driver options if :option:`--image-opts` is specified. .. option:: -e, --shared=NUM Allow up to *NUM* clients to share the device (default - ``1``), 0 for unlimited. Safe for readers, but for now, - consistency is not guaranteed between multiple writers. + ``1``), 0 for unlimited. .. option:: -t, --persistent diff --git a/include/block/nbd.h b/include/block/nbd.h index c5a29ce1c6..c74b7a9d2e 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2020 Red Hat, Inc. + * Copyright (C) 2016-2022 Red Hat, Inc. * Copyright (C) 2005 Anthony Liguori * * Network Block Device @@ -346,6 +346,7 @@ void nbd_client_put(NBDClient *client); void nbd_server_is_qemu_nbd(int max_connections); bool nbd_server_is_running(void); +int nbd_server_max_connections(void); void nbd_server_start(SocketAddress *addr, const char *tls_creds, const char *tls_authz, uint32_t max_connections, Error **errp); diff --git a/nbd/server.c b/nbd/server.c index 4cdbc062c1..213e00e761 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2021 Red Hat, Inc. + * Copyright (C) 2016-2022 Red Hat, Inc. * Copyright (C) 2005 Anthony Liguori * * Network Block Device Server Side @@ -1642,7 +1642,6 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args, int64_t size; uint64_t perm, shared_perm; bool readonly = !exp_args->writable; - bool shared = !exp_args->writable; BlockDirtyBitmapOrStrList *bitmaps; size_t i; int ret; @@ -1693,11 +1692,12 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args, exp->description = g_strdup(arg->description); exp->nbdflags = (NBD_FLAG_HAS_FLAGS | NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA | NBD_FLAG_SEND_CACHE); + + if (nbd_server_max_connections() != 1) { + exp->nbdflags |= NBD_FLAG_CAN_MULTI_CONN; + } if (readonly) { exp->nbdflags |= NBD_FLAG_READ_ONLY; - if (shared) { - exp->nbdflags |= NBD_FLAG_CAN_MULTI_CONN; - } } else { exp->nbdflags |= (NBD_FLAG_SEND_TRIM | NBD_FLAG_SEND_WRITE_ZEROES | NBD_FLAG_SEND_FAST_ZERO); diff --git a/qapi/block-export.json b/qapi/block-export.json index 1de16d2589..7776248435 100644 --- a/qapi/block-export.json +++ b/qapi/block-export.json @@ -22,7 +22,9 @@ # recreated on the fly while the NBD server is active. # If missing, it will default to denying access (since 4.0). # @max-connections: The maximum number of connections to allow at the same -# time, 0 for unlimited. (since 5.2; default: 0) +# time, 0 for unlimited. Setting this to 1 also stops +# the server from advertising multiple client support +# (since 5.2; default: 0) # # Since: 4.2 ## @@ -51,7 +53,9 @@ # recreated on the fly while the NBD server is active. # If missing, it will default to denying access (since 4.0). # @max-connections: The maximum number of connections to allow at the same -# time, 0 for unlimited. (since 5.2; default: 0) +# time, 0 for unlimited. Setting this to 1 also stops +# the server from advertising multiple client support +# (since 5.2; default: 0). # # Returns: error if the server is already running. # diff --git a/tests/qemu-iotests/tests/nbd-multiconn b/tests/qemu-iotests/tests/nbd-multiconn new file mode 100755 index 0000000000..b121f2e363 --- /dev/null +++ b/tests/qemu-iotests/tests/nbd-multiconn @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 +# group: rw auto quick +# +# Test cases for NBD multi-conn advertisement +# +# Copyright (C) 2022 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import os +from contextlib import contextmanager +import iotests +from iotests import qemu_img_create, qemu_io + + +disk = os.path.join(iotests.test_dir, 'disk') +size = '4M' +nbd_sock = os.path.join(iotests.sock_dir, 'nbd_sock') +nbd_uri = 'nbd+unix:///{}?socket=' + nbd_sock + + +@contextmanager +def open_nbd(export_name): + h = nbd.NBD() + try: + h.connect_uri(nbd_uri.format(export_name)) + yield h + finally: + h.shutdown() + +class TestNbdMulticonn(iotests.QMPTestCase): + def setUp(self): + qemu_img_create('-f', iotests.imgfmt, disk, size) + qemu_io('-c', 'w -P 1 0 2M', '-c', 'w -P 2 2M 2M', disk) + + self.vm = iotests.VM() + self.vm.launch() + result = self.vm.qmp('blockdev-add', { + 'driver': 'qcow2', + 'node-name': 'n', + 'file': {'driver': 'file', 'filename': disk} + }) + self.assert_qmp(result, 'return', {}) + + def tearDown(self): + self.vm.shutdown() + os.remove(disk) + try: + os.remove(nbd_sock) + except OSError: + pass + + @contextmanager + def run_server(self, max_connections=None): + args = { + 'addr': { + 'type': 'unix', + 'data': {'path': nbd_sock} + } + } + if max_connections is not None: + args['max-connections'] = max_connections + + result = self.vm.qmp('nbd-server-start', args) + self.assert_qmp(result, 'return', {}) + yield + + result = self.vm.qmp('nbd-server-stop') + self.assert_qmp(result, 'return', {}) + + def add_export(self, name, writable=None): + args = { + 'type': 'nbd', + 'id': name, + 'node-name': 'n', + 'name': name, + } + if writable is not None: + args['writable'] = writable + + result = self.vm.qmp('block-export-add', args) + self.assert_qmp(result, 'return', {}) + + def test_default_settings(self): + with self.run_server(): + self.add_export('r') + self.add_export('w', writable=True) + with open_nbd('r') as h: + self.assertTrue(h.can_multi_conn()) + with open_nbd('w') as h: + self.assertTrue(h.can_multi_conn()) + + def test_limited_connections(self): + with self.run_server(max_connections=1): + self.add_export('r') + self.add_export('w', writable=True) + with open_nbd('r') as h: + self.assertFalse(h.can_multi_conn()) + with open_nbd('w') as h: + self.assertFalse(h.can_multi_conn()) + + def test_parallel_writes(self): + with self.run_server(): + self.add_export('w', writable=True) + + clients = [nbd.NBD() for _ in range(3)] + for c in clients: + c.connect_uri(nbd_uri.format('w')) + self.assertTrue(c.can_multi_conn()) + + initial_data = clients[0].pread(1024 * 1024, 0) + self.assertEqual(initial_data, b'\x01' * 1024 * 1024) + + updated_data = b'\x03' * 1024 * 1024 + clients[1].pwrite(updated_data, 0) + clients[2].flush() + current_data = clients[0].pread(1024 * 1024, 0) + + self.assertEqual(updated_data, current_data) + + for i in range(3): + clients[i].shutdown() + + +if __name__ == '__main__': + try: + # Easier to use libnbd than to try and set up parallel + # 'qemu-nbd --list' or 'qemu-io' processes, but not all systems + # have libnbd installed. + import nbd # type: ignore + + iotests.main(supported_fmts=['qcow2']) + except ImportError: + iotests.notrun('libnbd not installed') diff --git a/tests/qemu-iotests/tests/nbd-multiconn.out b/tests/qemu-iotests/tests/nbd-multiconn.out new file mode 100644 index 0000000000..8d7e996700 --- /dev/null +++ b/tests/qemu-iotests/tests/nbd-multiconn.out @@ -0,0 +1,5 @@ +... +---------------------------------------------------------------------- +Ran 3 tests + +OK diff --git a/tests/qemu-iotests/tests/nbd-qemu-allocation.out b/tests/qemu-iotests/tests/nbd-qemu-allocation.out index 0bf1abb063..9d938db24e 100644 --- a/tests/qemu-iotests/tests/nbd-qemu-allocation.out +++ b/tests/qemu-iotests/tests/nbd-qemu-allocation.out @@ -17,7 +17,7 @@ wrote 2097152/2097152 bytes at offset 1048576 exports available: 1 export: '' size: 4194304 - flags: 0x58f ( readonly flush fua df multi cache ) + flags: 0x48f ( readonly flush fua df cache ) min block: 1 opt block: 4096 max block: 33554432 From 7adb75d6be0b11ace0fabfb8cddc890243773782 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 11 May 2022 13:50:43 -0400 Subject: [PATCH 265/935] vl: make machine type deprecation a warning error_report should generally be followed by a failure; if we can proceed anyway, that is just a warning and should be communicated properly to the user with warn_report. Reviewed-by: Markus Armbruster Message-Id: <20220511175043.27327-1-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- softmmu/vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/softmmu/vl.c b/softmmu/vl.c index edba74f075..817d515783 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -3631,7 +3631,7 @@ void qemu_init(int argc, char **argv, char **envp) machine_class = MACHINE_GET_CLASS(current_machine); if (!qtest_enabled() && machine_class->deprecation_reason) { - error_report("Machine type '%s' is deprecated: %s", + warn_report("Machine type '%s' is deprecated: %s", machine_class->name, machine_class->deprecation_reason); } From 333dbac358acc6cc174029263d633a22f66584b4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 11 May 2022 18:39:12 +0200 Subject: [PATCH 266/935] vmxcap: add tertiary execution controls Signed-off-by: Paolo Bonzini --- scripts/kvm/vmxcap | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/scripts/kvm/vmxcap b/scripts/kvm/vmxcap index f140040104..ce27f5e635 100755 --- a/scripts/kvm/vmxcap +++ b/scripts/kvm/vmxcap @@ -23,6 +23,7 @@ MSR_IA32_VMX_TRUE_PROCBASED_CTLS = 0x48E MSR_IA32_VMX_TRUE_EXIT_CTLS = 0x48F MSR_IA32_VMX_TRUE_ENTRY_CTLS = 0x490 MSR_IA32_VMX_VMFUNC = 0x491 +MSR_IA32_VMX_PROCBASED_CTLS3 = 0x492 class msr(object): def __init__(self): @@ -71,6 +72,13 @@ class Control(object): s = 'yes' print(' %-40s %s' % (self.bits[bit], s)) +# All 64 bits in the tertiary controls MSR are allowed-1 +class Allowed1Control(Control): + def read2(self, nr): + m = msr() + val = m.read(nr, 0) + return (0, val) + class Misc(object): def __init__(self, name, bits, msr): self.name = name @@ -135,6 +143,7 @@ controls = [ 12: 'RDTSC exiting', 15: 'CR3-load exiting', 16: 'CR3-store exiting', + 17: 'Activate tertiary controls', 19: 'CR8-load exiting', 20: 'CR8-store exiting', 21: 'Use TPR shadow', @@ -186,6 +195,14 @@ controls = [ cap_msr = MSR_IA32_VMX_PROCBASED_CTLS2, ), + Allowed1Control( + name = 'tertiary processor-based controls', + bits = { + 4: 'Enable IPI virtualization' + }, + cap_msr = MSR_IA32_VMX_PROCBASED_CTLS3, + ), + Control( name = 'VM-Exit controls', bits = { From f70625299ecc9ba577c87f3d1d75012c747c7d88 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 5 May 2022 11:47:23 +0200 Subject: [PATCH 267/935] qemu-iotests: inline common.config into common.rc common.rc has some complicated logic to find the common.config that dates back to xfstests and is completely unnecessary now. Just include the contents of the file. Signed-off-by: Paolo Bonzini Message-Id: <20220505094723.732116-1-pbonzini@redhat.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/common.config | 41 -------------------------------- tests/qemu-iotests/common.rc | 31 ++++++++++++++---------- 2 files changed, 19 insertions(+), 53 deletions(-) delete mode 100644 tests/qemu-iotests/common.config diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config deleted file mode 100644 index 9bd1a5a6fc..0000000000 --- a/tests/qemu-iotests/common.config +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright (C) 2009 Red Hat, Inc. -# Copyright (c) 2000-2003,2006 Silicon Graphics, Inc. All Rights Reserved. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it would be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# all tests should use a common language setting to prevent golden -# output mismatches. -export LANG=C - -PATH=".:$PATH" - -HOSTOS=$(uname -s) -arch=$(uname -m) -[[ "$arch" =~ "ppc64" ]] && qemu_arch=ppc64 || qemu_arch="$arch" - -# make sure we have a standard umask -umask 022 - -_optstr_add() -{ - if [ -n "$1" ]; then - echo "$1,$2" - else - echo "$2" - fi -} - -# make sure this script returns success -true diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 227e0a5be9..165b54a61e 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -17,6 +17,17 @@ # along with this program. If not, see . # +export LANG=C + +PATH=".:$PATH" + +HOSTOS=$(uname -s) +arch=$(uname -m) +[[ "$arch" =~ "ppc64" ]] && qemu_arch=ppc64 || qemu_arch="$arch" + +# make sure we have a standard umask +umask 022 + # bail out, setting up .notrun file _notrun() { @@ -120,18 +131,14 @@ peek_file_raw() dd if="$1" bs=1 skip="$2" count="$3" status=none } -config=common.config -test -f $config || config=../common.config -if ! test -f $config -then - echo "$0: failed to find common.config" - exit 1 -fi -if ! . $config - then - echo "$0: failed to source common.config" - exit 1 -fi +_optstr_add() +{ + if [ -n "$1" ]; then + echo "$1,$2" + else + echo "$2" + fi +} # Set the variables to the empty string to turn Valgrind off # for specific processes, e.g. From 06134e2bc35dc21543d4cbcf31f858c03d383442 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Mon, 7 Mar 2022 12:29:39 +0100 Subject: [PATCH 268/935] virtio: fix feature negotiation for ACCESS_PLATFORM Unlike most virtio features ACCESS_PLATFORM is considered mandatory by QEMU, i.e. the driver must accept it if offered by the device. The virtio specification says that the driver SHOULD accept the ACCESS_PLATFORM feature if offered, and that the device MAY fail to operate if ACCESS_PLATFORM was offered but not negotiated. While a SHOULD ain't exactly a MUST, we are certainly allowed to fail the device when the driver fences ACCESS_PLATFORM. With commit 2943b53f68 ("virtio: force VIRTIO_F_IOMMU_PLATFORM") we already made the decision to do so whenever the get_dma_as() callback is implemented (by the bus), which in practice means for the entirety of virtio-pci. That means, if the device needs to translate I/O addresses, then ACCESS_PLATFORM is mandatory. The aforementioned commit tells us in the commit message that this is for security reasons. More precisely if we were to allow a less then trusted driver (e.g. an user-space driver, or a nested guest) to make the device bypass the IOMMU by not negotiating ACCESS_PLATFORM, then the guest kernel would have no ability to control/police (by programming the IOMMU) what pieces of guest memory the driver may manipulate using the device. Which would break security assumptions within the guest. If ACCESS_PLATFORM is offered not because we want the device to utilize an IOMMU and do address translation, but because the device does not have access to the entire guest RAM, and needs the driver to grant access to the bits it needs access to (e.g. confidential guest support), we still require the guest to have the corresponding logic and to accept ACCESS_PLATFORM. If the driver does not accept ACCESS_PLATFORM, then things are bound to go wrong, and we may see failures much less graceful than failing the device because the driver didn't negotiate ACCESS_PLATFORM. So let us make ACCESS_PLATFORM mandatory for the driver regardless of whether the get_dma_as() callback is implemented or not. Signed-off-by: Halil Pasic Fixes: 2943b53f68 ("virtio: force VIRTIO_F_IOMMU_PLATFORM") Message-Id: <20220307112939.2780117-1-pasic@linux.ibm.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Cornelia Huck --- hw/virtio/virtio-bus.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c index 0f69d1c742..d7ec023adf 100644 --- a/hw/virtio/virtio-bus.c +++ b/hw/virtio/virtio-bus.c @@ -78,17 +78,23 @@ void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp) return; } - vdev_has_iommu = virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); - if (klass->get_dma_as != NULL && has_iommu) { + vdev->dma_as = &address_space_memory; + if (has_iommu) { + vdev_has_iommu = virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); + /* + * Present IOMMU_PLATFORM to the driver iff iommu_plattform=on and + * device operational. If the driver does not accept IOMMU_PLATFORM + * we fail the device. + */ virtio_add_feature(&vdev->host_features, VIRTIO_F_IOMMU_PLATFORM); - vdev->dma_as = klass->get_dma_as(qbus->parent); - if (!vdev_has_iommu && vdev->dma_as != &address_space_memory) { - error_setg(errp, + if (klass->get_dma_as) { + vdev->dma_as = klass->get_dma_as(qbus->parent); + if (!vdev_has_iommu && vdev->dma_as != &address_space_memory) { + error_setg(errp, "iommu_platform=true is not supported by the device"); - return; + return; + } } - } else { - vdev->dma_as = &address_space_memory; } } From 250227f4fa4efd6032da6c39d8fb2e6c9192d6ce Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 1 Apr 2022 10:28:24 +0800 Subject: [PATCH 269/935] intel-iommu: correct the value used for error_setg_errno() error_setg_errno() expects a normal errno value, not a negated one, so we should use ENOTSUP instead of -ENOSUP. Fixes: Coverity CID 1487174 Fixes: ("intel_iommu: support snoop control") Signed-off-by: Jason Wang Message-Id: <20220401022824.9337-1-jasowang@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Peter Maydell Reviewed-by: Peter Xu --- hw/i386/intel_iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index c64aa81a83..e05d69a2c0 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3032,7 +3032,7 @@ static int vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu, /* TODO: add support for VFIO and vhost users */ if (s->snoop_control) { - error_setg_errno(errp, -ENOTSUP, + error_setg_errno(errp, ENOTSUP, "Snoop Control with vhost or VFIO is not supported"); return -ENOTSUP; } From cf04aba2a9d276336c45d2434f94458838a01034 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:26 +0100 Subject: [PATCH 270/935] hw/pci/cxl: Add a CXL component type (interface) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A CXL component is a hardware entity that implements CXL component registers from the CXL 2.0 spec (8.2.3). Currently these represent 3 general types. 1. Host Bridge 2. Ports (root, upstream, downstream) 3. Devices (memory, other) A CXL component can be conceptually thought of as a PCIe device with extra functionality when enumerated and enabled. For this reason, CXL does here, and will continue to add on to existing PCI code paths. Host bridges will typically need to be handled specially and so they can implement this newly introduced interface or not. All other components should implement this interface. Implementing this interface allows the core PCI code to treat these devices as special where appropriate. Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Reviewed-by: Adam Manzanares Message-Id: <20220429144110.25167-2-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 10 ++++++++++ include/hw/pci/pci.h | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 9c58f02853..eb884adef9 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -200,6 +200,11 @@ static const TypeInfo pci_bus_info = { .class_init = pci_bus_class_init, }; +static const TypeInfo cxl_interface_info = { + .name = INTERFACE_CXL_DEVICE, + .parent = TYPE_INTERFACE, +}; + static const TypeInfo pcie_interface_info = { .name = INTERFACE_PCIE_DEVICE, .parent = TYPE_INTERFACE, @@ -2182,6 +2187,10 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp) pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; } + if (object_class_dynamic_cast(klass, INTERFACE_CXL_DEVICE)) { + pci_dev->cap_present |= QEMU_PCIE_CAP_CXL; + } + pci_dev = do_pci_register_device(pci_dev, object_get_typename(OBJECT(qdev)), pci_dev->devfn, errp); @@ -2938,6 +2947,7 @@ static void pci_register_types(void) type_register_static(&pci_bus_info); type_register_static(&pcie_bus_info); type_register_static(&conventional_pci_interface_info); + type_register_static(&cxl_interface_info); type_register_static(&pcie_interface_info); type_register_static(&pci_device_type_info); } diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 3a32b8dd40..98f0d1b844 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -194,6 +194,8 @@ enum { QEMU_PCIE_LNKSTA_DLLLA = (1 << QEMU_PCIE_LNKSTA_DLLLA_BITNR), #define QEMU_PCIE_EXTCAP_INIT_BITNR 9 QEMU_PCIE_EXTCAP_INIT = (1 << QEMU_PCIE_EXTCAP_INIT_BITNR), +#define QEMU_PCIE_CXL_BITNR 10 + QEMU_PCIE_CAP_CXL = (1 << QEMU_PCIE_CXL_BITNR), }; #define TYPE_PCI_DEVICE "pci-device" @@ -201,6 +203,12 @@ typedef struct PCIDeviceClass PCIDeviceClass; DECLARE_OBJ_CHECKERS(PCIDevice, PCIDeviceClass, PCI_DEVICE, TYPE_PCI_DEVICE) +/* + * Implemented by devices that can be plugged on CXL buses. In the spec, this is + * actually a "CXL Component, but we name it device to match the PCI naming. + */ +#define INTERFACE_CXL_DEVICE "cxl-device" + /* Implemented by devices that can be plugged on PCI Express buses */ #define INTERFACE_PCIE_DEVICE "pci-express-device" From 9e58f52d3f809712762bef735a02290fd4436b0c Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:27 +0100 Subject: [PATCH 271/935] hw/cxl/component: Introduce CXL components (8.1.x, 8.2.5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A CXL 2.0 component is any entity in the CXL topology. All components have a analogous function in PCIe. Except for the CXL host bridge, all have a PCIe config space that is accessible via the common PCIe mechanisms. CXL components are enumerated via DVSEC fields in the extended PCIe header space. CXL components will minimally implement some subset of CXL.mem and CXL.cache registers defined in 8.2.5 of the CXL 2.0 specification. Two headers and a utility library are introduced to support the minimum functionality needed to enumerate components. The cxl_pci header manages bits associated with PCI, specifically the DVSEC and related fields. The cxl_component.h variant has data structures and APIs that are useful for drivers implementing any of the CXL 2.0 components. The library takes care of making use of the DVSEC bits and the CXL.[mem|cache] registers. Per spec, the registers are little endian. None of the mechanisms required to enumerate a CXL capable hostbridge are introduced at this point. Note that the CXL.mem and CXL.cache registers used are always 4B wide. It's possible in the future that this constraint will not hold. Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Reviewed-by: Adam Manzanares Message-Id: <20220429144110.25167-3-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/Kconfig | 1 + hw/cxl/Kconfig | 3 + hw/cxl/cxl-component-utils.c | 313 +++++++++++++++++++++++++++++++++ hw/cxl/meson.build | 4 + hw/meson.build | 1 + include/hw/cxl/cxl.h | 16 ++ include/hw/cxl/cxl_component.h | 213 ++++++++++++++++++++++ include/hw/cxl/cxl_pci.h | 146 +++++++++++++++ 8 files changed, 697 insertions(+) create mode 100644 hw/cxl/Kconfig create mode 100644 hw/cxl/cxl-component-utils.c create mode 100644 hw/cxl/meson.build create mode 100644 include/hw/cxl/cxl.h create mode 100644 include/hw/cxl/cxl_component.h create mode 100644 include/hw/cxl/cxl_pci.h diff --git a/hw/Kconfig b/hw/Kconfig index ad20cce0a9..50e0952889 100644 --- a/hw/Kconfig +++ b/hw/Kconfig @@ -6,6 +6,7 @@ source audio/Kconfig source block/Kconfig source char/Kconfig source core/Kconfig +source cxl/Kconfig source display/Kconfig source dma/Kconfig source gpio/Kconfig diff --git a/hw/cxl/Kconfig b/hw/cxl/Kconfig new file mode 100644 index 0000000000..8e67519b16 --- /dev/null +++ b/hw/cxl/Kconfig @@ -0,0 +1,3 @@ +config CXL + bool + default y if PCI_EXPRESS diff --git a/hw/cxl/cxl-component-utils.c b/hw/cxl/cxl-component-utils.c new file mode 100644 index 0000000000..9457a1b029 --- /dev/null +++ b/hw/cxl/cxl-component-utils.c @@ -0,0 +1,313 @@ +/* + * CXL Utility library for components + * + * Copyright(C) 2020 Intel Corporation. + * + * This work is licensed under the terms of the GNU GPL, version 2. See the + * COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/pci/pci.h" +#include "hw/cxl/cxl.h" + +static uint64_t cxl_cache_mem_read_reg(void *opaque, hwaddr offset, + unsigned size) +{ + CXLComponentState *cxl_cstate = opaque; + ComponentRegisters *cregs = &cxl_cstate->crb; + + if (size == 8) { + qemu_log_mask(LOG_UNIMP, + "CXL 8 byte cache mem registers not implemented\n"); + return 0; + } + + if (cregs->special_ops && cregs->special_ops->read) { + return cregs->special_ops->read(cxl_cstate, offset, size); + } else { + return cregs->cache_mem_registers[offset / sizeof(*cregs->cache_mem_registers)]; + } +} + +static void cxl_cache_mem_write_reg(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + CXLComponentState *cxl_cstate = opaque; + ComponentRegisters *cregs = &cxl_cstate->crb; + uint32_t mask; + + if (size == 8) { + qemu_log_mask(LOG_UNIMP, + "CXL 8 byte cache mem registers not implemented\n"); + return; + } + mask = cregs->cache_mem_regs_write_mask[offset / sizeof(*cregs->cache_mem_regs_write_mask)]; + value &= mask; + /* RO bits should remain constant. Done by reading existing value */ + value |= ~mask & cregs->cache_mem_registers[offset / sizeof(*cregs->cache_mem_registers)]; + if (cregs->special_ops && cregs->special_ops->write) { + cregs->special_ops->write(cxl_cstate, offset, value, size); + } else { + cregs->cache_mem_registers[offset / sizeof(*cregs->cache_mem_registers)] = value; + } +} + +/* + * 8.2.3 + * The access restrictions specified in Section 8.2.2 also apply to CXL 2.0 + * Component Registers. + * + * 8.2.2 + * • A 32 bit register shall be accessed as a 4 Bytes quantity. Partial + * reads are not permitted. + * • A 64 bit register shall be accessed as a 8 Bytes quantity. Partial + * reads are not permitted. + * + * As of the spec defined today, only 4 byte registers exist. + */ +static const MemoryRegionOps cache_mem_ops = { + .read = cxl_cache_mem_read_reg, + .write = cxl_cache_mem_write_reg, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + .unaligned = false, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 8, + }, +}; + +void cxl_component_register_block_init(Object *obj, + CXLComponentState *cxl_cstate, + const char *type) +{ + ComponentRegisters *cregs = &cxl_cstate->crb; + + memory_region_init(&cregs->component_registers, obj, type, + CXL2_COMPONENT_BLOCK_SIZE); + + /* io registers controls link which we don't care about in QEMU */ + memory_region_init_io(&cregs->io, obj, NULL, cregs, ".io", + CXL2_COMPONENT_IO_REGION_SIZE); + memory_region_init_io(&cregs->cache_mem, obj, &cache_mem_ops, cregs, + ".cache_mem", CXL2_COMPONENT_CM_REGION_SIZE); + + memory_region_add_subregion(&cregs->component_registers, 0, &cregs->io); + memory_region_add_subregion(&cregs->component_registers, + CXL2_COMPONENT_IO_REGION_SIZE, + &cregs->cache_mem); +} + +static void ras_init_common(uint32_t *reg_state, uint32_t *write_msk) +{ + /* + * Error status is RW1C but given bits are not yet set, it can + * be handled as RO. + */ + reg_state[R_CXL_RAS_UNC_ERR_STATUS] = 0; + /* Bits 12-13 and 17-31 reserved in CXL 2.0 */ + reg_state[R_CXL_RAS_UNC_ERR_MASK] = 0x1cfff; + write_msk[R_CXL_RAS_UNC_ERR_MASK] = 0x1cfff; + reg_state[R_CXL_RAS_UNC_ERR_SEVERITY] = 0x1cfff; + write_msk[R_CXL_RAS_UNC_ERR_SEVERITY] = 0x1cfff; + reg_state[R_CXL_RAS_COR_ERR_STATUS] = 0; + reg_state[R_CXL_RAS_COR_ERR_MASK] = 0x7f; + write_msk[R_CXL_RAS_COR_ERR_MASK] = 0x7f; + /* CXL switches and devices must set */ + reg_state[R_CXL_RAS_ERR_CAP_CTRL] = 0x00; +} + +static void hdm_init_common(uint32_t *reg_state, uint32_t *write_msk) +{ + int decoder_count = 1; + int i; + + ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, DECODER_COUNT, + cxl_decoder_count_enc(decoder_count)); + ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, TARGET_COUNT, 1); + ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, INTERLEAVE_256B, 1); + ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, INTERLEAVE_4K, 1); + ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, POISON_ON_ERR_CAP, 0); + ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_GLOBAL_CONTROL, + HDM_DECODER_ENABLE, 0); + write_msk[R_CXL_HDM_DECODER_GLOBAL_CONTROL] = 0x3; + for (i = 0; i < decoder_count; i++) { + write_msk[R_CXL_HDM_DECODER0_BASE_LO + i * 0x20] = 0xf0000000; + write_msk[R_CXL_HDM_DECODER0_BASE_HI + i * 0x20] = 0xffffffff; + write_msk[R_CXL_HDM_DECODER0_SIZE_LO + i * 0x20] = 0xf0000000; + write_msk[R_CXL_HDM_DECODER0_SIZE_HI + i * 0x20] = 0xffffffff; + write_msk[R_CXL_HDM_DECODER0_CTRL + i * 0x20] = 0x13ff; + } +} + +void cxl_component_register_init_common(uint32_t *reg_state, uint32_t *write_msk, + enum reg_type type) +{ + int caps = 0; + + /* + * In CXL 2.0 the capabilities required for each CXL component are such that, + * with the ordering chosen here, a single number can be used to define + * which capabilities should be provided. + */ + switch (type) { + case CXL2_DOWNSTREAM_PORT: + case CXL2_DEVICE: + /* RAS, Link */ + caps = 2; + break; + case CXL2_UPSTREAM_PORT: + case CXL2_TYPE3_DEVICE: + case CXL2_LOGICAL_DEVICE: + /* + HDM */ + caps = 3; + break; + case CXL2_ROOT_PORT: + /* + Extended Security, + Snoop */ + caps = 5; + break; + default: + abort(); + } + + memset(reg_state, 0, CXL2_COMPONENT_CM_REGION_SIZE); + + /* CXL Capability Header Register */ + ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, ID, 1); + ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, VERSION, 1); + ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, CACHE_MEM_VERSION, 1); + ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, ARRAY_SIZE, caps); + +#define init_cap_reg(reg, id, version) \ + QEMU_BUILD_BUG_ON(CXL_##reg##_REGISTERS_OFFSET == 0); \ + do { \ + int which = R_CXL_##reg##_CAPABILITY_HEADER; \ + reg_state[which] = FIELD_DP32(reg_state[which], \ + CXL_##reg##_CAPABILITY_HEADER, ID, id); \ + reg_state[which] = \ + FIELD_DP32(reg_state[which], CXL_##reg##_CAPABILITY_HEADER, \ + VERSION, version); \ + reg_state[which] = \ + FIELD_DP32(reg_state[which], CXL_##reg##_CAPABILITY_HEADER, PTR, \ + CXL_##reg##_REGISTERS_OFFSET); \ + } while (0) + + init_cap_reg(RAS, 2, 2); + ras_init_common(reg_state, write_msk); + + init_cap_reg(LINK, 4, 2); + + if (caps < 3) { + return; + } + + init_cap_reg(HDM, 5, 1); + hdm_init_common(reg_state, write_msk); + + if (caps < 5) { + return; + } + + init_cap_reg(EXTSEC, 6, 1); + init_cap_reg(SNOOP, 8, 1); + +#undef init_cap_reg +} + +/* + * Helper to creates a DVSEC header for a CXL entity. The caller is responsible + * for tracking the valid offset. + * + * This function will build the DVSEC header on behalf of the caller and then + * copy in the remaining data for the vendor specific bits. + * It will also set up appropriate write masks. + */ +void cxl_component_create_dvsec(CXLComponentState *cxl, + enum reg_type cxl_dev_type, uint16_t length, + uint16_t type, uint8_t rev, uint8_t *body) +{ + PCIDevice *pdev = cxl->pdev; + uint16_t offset = cxl->dvsec_offset; + uint8_t *wmask = pdev->wmask; + + assert(offset >= PCI_CFG_SPACE_SIZE && + ((offset + length) < PCI_CFG_SPACE_EXP_SIZE)); + assert((length & 0xf000) == 0); + assert((rev & ~0xf) == 0); + + /* Create the DVSEC in the MCFG space */ + pcie_add_capability(pdev, PCI_EXT_CAP_ID_DVSEC, 1, offset, length); + pci_set_long(pdev->config + offset + PCIE_DVSEC_HEADER1_OFFSET, + (length << 20) | (rev << 16) | CXL_VENDOR_ID); + pci_set_word(pdev->config + offset + PCIE_DVSEC_ID_OFFSET, type); + memcpy(pdev->config + offset + sizeof(DVSECHeader), + body + sizeof(DVSECHeader), + length - sizeof(DVSECHeader)); + + /* Configure write masks */ + switch (type) { + case PCIE_CXL_DEVICE_DVSEC: + break; + case NON_CXL_FUNCTION_MAP_DVSEC: + break; /* Not yet implemented */ + case EXTENSIONS_PORT_DVSEC: + wmask[offset + offsetof(CXLDVSECPortExtensions, control)] = 0x0F; + wmask[offset + offsetof(CXLDVSECPortExtensions, control) + 1] = 0x40; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_bus_base)] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_bus_limit)] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_memory_base)] = 0xF0; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_memory_base) + 1] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_memory_limit)] = 0xF0; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_memory_limit) + 1] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base)] = 0xF0; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base) + 1] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit)] = 0xF0; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit) + 1] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base_high)] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base_high) + 1] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base_high) + 2] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base_high) + 3] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit_high)] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit_high) + 1] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit_high) + 2] = 0xFF; + wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit_high) + 3] = 0xFF; + break; + case GPF_PORT_DVSEC: + wmask[offset + offsetof(CXLDVSECPortGPF, phase1_ctrl)] = 0x0F; + wmask[offset + offsetof(CXLDVSECPortGPF, phase1_ctrl) + 1] = 0x0F; + wmask[offset + offsetof(CXLDVSECPortGPF, phase2_ctrl)] = 0x0F; + wmask[offset + offsetof(CXLDVSECPortGPF, phase2_ctrl) + 1] = 0x0F; + break; + case GPF_DEVICE_DVSEC: + wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_duration)] = 0x0F; + wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_duration) + 1] = 0x0F; + wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power)] = 0xFF; + wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power) + 1] = 0xFF; + wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power) + 2] = 0xFF; + wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power) + 3] = 0xFF; + break; + case PCIE_FLEXBUS_PORT_DVSEC: + switch (cxl_dev_type) { + case CXL2_ROOT_PORT: + /* No MLD */ + wmask[offset + offsetof(CXLDVSECPortFlexBus, ctrl)] = 0xbd; + break; + case CXL2_DOWNSTREAM_PORT: + wmask[offset + offsetof(CXLDVSECPortFlexBus, ctrl)] = 0xfd; + break; + default: /* Registers are RO for other component types */ + break; + } + /* There are rw1cs bits in the status register but never set currently */ + break; + } + + /* Update state for future DVSEC additions */ + range_init_nofail(&cxl->dvsecs[type], cxl->dvsec_offset, length); + cxl->dvsec_offset += length; +} diff --git a/hw/cxl/meson.build b/hw/cxl/meson.build new file mode 100644 index 0000000000..3231b5de1e --- /dev/null +++ b/hw/cxl/meson.build @@ -0,0 +1,4 @@ +softmmu_ss.add(when: 'CONFIG_CXL', + if_true: files( + 'cxl-component-utils.c', + )) diff --git a/hw/meson.build b/hw/meson.build index b3366c888e..9992c5101e 100644 --- a/hw/meson.build +++ b/hw/meson.build @@ -6,6 +6,7 @@ subdir('block') subdir('char') subdir('core') subdir('cpu') +subdir('cxl') subdir('display') subdir('dma') subdir('gpio') diff --git a/include/hw/cxl/cxl.h b/include/hw/cxl/cxl.h new file mode 100644 index 0000000000..8c738c7a2b --- /dev/null +++ b/include/hw/cxl/cxl.h @@ -0,0 +1,16 @@ +/* + * QEMU CXL Support + * + * Copyright (c) 2020 Intel + * + * This work is licensed under the terms of the GNU GPL, version 2. See the + * COPYING file in the top-level directory. + */ + +#ifndef CXL_H +#define CXL_H + +#include "cxl_pci.h" +#include "cxl_component.h" + +#endif diff --git a/include/hw/cxl/cxl_component.h b/include/hw/cxl/cxl_component.h new file mode 100644 index 0000000000..7d8f395cbe --- /dev/null +++ b/include/hw/cxl/cxl_component.h @@ -0,0 +1,213 @@ +/* + * QEMU CXL Component + * + * Copyright (c) 2020 Intel + * + * This work is licensed under the terms of the GNU GPL, version 2. See the + * COPYING file in the top-level directory. + */ + +#ifndef CXL_COMPONENT_H +#define CXL_COMPONENT_H + +/* CXL 2.0 - 8.2.4 */ +#define CXL2_COMPONENT_IO_REGION_SIZE 0x1000 +#define CXL2_COMPONENT_CM_REGION_SIZE 0x1000 +#define CXL2_COMPONENT_BLOCK_SIZE 0x10000 + +#include "qemu/compiler.h" +#include "qemu/range.h" +#include "qemu/typedefs.h" +#include "hw/register.h" + +enum reg_type { + CXL2_DEVICE, + CXL2_TYPE3_DEVICE, + CXL2_LOGICAL_DEVICE, + CXL2_ROOT_PORT, + CXL2_UPSTREAM_PORT, + CXL2_DOWNSTREAM_PORT +}; + +/* + * Capability registers are defined at the top of the CXL.cache/mem region and + * are packed. For our purposes we will always define the caps in the same + * order. + * CXL 2.0 - 8.2.5 Table 142 for details. + */ + +/* CXL 2.0 - 8.2.5.1 */ +REG32(CXL_CAPABILITY_HEADER, 0) + FIELD(CXL_CAPABILITY_HEADER, ID, 0, 16) + FIELD(CXL_CAPABILITY_HEADER, VERSION, 16, 4) + FIELD(CXL_CAPABILITY_HEADER, CACHE_MEM_VERSION, 20, 4) + FIELD(CXL_CAPABILITY_HEADER, ARRAY_SIZE, 24, 8) + +#define CXLx_CAPABILITY_HEADER(type, offset) \ + REG32(CXL_##type##_CAPABILITY_HEADER, offset) \ + FIELD(CXL_##type##_CAPABILITY_HEADER, ID, 0, 16) \ + FIELD(CXL_##type##_CAPABILITY_HEADER, VERSION, 16, 4) \ + FIELD(CXL_##type##_CAPABILITY_HEADER, PTR, 20, 12) +CXLx_CAPABILITY_HEADER(RAS, 0x4) +CXLx_CAPABILITY_HEADER(LINK, 0x8) +CXLx_CAPABILITY_HEADER(HDM, 0xc) +CXLx_CAPABILITY_HEADER(EXTSEC, 0x10) +CXLx_CAPABILITY_HEADER(SNOOP, 0x14) + +/* + * Capability structures contain the actual registers that the CXL component + * implements. Some of these are specific to certain types of components, but + * this implementation leaves enough space regardless. + */ +/* 8.2.5.9 - CXL RAS Capability Structure */ + +/* Give ample space for caps before this */ +#define CXL_RAS_REGISTERS_OFFSET 0x80 +#define CXL_RAS_REGISTERS_SIZE 0x58 +REG32(CXL_RAS_UNC_ERR_STATUS, CXL_RAS_REGISTERS_OFFSET) +REG32(CXL_RAS_UNC_ERR_MASK, CXL_RAS_REGISTERS_OFFSET + 0x4) +REG32(CXL_RAS_UNC_ERR_SEVERITY, CXL_RAS_REGISTERS_OFFSET + 0x8) +REG32(CXL_RAS_COR_ERR_STATUS, CXL_RAS_REGISTERS_OFFSET + 0xc) +REG32(CXL_RAS_COR_ERR_MASK, CXL_RAS_REGISTERS_OFFSET + 0x10) +REG32(CXL_RAS_ERR_CAP_CTRL, CXL_RAS_REGISTERS_OFFSET + 0x14) +/* Offset 0x18 - 0x58 reserved for RAS logs */ + +/* 8.2.5.10 - CXL Security Capability Structure */ +#define CXL_SEC_REGISTERS_OFFSET \ + (CXL_RAS_REGISTERS_OFFSET + CXL_RAS_REGISTERS_SIZE) +#define CXL_SEC_REGISTERS_SIZE 0 /* We don't implement 1.1 downstream ports */ + +/* 8.2.5.11 - CXL Link Capability Structure */ +#define CXL_LINK_REGISTERS_OFFSET \ + (CXL_SEC_REGISTERS_OFFSET + CXL_SEC_REGISTERS_SIZE) +#define CXL_LINK_REGISTERS_SIZE 0x38 + +/* 8.2.5.12 - CXL HDM Decoder Capability Structure */ +#define HDM_DECODE_MAX 10 /* 8.2.5.12.1 */ +#define CXL_HDM_REGISTERS_OFFSET \ + (CXL_LINK_REGISTERS_OFFSET + CXL_LINK_REGISTERS_SIZE) +#define CXL_HDM_REGISTERS_SIZE (0x10 + 0x20 * HDM_DECODE_MAX) +#define HDM_DECODER_INIT(n) \ + REG32(CXL_HDM_DECODER##n##_BASE_LO, \ + CXL_HDM_REGISTERS_OFFSET + (0x20 * n) + 0x10) \ + FIELD(CXL_HDM_DECODER##n##_BASE_LO, L, 28, 4) \ + REG32(CXL_HDM_DECODER##n##_BASE_HI, \ + CXL_HDM_REGISTERS_OFFSET + (0x20 * n) + 0x14) \ + REG32(CXL_HDM_DECODER##n##_SIZE_LO, \ + CXL_HDM_REGISTERS_OFFSET + (0x20 * n) + 0x18) \ + REG32(CXL_HDM_DECODER##n##_SIZE_HI, \ + CXL_HDM_REGISTERS_OFFSET + (0x20 * n) + 0x1C) \ + REG32(CXL_HDM_DECODER##n##_CTRL, \ + CXL_HDM_REGISTERS_OFFSET + (0x20 * n) + 0x20) \ + FIELD(CXL_HDM_DECODER##n##_CTRL, IG, 0, 4) \ + FIELD(CXL_HDM_DECODER##n##_CTRL, IW, 4, 4) \ + FIELD(CXL_HDM_DECODER##n##_CTRL, LOCK_ON_COMMIT, 8, 1) \ + FIELD(CXL_HDM_DECODER##n##_CTRL, COMMIT, 9, 1) \ + FIELD(CXL_HDM_DECODER##n##_CTRL, COMMITTED, 10, 1) \ + FIELD(CXL_HDM_DECODER##n##_CTRL, ERR, 11, 1) \ + FIELD(CXL_HDM_DECODER##n##_CTRL, TYPE, 12, 1) \ + REG32(CXL_HDM_DECODER##n##_TARGET_LIST_LO, \ + CXL_HDM_REGISTERS_OFFSET + (0x20 * n) + 0x24) \ + REG32(CXL_HDM_DECODER##n##_TARGET_LIST_HI, \ + CXL_HDM_REGISTERS_OFFSET + (0x20 * n) + 0x28) + +REG32(CXL_HDM_DECODER_CAPABILITY, CXL_HDM_REGISTERS_OFFSET) + FIELD(CXL_HDM_DECODER_CAPABILITY, DECODER_COUNT, 0, 4) + FIELD(CXL_HDM_DECODER_CAPABILITY, TARGET_COUNT, 4, 4) + FIELD(CXL_HDM_DECODER_CAPABILITY, INTERLEAVE_256B, 8, 1) + FIELD(CXL_HDM_DECODER_CAPABILITY, INTERLEAVE_4K, 9, 1) + FIELD(CXL_HDM_DECODER_CAPABILITY, POISON_ON_ERR_CAP, 10, 1) +REG32(CXL_HDM_DECODER_GLOBAL_CONTROL, CXL_HDM_REGISTERS_OFFSET + 4) + FIELD(CXL_HDM_DECODER_GLOBAL_CONTROL, POISON_ON_ERR_EN, 0, 1) + FIELD(CXL_HDM_DECODER_GLOBAL_CONTROL, HDM_DECODER_ENABLE, 1, 1) + +HDM_DECODER_INIT(0); + +/* 8.2.5.13 - CXL Extended Security Capability Structure (Root complex only) */ +#define EXTSEC_ENTRY_MAX 256 +#define CXL_EXTSEC_REGISTERS_OFFSET \ + (CXL_HDM_REGISTERS_OFFSET + CXL_HDM_REGISTERS_SIZE) +#define CXL_EXTSEC_REGISTERS_SIZE (8 * EXTSEC_ENTRY_MAX + 4) + +/* 8.2.5.14 - CXL IDE Capability Structure */ +#define CXL_IDE_REGISTERS_OFFSET \ + (CXL_EXTSEC_REGISTERS_OFFSET + CXL_EXTSEC_REGISTERS_SIZE) +#define CXL_IDE_REGISTERS_SIZE 0x20 + +/* 8.2.5.15 - CXL Snoop Filter Capability Structure */ +#define CXL_SNOOP_REGISTERS_OFFSET \ + (CXL_IDE_REGISTERS_OFFSET + CXL_IDE_REGISTERS_SIZE) +#define CXL_SNOOP_REGISTERS_SIZE 0x8 + +QEMU_BUILD_BUG_MSG((CXL_SNOOP_REGISTERS_OFFSET + CXL_SNOOP_REGISTERS_SIZE) >= 0x1000, + "No space for registers"); + +typedef struct component_registers { + /* + * Main memory region to be registered with QEMU core. + */ + MemoryRegion component_registers; + + /* + * 8.2.4 Table 141: + * 0x0000 - 0x0fff CXL.io registers + * 0x1000 - 0x1fff CXL.cache and CXL.mem + * 0x2000 - 0xdfff Implementation specific + * 0xe000 - 0xe3ff CXL ARB/MUX registers + * 0xe400 - 0xffff RSVD + */ + uint32_t io_registers[CXL2_COMPONENT_IO_REGION_SIZE >> 2]; + MemoryRegion io; + + uint32_t cache_mem_registers[CXL2_COMPONENT_CM_REGION_SIZE >> 2]; + uint32_t cache_mem_regs_write_mask[CXL2_COMPONENT_CM_REGION_SIZE >> 2]; + MemoryRegion cache_mem; + + MemoryRegion impl_specific; + MemoryRegion arb_mux; + MemoryRegion rsvd; + + /* special_ops is used for any component that needs any specific handling */ + MemoryRegionOps *special_ops; +} ComponentRegisters; + +/* + * A CXL component represents all entities in a CXL hierarchy. This includes, + * host bridges, root ports, upstream/downstream switch ports, and devices + */ +typedef struct cxl_component { + ComponentRegisters crb; + union { + struct { + Range dvsecs[CXL20_MAX_DVSEC]; + uint16_t dvsec_offset; + struct PCIDevice *pdev; + }; + }; +} CXLComponentState; + +void cxl_component_register_block_init(Object *obj, + CXLComponentState *cxl_cstate, + const char *type); +void cxl_component_register_init_common(uint32_t *reg_state, + uint32_t *write_msk, + enum reg_type type); + +void cxl_component_create_dvsec(CXLComponentState *cxl_cstate, + enum reg_type cxl_dev_type, uint16_t length, + uint16_t type, uint8_t rev, uint8_t *body); + +static inline int cxl_decoder_count_enc(int count) +{ + switch (count) { + case 1: return 0; + case 2: return 1; + case 4: return 2; + case 6: return 3; + case 8: return 4; + case 10: return 5; + } + return 0; +} + +#endif diff --git a/include/hw/cxl/cxl_pci.h b/include/hw/cxl/cxl_pci.h new file mode 100644 index 0000000000..3f7e44daac --- /dev/null +++ b/include/hw/cxl/cxl_pci.h @@ -0,0 +1,146 @@ +/* + * QEMU CXL PCI interfaces + * + * Copyright (c) 2020 Intel + * + * This work is licensed under the terms of the GNU GPL, version 2. See the + * COPYING file in the top-level directory. + */ + +#ifndef CXL_PCI_H +#define CXL_PCI_H + +#include "qemu/compiler.h" +#include "hw/pci/pci.h" +#include "hw/pci/pcie.h" + +#define CXL_VENDOR_ID 0x1e98 + +#define PCIE_DVSEC_HEADER1_OFFSET 0x4 /* Offset from start of extend cap */ +#define PCIE_DVSEC_ID_OFFSET 0x8 + +#define PCIE_CXL_DEVICE_DVSEC_LENGTH 0x38 +#define PCIE_CXL1_DEVICE_DVSEC_REVID 0 +#define PCIE_CXL2_DEVICE_DVSEC_REVID 1 + +#define EXTENSIONS_PORT_DVSEC_LENGTH 0x28 +#define EXTENSIONS_PORT_DVSEC_REVID 0 + +#define GPF_PORT_DVSEC_LENGTH 0x10 +#define GPF_PORT_DVSEC_REVID 0 + +#define GPF_DEVICE_DVSEC_LENGTH 0x10 +#define GPF_DEVICE_DVSEC_REVID 0 + +#define PCIE_FLEXBUS_PORT_DVSEC_LENGTH_2_0 0x14 +#define PCIE_FLEXBUS_PORT_DVSEC_REVID_2_0 1 + +#define REG_LOC_DVSEC_LENGTH 0x24 +#define REG_LOC_DVSEC_REVID 0 + +enum { + PCIE_CXL_DEVICE_DVSEC = 0, + NON_CXL_FUNCTION_MAP_DVSEC = 2, + EXTENSIONS_PORT_DVSEC = 3, + GPF_PORT_DVSEC = 4, + GPF_DEVICE_DVSEC = 5, + PCIE_FLEXBUS_PORT_DVSEC = 7, + REG_LOC_DVSEC = 8, + MLD_DVSEC = 9, + CXL20_MAX_DVSEC +}; + +typedef struct DVSECHeader { + uint32_t cap_hdr; + uint32_t dv_hdr1; + uint16_t dv_hdr2; +} QEMU_PACKED DVSECHeader; +QEMU_BUILD_BUG_ON(sizeof(DVSECHeader) != 10); + +/* + * CXL 2.0 devices must implement certain DVSEC IDs, and can [optionally] + * implement others. + * + * CXL 2.0 Device: 0, [2], 5, 8 + * CXL 2.0 RP: 3, 4, 7, 8 + * CXL 2.0 Upstream Port: [2], 7, 8 + * CXL 2.0 Downstream Port: 3, 4, 7, 8 + */ + +/* CXL 2.0 - 8.1.5 (ID 0003) */ +typedef struct CXLDVSECPortExtensions { + DVSECHeader hdr; + uint16_t status; + uint16_t control; + uint8_t alt_bus_base; + uint8_t alt_bus_limit; + uint16_t alt_memory_base; + uint16_t alt_memory_limit; + uint16_t alt_prefetch_base; + uint16_t alt_prefetch_limit; + uint32_t alt_prefetch_base_high; + uint32_t alt_prefetch_limit_high; + uint32_t rcrb_base; + uint32_t rcrb_base_high; +} CXLDVSECPortExtensions; +QEMU_BUILD_BUG_ON(sizeof(CXLDVSECPortExtensions) != 0x28); + +#define PORT_CONTROL_OFFSET 0xc +#define PORT_CONTROL_UNMASK_SBR 1 +#define PORT_CONTROL_ALT_MEMID_EN 4 + +/* CXL 2.0 - 8.1.6 GPF DVSEC (ID 0004) */ +typedef struct CXLDVSECPortGPF { + DVSECHeader hdr; + uint16_t rsvd; + uint16_t phase1_ctrl; + uint16_t phase2_ctrl; +} CXLDVSECPortGPF; +QEMU_BUILD_BUG_ON(sizeof(CXLDVSECPortGPF) != 0x10); + +/* CXL 2.0 - 8.1.7 GPF DVSEC for CXL Device */ +typedef struct CXLDVSECDeviceGPF { + DVSECHeader hdr; + uint16_t phase2_duration; + uint32_t phase2_power; +} CXLDVSECDeviceGPF; +QEMU_BUILD_BUG_ON(sizeof(CXLDVSECDeviceGPF) != 0x10); + +/* CXL 2.0 - 8.1.8/8.2.1.3 Flex Bus DVSEC (ID 0007) */ +typedef struct CXLDVSECPortFlexBus { + DVSECHeader hdr; + uint16_t cap; + uint16_t ctrl; + uint16_t status; + uint32_t rcvd_mod_ts_data_phase1; +} CXLDVSECPortFlexBus; +QEMU_BUILD_BUG_ON(sizeof(CXLDVSECPortFlexBus) != 0x14); + +/* CXL 2.0 - 8.1.9 Register Locator DVSEC (ID 0008) */ +typedef struct CXLDVSECRegisterLocator { + DVSECHeader hdr; + uint16_t rsvd; + uint32_t reg0_base_lo; + uint32_t reg0_base_hi; + uint32_t reg1_base_lo; + uint32_t reg1_base_hi; + uint32_t reg2_base_lo; + uint32_t reg2_base_hi; +} CXLDVSECRegisterLocator; +QEMU_BUILD_BUG_ON(sizeof(CXLDVSECRegisterLocator) != 0x24); + +/* BAR Equivalence Indicator */ +#define BEI_BAR_10H 0 +#define BEI_BAR_14H 1 +#define BEI_BAR_18H 2 +#define BEI_BAR_1cH 3 +#define BEI_BAR_20H 4 +#define BEI_BAR_24H 5 + +/* Register Block Identifier */ +#define RBI_EMPTY 0 +#define RBI_COMPONENT_REG (1 << 8) +#define RBI_BAR_VIRT_ACL (2 << 8) +#define RBI_CXL_DEVICE_REG (3 << 8) + +#endif From 502730ee3cc3acbf421f07c26a15652f4929e309 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 29 Apr 2022 15:40:28 +0100 Subject: [PATCH 272/935] MAINTAINERS: Add entry for Compute Express Link Emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CXL emulation will be jointly maintained by Ben Widawsky and Jonathan Cameron. Broken out as a separate patch to improve visibility. Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-4-Jonathan.Cameron@huawei.com> --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index fbc0662627..dff0200f70 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2545,6 +2545,13 @@ F: qapi/block*.json F: qapi/transaction.json T: git https://repo.or.cz/qemu/armbru.git block-next +Compute Express Link +M: Ben Widawsky +M: Jonathan Cameron +S: Supported +F: hw/cxl/ +F: include/hw/cxl/ + Dirty Bitmaps M: Eric Blake M: Vladimir Sementsov-Ogievskiy From cd90126b4ced427697d79eb5002544a7621ec647 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:29 +0100 Subject: [PATCH 273/935] hw/cxl/device: Introduce a CXL device (8.2.8) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A CXL device is a type of CXL component. Conceptually, a CXL device would be a leaf node in a CXL topology. From an emulation perspective, CXL devices are the most complex and so the actual implementation is reserved for discrete commits. This new device type is specifically catered towards the eventual implementation of a Type3 CXL.mem device, 8.2.8.5 in the CXL 2.0 specification. Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Reviewed-by: Adam Manzanares Message-Id: <20220429144110.25167-5-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/hw/cxl/cxl.h | 1 + include/hw/cxl/cxl_device.h | 166 ++++++++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 include/hw/cxl/cxl_device.h diff --git a/include/hw/cxl/cxl.h b/include/hw/cxl/cxl.h index 8c738c7a2b..b9d1ac3fad 100644 --- a/include/hw/cxl/cxl.h +++ b/include/hw/cxl/cxl.h @@ -12,5 +12,6 @@ #include "cxl_pci.h" #include "cxl_component.h" +#include "cxl_device.h" #endif diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h new file mode 100644 index 0000000000..9513aaac77 --- /dev/null +++ b/include/hw/cxl/cxl_device.h @@ -0,0 +1,166 @@ +/* + * QEMU CXL Devices + * + * Copyright (c) 2020 Intel + * + * This work is licensed under the terms of the GNU GPL, version 2. See the + * COPYING file in the top-level directory. + */ + +#ifndef CXL_DEVICE_H +#define CXL_DEVICE_H + +#include "hw/register.h" + +/* + * The following is how a CXL device's Memory Device registers are laid out. + * The only requirement from the spec is that the capabilities array and the + * capability headers start at offset 0 and are contiguously packed. The headers + * themselves provide offsets to the register fields. For this emulation, the + * actual registers * will start at offset 0x80 (m == 0x80). No secondary + * mailbox is implemented which means that the offset of the start of the + * mailbox payload (n) is given by + * n = m + sizeof(mailbox registers) + sizeof(device registers). + * + * +---------------------------------+ + * | | + * | Memory Device Registers | + * | | + * n + PAYLOAD_SIZE_MAX ----------------------------------- + * ^ | | + * | | | + * | | | + * | | | + * | | | + * | | Mailbox Payload | + * | | | + * | | | + * | | | + * n ----------------------------------- + * ^ | Mailbox Registers | + * | | | + * | ----------------------------------- + * | | | + * | | Device Registers | + * | | | + * m ----------------------------------> + * ^ | Memory Device Capability Header| + * | ----------------------------------- + * | | Mailbox Capability Header | + * | ----------------------------------- + * | | Device Capability Header | + * | ----------------------------------- + * | | Device Cap Array Register | + * 0 +---------------------------------+ + * + */ + +#define CXL_DEVICE_CAP_HDR1_OFFSET 0x10 /* Figure 138 */ +#define CXL_DEVICE_CAP_REG_SIZE 0x10 /* 8.2.8.2 */ +#define CXL_DEVICE_CAPS_MAX 4 /* 8.2.8.2.1 + 8.2.8.5 */ + +#define CXL_DEVICE_STATUS_REGISTERS_OFFSET 0x80 /* Read comment above */ +#define CXL_DEVICE_STATUS_REGISTERS_LENGTH 0x8 /* 8.2.8.3.1 */ + +#define CXL_MAILBOX_REGISTERS_OFFSET \ + (CXL_DEVICE_STATUS_REGISTERS_OFFSET + CXL_DEVICE_STATUS_REGISTERS_LENGTH) +#define CXL_MAILBOX_REGISTERS_SIZE 0x20 /* 8.2.8.4, Figure 139 */ +#define CXL_MAILBOX_PAYLOAD_SHIFT 11 +#define CXL_MAILBOX_MAX_PAYLOAD_SIZE (1 << CXL_MAILBOX_PAYLOAD_SHIFT) +#define CXL_MAILBOX_REGISTERS_LENGTH \ + (CXL_MAILBOX_REGISTERS_SIZE + CXL_MAILBOX_MAX_PAYLOAD_SIZE) + +typedef struct cxl_device_state { + MemoryRegion device_registers; + + /* mmio for device capabilities array - 8.2.8.2 */ + MemoryRegion device; + MemoryRegion caps; + + /* mmio for the mailbox registers 8.2.8.4 */ + MemoryRegion mailbox; + + /* memory region for persistent memory, HDM */ + uint64_t pmem_size; +} CXLDeviceState; + +/* Initialize the register block for a device */ +void cxl_device_register_block_init(Object *obj, CXLDeviceState *dev); + +/* Set up default values for the register block */ +void cxl_device_register_init_common(CXLDeviceState *dev); + +/* + * CXL 2.0 - 8.2.8.1 including errata F4 + * Documented as a 128 bit register, but 64 bit accesses and the second + * 64 bits are currently reserved. + */ +REG64(CXL_DEV_CAP_ARRAY, 0) /* Documented as 128 bit register but 64 byte accesses */ + FIELD(CXL_DEV_CAP_ARRAY, CAP_ID, 0, 16) + FIELD(CXL_DEV_CAP_ARRAY, CAP_VERSION, 16, 8) + FIELD(CXL_DEV_CAP_ARRAY, CAP_COUNT, 32, 16) + +/* + * Helper macro to initialize capability headers for CXL devices. + * + * In the 8.2.8.2, this is listed as a 128b register, but in 8.2.8, it says: + * > No registers defined in Section 8.2.8 are larger than 64-bits wide so that + * > is the maximum access size allowed for these registers. If this rule is not + * > followed, the behavior is undefined + * + * CXL 2.0 Errata F4 states futher that the layouts in the specification are + * shown as greater than 128 bits, but implementations are expected to + * use any size of access up to 64 bits. + * + * Here we've chosen to make it 4 dwords. The spec allows any pow2 multiple + * access to be used for a register up to 64 bits. + */ +#define CXL_DEVICE_CAPABILITY_HEADER_REGISTER(n, offset) \ + REG32(CXL_DEV_##n##_CAP_HDR0, offset) \ + FIELD(CXL_DEV_##n##_CAP_HDR0, CAP_ID, 0, 16) \ + FIELD(CXL_DEV_##n##_CAP_HDR0, CAP_VERSION, 16, 8) \ + REG32(CXL_DEV_##n##_CAP_HDR1, offset + 4) \ + FIELD(CXL_DEV_##n##_CAP_HDR1, CAP_OFFSET, 0, 32) \ + REG32(CXL_DEV_##n##_CAP_HDR2, offset + 8) \ + FIELD(CXL_DEV_##n##_CAP_HDR2, CAP_LENGTH, 0, 32) + +CXL_DEVICE_CAPABILITY_HEADER_REGISTER(DEVICE_STATUS, CXL_DEVICE_CAP_HDR1_OFFSET) +CXL_DEVICE_CAPABILITY_HEADER_REGISTER(MAILBOX, CXL_DEVICE_CAP_HDR1_OFFSET + \ + CXL_DEVICE_CAP_REG_SIZE) + +/* CXL 2.0 8.2.8.4.3 Mailbox Capabilities Register */ +REG32(CXL_DEV_MAILBOX_CAP, 0) + FIELD(CXL_DEV_MAILBOX_CAP, PAYLOAD_SIZE, 0, 5) + FIELD(CXL_DEV_MAILBOX_CAP, INT_CAP, 5, 1) + FIELD(CXL_DEV_MAILBOX_CAP, BG_INT_CAP, 6, 1) + FIELD(CXL_DEV_MAILBOX_CAP, MSI_N, 7, 4) + +/* CXL 2.0 8.2.8.4.4 Mailbox Control Register */ +REG32(CXL_DEV_MAILBOX_CTRL, 4) + FIELD(CXL_DEV_MAILBOX_CTRL, DOORBELL, 0, 1) + FIELD(CXL_DEV_MAILBOX_CTRL, INT_EN, 1, 1) + FIELD(CXL_DEV_MAILBOX_CTRL, BG_INT_EN, 2, 1) + +/* CXL 2.0 8.2.8.4.5 Command Register */ +REG64(CXL_DEV_MAILBOX_CMD, 8) + FIELD(CXL_DEV_MAILBOX_CMD, COMMAND, 0, 8) + FIELD(CXL_DEV_MAILBOX_CMD, COMMAND_SET, 8, 8) + FIELD(CXL_DEV_MAILBOX_CMD, LENGTH, 16, 20) + +/* CXL 2.0 8.2.8.4.6 Mailbox Status Register */ +REG64(CXL_DEV_MAILBOX_STS, 0x10) + FIELD(CXL_DEV_MAILBOX_STS, BG_OP, 0, 1) + FIELD(CXL_DEV_MAILBOX_STS, ERRNO, 32, 16) + FIELD(CXL_DEV_MAILBOX_STS, VENDOR_ERRNO, 48, 16) + +/* CXL 2.0 8.2.8.4.7 Background Command Status Register */ +REG64(CXL_DEV_BG_CMD_STS, 0x18) + FIELD(CXL_DEV_BG_CMD_STS, OP, 0, 16) + FIELD(CXL_DEV_BG_CMD_STS, PERCENTAGE_COMP, 16, 7) + FIELD(CXL_DEV_BG_CMD_STS, RET_CODE, 32, 16) + FIELD(CXL_DEV_BG_CMD_STS, VENDOR_RET_CODE, 48, 16) + +/* CXL 2.0 8.2.8.4.8 Command Payload Registers */ +REG32(CXL_DEV_CMD_PAYLOAD, 0x20) + +#endif From 6364adacdfa6a24e3f5b08f6b5ffa789a5d828a7 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:30 +0100 Subject: [PATCH 274/935] hw/cxl/device: Implement the CAP array (8.2.8.1-2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This implements all device MMIO up to the first capability. That includes the CXL Device Capabilities Array Register, as well as all of the CXL Device Capability Header Registers. The latter are filled in as they are implemented in the following patches. Endianness and alignment are managed by softmmu memory core. Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-6-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-device-utils.c | 109 ++++++++++++++++++++++++++++++++++++ hw/cxl/meson.build | 1 + include/hw/cxl/cxl_device.h | 31 +++++++++- 3 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 hw/cxl/cxl-device-utils.c diff --git a/hw/cxl/cxl-device-utils.c b/hw/cxl/cxl-device-utils.c new file mode 100644 index 0000000000..241f9f82e3 --- /dev/null +++ b/hw/cxl/cxl-device-utils.c @@ -0,0 +1,109 @@ +/* + * CXL Utility library for devices + * + * Copyright(C) 2020 Intel Corporation. + * + * This work is licensed under the terms of the GNU GPL, version 2. See the + * COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/cxl/cxl.h" + +/* + * Device registers have no restrictions per the spec, and so fall back to the + * default memory mapped register rules in 8.2: + * Software shall use CXL.io Memory Read and Write to access memory mapped + * register defined in this section. Unless otherwise specified, software + * shall restrict the accesses width based on the following: + * • A 32 bit register shall be accessed as a 1 Byte, 2 Bytes or 4 Bytes + * quantity. + * • A 64 bit register shall be accessed as a 1 Byte, 2 Bytes, 4 Bytes or 8 + * Bytes + * • The address shall be a multiple of the access width, e.g. when + * accessing a register as a 4 Byte quantity, the address shall be + * multiple of 4. + * • The accesses shall map to contiguous bytes.If these rules are not + * followed, the behavior is undefined + */ + +static uint64_t caps_reg_read(void *opaque, hwaddr offset, unsigned size) +{ + CXLDeviceState *cxl_dstate = opaque; + + if (size == 4) { + return cxl_dstate->caps_reg_state32[offset / sizeof(*cxl_dstate->caps_reg_state32)]; + } else { + return cxl_dstate->caps_reg_state64[offset / sizeof(*cxl_dstate->caps_reg_state64)]; + } +} + +static uint64_t dev_reg_read(void *opaque, hwaddr offset, unsigned size) +{ + return 0; +} + +static const MemoryRegionOps dev_ops = { + .read = dev_reg_read, + .write = NULL, /* status register is read only */ + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = false, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + +static const MemoryRegionOps caps_ops = { + .read = caps_reg_read, + .write = NULL, /* caps registers are read only */ + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = false, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 8, + }, +}; + +void cxl_device_register_block_init(Object *obj, CXLDeviceState *cxl_dstate) +{ + /* This will be a BAR, so needs to be rounded up to pow2 for PCI spec */ + memory_region_init(&cxl_dstate->device_registers, obj, "device-registers", + pow2ceil(CXL_MMIO_SIZE)); + + memory_region_init_io(&cxl_dstate->caps, obj, &caps_ops, cxl_dstate, + "cap-array", CXL_CAPS_SIZE); + memory_region_init_io(&cxl_dstate->device, obj, &dev_ops, cxl_dstate, + "device-status", CXL_DEVICE_STATUS_REGISTERS_LENGTH); + + memory_region_add_subregion(&cxl_dstate->device_registers, 0, + &cxl_dstate->caps); + memory_region_add_subregion(&cxl_dstate->device_registers, + CXL_DEVICE_STATUS_REGISTERS_OFFSET, + &cxl_dstate->device); +} + +static void device_reg_init_common(CXLDeviceState *cxl_dstate) { } + +void cxl_device_register_init_common(CXLDeviceState *cxl_dstate) +{ + uint64_t *cap_hdrs = cxl_dstate->caps_reg_state64; + const int cap_count = 1; + + /* CXL Device Capabilities Array Register */ + ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_ID, 0); + ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_VERSION, 1); + ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_COUNT, cap_count); + + cxl_device_cap_init(cxl_dstate, DEVICE_STATUS, 1); + device_reg_init_common(cxl_dstate); +} diff --git a/hw/cxl/meson.build b/hw/cxl/meson.build index 3231b5de1e..dd7c6f8e5a 100644 --- a/hw/cxl/meson.build +++ b/hw/cxl/meson.build @@ -1,4 +1,5 @@ softmmu_ss.add(when: 'CONFIG_CXL', if_true: files( 'cxl-component-utils.c', + 'cxl-device-utils.c', )) diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index 9513aaac77..599c887616 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -58,6 +58,8 @@ #define CXL_DEVICE_CAP_HDR1_OFFSET 0x10 /* Figure 138 */ #define CXL_DEVICE_CAP_REG_SIZE 0x10 /* 8.2.8.2 */ #define CXL_DEVICE_CAPS_MAX 4 /* 8.2.8.2.1 + 8.2.8.5 */ +#define CXL_CAPS_SIZE \ + (CXL_DEVICE_CAP_REG_SIZE * (CXL_DEVICE_CAPS_MAX + 1)) /* +1 for header */ #define CXL_DEVICE_STATUS_REGISTERS_OFFSET 0x80 /* Read comment above */ #define CXL_DEVICE_STATUS_REGISTERS_LENGTH 0x8 /* 8.2.8.3.1 */ @@ -70,12 +72,22 @@ #define CXL_MAILBOX_REGISTERS_LENGTH \ (CXL_MAILBOX_REGISTERS_SIZE + CXL_MAILBOX_MAX_PAYLOAD_SIZE) +#define CXL_MMIO_SIZE \ + (CXL_DEVICE_CAP_REG_SIZE + CXL_DEVICE_STATUS_REGISTERS_LENGTH + \ + CXL_MAILBOX_REGISTERS_LENGTH) + typedef struct cxl_device_state { MemoryRegion device_registers; /* mmio for device capabilities array - 8.2.8.2 */ MemoryRegion device; - MemoryRegion caps; + struct { + MemoryRegion caps; + union { + uint32_t caps_reg_state32[CXL_CAPS_SIZE / 4]; + uint64_t caps_reg_state64[CXL_CAPS_SIZE / 8]; + }; + }; /* mmio for the mailbox registers 8.2.8.4 */ MemoryRegion mailbox; @@ -128,6 +140,23 @@ CXL_DEVICE_CAPABILITY_HEADER_REGISTER(DEVICE_STATUS, CXL_DEVICE_CAP_HDR1_OFFSET) CXL_DEVICE_CAPABILITY_HEADER_REGISTER(MAILBOX, CXL_DEVICE_CAP_HDR1_OFFSET + \ CXL_DEVICE_CAP_REG_SIZE) +#define cxl_device_cap_init(dstate, reg, cap_id) \ + do { \ + uint32_t *cap_hdrs = dstate->caps_reg_state32; \ + int which = R_CXL_DEV_##reg##_CAP_HDR0; \ + cap_hdrs[which] = \ + FIELD_DP32(cap_hdrs[which], CXL_DEV_##reg##_CAP_HDR0, \ + CAP_ID, cap_id); \ + cap_hdrs[which] = FIELD_DP32( \ + cap_hdrs[which], CXL_DEV_##reg##_CAP_HDR0, CAP_VERSION, 1); \ + cap_hdrs[which + 1] = \ + FIELD_DP32(cap_hdrs[which + 1], CXL_DEV_##reg##_CAP_HDR1, \ + CAP_OFFSET, CXL_##reg##_REGISTERS_OFFSET); \ + cap_hdrs[which + 2] = \ + FIELD_DP32(cap_hdrs[which + 2], CXL_DEV_##reg##_CAP_HDR2, \ + CAP_LENGTH, CXL_##reg##_REGISTERS_LENGTH); \ + } while (0) + /* CXL 2.0 8.2.8.4.3 Mailbox Capabilities Register */ REG32(CXL_DEV_MAILBOX_CAP, 0) FIELD(CXL_DEV_MAILBOX_CAP, PAYLOAD_SIZE, 0, 5) From 464e14ac438e21c532889d78caf54a1dc837012a Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:31 +0100 Subject: [PATCH 275/935] hw/cxl/device: Implement basic mailbox (8.2.8.4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the beginning of implementing mailbox support for CXL 2.0 devices. The implementation recognizes when the doorbell is rung, handles the command/payload, clears the doorbell while returning error codes and data. Generally the mailbox mechanism is designed to permit communication between the host OS and the firmware running on the device. For our purposes, we emulate both the firmware, implemented primarily in cxl-mailbox-utils.c, and the hardware. No commands are implemented yet. Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-7-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-device-utils.c | 122 ++++++++++++++++++++++++++- hw/cxl/cxl-mailbox-utils.c | 164 ++++++++++++++++++++++++++++++++++++ hw/cxl/meson.build | 1 + include/hw/cxl/cxl.h | 3 + include/hw/cxl/cxl_device.h | 19 ++++- 5 files changed, 307 insertions(+), 2 deletions(-) create mode 100644 hw/cxl/cxl-mailbox-utils.c diff --git a/hw/cxl/cxl-device-utils.c b/hw/cxl/cxl-device-utils.c index 241f9f82e3..f6c3e0f095 100644 --- a/hw/cxl/cxl-device-utils.c +++ b/hw/cxl/cxl-device-utils.c @@ -44,6 +44,108 @@ static uint64_t dev_reg_read(void *opaque, hwaddr offset, unsigned size) return 0; } +static uint64_t mailbox_reg_read(void *opaque, hwaddr offset, unsigned size) +{ + CXLDeviceState *cxl_dstate = opaque; + + switch (size) { + case 1: + return cxl_dstate->mbox_reg_state[offset]; + case 2: + return cxl_dstate->mbox_reg_state16[offset / size]; + case 4: + return cxl_dstate->mbox_reg_state32[offset / size]; + case 8: + return cxl_dstate->mbox_reg_state64[offset / size]; + default: + g_assert_not_reached(); + } +} + +static void mailbox_mem_writel(uint32_t *reg_state, hwaddr offset, + uint64_t value) +{ + switch (offset) { + case A_CXL_DEV_MAILBOX_CTRL: + /* fallthrough */ + case A_CXL_DEV_MAILBOX_CAP: + /* RO register */ + break; + default: + qemu_log_mask(LOG_UNIMP, + "%s Unexpected 32-bit access to 0x%" PRIx64 " (WI)\n", + __func__, offset); + return; + } + + reg_state[offset / sizeof(*reg_state)] = value; +} + +static void mailbox_mem_writeq(uint64_t *reg_state, hwaddr offset, + uint64_t value) +{ + switch (offset) { + case A_CXL_DEV_MAILBOX_CMD: + break; + case A_CXL_DEV_BG_CMD_STS: + /* BG not supported */ + /* fallthrough */ + case A_CXL_DEV_MAILBOX_STS: + /* Read only register, will get updated by the state machine */ + return; + default: + qemu_log_mask(LOG_UNIMP, + "%s Unexpected 64-bit access to 0x%" PRIx64 " (WI)\n", + __func__, offset); + return; + } + + + reg_state[offset / sizeof(*reg_state)] = value; +} + +static void mailbox_reg_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + CXLDeviceState *cxl_dstate = opaque; + + if (offset >= A_CXL_DEV_CMD_PAYLOAD) { + memcpy(cxl_dstate->mbox_reg_state + offset, &value, size); + return; + } + + switch (size) { + case 4: + mailbox_mem_writel(cxl_dstate->mbox_reg_state32, offset, value); + break; + case 8: + mailbox_mem_writeq(cxl_dstate->mbox_reg_state64, offset, value); + break; + default: + g_assert_not_reached(); + } + + if (ARRAY_FIELD_EX32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CTRL, + DOORBELL)) { + cxl_process_mailbox(cxl_dstate); + } +} + +static const MemoryRegionOps mailbox_ops = { + .read = mailbox_reg_read, + .write = mailbox_reg_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = false, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + static const MemoryRegionOps dev_ops = { .read = dev_reg_read, .write = NULL, /* status register is read only */ @@ -84,20 +186,33 @@ void cxl_device_register_block_init(Object *obj, CXLDeviceState *cxl_dstate) "cap-array", CXL_CAPS_SIZE); memory_region_init_io(&cxl_dstate->device, obj, &dev_ops, cxl_dstate, "device-status", CXL_DEVICE_STATUS_REGISTERS_LENGTH); + memory_region_init_io(&cxl_dstate->mailbox, obj, &mailbox_ops, cxl_dstate, + "mailbox", CXL_MAILBOX_REGISTERS_LENGTH); memory_region_add_subregion(&cxl_dstate->device_registers, 0, &cxl_dstate->caps); memory_region_add_subregion(&cxl_dstate->device_registers, CXL_DEVICE_STATUS_REGISTERS_OFFSET, &cxl_dstate->device); + memory_region_add_subregion(&cxl_dstate->device_registers, + CXL_MAILBOX_REGISTERS_OFFSET, + &cxl_dstate->mailbox); } static void device_reg_init_common(CXLDeviceState *cxl_dstate) { } +static void mailbox_reg_init_common(CXLDeviceState *cxl_dstate) +{ + /* 2048 payload size, with no interrupt or background support */ + ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CAP, + PAYLOAD_SIZE, CXL_MAILBOX_PAYLOAD_SHIFT); + cxl_dstate->payload_size = CXL_MAILBOX_MAX_PAYLOAD_SIZE; +} + void cxl_device_register_init_common(CXLDeviceState *cxl_dstate) { uint64_t *cap_hdrs = cxl_dstate->caps_reg_state64; - const int cap_count = 1; + const int cap_count = 2; /* CXL Device Capabilities Array Register */ ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_ID, 0); @@ -106,4 +221,9 @@ void cxl_device_register_init_common(CXLDeviceState *cxl_dstate) cxl_device_cap_init(cxl_dstate, DEVICE_STATUS, 1); device_reg_init_common(cxl_dstate); + + cxl_device_cap_init(cxl_dstate, MAILBOX, 2); + mailbox_reg_init_common(cxl_dstate); + + assert(cxl_initialize_mailbox(cxl_dstate) == 0); } diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c new file mode 100644 index 0000000000..2557f41f61 --- /dev/null +++ b/hw/cxl/cxl-mailbox-utils.c @@ -0,0 +1,164 @@ +/* + * CXL Utility library for mailbox interface + * + * Copyright(C) 2020 Intel Corporation. + * + * This work is licensed under the terms of the GNU GPL, version 2. See the + * COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/cxl/cxl.h" +#include "hw/pci/pci.h" +#include "qemu/log.h" +#include "qemu/uuid.h" + +/* + * How to add a new command, example. The command set FOO, with cmd BAR. + * 1. Add the command set and cmd to the enum. + * FOO = 0x7f, + * #define BAR 0 + * 2. Implement the handler + * static ret_code cmd_foo_bar(struct cxl_cmd *cmd, + * CXLDeviceState *cxl_dstate, uint16_t *len) + * 3. Add the command to the cxl_cmd_set[][] + * [FOO][BAR] = { "FOO_BAR", cmd_foo_bar, x, y }, + * 4. Implement your handler + * define_mailbox_handler(FOO_BAR) { ... return CXL_MBOX_SUCCESS; } + * + * + * Writing the handler: + * The handler will provide the &struct cxl_cmd, the &CXLDeviceState, and the + * in/out length of the payload. The handler is responsible for consuming the + * payload from cmd->payload and operating upon it as necessary. It must then + * fill the output data into cmd->payload (overwriting what was there), + * setting the length, and returning a valid return code. + * + * XXX: The handler need not worry about endianess. The payload is read out of + * a register interface that already deals with it. + */ + +/* 8.2.8.4.5.1 Command Return Codes */ +typedef enum { + CXL_MBOX_SUCCESS = 0x0, + CXL_MBOX_BG_STARTED = 0x1, + CXL_MBOX_INVALID_INPUT = 0x2, + CXL_MBOX_UNSUPPORTED = 0x3, + CXL_MBOX_INTERNAL_ERROR = 0x4, + CXL_MBOX_RETRY_REQUIRED = 0x5, + CXL_MBOX_BUSY = 0x6, + CXL_MBOX_MEDIA_DISABLED = 0x7, + CXL_MBOX_FW_XFER_IN_PROGRESS = 0x8, + CXL_MBOX_FW_XFER_OUT_OF_ORDER = 0x9, + CXL_MBOX_FW_AUTH_FAILED = 0xa, + CXL_MBOX_FW_INVALID_SLOT = 0xb, + CXL_MBOX_FW_ROLLEDBACK = 0xc, + CXL_MBOX_FW_REST_REQD = 0xd, + CXL_MBOX_INVALID_HANDLE = 0xe, + CXL_MBOX_INVALID_PA = 0xf, + CXL_MBOX_INJECT_POISON_LIMIT = 0x10, + CXL_MBOX_PERMANENT_MEDIA_FAILURE = 0x11, + CXL_MBOX_ABORTED = 0x12, + CXL_MBOX_INVALID_SECURITY_STATE = 0x13, + CXL_MBOX_INCORRECT_PASSPHRASE = 0x14, + CXL_MBOX_UNSUPPORTED_MAILBOX = 0x15, + CXL_MBOX_INVALID_PAYLOAD_LENGTH = 0x16, + CXL_MBOX_MAX = 0x17 +} ret_code; + +struct cxl_cmd; +typedef ret_code (*opcode_handler)(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, uint16_t *len); +struct cxl_cmd { + const char *name; + opcode_handler handler; + ssize_t in; + uint16_t effect; /* Reported in CEL */ + uint8_t *payload; +}; + +#define DEFINE_MAILBOX_HANDLER_ZEROED(name, size) \ + uint16_t __zero##name = size; \ + static ret_code cmd_##name(struct cxl_cmd *cmd, \ + CXLDeviceState *cxl_dstate, uint16_t *len) \ + { \ + *len = __zero##name; \ + memset(cmd->payload, 0, *len); \ + return CXL_MBOX_SUCCESS; \ + } +#define DEFINE_MAILBOX_HANDLER_NOP(name) \ + static ret_code cmd_##name(struct cxl_cmd *cmd, \ + CXLDeviceState *cxl_dstate, uint16_t *len) \ + { \ + return CXL_MBOX_SUCCESS; \ + } + +static QemuUUID cel_uuid; + +static struct cxl_cmd cxl_cmd_set[256][256] = {}; + +void cxl_process_mailbox(CXLDeviceState *cxl_dstate) +{ + uint16_t ret = CXL_MBOX_SUCCESS; + struct cxl_cmd *cxl_cmd; + uint64_t status_reg; + opcode_handler h; + uint64_t command_reg = cxl_dstate->mbox_reg_state64[R_CXL_DEV_MAILBOX_CMD]; + + uint8_t set = FIELD_EX64(command_reg, CXL_DEV_MAILBOX_CMD, COMMAND_SET); + uint8_t cmd = FIELD_EX64(command_reg, CXL_DEV_MAILBOX_CMD, COMMAND); + uint16_t len = FIELD_EX64(command_reg, CXL_DEV_MAILBOX_CMD, LENGTH); + cxl_cmd = &cxl_cmd_set[set][cmd]; + h = cxl_cmd->handler; + if (h) { + if (len == cxl_cmd->in) { + cxl_cmd->payload = cxl_dstate->mbox_reg_state + + A_CXL_DEV_CMD_PAYLOAD; + ret = (*h)(cxl_cmd, cxl_dstate, &len); + assert(len <= cxl_dstate->payload_size); + } else { + ret = CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } + } else { + qemu_log_mask(LOG_UNIMP, "Command %04xh not implemented\n", + set << 8 | cmd); + ret = CXL_MBOX_UNSUPPORTED; + } + + /* Set the return code */ + status_reg = FIELD_DP64(0, CXL_DEV_MAILBOX_STS, ERRNO, ret); + + /* Set the return length */ + command_reg = FIELD_DP64(command_reg, CXL_DEV_MAILBOX_CMD, COMMAND_SET, 0); + command_reg = FIELD_DP64(command_reg, CXL_DEV_MAILBOX_CMD, COMMAND, 0); + command_reg = FIELD_DP64(command_reg, CXL_DEV_MAILBOX_CMD, LENGTH, len); + + cxl_dstate->mbox_reg_state64[R_CXL_DEV_MAILBOX_CMD] = command_reg; + cxl_dstate->mbox_reg_state64[R_CXL_DEV_MAILBOX_STS] = status_reg; + + /* Tell the host we're done */ + ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CTRL, + DOORBELL, 0); +} + +int cxl_initialize_mailbox(CXLDeviceState *cxl_dstate) +{ + /* CXL 2.0: Table 169 Get Supported Logs Log Entry */ + const char *cel_uuidstr = "0da9c0b5-bf41-4b78-8f79-96b1623b3f17"; + + for (int set = 0; set < 256; set++) { + for (int cmd = 0; cmd < 256; cmd++) { + if (cxl_cmd_set[set][cmd].handler) { + struct cxl_cmd *c = &cxl_cmd_set[set][cmd]; + struct cel_log *log = + &cxl_dstate->cel_log[cxl_dstate->cel_size]; + + log->opcode = (set << 8) | cmd; + log->effect = c->effect; + cxl_dstate->cel_size++; + } + } + } + + return qemu_uuid_parse(cel_uuidstr, &cel_uuid); +} diff --git a/hw/cxl/meson.build b/hw/cxl/meson.build index dd7c6f8e5a..e68eea2358 100644 --- a/hw/cxl/meson.build +++ b/hw/cxl/meson.build @@ -2,4 +2,5 @@ softmmu_ss.add(when: 'CONFIG_CXL', if_true: files( 'cxl-component-utils.c', 'cxl-device-utils.c', + 'cxl-mailbox-utils.c', )) diff --git a/include/hw/cxl/cxl.h b/include/hw/cxl/cxl.h index b9d1ac3fad..554ad93b6b 100644 --- a/include/hw/cxl/cxl.h +++ b/include/hw/cxl/cxl.h @@ -14,4 +14,7 @@ #include "cxl_component.h" #include "cxl_device.h" +#define CXL_COMPONENT_REG_BAR_IDX 0 +#define CXL_DEVICE_REG_BAR_IDX 2 + #endif diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index 599c887616..35489f635a 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -90,7 +90,21 @@ typedef struct cxl_device_state { }; /* mmio for the mailbox registers 8.2.8.4 */ - MemoryRegion mailbox; + struct { + MemoryRegion mailbox; + uint16_t payload_size; + union { + uint8_t mbox_reg_state[CXL_MAILBOX_REGISTERS_LENGTH]; + uint16_t mbox_reg_state16[CXL_MAILBOX_REGISTERS_LENGTH / 2]; + uint32_t mbox_reg_state32[CXL_MAILBOX_REGISTERS_LENGTH / 4]; + uint64_t mbox_reg_state64[CXL_MAILBOX_REGISTERS_LENGTH / 8]; + }; + struct cel_log { + uint16_t opcode; + uint16_t effect; + } cel_log[1 << 16]; + size_t cel_size; + }; /* memory region for persistent memory, HDM */ uint64_t pmem_size; @@ -140,6 +154,9 @@ CXL_DEVICE_CAPABILITY_HEADER_REGISTER(DEVICE_STATUS, CXL_DEVICE_CAP_HDR1_OFFSET) CXL_DEVICE_CAPABILITY_HEADER_REGISTER(MAILBOX, CXL_DEVICE_CAP_HDR1_OFFSET + \ CXL_DEVICE_CAP_REG_SIZE) +int cxl_initialize_mailbox(CXLDeviceState *cxl_dstate); +void cxl_process_mailbox(CXLDeviceState *cxl_dstate); + #define cxl_device_cap_init(dstate, reg, cap_id) \ do { \ uint32_t *cap_hdrs = dstate->caps_reg_state32; \ From ce3b4e5c152fe1c05aaf03b5bbe7579338446318 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:32 +0100 Subject: [PATCH 276/935] hw/cxl/device: Add memory device utilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Memory devices implement extra capabilities on top of CXL devices. This adds support for that. A large part of memory devices is the mailbox/command interface. All of the mailbox handling is done in the mailbox-utils library. Longer term, new CXL devices that are being emulated may want to handle commands differently, and therefore would need a mechanism to opt in/out of the specific generic handlers. As such, this is considered sufficient for now, but may need more depth in the future. Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-8-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-device-utils.c | 38 ++++++++++++++++++++++++++++++++++++- include/hw/cxl/cxl_device.h | 21 +++++++++++++++++--- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/hw/cxl/cxl-device-utils.c b/hw/cxl/cxl-device-utils.c index f6c3e0f095..687759b301 100644 --- a/hw/cxl/cxl-device-utils.c +++ b/hw/cxl/cxl-device-utils.c @@ -131,6 +131,31 @@ static void mailbox_reg_write(void *opaque, hwaddr offset, uint64_t value, } } +static uint64_t mdev_reg_read(void *opaque, hwaddr offset, unsigned size) +{ + uint64_t retval = 0; + + retval = FIELD_DP64(retval, CXL_MEM_DEV_STS, MEDIA_STATUS, 1); + retval = FIELD_DP64(retval, CXL_MEM_DEV_STS, MBOX_READY, 1); + + return retval; +} + +static const MemoryRegionOps mdev_ops = { + .read = mdev_reg_read, + .write = NULL, /* memory device register is read only */ + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = false, + }, + .impl = { + .min_access_size = 8, + .max_access_size = 8, + }, +}; + static const MemoryRegionOps mailbox_ops = { .read = mailbox_reg_read, .write = mailbox_reg_write, @@ -188,6 +213,9 @@ void cxl_device_register_block_init(Object *obj, CXLDeviceState *cxl_dstate) "device-status", CXL_DEVICE_STATUS_REGISTERS_LENGTH); memory_region_init_io(&cxl_dstate->mailbox, obj, &mailbox_ops, cxl_dstate, "mailbox", CXL_MAILBOX_REGISTERS_LENGTH); + memory_region_init_io(&cxl_dstate->memory_device, obj, &mdev_ops, + cxl_dstate, "memory device caps", + CXL_MEMORY_DEVICE_REGISTERS_LENGTH); memory_region_add_subregion(&cxl_dstate->device_registers, 0, &cxl_dstate->caps); @@ -197,6 +225,9 @@ void cxl_device_register_block_init(Object *obj, CXLDeviceState *cxl_dstate) memory_region_add_subregion(&cxl_dstate->device_registers, CXL_MAILBOX_REGISTERS_OFFSET, &cxl_dstate->mailbox); + memory_region_add_subregion(&cxl_dstate->device_registers, + CXL_MEMORY_DEVICE_REGISTERS_OFFSET, + &cxl_dstate->memory_device); } static void device_reg_init_common(CXLDeviceState *cxl_dstate) { } @@ -209,10 +240,12 @@ static void mailbox_reg_init_common(CXLDeviceState *cxl_dstate) cxl_dstate->payload_size = CXL_MAILBOX_MAX_PAYLOAD_SIZE; } +static void memdev_reg_init_common(CXLDeviceState *cxl_dstate) { } + void cxl_device_register_init_common(CXLDeviceState *cxl_dstate) { uint64_t *cap_hdrs = cxl_dstate->caps_reg_state64; - const int cap_count = 2; + const int cap_count = 3; /* CXL Device Capabilities Array Register */ ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_ID, 0); @@ -225,5 +258,8 @@ void cxl_device_register_init_common(CXLDeviceState *cxl_dstate) cxl_device_cap_init(cxl_dstate, MAILBOX, 2); mailbox_reg_init_common(cxl_dstate); + cxl_device_cap_init(cxl_dstate, MEMORY_DEVICE, 0x4000); + memdev_reg_init_common(cxl_dstate); + assert(cxl_initialize_mailbox(cxl_dstate) == 0); } diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index 35489f635a..954205653e 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -72,15 +72,20 @@ #define CXL_MAILBOX_REGISTERS_LENGTH \ (CXL_MAILBOX_REGISTERS_SIZE + CXL_MAILBOX_MAX_PAYLOAD_SIZE) -#define CXL_MMIO_SIZE \ - (CXL_DEVICE_CAP_REG_SIZE + CXL_DEVICE_STATUS_REGISTERS_LENGTH + \ - CXL_MAILBOX_REGISTERS_LENGTH) +#define CXL_MEMORY_DEVICE_REGISTERS_OFFSET \ + (CXL_MAILBOX_REGISTERS_OFFSET + CXL_MAILBOX_REGISTERS_LENGTH) +#define CXL_MEMORY_DEVICE_REGISTERS_LENGTH 0x8 + +#define CXL_MMIO_SIZE \ + (CXL_DEVICE_CAP_REG_SIZE + CXL_DEVICE_STATUS_REGISTERS_LENGTH + \ + CXL_MAILBOX_REGISTERS_LENGTH + CXL_MEMORY_DEVICE_REGISTERS_LENGTH) typedef struct cxl_device_state { MemoryRegion device_registers; /* mmio for device capabilities array - 8.2.8.2 */ MemoryRegion device; + MemoryRegion memory_device; struct { MemoryRegion caps; union { @@ -153,6 +158,9 @@ REG64(CXL_DEV_CAP_ARRAY, 0) /* Documented as 128 bit register but 64 byte access CXL_DEVICE_CAPABILITY_HEADER_REGISTER(DEVICE_STATUS, CXL_DEVICE_CAP_HDR1_OFFSET) CXL_DEVICE_CAPABILITY_HEADER_REGISTER(MAILBOX, CXL_DEVICE_CAP_HDR1_OFFSET + \ CXL_DEVICE_CAP_REG_SIZE) +CXL_DEVICE_CAPABILITY_HEADER_REGISTER(MEMORY_DEVICE, + CXL_DEVICE_CAP_HDR1_OFFSET + + CXL_DEVICE_CAP_REG_SIZE * 2) int cxl_initialize_mailbox(CXLDeviceState *cxl_dstate); void cxl_process_mailbox(CXLDeviceState *cxl_dstate); @@ -209,4 +217,11 @@ REG64(CXL_DEV_BG_CMD_STS, 0x18) /* CXL 2.0 8.2.8.4.8 Command Payload Registers */ REG32(CXL_DEV_CMD_PAYLOAD, 0x20) +REG64(CXL_MEM_DEV_STS, 0) + FIELD(CXL_MEM_DEV_STS, FATAL, 0, 1) + FIELD(CXL_MEM_DEV_STS, FW_HALT, 1, 1) + FIELD(CXL_MEM_DEV_STS, MEDIA_STATUS, 2, 2) + FIELD(CXL_MEM_DEV_STS, MBOX_READY, 4, 1) + FIELD(CXL_MEM_DEV_STS, RESET_NEEDED, 5, 3) + #endif From 57c02b355fd38c279bf54b5f492e6fdc7114a188 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:33 +0100 Subject: [PATCH 277/935] hw/cxl/device: Add cheap EVENTS implementation (8.2.9.1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using the previously implemented stubbed helpers, it is now possible to easily add the missing, required commands to the implementation. Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-9-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 2557f41f61..fb1f53f48e 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -38,6 +38,14 @@ * a register interface that already deals with it. */ +enum { + EVENTS = 0x01, + #define GET_RECORDS 0x0 + #define CLEAR_RECORDS 0x1 + #define GET_INTERRUPT_POLICY 0x2 + #define SET_INTERRUPT_POLICY 0x3 +}; + /* 8.2.8.4.5.1 Command Return Codes */ typedef enum { CXL_MBOX_SUCCESS = 0x0, @@ -93,9 +101,26 @@ struct cxl_cmd { return CXL_MBOX_SUCCESS; \ } +DEFINE_MAILBOX_HANDLER_ZEROED(events_get_records, 0x20); +DEFINE_MAILBOX_HANDLER_NOP(events_clear_records); +DEFINE_MAILBOX_HANDLER_ZEROED(events_get_interrupt_policy, 4); +DEFINE_MAILBOX_HANDLER_NOP(events_set_interrupt_policy); + static QemuUUID cel_uuid; -static struct cxl_cmd cxl_cmd_set[256][256] = {}; +#define IMMEDIATE_CONFIG_CHANGE (1 << 1) +#define IMMEDIATE_LOG_CHANGE (1 << 4) + +static struct cxl_cmd cxl_cmd_set[256][256] = { + [EVENTS][GET_RECORDS] = { "EVENTS_GET_RECORDS", + cmd_events_get_records, 1, 0 }, + [EVENTS][CLEAR_RECORDS] = { "EVENTS_CLEAR_RECORDS", + cmd_events_clear_records, ~0, IMMEDIATE_LOG_CHANGE }, + [EVENTS][GET_INTERRUPT_POLICY] = { "EVENTS_GET_INTERRUPT_POLICY", + cmd_events_get_interrupt_policy, 0, 0 }, + [EVENTS][SET_INTERRUPT_POLICY] = { "EVENTS_SET_INTERRUPT_POLICY", + cmd_events_set_interrupt_policy, 4, IMMEDIATE_CONFIG_CHANGE }, +}; void cxl_process_mailbox(CXLDeviceState *cxl_dstate) { From 557a79c83e73e5c524a1d44626b509644efa0103 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:34 +0100 Subject: [PATCH 278/935] hw/cxl/device: Timestamp implementation (8.2.9.3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Errata F4 to CXL 2.0 clarified the meaning of the timer as the sum of the value set with the timestamp set command and the number of nano seconds since it was last set. Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-10-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 42 +++++++++++++++++++++++++++++++++++++ include/hw/cxl/cxl_device.h | 6 ++++++ 2 files changed, 48 insertions(+) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index fb1f53f48e..4584aa31f7 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -44,6 +44,9 @@ enum { #define CLEAR_RECORDS 0x1 #define GET_INTERRUPT_POLICY 0x2 #define SET_INTERRUPT_POLICY 0x3 + TIMESTAMP = 0x03, + #define GET 0x0 + #define SET 0x1 }; /* 8.2.8.4.5.1 Command Return Codes */ @@ -106,9 +109,46 @@ DEFINE_MAILBOX_HANDLER_NOP(events_clear_records); DEFINE_MAILBOX_HANDLER_ZEROED(events_get_interrupt_policy, 4); DEFINE_MAILBOX_HANDLER_NOP(events_set_interrupt_policy); +/* 8.2.9.3.1 */ +static ret_code cmd_timestamp_get(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len) +{ + uint64_t time, delta; + uint64_t final_time = 0; + + if (cxl_dstate->timestamp.set) { + /* First find the delta from the last time the host set the time. */ + time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + delta = time - cxl_dstate->timestamp.last_set; + final_time = cxl_dstate->timestamp.host_set + delta; + } + + /* Then adjust the actual time */ + stq_le_p(cmd->payload, final_time); + *len = 8; + + return CXL_MBOX_SUCCESS; +} + +/* 8.2.9.3.2 */ +static ret_code cmd_timestamp_set(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len) +{ + cxl_dstate->timestamp.set = true; + cxl_dstate->timestamp.last_set = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + + cxl_dstate->timestamp.host_set = le64_to_cpu(*(uint64_t *)cmd->payload); + + *len = 0; + return CXL_MBOX_SUCCESS; +} + static QemuUUID cel_uuid; #define IMMEDIATE_CONFIG_CHANGE (1 << 1) +#define IMMEDIATE_POLICY_CHANGE (1 << 3) #define IMMEDIATE_LOG_CHANGE (1 << 4) static struct cxl_cmd cxl_cmd_set[256][256] = { @@ -120,6 +160,8 @@ static struct cxl_cmd cxl_cmd_set[256][256] = { cmd_events_get_interrupt_policy, 0, 0 }, [EVENTS][SET_INTERRUPT_POLICY] = { "EVENTS_SET_INTERRUPT_POLICY", cmd_events_set_interrupt_policy, 4, IMMEDIATE_CONFIG_CHANGE }, + [TIMESTAMP][GET] = { "TIMESTAMP_GET", cmd_timestamp_get, 0, 0 }, + [TIMESTAMP][SET] = { "TIMESTAMP_SET", cmd_timestamp_set, 8, IMMEDIATE_POLICY_CHANGE }, }; void cxl_process_mailbox(CXLDeviceState *cxl_dstate) diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index 954205653e..797a22ddb4 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -111,6 +111,12 @@ typedef struct cxl_device_state { size_t cel_size; }; + struct { + bool set; + uint64_t last_set; + uint64_t host_set; + } timestamp; + /* memory region for persistent memory, HDM */ uint64_t pmem_size; } CXLDeviceState; From 056172691bbfc2cd7c7e8ac6a14f78b45ddadba1 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:35 +0100 Subject: [PATCH 279/935] hw/cxl/device: Add log commands (8.2.9.4) + CEL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CXL specification provides for the ability to obtain logs from the device. Logs are either spec defined, like the "Command Effects Log" (CEL), or vendor specific. UUIDs are defined for all log types. The CEL is a mechanism to provide information to the host about which commands are supported. It is useful both to determine which spec'd optional commands are supported, as well as provide a list of vendor specified commands that might be used. The CEL is already created as part of mailbox initialization, but here it is now exported to hosts that use these log commands. Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-11-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 69 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 4584aa31f7..db473135c7 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -47,6 +47,9 @@ enum { TIMESTAMP = 0x03, #define GET 0x0 #define SET 0x1 + LOGS = 0x04, + #define GET_SUPPORTED 0x0 + #define GET_LOG 0x1 }; /* 8.2.8.4.5.1 Command Return Codes */ @@ -147,6 +150,70 @@ static ret_code cmd_timestamp_set(struct cxl_cmd *cmd, static QemuUUID cel_uuid; +/* 8.2.9.4.1 */ +static ret_code cmd_logs_get_supported(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len) +{ + struct { + uint16_t entries; + uint8_t rsvd[6]; + struct { + QemuUUID uuid; + uint32_t size; + } log_entries[1]; + } QEMU_PACKED *supported_logs = (void *)cmd->payload; + QEMU_BUILD_BUG_ON(sizeof(*supported_logs) != 0x1c); + + supported_logs->entries = 1; + supported_logs->log_entries[0].uuid = cel_uuid; + supported_logs->log_entries[0].size = 4 * cxl_dstate->cel_size; + + *len = sizeof(*supported_logs); + return CXL_MBOX_SUCCESS; +} + +/* 8.2.9.4.2 */ +static ret_code cmd_logs_get_log(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len) +{ + struct { + QemuUUID uuid; + uint32_t offset; + uint32_t length; + } QEMU_PACKED QEMU_ALIGNED(16) *get_log = (void *)cmd->payload; + + /* + * 8.2.9.4.2 + * The device shall return Invalid Parameter if the Offset or Length + * fields attempt to access beyond the size of the log as reported by Get + * Supported Logs. + * + * XXX: Spec is wrong, "Invalid Parameter" isn't a thing. + * XXX: Spec doesn't address incorrect UUID incorrectness. + * + * The CEL buffer is large enough to fit all commands in the emulation, so + * the only possible failure would be if the mailbox itself isn't big + * enough. + */ + if (get_log->offset + get_log->length > cxl_dstate->payload_size) { + return CXL_MBOX_INVALID_INPUT; + } + + if (!qemu_uuid_is_equal(&get_log->uuid, &cel_uuid)) { + return CXL_MBOX_UNSUPPORTED; + } + + /* Store off everything to local variables so we can wipe out the payload */ + *len = get_log->length; + + memmove(cmd->payload, cxl_dstate->cel_log + get_log->offset, + get_log->length); + + return CXL_MBOX_SUCCESS; +} + #define IMMEDIATE_CONFIG_CHANGE (1 << 1) #define IMMEDIATE_POLICY_CHANGE (1 << 3) #define IMMEDIATE_LOG_CHANGE (1 << 4) @@ -162,6 +229,8 @@ static struct cxl_cmd cxl_cmd_set[256][256] = { cmd_events_set_interrupt_policy, 4, IMMEDIATE_CONFIG_CHANGE }, [TIMESTAMP][GET] = { "TIMESTAMP_GET", cmd_timestamp_get, 0, 0 }, [TIMESTAMP][SET] = { "TIMESTAMP_SET", cmd_timestamp_set, 8, IMMEDIATE_POLICY_CHANGE }, + [LOGS][GET_SUPPORTED] = { "LOGS_GET_SUPPORTED", cmd_logs_get_supported, 0, 0 }, + [LOGS][GET_LOG] = { "LOGS_GET_LOG", cmd_logs_get_log, 0x18, 0 }, }; void cxl_process_mailbox(CXLDeviceState *cxl_dstate) From 25a2e524e34e9a7cdf709a380b9deaada9dc4995 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:36 +0100 Subject: [PATCH 280/935] hw/pxb: Use a type for realizing expanders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This opens up the possibility for more types of expanders (other than PCI and PCIe). We'll need this to create a CXL expander. Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-12-Jonathan.Cameron@huawei.com> --- hw/pci-bridge/pci_expander_bridge.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index de932286b5..d4514227a8 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -24,6 +24,8 @@ #include "hw/boards.h" #include "qom/object.h" +enum BusType { PCI, PCIE }; + #define TYPE_PXB_BUS "pxb-bus" typedef struct PXBBus PXBBus; DECLARE_INSTANCE_CHECKER(PXBBus, PXB_BUS, @@ -221,7 +223,8 @@ static gint pxb_compare(gconstpointer a, gconstpointer b) 0; } -static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp) +static void pxb_dev_realize_common(PCIDevice *dev, enum BusType type, + Error **errp) { PXBDev *pxb = convert_to_pxb(dev); DeviceState *ds, *bds = NULL; @@ -246,7 +249,7 @@ static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp) } ds = qdev_new(TYPE_PXB_HOST); - if (pcie) { + if (type == PCIE) { bus = pci_root_bus_new(ds, dev_name, NULL, NULL, 0, TYPE_PXB_PCIE_BUS); } else { bus = pci_root_bus_new(ds, "pxb-internal", NULL, NULL, 0, TYPE_PXB_BUS); @@ -295,7 +298,7 @@ static void pxb_dev_realize(PCIDevice *dev, Error **errp) return; } - pxb_dev_realize_common(dev, false, errp); + pxb_dev_realize_common(dev, PCI, errp); } static void pxb_dev_exitfn(PCIDevice *pci_dev) @@ -348,7 +351,7 @@ static void pxb_pcie_dev_realize(PCIDevice *dev, Error **errp) return; } - pxb_dev_realize_common(dev, true, errp); + pxb_dev_realize_common(dev, PCIE, errp); } static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data) From 9dccb1216bf9d120579612979f4d58fd97bf0150 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:37 +0100 Subject: [PATCH 281/935] hw/pci/cxl: Create a CXL bus type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The easiest way to differentiate a CXL bus, and a PCIE bus is using a flag. A CXL bus, in hardware, is backward compatible with PCIE, and therefore the code tries pretty hard to keep them in sync as much as possible. The other way to implement this would be to try to cast the bus to the correct type. This is less code and useful for debugging via simply looking at the flags. Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-13-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci-bridge/pci_expander_bridge.c | 9 ++++++++- include/hw/pci/pci_bus.h | 7 +++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index d4514227a8..a6caa1e7b5 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -24,7 +24,7 @@ #include "hw/boards.h" #include "qom/object.h" -enum BusType { PCI, PCIE }; +enum BusType { PCI, PCIE, CXL }; #define TYPE_PXB_BUS "pxb-bus" typedef struct PXBBus PXBBus; @@ -35,6 +35,10 @@ DECLARE_INSTANCE_CHECKER(PXBBus, PXB_BUS, DECLARE_INSTANCE_CHECKER(PXBBus, PXB_PCIE_BUS, TYPE_PXB_PCIE_BUS) +#define TYPE_PXB_CXL_BUS "pxb-cxl-bus" +DECLARE_INSTANCE_CHECKER(PXBBus, PXB_CXL_BUS, + TYPE_PXB_CXL_BUS) + struct PXBBus { /*< private >*/ PCIBus parent_obj; @@ -251,6 +255,9 @@ static void pxb_dev_realize_common(PCIDevice *dev, enum BusType type, ds = qdev_new(TYPE_PXB_HOST); if (type == PCIE) { bus = pci_root_bus_new(ds, dev_name, NULL, NULL, 0, TYPE_PXB_PCIE_BUS); + } else if (type == CXL) { + bus = pci_root_bus_new(ds, dev_name, NULL, NULL, 0, TYPE_PXB_CXL_BUS); + bus->flags |= PCI_BUS_CXL; } else { bus = pci_root_bus_new(ds, "pxb-internal", NULL, NULL, 0, TYPE_PXB_BUS); bds = qdev_new("pci-bridge"); diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h index 347440d42c..eb94e7e85c 100644 --- a/include/hw/pci/pci_bus.h +++ b/include/hw/pci/pci_bus.h @@ -24,6 +24,8 @@ enum PCIBusFlags { PCI_BUS_IS_ROOT = 0x0001, /* PCIe extended configuration space is accessible on this bus */ PCI_BUS_EXTENDED_CONFIG_SPACE = 0x0002, + /* This is a CXL Type BUS */ + PCI_BUS_CXL = 0x0004, }; struct PCIBus { @@ -53,6 +55,11 @@ struct PCIBus { Notifier machine_done; }; +static inline bool pci_bus_is_cxl(PCIBus *bus) +{ + return !!(bus->flags & PCI_BUS_CXL); +} + static inline bool pci_bus_is_root(PCIBus *bus) { return !!(bus->flags & PCI_BUS_IS_ROOT); From abb3009baf90e5984ff1c230af0bc92a45e64864 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 29 Apr 2022 15:40:38 +0100 Subject: [PATCH 282/935] cxl: Machine level control on whether CXL support is enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are going to be some potential overheads to CXL enablement, for example the host bridge region reserved in memory maps. Add a machine level control so that CXL is disabled by default. Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-14-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/core/machine.c | 28 ++++++++++++++++++++++++++++ hw/i386/pc.c | 1 + include/hw/boards.h | 2 ++ include/hw/cxl/cxl.h | 4 ++++ 4 files changed, 35 insertions(+) diff --git a/hw/core/machine.c b/hw/core/machine.c index 3264c1e11d..b03d9192ba 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -33,6 +33,7 @@ #include "sysemu/qtest.h" #include "hw/pci/pci.h" #include "hw/mem/nvdimm.h" +#include "hw/cxl/cxl.h" #include "migration/global_state.h" #include "migration/vmstate.h" #include "exec/confidential-guest-support.h" @@ -625,6 +626,20 @@ static void machine_set_nvdimm_persistence(Object *obj, const char *value, nvdimms_state->persistence_string = g_strdup(value); } +static bool machine_get_cxl(Object *obj, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + return ms->cxl_devices_state->is_enabled; +} + +static void machine_set_cxl(Object *obj, bool value, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + ms->cxl_devices_state->is_enabled = value; +} + void machine_class_allow_dynamic_sysbus_dev(MachineClass *mc, const char *type) { QAPI_LIST_PREPEND(mc->allowed_dynamic_sysbus_devices, g_strdup(type)); @@ -911,6 +926,8 @@ static void machine_class_init(ObjectClass *oc, void *data) mc->default_ram_size = 128 * MiB; mc->rom_file_has_mr = true; + /* Few machines support CXL, so default to off */ + mc->cxl_supported = false; /* numa node memory size aligned on 8MB by default. * On Linux, each node's border has to be 8MB aligned */ @@ -1071,6 +1088,16 @@ static void machine_initfn(Object *obj) "Valid values are cpu, mem-ctrl"); } + if (mc->cxl_supported) { + Object *obj = OBJECT(ms); + + ms->cxl_devices_state = g_new0(CXLState, 1); + object_property_add_bool(obj, "cxl", machine_get_cxl, machine_set_cxl); + object_property_set_description(obj, "cxl", + "Set on/off to enable/disable " + "CXL instantiation"); + } + if (mc->cpu_index_to_instance_props && mc->get_default_cpu_node_id) { ms->numa_state = g_new0(NumaState, 1); object_property_add_bool(obj, "hmat", @@ -1108,6 +1135,7 @@ static void machine_finalize(Object *obj) g_free(ms->device_memory); g_free(ms->nvdimms_state); g_free(ms->numa_state); + g_free(ms->cxl_devices_state); } bool machine_usb(MachineState *machine) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 305d2c0820..45e2d6092f 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1761,6 +1761,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) mc->default_cpu_type = TARGET_DEFAULT_CPU_TYPE; mc->nvdimm_supported = true; mc->smp_props.dies_supported = true; + mc->cxl_supported = true; mc->default_ram_id = "pc.ram"; object_class_property_add(oc, PC_MACHINE_MAX_RAM_BELOW_4G, "size", diff --git a/include/hw/boards.h b/include/hw/boards.h index 7b416c9787..fa57bac4fb 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -269,6 +269,7 @@ struct MachineClass { bool ignore_boot_device_suffixes; bool smbus_no_migration_support; bool nvdimm_supported; + bool cxl_supported; bool numa_mem_supported; bool auto_enable_numa; SMPCompatProps smp_props; @@ -359,6 +360,7 @@ struct MachineState { CPUArchIdList *possible_cpus; CpuTopology smp; struct NVDIMMState *nvdimms_state; + struct CXLState *cxl_devices_state; struct NumaState *numa_state; }; diff --git a/include/hw/cxl/cxl.h b/include/hw/cxl/cxl.h index 554ad93b6b..31af92fd5e 100644 --- a/include/hw/cxl/cxl.h +++ b/include/hw/cxl/cxl.h @@ -17,4 +17,8 @@ #define CXL_COMPONENT_REG_BAR_IDX 0 #define CXL_DEVICE_REG_BAR_IDX 2 +typedef struct CXLState { + bool is_enabled; +} CXLState; + #endif From 4f8db8711cbd27c9acf17e685987e9e74815e087 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:39 +0100 Subject: [PATCH 283/935] hw/pxb: Allow creation of a CXL PXB (host bridge) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This works like adding a typical pxb device, except the name is 'pxb-cxl' instead of 'pxb-pcie'. An example command line would be as follows: -device pxb-cxl,id=cxl.0,bus="pcie.0",bus_nr=1 A CXL PXB is backward compatible with PCIe. What this means in practice is that an operating system that is unaware of CXL should still be able to enumerate this topology as if it were PCIe. One can create multiple CXL PXB host bridges, but a host bridge can only be connected to the main root bus. Host bridges cannot appear elsewhere in the topology. Note that as of this patch, the ACPI tables needed for the host bridge (specifically, an ACPI object in _SB named ACPI0016 and the CEDT) aren't created. So while this patch internally creates it, it cannot be properly used by an operating system or other system software. Also necessary is to add an exception to scripts/device-crash-test similar to that for exiting pxb as both must created on a PCIexpress host bus. Signed-off-by: Ben Widawsky Signed-off-by: Jonathan.Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-15-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci-bridge/pci_expander_bridge.c | 86 ++++++++++++++++++++++++++++- hw/pci/pci.c | 7 +++ include/hw/pci/pci.h | 6 ++ scripts/device-crash-test | 1 + 4 files changed, 98 insertions(+), 2 deletions(-) diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index a6caa1e7b5..f762eb4a6e 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -17,6 +17,7 @@ #include "hw/pci/pci_host.h" #include "hw/qdev-properties.h" #include "hw/pci/pci_bridge.h" +#include "hw/cxl/cxl.h" #include "qemu/range.h" #include "qemu/error-report.h" #include "qemu/module.h" @@ -56,6 +57,16 @@ DECLARE_INSTANCE_CHECKER(PXBDev, PXB_DEV, DECLARE_INSTANCE_CHECKER(PXBDev, PXB_PCIE_DEV, TYPE_PXB_PCIE_DEVICE) +#define TYPE_PXB_CXL_DEVICE "pxb-cxl" +DECLARE_INSTANCE_CHECKER(PXBDev, PXB_CXL_DEV, + TYPE_PXB_CXL_DEVICE) + +typedef struct CXLHost { + PCIHostState parent_obj; + + CXLComponentState cxl_cstate; +} CXLHost; + struct PXBDev { /*< private >*/ PCIDevice parent_obj; @@ -68,6 +79,11 @@ struct PXBDev { static PXBDev *convert_to_pxb(PCIDevice *dev) { + /* A CXL PXB's parent bus is PCIe, so the normal check won't work */ + if (object_dynamic_cast(OBJECT(dev), TYPE_PXB_CXL_DEVICE)) { + return PXB_CXL_DEV(dev); + } + return pci_bus_is_express(pci_get_bus(dev)) ? PXB_PCIE_DEV(dev) : PXB_DEV(dev); } @@ -112,11 +128,20 @@ static const TypeInfo pxb_pcie_bus_info = { .class_init = pxb_bus_class_init, }; +static const TypeInfo pxb_cxl_bus_info = { + .name = TYPE_PXB_CXL_BUS, + .parent = TYPE_CXL_BUS, + .instance_size = sizeof(PXBBus), + .class_init = pxb_bus_class_init, +}; + static const char *pxb_host_root_bus_path(PCIHostState *host_bridge, PCIBus *rootbus) { - PXBBus *bus = pci_bus_is_express(rootbus) ? - PXB_PCIE_BUS(rootbus) : PXB_BUS(rootbus); + PXBBus *bus = pci_bus_is_cxl(rootbus) ? + PXB_CXL_BUS(rootbus) : + pci_bus_is_express(rootbus) ? PXB_PCIE_BUS(rootbus) : + PXB_BUS(rootbus); snprintf(bus->bus_path, 8, "0000:%02x", pxb_bus_num(rootbus)); return bus->bus_path; @@ -218,6 +243,10 @@ static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin) return pin - PCI_SLOT(pxb->devfn); } +static void pxb_dev_reset(DeviceState *dev) +{ +} + static gint pxb_compare(gconstpointer a, gconstpointer b) { const PXBDev *pxb_a = a, *pxb_b = b; @@ -389,13 +418,66 @@ static const TypeInfo pxb_pcie_dev_info = { }, }; +static void pxb_cxl_dev_realize(PCIDevice *dev, Error **errp) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + + /* A CXL PXB's parent bus is still PCIe */ + if (!pci_bus_is_express(pci_get_bus(dev))) { + error_setg(errp, "pxb-cxl devices cannot reside on a PCI bus"); + return; + } + if (!ms->cxl_devices_state->is_enabled) { + error_setg(errp, "Machine does not have cxl=on"); + return; + } + + pxb_dev_realize_common(dev, CXL, errp); + pxb_dev_reset(DEVICE(dev)); +} + +static void pxb_cxl_dev_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->realize = pxb_cxl_dev_realize; + k->exit = pxb_dev_exitfn; + /* + * XXX: These types of bridges don't actually show up in the hierarchy so + * vendor, device, class, etc. ids are intentionally left out. + */ + + dc->desc = "CXL Host Bridge"; + device_class_set_props(dc, pxb_dev_properties); + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); + + /* Host bridges aren't hotpluggable. FIXME: spec reference */ + dc->hotpluggable = false; + dc->reset = pxb_dev_reset; +} + +static const TypeInfo pxb_cxl_dev_info = { + .name = TYPE_PXB_CXL_DEVICE, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PXBDev), + .class_init = pxb_cxl_dev_class_init, + .interfaces = + (InterfaceInfo[]){ + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + {}, + }, +}; + static void pxb_register_types(void) { type_register_static(&pxb_bus_info); type_register_static(&pxb_pcie_bus_info); + type_register_static(&pxb_cxl_bus_info); type_register_static(&pxb_host_info); type_register_static(&pxb_dev_info); type_register_static(&pxb_pcie_dev_info); + type_register_static(&pxb_cxl_dev_info); } type_init(pxb_register_types) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index eb884adef9..6c0656f604 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -228,6 +228,12 @@ static const TypeInfo pcie_bus_info = { .class_init = pcie_bus_class_init, }; +static const TypeInfo cxl_bus_info = { + .name = TYPE_CXL_BUS, + .parent = TYPE_PCIE_BUS, + .class_init = pcie_bus_class_init, +}; + static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num); static void pci_update_mappings(PCIDevice *d); static void pci_irq_handler(void *opaque, int irq_num, int level); @@ -2946,6 +2952,7 @@ static void pci_register_types(void) { type_register_static(&pci_bus_info); type_register_static(&pcie_bus_info); + type_register_static(&cxl_bus_info); type_register_static(&conventional_pci_interface_info); type_register_static(&cxl_interface_info); type_register_static(&pcie_interface_info); diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 98f0d1b844..44dacfa224 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -408,6 +408,7 @@ typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin); #define TYPE_PCI_BUS "PCI" OBJECT_DECLARE_TYPE(PCIBus, PCIBusClass, PCI_BUS) #define TYPE_PCIE_BUS "PCIE" +#define TYPE_CXL_BUS "CXL" typedef void (*pci_bus_dev_fn)(PCIBus *b, PCIDevice *d, void *opaque); typedef void (*pci_bus_fn)(PCIBus *b, void *opaque); @@ -770,6 +771,11 @@ static inline void pci_irq_pulse(PCIDevice *pci_dev) pci_irq_deassert(pci_dev); } +static inline int pci_is_cxl(const PCIDevice *d) +{ + return d->cap_present & QEMU_PCIE_CAP_CXL; +} + static inline int pci_is_express(const PCIDevice *d) { return d->cap_present & QEMU_PCI_CAP_EXPRESS; diff --git a/scripts/device-crash-test b/scripts/device-crash-test index 4bfc68c008..a203b3fdea 100755 --- a/scripts/device-crash-test +++ b/scripts/device-crash-test @@ -93,6 +93,7 @@ ERROR_RULE_LIST = [ {'device':'pci-bridge', 'expected':True}, # Bridge chassis not specified. Each bridge is required to be assigned a unique chassis id > 0. {'device':'pci-bridge-seat', 'expected':True}, # Bridge chassis not specified. Each bridge is required to be assigned a unique chassis id > 0. {'device':'pxb', 'expected':True}, # Bridge chassis not specified. Each bridge is required to be assigned a unique chassis id > 0. + {'device':'pxb-cxl', 'expected':True}, # pxb-cxl devices cannot reside on a PCI bus. {'device':'scsi-block', 'expected':True}, # drive property not set {'device':'scsi-generic', 'expected':True}, # drive property not set {'device':'scsi-hd', 'expected':True}, # drive property not set From 33c47ab967558dfb02b3439b37e7dcfcdced0157 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 29 Apr 2022 15:40:40 +0100 Subject: [PATCH 284/935] qtest/cxl: Introduce initial test for pxb-cxl only. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initial test with just pxb-cxl. Other tests will be added alongside functionality. Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Tested-by: Alex Bennée Message-Id: <20220429144110.25167-16-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/cxl-test.c | 22 ++++++++++++++++++++++ tests/qtest/meson.build | 4 ++++ 2 files changed, 26 insertions(+) create mode 100644 tests/qtest/cxl-test.c diff --git a/tests/qtest/cxl-test.c b/tests/qtest/cxl-test.c new file mode 100644 index 0000000000..c031049930 --- /dev/null +++ b/tests/qtest/cxl-test.c @@ -0,0 +1,22 @@ +/* + * QTest testcase for CXL + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "libqtest-single.h" + +static void cxl_basic_pxb(void) +{ + qtest_start("-machine q35,cxl=on -device pxb-cxl,bus=pcie.0"); + qtest_end(); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + qtest_add_func("/pci/cxl/basic_pxb", cxl_basic_pxb); + return g_test_run(); +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 3551b9c946..71e86bc2a3 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -35,6 +35,9 @@ qtests_pci = \ (config_all_devices.has_key('CONFIG_VGA') ? ['display-vga-test'] : []) + \ (config_all_devices.has_key('CONFIG_IVSHMEM_DEVICE') ? ['ivshmem-test'] : []) +qtests_cxl = \ + (config_all_devices.has_key('CONFIG_CXL') ? ['cxl-test'] : []) + qtests_i386 = \ (slirp.found() ? ['pxe-test', 'test-netfilter'] : []) + \ (config_host.has_key('CONFIG_POSIX') ? ['test-filter-mirror'] : []) + \ @@ -74,6 +77,7 @@ qtests_i386 = \ slirp.found() ? ['virtio-net-failover'] : []) + \ (unpack_edk2_blobs ? ['bios-tables-test'] : []) + \ qtests_pci + \ + qtests_cxl + \ ['fdc-test', 'ide-test', 'hd-geo-test', From d86d30192b7bc5a10fa6c82c073f55aea25f9291 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:41 +0100 Subject: [PATCH 285/935] hw/cxl/rp: Add a root port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds just enough of a root port implementation to be able to enumerate root ports (creating the required DVSEC entries). What's not here yet is the MMIO nor the ability to write some of the DVSEC entries. This can be added with the qemu commandline by adding a rootport to a specific CXL host bridge. For example: -device cxl-rp,id=rp0,bus="cxl.0",addr=0.0,chassis=4 Like the host bridge patch, the ACPI tables aren't generated at this point and so system software cannot use it. Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-17-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci-bridge/Kconfig | 5 + hw/pci-bridge/cxl_root_port.c | 236 +++++++++++++++++++++++++++++++++ hw/pci-bridge/meson.build | 1 + hw/pci-bridge/pcie_root_port.c | 6 +- hw/pci/pci.c | 4 +- 5 files changed, 250 insertions(+), 2 deletions(-) create mode 100644 hw/pci-bridge/cxl_root_port.c diff --git a/hw/pci-bridge/Kconfig b/hw/pci-bridge/Kconfig index f8df4315ba..02614f49aa 100644 --- a/hw/pci-bridge/Kconfig +++ b/hw/pci-bridge/Kconfig @@ -27,3 +27,8 @@ config DEC_PCI config SIMBA bool + +config CXL + bool + default y if PCI_EXPRESS && PXB + depends on PCI_EXPRESS && MSI_NONBROKEN && PXB diff --git a/hw/pci-bridge/cxl_root_port.c b/hw/pci-bridge/cxl_root_port.c new file mode 100644 index 0000000000..fb213fa06e --- /dev/null +++ b/hw/pci-bridge/cxl_root_port.c @@ -0,0 +1,236 @@ +/* + * CXL 2.0 Root Port Implementation + * + * Copyright(C) 2020 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/range.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pcie_port.h" +#include "hw/qdev-properties.h" +#include "hw/sysbus.h" +#include "qapi/error.h" +#include "hw/cxl/cxl.h" + +#define CXL_ROOT_PORT_DID 0x7075 + +/* Copied from the gen root port which we derive */ +#define GEN_PCIE_ROOT_PORT_AER_OFFSET 0x100 +#define GEN_PCIE_ROOT_PORT_ACS_OFFSET \ + (GEN_PCIE_ROOT_PORT_AER_OFFSET + PCI_ERR_SIZEOF) +#define CXL_ROOT_PORT_DVSEC_OFFSET \ + (GEN_PCIE_ROOT_PORT_ACS_OFFSET + PCI_ACS_SIZEOF) + +typedef struct CXLRootPort { + /*< private >*/ + PCIESlot parent_obj; + + CXLComponentState cxl_cstate; + PCIResReserve res_reserve; +} CXLRootPort; + +#define TYPE_CXL_ROOT_PORT "cxl-rp" +DECLARE_INSTANCE_CHECKER(CXLRootPort, CXL_ROOT_PORT, TYPE_CXL_ROOT_PORT) + +static void latch_registers(CXLRootPort *crp) +{ + uint32_t *reg_state = crp->cxl_cstate.crb.cache_mem_registers; + uint32_t *write_msk = crp->cxl_cstate.crb.cache_mem_regs_write_mask; + + cxl_component_register_init_common(reg_state, write_msk, CXL2_ROOT_PORT); +} + +static void build_dvsecs(CXLComponentState *cxl) +{ + uint8_t *dvsec; + + dvsec = (uint8_t *)&(CXLDVSECPortExtensions){ 0 }; + cxl_component_create_dvsec(cxl, CXL2_ROOT_PORT, + EXTENSIONS_PORT_DVSEC_LENGTH, + EXTENSIONS_PORT_DVSEC, + EXTENSIONS_PORT_DVSEC_REVID, dvsec); + + dvsec = (uint8_t *)&(CXLDVSECPortGPF){ + .rsvd = 0, + .phase1_ctrl = 1, /* 1μs timeout */ + .phase2_ctrl = 1, /* 1μs timeout */ + }; + cxl_component_create_dvsec(cxl, CXL2_ROOT_PORT, + GPF_PORT_DVSEC_LENGTH, GPF_PORT_DVSEC, + GPF_PORT_DVSEC_REVID, dvsec); + + dvsec = (uint8_t *)&(CXLDVSECPortFlexBus){ + .cap = 0x26, /* IO, Mem, non-MLD */ + .ctrl = 0x2, + .status = 0x26, /* same */ + .rcvd_mod_ts_data_phase1 = 0xef, + }; + cxl_component_create_dvsec(cxl, CXL2_ROOT_PORT, + PCIE_FLEXBUS_PORT_DVSEC_LENGTH_2_0, + PCIE_FLEXBUS_PORT_DVSEC, + PCIE_FLEXBUS_PORT_DVSEC_REVID_2_0, dvsec); + + dvsec = (uint8_t *)&(CXLDVSECRegisterLocator){ + .rsvd = 0, + .reg0_base_lo = RBI_COMPONENT_REG | CXL_COMPONENT_REG_BAR_IDX, + .reg0_base_hi = 0, + }; + cxl_component_create_dvsec(cxl, CXL2_ROOT_PORT, + REG_LOC_DVSEC_LENGTH, REG_LOC_DVSEC, + REG_LOC_DVSEC_REVID, dvsec); +} + +static void cxl_rp_realize(DeviceState *dev, Error **errp) +{ + PCIDevice *pci_dev = PCI_DEVICE(dev); + PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev); + CXLRootPort *crp = CXL_ROOT_PORT(dev); + CXLComponentState *cxl_cstate = &crp->cxl_cstate; + ComponentRegisters *cregs = &cxl_cstate->crb; + MemoryRegion *component_bar = &cregs->component_registers; + Error *local_err = NULL; + + rpc->parent_realize(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + int rc = + pci_bridge_qemu_reserve_cap_init(pci_dev, 0, crp->res_reserve, errp); + if (rc < 0) { + rpc->parent_class.exit(pci_dev); + return; + } + + if (!crp->res_reserve.io || crp->res_reserve.io == -1) { + pci_word_test_and_clear_mask(pci_dev->wmask + PCI_COMMAND, + PCI_COMMAND_IO); + pci_dev->wmask[PCI_IO_BASE] = 0; + pci_dev->wmask[PCI_IO_LIMIT] = 0; + } + + cxl_cstate->dvsec_offset = CXL_ROOT_PORT_DVSEC_OFFSET; + cxl_cstate->pdev = pci_dev; + build_dvsecs(&crp->cxl_cstate); + + cxl_component_register_block_init(OBJECT(pci_dev), cxl_cstate, + TYPE_CXL_ROOT_PORT); + + pci_register_bar(pci_dev, CXL_COMPONENT_REG_BAR_IDX, + PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_TYPE_64, + component_bar); +} + +static void cxl_rp_reset(DeviceState *dev) +{ + PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev); + CXLRootPort *crp = CXL_ROOT_PORT(dev); + + rpc->parent_reset(dev); + + latch_registers(crp); +} + +static Property gen_rp_props[] = { + DEFINE_PROP_UINT32("bus-reserve", CXLRootPort, res_reserve.bus, -1), + DEFINE_PROP_SIZE("io-reserve", CXLRootPort, res_reserve.io, -1), + DEFINE_PROP_SIZE("mem-reserve", CXLRootPort, res_reserve.mem_non_pref, -1), + DEFINE_PROP_SIZE("pref32-reserve", CXLRootPort, res_reserve.mem_pref_32, + -1), + DEFINE_PROP_SIZE("pref64-reserve", CXLRootPort, res_reserve.mem_pref_64, + -1), + DEFINE_PROP_END_OF_LIST() +}; + +static void cxl_rp_dvsec_write_config(PCIDevice *dev, uint32_t addr, + uint32_t val, int len) +{ + CXLRootPort *crp = CXL_ROOT_PORT(dev); + + if (range_contains(&crp->cxl_cstate.dvsecs[EXTENSIONS_PORT_DVSEC], addr)) { + uint8_t *reg = &dev->config[addr]; + addr -= crp->cxl_cstate.dvsecs[EXTENSIONS_PORT_DVSEC].lob; + if (addr == PORT_CONTROL_OFFSET) { + if (pci_get_word(reg) & PORT_CONTROL_UNMASK_SBR) { + /* unmask SBR */ + qemu_log_mask(LOG_UNIMP, "SBR mask control is not supported\n"); + } + if (pci_get_word(reg) & PORT_CONTROL_ALT_MEMID_EN) { + /* Alt Memory & ID Space Enable */ + qemu_log_mask(LOG_UNIMP, + "Alt Memory & ID space is not supported\n"); + } + } + } +} + +static void cxl_rp_write_config(PCIDevice *d, uint32_t address, uint32_t val, + int len) +{ + uint16_t slt_ctl, slt_sta; + + pcie_cap_slot_get(d, &slt_ctl, &slt_sta); + pci_bridge_write_config(d, address, val, len); + pcie_cap_flr_write_config(d, address, val, len); + pcie_cap_slot_write_config(d, slt_ctl, slt_sta, address, val, len); + pcie_aer_write_config(d, address, val, len); + + cxl_rp_dvsec_write_config(d, address, val, len); +} + +static void cxl_root_port_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PCIDeviceClass *k = PCI_DEVICE_CLASS(oc); + PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(oc); + + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = CXL_ROOT_PORT_DID; + dc->desc = "CXL Root Port"; + k->revision = 0; + device_class_set_props(dc, gen_rp_props); + k->config_write = cxl_rp_write_config; + + device_class_set_parent_realize(dc, cxl_rp_realize, &rpc->parent_realize); + device_class_set_parent_reset(dc, cxl_rp_reset, &rpc->parent_reset); + + rpc->aer_offset = GEN_PCIE_ROOT_PORT_AER_OFFSET; + rpc->acs_offset = GEN_PCIE_ROOT_PORT_ACS_OFFSET; + + dc->hotpluggable = false; +} + +static const TypeInfo cxl_root_port_info = { + .name = TYPE_CXL_ROOT_PORT, + .parent = TYPE_PCIE_ROOT_PORT, + .instance_size = sizeof(CXLRootPort), + .class_init = cxl_root_port_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CXL_DEVICE }, + { } + }, +}; + +static void cxl_register(void) +{ + type_register_static(&cxl_root_port_info); +} + +type_init(cxl_register); diff --git a/hw/pci-bridge/meson.build b/hw/pci-bridge/meson.build index daab8acf2a..b6d26a03d5 100644 --- a/hw/pci-bridge/meson.build +++ b/hw/pci-bridge/meson.build @@ -5,6 +5,7 @@ pci_ss.add(when: 'CONFIG_IOH3420', if_true: files('ioh3420.c')) pci_ss.add(when: 'CONFIG_PCIE_PORT', if_true: files('pcie_root_port.c', 'gen_pcie_root_port.c', 'pcie_pci_bridge.c')) pci_ss.add(when: 'CONFIG_PXB', if_true: files('pci_expander_bridge.c')) pci_ss.add(when: 'CONFIG_XIO3130', if_true: files('xio3130_upstream.c', 'xio3130_downstream.c')) +pci_ss.add(when: 'CONFIG_CXL', if_true: files('cxl_root_port.c')) # NewWorld PowerMac pci_ss.add(when: 'CONFIG_DEC_PCI', if_true: files('dec.c')) diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c index f1cfe9d14a..460e48269d 100644 --- a/hw/pci-bridge/pcie_root_port.c +++ b/hw/pci-bridge/pcie_root_port.c @@ -67,7 +67,11 @@ static void rp_realize(PCIDevice *d, Error **errp) int rc; pci_config_set_interrupt_pin(d->config, 1); - pci_bridge_initfn(d, TYPE_PCIE_BUS); + if (d->cap_present & QEMU_PCIE_CAP_CXL) { + pci_bridge_initfn(d, TYPE_CXL_BUS); + } else { + pci_bridge_initfn(d, TYPE_PCIE_BUS); + } pcie_port_init_reg(d); rc = pci_bridge_ssvid_init(d, rpc->ssvid_offset, dc->vendor_id, diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 6c0656f604..a9b37f8000 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2762,7 +2762,9 @@ static void pci_device_class_base_init(ObjectClass *klass, void *data) object_class_dynamic_cast(klass, INTERFACE_CONVENTIONAL_PCI_DEVICE); ObjectClass *pcie = object_class_dynamic_cast(klass, INTERFACE_PCIE_DEVICE); - assert(conventional || pcie); + ObjectClass *cxl = + object_class_dynamic_cast(klass, INTERFACE_CXL_DEVICE); + assert(conventional || pcie || cxl); } } From e1706ea83da0120be6708b66394ec3a9f3ec48ca Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:42 +0100 Subject: [PATCH 286/935] hw/cxl/device: Add a memory device (8.2.8.5) A CXL memory device (AKA Type 3) is a CXL component that contains some combination of volatile and persistent memory. It also implements the previously defined mailbox interface as well as the memory device firmware interface. Although the memory device is configured like a normal PCIe device, the memory traffic is on an entirely separate bus conceptually (using the same physical wires as PCIe, but different protocol). Once the CXL topology is fully configure and address decoders committed, the guest physical address for the memory device is part of a larger window which is owned by the platform. The creation of these windows is later in this series. The following example will create a 256M device in a 512M window: -object "memory-backend-file,id=cxl-mem1,share,mem-path=cxl-type3,size=512M" -device "cxl-type3,bus=rp0,memdev=cxl-mem1,id=cxl-pmem0" Note: Dropped PCDIMM info interfaces for now. They can be added if appropriate at a later date. Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Message-Id: <20220429144110.25167-18-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-component-utils.c | 18 ++++ hw/cxl/cxl-mailbox-utils.c | 46 ++++++++++ hw/mem/Kconfig | 5 ++ hw/mem/cxl_type3.c | 162 +++++++++++++++++++++++++++++++++++ hw/mem/meson.build | 1 + include/hw/cxl/cxl_device.h | 15 ++++ include/hw/cxl/cxl_pci.h | 21 +++++ include/hw/pci/pci_ids.h | 1 + 8 files changed, 269 insertions(+) create mode 100644 hw/mem/cxl_type3.c diff --git a/hw/cxl/cxl-component-utils.c b/hw/cxl/cxl-component-utils.c index 9457a1b029..afc97b17c2 100644 --- a/hw/cxl/cxl-component-utils.c +++ b/hw/cxl/cxl-component-utils.c @@ -252,6 +252,24 @@ void cxl_component_create_dvsec(CXLComponentState *cxl, /* Configure write masks */ switch (type) { case PCIE_CXL_DEVICE_DVSEC: + /* Cntrl RW Lock - so needs explicit blocking when lock is set */ + wmask[offset + offsetof(CXLDVSECDevice, ctrl)] = 0xFD; + wmask[offset + offsetof(CXLDVSECDevice, ctrl) + 1] = 0x4F; + /* Status is RW1CS */ + wmask[offset + offsetof(CXLDVSECDevice, ctrl2)] = 0x0F; + /* Lock is RW Once */ + wmask[offset + offsetof(CXLDVSECDevice, lock)] = 0x01; + /* range1/2_base_high/low is RW Lock */ + wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi)] = 0xFF; + wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi) + 1] = 0xFF; + wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi) + 2] = 0xFF; + wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi) + 3] = 0xFF; + wmask[offset + offsetof(CXLDVSECDevice, range1_base_lo) + 3] = 0xF0; + wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi)] = 0xFF; + wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi) + 1] = 0xFF; + wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi) + 2] = 0xFF; + wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi) + 3] = 0xFF; + wmask[offset + offsetof(CXLDVSECDevice, range2_base_lo) + 3] = 0xF0; break; case NON_CXL_FUNCTION_MAP_DVSEC: break; /* Not yet implemented */ diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index db473135c7..4ae0561dfc 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -50,6 +50,8 @@ enum { LOGS = 0x04, #define GET_SUPPORTED 0x0 #define GET_LOG 0x1 + IDENTIFY = 0x40, + #define MEMORY_DEVICE 0x0 }; /* 8.2.8.4.5.1 Command Return Codes */ @@ -214,6 +216,48 @@ static ret_code cmd_logs_get_log(struct cxl_cmd *cmd, return CXL_MBOX_SUCCESS; } +/* 8.2.9.5.1.1 */ +static ret_code cmd_identify_memory_device(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len) +{ + struct { + char fw_revision[0x10]; + uint64_t total_capacity; + uint64_t volatile_capacity; + uint64_t persistent_capacity; + uint64_t partition_align; + uint16_t info_event_log_size; + uint16_t warning_event_log_size; + uint16_t failure_event_log_size; + uint16_t fatal_event_log_size; + uint32_t lsa_size; + uint8_t poison_list_max_mer[3]; + uint16_t inject_poison_limit; + uint8_t poison_caps; + uint8_t qos_telemetry_caps; + } QEMU_PACKED *id; + QEMU_BUILD_BUG_ON(sizeof(*id) != 0x43); + + uint64_t size = cxl_dstate->pmem_size; + + if (!QEMU_IS_ALIGNED(size, 256 << 20)) { + return CXL_MBOX_INTERNAL_ERROR; + } + + id = (void *)cmd->payload; + memset(id, 0, sizeof(*id)); + + /* PMEM only */ + snprintf(id->fw_revision, 0x10, "BWFW VERSION %02d", 0); + + id->total_capacity = size / (256 << 20); + id->persistent_capacity = size / (256 << 20); + + *len = sizeof(*id); + return CXL_MBOX_SUCCESS; +} + #define IMMEDIATE_CONFIG_CHANGE (1 << 1) #define IMMEDIATE_POLICY_CHANGE (1 << 3) #define IMMEDIATE_LOG_CHANGE (1 << 4) @@ -231,6 +275,8 @@ static struct cxl_cmd cxl_cmd_set[256][256] = { [TIMESTAMP][SET] = { "TIMESTAMP_SET", cmd_timestamp_set, 8, IMMEDIATE_POLICY_CHANGE }, [LOGS][GET_SUPPORTED] = { "LOGS_GET_SUPPORTED", cmd_logs_get_supported, 0, 0 }, [LOGS][GET_LOG] = { "LOGS_GET_LOG", cmd_logs_get_log, 0x18, 0 }, + [IDENTIFY][MEMORY_DEVICE] = { "IDENTIFY_MEMORY_DEVICE", + cmd_identify_memory_device, 0, 0 }, }; void cxl_process_mailbox(CXLDeviceState *cxl_dstate) diff --git a/hw/mem/Kconfig b/hw/mem/Kconfig index 03dbb3c7df..73c5ae8ad9 100644 --- a/hw/mem/Kconfig +++ b/hw/mem/Kconfig @@ -11,3 +11,8 @@ config NVDIMM config SPARSE_MEM bool + +config CXL_MEM_DEVICE + bool + default y if CXL + select MEM_DEVICE diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c new file mode 100644 index 0000000000..290c088dd6 --- /dev/null +++ b/hw/mem/cxl_type3.c @@ -0,0 +1,162 @@ +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qemu/error-report.h" +#include "hw/mem/memory-device.h" +#include "hw/mem/pc-dimm.h" +#include "hw/pci/pci.h" +#include "hw/qdev-properties.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/range.h" +#include "qemu/rcu.h" +#include "sysemu/hostmem.h" +#include "hw/cxl/cxl.h" + +static void build_dvsecs(CXLType3Dev *ct3d) +{ + CXLComponentState *cxl_cstate = &ct3d->cxl_cstate; + uint8_t *dvsec; + + dvsec = (uint8_t *)&(CXLDVSECDevice){ + .cap = 0x1e, + .ctrl = 0x2, + .status2 = 0x2, + .range1_size_hi = ct3d->hostmem->size >> 32, + .range1_size_lo = (2 << 5) | (2 << 2) | 0x3 | + (ct3d->hostmem->size & 0xF0000000), + .range1_base_hi = 0, + .range1_base_lo = 0, + }; + cxl_component_create_dvsec(cxl_cstate, CXL2_TYPE3_DEVICE, + PCIE_CXL_DEVICE_DVSEC_LENGTH, + PCIE_CXL_DEVICE_DVSEC, + PCIE_CXL2_DEVICE_DVSEC_REVID, dvsec); + + dvsec = (uint8_t *)&(CXLDVSECRegisterLocator){ + .rsvd = 0, + .reg0_base_lo = RBI_COMPONENT_REG | CXL_COMPONENT_REG_BAR_IDX, + .reg0_base_hi = 0, + .reg1_base_lo = RBI_CXL_DEVICE_REG | CXL_DEVICE_REG_BAR_IDX, + .reg1_base_hi = 0, + }; + cxl_component_create_dvsec(cxl_cstate, CXL2_TYPE3_DEVICE, + REG_LOC_DVSEC_LENGTH, REG_LOC_DVSEC, + REG_LOC_DVSEC_REVID, dvsec); + dvsec = (uint8_t *)&(CXLDVSECDeviceGPF){ + .phase2_duration = 0x603, /* 3 seconds */ + .phase2_power = 0x33, /* 0x33 miliwatts */ + }; + cxl_component_create_dvsec(cxl_cstate, CXL2_TYPE3_DEVICE, + GPF_DEVICE_DVSEC_LENGTH, GPF_PORT_DVSEC, + GPF_DEVICE_DVSEC_REVID, dvsec); +} + +static bool cxl_setup_memory(CXLType3Dev *ct3d, Error **errp) +{ + MemoryRegion *mr; + + if (!ct3d->hostmem) { + error_setg(errp, "memdev property must be set"); + return false; + } + + mr = host_memory_backend_get_memory(ct3d->hostmem); + if (!mr) { + error_setg(errp, "memdev property must be set"); + return false; + } + memory_region_set_nonvolatile(mr, true); + memory_region_set_enabled(mr, true); + host_memory_backend_set_mapped(ct3d->hostmem, true); + ct3d->cxl_dstate.pmem_size = ct3d->hostmem->size; + + return true; +} + +static void ct3_realize(PCIDevice *pci_dev, Error **errp) +{ + CXLType3Dev *ct3d = CXL_TYPE3(pci_dev); + CXLComponentState *cxl_cstate = &ct3d->cxl_cstate; + ComponentRegisters *regs = &cxl_cstate->crb; + MemoryRegion *mr = ®s->component_registers; + uint8_t *pci_conf = pci_dev->config; + + if (!cxl_setup_memory(ct3d, errp)) { + return; + } + + pci_config_set_prog_interface(pci_conf, 0x10); + pci_config_set_class(pci_conf, PCI_CLASS_MEMORY_CXL); + + pcie_endpoint_cap_init(pci_dev, 0x80); + cxl_cstate->dvsec_offset = 0x100; + + ct3d->cxl_cstate.pdev = pci_dev; + build_dvsecs(ct3d); + + cxl_component_register_block_init(OBJECT(pci_dev), cxl_cstate, + TYPE_CXL_TYPE3); + + pci_register_bar( + pci_dev, CXL_COMPONENT_REG_BAR_IDX, + PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64, mr); + + cxl_device_register_block_init(OBJECT(pci_dev), &ct3d->cxl_dstate); + pci_register_bar(pci_dev, CXL_DEVICE_REG_BAR_IDX, + PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_TYPE_64, + &ct3d->cxl_dstate.device_registers); +} + +static void ct3d_reset(DeviceState *dev) +{ + CXLType3Dev *ct3d = CXL_TYPE3(dev); + uint32_t *reg_state = ct3d->cxl_cstate.crb.cache_mem_registers; + uint32_t *write_msk = ct3d->cxl_cstate.crb.cache_mem_regs_write_mask; + + cxl_component_register_init_common(reg_state, write_msk, CXL2_TYPE3_DEVICE); + cxl_device_register_init_common(&ct3d->cxl_dstate); +} + +static Property ct3_props[] = { + DEFINE_PROP_LINK("memdev", CXLType3Dev, hostmem, TYPE_MEMORY_BACKEND, + HostMemoryBackend *), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ct3_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc); + + pc->realize = ct3_realize; + pc->class_id = PCI_CLASS_STORAGE_EXPRESS; + pc->vendor_id = PCI_VENDOR_ID_INTEL; + pc->device_id = 0xd93; /* LVF for now */ + pc->revision = 1; + + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + dc->desc = "CXL PMEM Device (Type 3)"; + dc->reset = ct3d_reset; + device_class_set_props(dc, ct3_props); +} + +static const TypeInfo ct3d_info = { + .name = TYPE_CXL_TYPE3, + .parent = TYPE_PCI_DEVICE, + .class_init = ct3_class_init, + .instance_size = sizeof(CXLType3Dev), + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CXL_DEVICE }, + { INTERFACE_PCIE_DEVICE }, + {} + }, +}; + +static void ct3d_registers(void) +{ + type_register_static(&ct3d_info); +} + +type_init(ct3d_registers); diff --git a/hw/mem/meson.build b/hw/mem/meson.build index 82f86d117e..609b2b36fc 100644 --- a/hw/mem/meson.build +++ b/hw/mem/meson.build @@ -3,6 +3,7 @@ mem_ss.add(files('memory-device.c')) mem_ss.add(when: 'CONFIG_DIMM', if_true: files('pc-dimm.c')) mem_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_mc.c')) mem_ss.add(when: 'CONFIG_NVDIMM', if_true: files('nvdimm.c')) +mem_ss.add(when: 'CONFIG_CXL_MEM_DEVICE', if_true: files('cxl_type3.c')) softmmu_ss.add_all(when: 'CONFIG_MEM_DEVICE', if_true: mem_ss) diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index 797a22ddb4..d8da2c7b68 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -230,4 +230,19 @@ REG64(CXL_MEM_DEV_STS, 0) FIELD(CXL_MEM_DEV_STS, MBOX_READY, 4, 1) FIELD(CXL_MEM_DEV_STS, RESET_NEEDED, 5, 3) +struct CXLType3Dev { + /* Private */ + PCIDevice parent_obj; + + /* Properties */ + HostMemoryBackend *hostmem; + + /* State */ + CXLComponentState cxl_cstate; + CXLDeviceState cxl_dstate; +}; + +#define TYPE_CXL_TYPE3 "cxl-type3" +OBJECT_DECLARE_SIMPLE_TYPE(CXLType3Dev, CXL_TYPE3) + #endif diff --git a/include/hw/cxl/cxl_pci.h b/include/hw/cxl/cxl_pci.h index 3f7e44daac..01cf002096 100644 --- a/include/hw/cxl/cxl_pci.h +++ b/include/hw/cxl/cxl_pci.h @@ -67,6 +67,27 @@ QEMU_BUILD_BUG_ON(sizeof(DVSECHeader) != 10); * CXL 2.0 Downstream Port: 3, 4, 7, 8 */ +/* CXL 2.0 - 8.1.3 (ID 0001) */ +typedef struct CXLDVSECDevice { + DVSECHeader hdr; + uint16_t cap; + uint16_t ctrl; + uint16_t status; + uint16_t ctrl2; + uint16_t status2; + uint16_t lock; + uint16_t cap2; + uint32_t range1_size_hi; + uint32_t range1_size_lo; + uint32_t range1_base_hi; + uint32_t range1_base_lo; + uint32_t range2_size_hi; + uint32_t range2_size_lo; + uint32_t range2_base_hi; + uint32_t range2_base_lo; +} CXLDVSECDevice; +QEMU_BUILD_BUG_ON(sizeof(CXLDVSECDevice) != 0x38); + /* CXL 2.0 - 8.1.5 (ID 0003) */ typedef struct CXLDVSECPortExtensions { DVSECHeader hdr; diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h index 11abe22d46..898083b86f 100644 --- a/include/hw/pci/pci_ids.h +++ b/include/hw/pci/pci_ids.h @@ -53,6 +53,7 @@ #define PCI_BASE_CLASS_MEMORY 0x05 #define PCI_CLASS_MEMORY_RAM 0x0500 #define PCI_CLASS_MEMORY_FLASH 0x0501 +#define PCI_CLASS_MEMORY_CXL 0x0502 #define PCI_CLASS_MEMORY_OTHER 0x0580 #define PCI_BASE_CLASS_BRIDGE 0x06 From 947515fc4274bd46cc93f82c3121df6ee4968786 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:43 +0100 Subject: [PATCH 287/935] hw/cxl/device: Implement MMIO HDM decoding (8.2.5.12) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A device's volatile and persistent memory are known Host Defined Memory (HDM) regions. The mechanism by which the device is programmed to claim the addresses associated with those regions is through dedicated logic known as the HDM decoder. In order to allow the OS to properly program the HDMs, the HDM decoders must be modeled. There are two ways the HDM decoders can be implemented, the legacy mechanism is through the PCIe DVSEC programming from CXL 1.1 (8.1.3.8), and MMIO is found in 8.2.5.12 of the spec. For now, 8.1.3.8 is not implemented. Much of CXL device logic is implemented in cxl-utils. The HDM decoder however is implemented directly by the device implementation. Whilst the implementation currently does no validity checks on the encoder set up, future work will add sanity checking specific to the type of cxl component. Signed-off-by: Ben Widawsky Co-developed-by: Jonathan Cameron Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-19-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/mem/cxl_type3.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index 290c088dd6..318b6f9fbc 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -52,6 +52,48 @@ static void build_dvsecs(CXLType3Dev *ct3d) GPF_DEVICE_DVSEC_REVID, dvsec); } +static void hdm_decoder_commit(CXLType3Dev *ct3d, int which) +{ + ComponentRegisters *cregs = &ct3d->cxl_cstate.crb; + uint32_t *cache_mem = cregs->cache_mem_registers; + + assert(which == 0); + + /* TODO: Sanity checks that the decoder is possible */ + ARRAY_FIELD_DP32(cache_mem, CXL_HDM_DECODER0_CTRL, COMMIT, 0); + ARRAY_FIELD_DP32(cache_mem, CXL_HDM_DECODER0_CTRL, ERR, 0); + + ARRAY_FIELD_DP32(cache_mem, CXL_HDM_DECODER0_CTRL, COMMITTED, 1); +} + +static void ct3d_reg_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + CXLComponentState *cxl_cstate = opaque; + ComponentRegisters *cregs = &cxl_cstate->crb; + CXLType3Dev *ct3d = container_of(cxl_cstate, CXLType3Dev, cxl_cstate); + uint32_t *cache_mem = cregs->cache_mem_registers; + bool should_commit = false; + int which_hdm = -1; + + assert(size == 4); + g_assert(offset < CXL2_COMPONENT_CM_REGION_SIZE); + + switch (offset) { + case A_CXL_HDM_DECODER0_CTRL: + should_commit = FIELD_EX32(value, CXL_HDM_DECODER0_CTRL, COMMIT); + which_hdm = 0; + break; + default: + break; + } + + stl_le_p((uint8_t *)cache_mem + offset, value); + if (should_commit) { + hdm_decoder_commit(ct3d, which_hdm); + } +} + static bool cxl_setup_memory(CXLType3Dev *ct3d, Error **errp) { MemoryRegion *mr; @@ -95,6 +137,9 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp) ct3d->cxl_cstate.pdev = pci_dev; build_dvsecs(ct3d); + regs->special_ops = g_new0(MemoryRegionOps, 1); + regs->special_ops->write = ct3d_reg_write; + cxl_component_register_block_init(OBJECT(pci_dev), cxl_cstate, TYPE_CXL_TYPE3); @@ -109,6 +154,15 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp) &ct3d->cxl_dstate.device_registers); } +static void ct3_exit(PCIDevice *pci_dev) +{ + CXLType3Dev *ct3d = CXL_TYPE3(pci_dev); + CXLComponentState *cxl_cstate = &ct3d->cxl_cstate; + ComponentRegisters *regs = &cxl_cstate->crb; + + g_free(regs->special_ops); +} + static void ct3d_reset(DeviceState *dev) { CXLType3Dev *ct3d = CXL_TYPE3(dev); @@ -131,6 +185,7 @@ static void ct3_class_init(ObjectClass *oc, void *data) PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc); pc->realize = ct3_realize; + pc->exit = ct3_exit; pc->class_id = PCI_CLASS_STORAGE_EXPRESS; pc->vendor_id = PCI_VENDOR_ID_INTEL; pc->device_id = 0xd93; /* LVF for now */ From 092c6b11f2ab835f50b3167d0559c197a21a051e Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:44 +0100 Subject: [PATCH 288/935] hw/cxl/device: Add some trivial commands GET_FW_INFO and GET_PARTITION_INFO, for this emulation, is equivalent to info already returned in the IDENTIFY command. To have a more robust implementation, add those. Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Message-Id: <20220429144110.25167-20-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 69 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 4ae0561dfc..c8188d7087 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -10,6 +10,7 @@ #include "qemu/osdep.h" #include "hw/cxl/cxl.h" #include "hw/pci/pci.h" +#include "qemu/cutils.h" #include "qemu/log.h" #include "qemu/uuid.h" @@ -44,6 +45,8 @@ enum { #define CLEAR_RECORDS 0x1 #define GET_INTERRUPT_POLICY 0x2 #define SET_INTERRUPT_POLICY 0x3 + FIRMWARE_UPDATE = 0x02, + #define GET_INFO 0x0 TIMESTAMP = 0x03, #define GET 0x0 #define SET 0x1 @@ -52,6 +55,8 @@ enum { #define GET_LOG 0x1 IDENTIFY = 0x40, #define MEMORY_DEVICE 0x0 + CCLS = 0x41, + #define GET_PARTITION_INFO 0x0 }; /* 8.2.8.4.5.1 Command Return Codes */ @@ -114,6 +119,39 @@ DEFINE_MAILBOX_HANDLER_NOP(events_clear_records); DEFINE_MAILBOX_HANDLER_ZEROED(events_get_interrupt_policy, 4); DEFINE_MAILBOX_HANDLER_NOP(events_set_interrupt_policy); +/* 8.2.9.2.1 */ +static ret_code cmd_firmware_update_get_info(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len) +{ + struct { + uint8_t slots_supported; + uint8_t slot_info; + uint8_t caps; + uint8_t rsvd[0xd]; + char fw_rev1[0x10]; + char fw_rev2[0x10]; + char fw_rev3[0x10]; + char fw_rev4[0x10]; + } QEMU_PACKED *fw_info; + QEMU_BUILD_BUG_ON(sizeof(*fw_info) != 0x50); + + if (cxl_dstate->pmem_size < (256 << 20)) { + return CXL_MBOX_INTERNAL_ERROR; + } + + fw_info = (void *)cmd->payload; + memset(fw_info, 0, sizeof(*fw_info)); + + fw_info->slots_supported = 2; + fw_info->slot_info = BIT(0) | BIT(3); + fw_info->caps = 0; + pstrcpy(fw_info->fw_rev1, sizeof(fw_info->fw_rev1), "BWFW VERSION 0"); + + *len = sizeof(*fw_info); + return CXL_MBOX_SUCCESS; +} + /* 8.2.9.3.1 */ static ret_code cmd_timestamp_get(struct cxl_cmd *cmd, CXLDeviceState *cxl_dstate, @@ -258,6 +296,33 @@ static ret_code cmd_identify_memory_device(struct cxl_cmd *cmd, return CXL_MBOX_SUCCESS; } +static ret_code cmd_ccls_get_partition_info(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len) +{ + struct { + uint64_t active_vmem; + uint64_t active_pmem; + uint64_t next_vmem; + uint64_t next_pmem; + } QEMU_PACKED *part_info = (void *)cmd->payload; + QEMU_BUILD_BUG_ON(sizeof(*part_info) != 0x20); + uint64_t size = cxl_dstate->pmem_size; + + if (!QEMU_IS_ALIGNED(size, 256 << 20)) { + return CXL_MBOX_INTERNAL_ERROR; + } + + /* PMEM only */ + part_info->active_vmem = 0; + part_info->next_vmem = 0; + part_info->active_pmem = size / (256 << 20); + part_info->next_pmem = 0; + + *len = sizeof(*part_info); + return CXL_MBOX_SUCCESS; +} + #define IMMEDIATE_CONFIG_CHANGE (1 << 1) #define IMMEDIATE_POLICY_CHANGE (1 << 3) #define IMMEDIATE_LOG_CHANGE (1 << 4) @@ -271,12 +336,16 @@ static struct cxl_cmd cxl_cmd_set[256][256] = { cmd_events_get_interrupt_policy, 0, 0 }, [EVENTS][SET_INTERRUPT_POLICY] = { "EVENTS_SET_INTERRUPT_POLICY", cmd_events_set_interrupt_policy, 4, IMMEDIATE_CONFIG_CHANGE }, + [FIRMWARE_UPDATE][GET_INFO] = { "FIRMWARE_UPDATE_GET_INFO", + cmd_firmware_update_get_info, 0, 0 }, [TIMESTAMP][GET] = { "TIMESTAMP_GET", cmd_timestamp_get, 0, 0 }, [TIMESTAMP][SET] = { "TIMESTAMP_SET", cmd_timestamp_set, 8, IMMEDIATE_POLICY_CHANGE }, [LOGS][GET_SUPPORTED] = { "LOGS_GET_SUPPORTED", cmd_logs_get_supported, 0, 0 }, [LOGS][GET_LOG] = { "LOGS_GET_LOG", cmd_logs_get_log, 0x18, 0 }, [IDENTIFY][MEMORY_DEVICE] = { "IDENTIFY_MEMORY_DEVICE", cmd_identify_memory_device, 0, 0 }, + [CCLS][GET_PARTITION_INFO] = { "CCLS_GET_PARTITION_INFO", + cmd_ccls_get_partition_info, 0, 0 }, }; void cxl_process_mailbox(CXLDeviceState *cxl_dstate) From 639daf8e93bcf266d0518eecbcfe12d26644a0a9 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:45 +0100 Subject: [PATCH 289/935] hw/cxl/device: Plumb real Label Storage Area (LSA) sizing This should introduce no change. Subsequent work will make use of this new class member. Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Message-Id: <20220429144110.25167-21-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 3 +++ hw/mem/cxl_type3.c | 9 +++++++++ include/hw/cxl/cxl_device.h | 11 ++++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index c8188d7087..492739aef3 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -277,6 +277,8 @@ static ret_code cmd_identify_memory_device(struct cxl_cmd *cmd, } QEMU_PACKED *id; QEMU_BUILD_BUG_ON(sizeof(*id) != 0x43); + CXLType3Dev *ct3d = container_of(cxl_dstate, CXLType3Dev, cxl_dstate); + CXLType3Class *cvc = CXL_TYPE3_GET_CLASS(ct3d); uint64_t size = cxl_dstate->pmem_size; if (!QEMU_IS_ALIGNED(size, 256 << 20)) { @@ -291,6 +293,7 @@ static ret_code cmd_identify_memory_device(struct cxl_cmd *cmd, id->total_capacity = size / (256 << 20); id->persistent_capacity = size / (256 << 20); + id->lsa_size = cvc->get_lsa_size(ct3d); *len = sizeof(*id); return CXL_MBOX_SUCCESS; diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index 318b6f9fbc..b5aa1067df 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -179,10 +179,16 @@ static Property ct3_props[] = { DEFINE_PROP_END_OF_LIST(), }; +static uint64_t get_lsa_size(CXLType3Dev *ct3d) +{ + return 0; +} + static void ct3_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc); + CXLType3Class *cvc = CXL_TYPE3_CLASS(oc); pc->realize = ct3_realize; pc->exit = ct3_exit; @@ -195,11 +201,14 @@ static void ct3_class_init(ObjectClass *oc, void *data) dc->desc = "CXL PMEM Device (Type 3)"; dc->reset = ct3d_reset; device_class_set_props(dc, ct3_props); + + cvc->get_lsa_size = get_lsa_size; } static const TypeInfo ct3d_info = { .name = TYPE_CXL_TYPE3, .parent = TYPE_PCI_DEVICE, + .class_size = sizeof(struct CXLType3Class), .class_init = ct3_class_init, .instance_size = sizeof(CXLType3Dev), .interfaces = (InterfaceInfo[]) { diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index d8da2c7b68..ea2571a69b 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -236,6 +236,7 @@ struct CXLType3Dev { /* Properties */ HostMemoryBackend *hostmem; + HostMemoryBackend *lsa; /* State */ CXLComponentState cxl_cstate; @@ -243,6 +244,14 @@ struct CXLType3Dev { }; #define TYPE_CXL_TYPE3 "cxl-type3" -OBJECT_DECLARE_SIMPLE_TYPE(CXLType3Dev, CXL_TYPE3) +OBJECT_DECLARE_TYPE(CXLType3Dev, CXLType3Class, CXL_TYPE3) + +struct CXLType3Class { + /* Private */ + PCIDeviceClass parent_class; + + /* public */ + uint64_t (*get_lsa_size)(CXLType3Dev *ct3d); +}; #endif From 3ebe676a3463b886cfc112b3eff58e4991051b0d Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:46 +0100 Subject: [PATCH 290/935] hw/cxl/device: Implement get/set Label Storage Area (LSA) Implement get and set handlers for the Label Storage Area used to hold data describing persistent memory configuration so that it can be ensured it is seen in the same configuration after reboot. Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Message-Id: <20220429144110.25167-22-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 60 +++++++++++++++++++++++++++++++++++++ hw/mem/cxl_type3.c | 56 +++++++++++++++++++++++++++++++++- include/hw/cxl/cxl_device.h | 5 ++++ 3 files changed, 120 insertions(+), 1 deletion(-) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 492739aef3..bb66c765a5 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -57,6 +57,8 @@ enum { #define MEMORY_DEVICE 0x0 CCLS = 0x41, #define GET_PARTITION_INFO 0x0 + #define GET_LSA 0x2 + #define SET_LSA 0x3 }; /* 8.2.8.4.5.1 Command Return Codes */ @@ -326,7 +328,62 @@ static ret_code cmd_ccls_get_partition_info(struct cxl_cmd *cmd, return CXL_MBOX_SUCCESS; } +static ret_code cmd_ccls_get_lsa(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len) +{ + struct { + uint32_t offset; + uint32_t length; + } QEMU_PACKED *get_lsa; + CXLType3Dev *ct3d = container_of(cxl_dstate, CXLType3Dev, cxl_dstate); + CXLType3Class *cvc = CXL_TYPE3_GET_CLASS(ct3d); + uint32_t offset, length; + + get_lsa = (void *)cmd->payload; + offset = get_lsa->offset; + length = get_lsa->length; + + if (offset + length > cvc->get_lsa_size(ct3d)) { + *len = 0; + return CXL_MBOX_INVALID_INPUT; + } + + *len = cvc->get_lsa(ct3d, get_lsa, length, offset); + return CXL_MBOX_SUCCESS; +} + +static ret_code cmd_ccls_set_lsa(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len) +{ + struct set_lsa_pl { + uint32_t offset; + uint32_t rsvd; + uint8_t data[]; + } QEMU_PACKED; + struct set_lsa_pl *set_lsa_payload = (void *)cmd->payload; + CXLType3Dev *ct3d = container_of(cxl_dstate, CXLType3Dev, cxl_dstate); + CXLType3Class *cvc = CXL_TYPE3_GET_CLASS(ct3d); + const size_t hdr_len = offsetof(struct set_lsa_pl, data); + uint16_t plen = *len; + + *len = 0; + if (!plen) { + return CXL_MBOX_SUCCESS; + } + + if (set_lsa_payload->offset + plen > cvc->get_lsa_size(ct3d) + hdr_len) { + return CXL_MBOX_INVALID_INPUT; + } + plen -= hdr_len; + + cvc->set_lsa(ct3d, set_lsa_payload->data, plen, set_lsa_payload->offset); + return CXL_MBOX_SUCCESS; +} + #define IMMEDIATE_CONFIG_CHANGE (1 << 1) +#define IMMEDIATE_DATA_CHANGE (1 << 2) #define IMMEDIATE_POLICY_CHANGE (1 << 3) #define IMMEDIATE_LOG_CHANGE (1 << 4) @@ -349,6 +406,9 @@ static struct cxl_cmd cxl_cmd_set[256][256] = { cmd_identify_memory_device, 0, 0 }, [CCLS][GET_PARTITION_INFO] = { "CCLS_GET_PARTITION_INFO", cmd_ccls_get_partition_info, 0, 0 }, + [CCLS][GET_LSA] = { "CCLS_GET_LSA", cmd_ccls_get_lsa, 0, 0 }, + [CCLS][SET_LSA] = { "CCLS_SET_LSA", cmd_ccls_set_lsa, + ~0, IMMEDIATE_CONFIG_CHANGE | IMMEDIATE_DATA_CHANGE }, }; void cxl_process_mailbox(CXLDeviceState *cxl_dstate) diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index b5aa1067df..6c6ed9a776 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -8,6 +8,7 @@ #include "qapi/error.h" #include "qemu/log.h" #include "qemu/module.h" +#include "qemu/pmem.h" #include "qemu/range.h" #include "qemu/rcu.h" #include "sysemu/hostmem.h" @@ -113,6 +114,11 @@ static bool cxl_setup_memory(CXLType3Dev *ct3d, Error **errp) host_memory_backend_set_mapped(ct3d->hostmem, true); ct3d->cxl_dstate.pmem_size = ct3d->hostmem->size; + if (!ct3d->lsa) { + error_setg(errp, "lsa property must be set"); + return false; + } + return true; } @@ -176,12 +182,58 @@ static void ct3d_reset(DeviceState *dev) static Property ct3_props[] = { DEFINE_PROP_LINK("memdev", CXLType3Dev, hostmem, TYPE_MEMORY_BACKEND, HostMemoryBackend *), + DEFINE_PROP_LINK("lsa", CXLType3Dev, lsa, TYPE_MEMORY_BACKEND, + HostMemoryBackend *), DEFINE_PROP_END_OF_LIST(), }; static uint64_t get_lsa_size(CXLType3Dev *ct3d) { - return 0; + MemoryRegion *mr; + + mr = host_memory_backend_get_memory(ct3d->lsa); + return memory_region_size(mr); +} + +static void validate_lsa_access(MemoryRegion *mr, uint64_t size, + uint64_t offset) +{ + assert(offset + size <= memory_region_size(mr)); + assert(offset + size > offset); +} + +static uint64_t get_lsa(CXLType3Dev *ct3d, void *buf, uint64_t size, + uint64_t offset) +{ + MemoryRegion *mr; + void *lsa; + + mr = host_memory_backend_get_memory(ct3d->lsa); + validate_lsa_access(mr, size, offset); + + lsa = memory_region_get_ram_ptr(mr) + offset; + memcpy(buf, lsa, size); + + return size; +} + +static void set_lsa(CXLType3Dev *ct3d, const void *buf, uint64_t size, + uint64_t offset) +{ + MemoryRegion *mr; + void *lsa; + + mr = host_memory_backend_get_memory(ct3d->lsa); + validate_lsa_access(mr, size, offset); + + lsa = memory_region_get_ram_ptr(mr) + offset; + memcpy(lsa, buf, size); + memory_region_set_dirty(mr, offset, size); + + /* + * Just like the PMEM, if the guest is not allowed to exit gracefully, label + * updates will get lost. + */ } static void ct3_class_init(ObjectClass *oc, void *data) @@ -203,6 +255,8 @@ static void ct3_class_init(ObjectClass *oc, void *data) device_class_set_props(dc, ct3_props); cvc->get_lsa_size = get_lsa_size; + cvc->get_lsa = get_lsa; + cvc->set_lsa = set_lsa; } static const TypeInfo ct3d_info = { diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index ea2571a69b..4285fbda08 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -252,6 +252,11 @@ struct CXLType3Class { /* public */ uint64_t (*get_lsa_size)(CXLType3Dev *ct3d); + + uint64_t (*get_lsa)(CXLType3Dev *ct3d, void *buf, uint64_t size, + uint64_t offset); + void (*set_lsa)(CXLType3Dev *ct3d, const void *buf, uint64_t size, + uint64_t offset); }; #endif From 92fd46b68a0ca2f37d46fd69616034b2703966b2 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 29 Apr 2022 15:40:47 +0100 Subject: [PATCH 291/935] qtests/cxl: Add initial root port and CXL type3 tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At this stage we can boot configurations with host bridges, root ports and type 3 memory devices, so add appropriate tests. Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-23-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/cxl-test.c | 127 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/tests/qtest/cxl-test.c b/tests/qtest/cxl-test.c index c031049930..5f0794e816 100644 --- a/tests/qtest/cxl-test.c +++ b/tests/qtest/cxl-test.c @@ -8,15 +8,142 @@ #include "qemu/osdep.h" #include "libqtest-single.h" +#define QEMU_PXB_CMD "-machine q35,cxl=on " \ + "-device pxb-cxl,id=cxl.0,bus=pcie.0,bus_nr=52 " + +#define QEMU_2PXB_CMD "-machine q35,cxl=on " \ + "-device pxb-cxl,id=cxl.0,bus=pcie.0,bus_nr=52 " \ + "-device pxb-cxl,id=cxl.1,bus=pcie.0,bus_nr=53 " + +#define QEMU_RP "-device cxl-rp,id=rp0,bus=cxl.0,chassis=0,slot=0 " + +/* Dual ports on first pxb */ +#define QEMU_2RP "-device cxl-rp,id=rp0,bus=cxl.0,chassis=0,slot=0 " \ + "-device cxl-rp,id=rp1,bus=cxl.0,chassis=0,slot=1 " + +/* Dual ports on each of the pxb instances */ +#define QEMU_4RP "-device cxl-rp,id=rp0,bus=cxl.0,chassis=0,slot=0 " \ + "-device cxl-rp,id=rp1,bus=cxl.0,chassis=0,slot=1 " \ + "-device cxl-rp,id=rp2,bus=cxl.1,chassis=0,slot=2 " \ + "-device cxl-rp,id=rp3,bus=cxl.1,chassis=0,slot=3 " + +#define QEMU_T3D "-object memory-backend-file,id=cxl-mem0,mem-path=%s,size=256M " \ + "-object memory-backend-file,id=lsa0,mem-path=%s,size=256M " \ + "-device cxl-type3,bus=rp0,memdev=cxl-mem0,lsa=lsa0,id=cxl-pmem0 " + +#define QEMU_2T3D "-object memory-backend-file,id=cxl-mem0,mem-path=%s,size=256M " \ + "-object memory-backend-file,id=lsa0,mem-path=%s,size=256M " \ + "-device cxl-type3,bus=rp0,memdev=cxl-mem0,lsa=lsa0,id=cxl-pmem0 " \ + "-object memory-backend-file,id=cxl-mem1,mem-path=%s,size=256M " \ + "-object memory-backend-file,id=lsa1,mem-path=%s,size=256M " \ + "-device cxl-type3,bus=rp1,memdev=cxl-mem1,lsa=lsa1,id=cxl-pmem1 " + +#define QEMU_4T3D "-object memory-backend-file,id=cxl-mem0,mem-path=%s,size=256M " \ + "-object memory-backend-file,id=lsa0,mem-path=%s,size=256M " \ + "-device cxl-type3,bus=rp0,memdev=cxl-mem0,lsa=lsa0,id=cxl-pmem0 " \ + "-object memory-backend-file,id=cxl-mem1,mem-path=%s,size=256M " \ + "-object memory-backend-file,id=lsa1,mem-path=%s,size=256M " \ + "-device cxl-type3,bus=rp1,memdev=cxl-mem1,lsa=lsa1,id=cxl-pmem1 " \ + "-object memory-backend-file,id=cxl-mem2,mem-path=%s,size=256M " \ + "-object memory-backend-file,id=lsa2,mem-path=%s,size=256M " \ + "-device cxl-type3,bus=rp2,memdev=cxl-mem2,lsa=lsa2,id=cxl-pmem2 " \ + "-object memory-backend-file,id=cxl-mem3,mem-path=%s,size=256M " \ + "-object memory-backend-file,id=lsa3,mem-path=%s,size=256M " \ + "-device cxl-type3,bus=rp3,memdev=cxl-mem3,lsa=lsa3,id=cxl-pmem3 " + +static void cxl_basic_hb(void) +{ + qtest_start("-machine q35,cxl=on"); + qtest_end(); +} + static void cxl_basic_pxb(void) { qtest_start("-machine q35,cxl=on -device pxb-cxl,bus=pcie.0"); qtest_end(); } +static void cxl_pxb_with_window(void) +{ + qtest_start(QEMU_PXB_CMD); + qtest_end(); +} + +static void cxl_2pxb_with_window(void) +{ + qtest_start(QEMU_2PXB_CMD); + qtest_end(); +} + +static void cxl_root_port(void) +{ + qtest_start(QEMU_PXB_CMD QEMU_RP); + qtest_end(); +} + +static void cxl_2root_port(void) +{ + qtest_start(QEMU_PXB_CMD QEMU_2RP); + qtest_end(); +} + +static void cxl_t3d(void) +{ + g_autoptr(GString) cmdline = g_string_new(NULL); + char template[] = "/tmp/cxl-test-XXXXXX"; + const char *tmpfs; + + tmpfs = mkdtemp(template); + + g_string_printf(cmdline, QEMU_PXB_CMD QEMU_RP QEMU_T3D, tmpfs, tmpfs); + + qtest_start(cmdline->str); + qtest_end(); +} + +static void cxl_1pxb_2rp_2t3d(void) +{ + g_autoptr(GString) cmdline = g_string_new(NULL); + char template[] = "/tmp/cxl-test-XXXXXX"; + const char *tmpfs; + + tmpfs = mkdtemp(template); + + g_string_printf(cmdline, QEMU_PXB_CMD QEMU_2RP QEMU_2T3D, + tmpfs, tmpfs, tmpfs, tmpfs); + + qtest_start(cmdline->str); + qtest_end(); +} + +static void cxl_2pxb_4rp_4t3d(void) +{ + g_autoptr(GString) cmdline = g_string_new(NULL); + char template[] = "/tmp/cxl-test-XXXXXX"; + const char *tmpfs; + + tmpfs = mkdtemp(template); + + g_string_printf(cmdline, QEMU_2PXB_CMD QEMU_4RP QEMU_4T3D, + tmpfs, tmpfs, tmpfs, tmpfs, tmpfs, tmpfs, + tmpfs, tmpfs); + + qtest_start(cmdline->str); + qtest_end(); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); + + qtest_add_func("/pci/cxl/basic_hostbridge", cxl_basic_hb); qtest_add_func("/pci/cxl/basic_pxb", cxl_basic_pxb); + qtest_add_func("/pci/cxl/pxb_with_window", cxl_pxb_with_window); + qtest_add_func("/pci/cxl/pxb_x2_with_window", cxl_2pxb_with_window); + qtest_add_func("/pci/cxl/rp", cxl_root_port); + qtest_add_func("/pci/cxl/rp_x2", cxl_2root_port); + qtest_add_func("/pci/cxl/type3_device", cxl_t3d); + qtest_add_func("/pci/cxl/rp_x2_type3_x2", cxl_1pxb_2rp_2t3d); + qtest_add_func("/pci/cxl/pxb_x2_root_port_x4_type3_x4", cxl_2pxb_4rp_4t3d); return g_test_run(); } From 6e4e3ae936e6bc1501fc0d67444738cec7a1e78a Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:48 +0100 Subject: [PATCH 292/935] hw/cxl/component: Implement host bridge MMIO (8.2.5, table 142) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CXL host bridges themselves may have MMIO. Since host bridges don't have a BAR they are treated as special for MMIO. This patch includes i386/pc support. Also hook up the device reset now that we have have the MMIO space in which the results are visible. Note that we duplicate the PCI express case for the aml_build but the implementations will diverge when the CXL specific _OSC is introduced. Signed-off-by: Ben Widawsky Co-developed-by: Jonathan Cameron Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-24-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 25 ++++++++++- hw/i386/pc.c | 27 +++++++++++- hw/pci-bridge/pci_expander_bridge.c | 66 ++++++++++++++++++++++++++--- include/hw/cxl/cxl.h | 14 ++++++ 4 files changed, 122 insertions(+), 10 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index dcf6ece3d0..2d81b0f40c 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -28,6 +28,7 @@ #include "qemu/bitmap.h" #include "qemu/error-report.h" #include "hw/pci/pci.h" +#include "hw/cxl/cxl.h" #include "hw/core/cpu.h" #include "target/i386/cpu.h" #include "hw/misc/pvpanic.h" @@ -1572,10 +1573,21 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, } scope = aml_scope("\\_SB"); - dev = aml_device("PC%.02X", bus_num); + + if (pci_bus_is_cxl(bus)) { + dev = aml_device("CL%.02X", bus_num); + } else { + dev = aml_device("PC%.02X", bus_num); + } aml_append(dev, aml_name_decl("_UID", aml_int(bus_num))); aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num))); - if (pci_bus_is_express(bus)) { + if (pci_bus_is_cxl(bus)) { + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); + aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); + + /* Expander bridges do not have ACPI PCI Hot-plug enabled */ + aml_append(dev, build_q35_osc_method(true)); + } else if (pci_bus_is_express(bus)) { aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); @@ -1595,6 +1607,15 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dev, aml_name_decl("_CRS", crs)); aml_append(scope, dev); aml_append(dsdt, scope); + + /* Handle the ranges for the PXB expanders */ + if (pci_bus_is_cxl(bus)) { + MemoryRegion *mr = &machine->cxl_devices_state->host_mr; + uint64_t base = mr->addr; + + crs_range_insert(crs_range_set.mem_ranges, base, + base + memory_region_size(mr) - 1); + } } } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 45e2d6092f..03d14f6564 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -75,6 +75,7 @@ #include "acpi-build.h" #include "hw/mem/pc-dimm.h" #include "hw/mem/nvdimm.h" +#include "hw/cxl/cxl.h" #include "qapi/error.h" #include "qapi/qapi-visit-common.h" #include "qapi/qapi-visit-machine.h" @@ -816,6 +817,7 @@ void pc_memory_init(PCMachineState *pcms, MachineClass *mc = MACHINE_GET_CLASS(machine); PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); X86MachineState *x86ms = X86_MACHINE(pcms); + hwaddr cxl_base; assert(machine->ram_size == x86ms->below_4g_mem_size + x86ms->above_4g_mem_size); @@ -905,6 +907,26 @@ void pc_memory_init(PCMachineState *pcms, &machine->device_memory->mr); } + if (machine->cxl_devices_state->is_enabled) { + MemoryRegion *mr = &machine->cxl_devices_state->host_mr; + hwaddr cxl_size = MiB; + + if (pcmc->has_reserved_memory && machine->device_memory->base) { + cxl_base = machine->device_memory->base; + if (!pcmc->broken_reserved_end) { + cxl_base += memory_region_size(&machine->device_memory->mr); + } + } else if (pcms->sgx_epc.size != 0) { + cxl_base = sgx_epc_above_4g_end(&pcms->sgx_epc); + } else { + cxl_base = 0x100000000ULL + x86ms->above_4g_mem_size; + } + + e820_add_entry(cxl_base, cxl_size, E820_RESERVED); + memory_region_init(mr, OBJECT(machine), "cxl_host_reg", cxl_size); + memory_region_add_subregion(system_memory, cxl_base, mr); + } + /* Initialize PC system firmware */ pc_system_firmware_init(pcms, rom_memory); @@ -965,7 +987,10 @@ uint64_t pc_pci_hole64_start(void) X86MachineState *x86ms = X86_MACHINE(pcms); uint64_t hole64_start = 0; - if (pcmc->has_reserved_memory && ms->device_memory->base) { + if (ms->cxl_devices_state->host_mr.addr) { + hole64_start = ms->cxl_devices_state->host_mr.addr + + memory_region_size(&ms->cxl_devices_state->host_mr); + } else if (pcmc->has_reserved_memory && ms->device_memory->base) { hole64_start = ms->device_memory->base; if (!pcmc->broken_reserved_end) { hole64_start += memory_region_size(&ms->device_memory->mr); diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index f762eb4a6e..8fb4f2ea91 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -61,12 +61,6 @@ DECLARE_INSTANCE_CHECKER(PXBDev, PXB_PCIE_DEV, DECLARE_INSTANCE_CHECKER(PXBDev, PXB_CXL_DEV, TYPE_PXB_CXL_DEVICE) -typedef struct CXLHost { - PCIHostState parent_obj; - - CXLComponentState cxl_cstate; -} CXLHost; - struct PXBDev { /*< private >*/ PCIDevice parent_obj; @@ -75,6 +69,9 @@ struct PXBDev { uint8_t bus_nr; uint16_t numa_node; bool bypass_iommu; + struct cxl_dev { + CXLHost *cxl_host_bridge; + } cxl; }; static PXBDev *convert_to_pxb(PCIDevice *dev) @@ -197,6 +194,52 @@ static const TypeInfo pxb_host_info = { .class_init = pxb_host_class_init, }; +static void pxb_cxl_realize(DeviceState *dev, Error **errp) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + CXLHost *cxl = PXB_CXL_HOST(dev); + CXLComponentState *cxl_cstate = &cxl->cxl_cstate; + struct MemoryRegion *mr = &cxl_cstate->crb.component_registers; + hwaddr offset; + + cxl_component_register_block_init(OBJECT(dev), cxl_cstate, + TYPE_PXB_CXL_HOST); + sysbus_init_mmio(sbd, mr); + + offset = memory_region_size(mr) * ms->cxl_devices_state->next_mr_idx; + if (offset > memory_region_size(&ms->cxl_devices_state->host_mr)) { + error_setg(errp, "Insufficient space for pxb cxl host register space"); + return; + } + + memory_region_add_subregion(&ms->cxl_devices_state->host_mr, offset, mr); + ms->cxl_devices_state->next_mr_idx++; +} + +static void pxb_cxl_host_class_init(ObjectClass *class, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(class); + PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class); + + hc->root_bus_path = pxb_host_root_bus_path; + dc->fw_name = "cxl"; + dc->realize = pxb_cxl_realize; + /* Reason: Internal part of the pxb/pxb-pcie device, not usable by itself */ + dc->user_creatable = false; +} + +/* + * This is a device to handle the MMIO for a CXL host bridge. It does nothing + * else. + */ +static const TypeInfo cxl_host_info = { + .name = TYPE_PXB_CXL_HOST, + .parent = TYPE_PCI_HOST_BRIDGE, + .instance_size = sizeof(CXLHost), + .class_init = pxb_cxl_host_class_init, +}; + /* * Registers the PXB bus as a child of pci host root bus. */ @@ -245,6 +288,13 @@ static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin) static void pxb_dev_reset(DeviceState *dev) { + CXLHost *cxl = PXB_CXL_DEV(dev)->cxl.cxl_host_bridge; + CXLComponentState *cxl_cstate = &cxl->cxl_cstate; + uint32_t *reg_state = cxl_cstate->crb.cache_mem_registers; + uint32_t *write_msk = cxl_cstate->crb.cache_mem_regs_write_mask; + + cxl_component_register_init_common(reg_state, write_msk, CXL2_ROOT_PORT); + ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, TARGET_COUNT, 8); } static gint pxb_compare(gconstpointer a, gconstpointer b) @@ -281,12 +331,13 @@ static void pxb_dev_realize_common(PCIDevice *dev, enum BusType type, dev_name = dev->qdev.id; } - ds = qdev_new(TYPE_PXB_HOST); + ds = qdev_new(type == CXL ? TYPE_PXB_CXL_HOST : TYPE_PXB_HOST); if (type == PCIE) { bus = pci_root_bus_new(ds, dev_name, NULL, NULL, 0, TYPE_PXB_PCIE_BUS); } else if (type == CXL) { bus = pci_root_bus_new(ds, dev_name, NULL, NULL, 0, TYPE_PXB_CXL_BUS); bus->flags |= PCI_BUS_CXL; + PXB_CXL_DEV(dev)->cxl.cxl_host_bridge = PXB_CXL_HOST(ds); } else { bus = pci_root_bus_new(ds, "pxb-internal", NULL, NULL, 0, TYPE_PXB_BUS); bds = qdev_new("pci-bridge"); @@ -475,6 +526,7 @@ static void pxb_register_types(void) type_register_static(&pxb_pcie_bus_info); type_register_static(&pxb_cxl_bus_info); type_register_static(&pxb_host_info); + type_register_static(&cxl_host_info); type_register_static(&pxb_dev_info); type_register_static(&pxb_pcie_dev_info); type_register_static(&pxb_cxl_dev_info); diff --git a/include/hw/cxl/cxl.h b/include/hw/cxl/cxl.h index 31af92fd5e..8d1a7245d0 100644 --- a/include/hw/cxl/cxl.h +++ b/include/hw/cxl/cxl.h @@ -10,6 +10,7 @@ #ifndef CXL_H #define CXL_H +#include "hw/pci/pci_host.h" #include "cxl_pci.h" #include "cxl_component.h" #include "cxl_device.h" @@ -17,8 +18,21 @@ #define CXL_COMPONENT_REG_BAR_IDX 0 #define CXL_DEVICE_REG_BAR_IDX 2 +#define CXL_WINDOW_MAX 10 + typedef struct CXLState { bool is_enabled; + MemoryRegion host_mr; + unsigned int next_mr_idx; } CXLState; +struct CXLHost { + PCIHostState parent_obj; + + CXLComponentState cxl_cstate; +}; + +#define TYPE_PXB_CXL_HOST "pxb-cxl-host" +OBJECT_DECLARE_SIMPLE_TYPE(CXLHost, PXB_CXL_HOST) + #endif From 2a3282c68ee21cd04ee9d9ef62549f1771929828 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:49 +0100 Subject: [PATCH 293/935] acpi/cxl: Add _OSC implementation (9.14.2) CXL 2.0 specification adds 2 new dwords to the existing _OSC definition from PCIe. The new dwords are accessed with a new uuid. This implementation supports what is in the specification. iasl -d decodes the result of this patch as: Name (SUPP, Zero) Name (CTRL, Zero) Name (SUPC, Zero) Name (CTRC, Zero) Method (_OSC, 4, NotSerialized) // _OSC: Operating System Capabilities { CreateDWordField (Arg3, Zero, CDW1) If (((Arg0 == ToUUID ("33db4d5b-1ff7-401c-9657-7441c03dd766") /* PCI Host Bridge Device */) || (Arg0 == ToUUID ("68f2d50b-c469-4d8a-bd3d-941a103fd3fc") /* Unknown UUID */))) { CreateDWordField (Arg3, 0x04, CDW2) CreateDWordField (Arg3, 0x08, CDW3) Local0 = CDW3 /* \_SB_.PC0C._OSC.CDW3 */ Local0 &= 0x1F If ((Arg1 != One)) { CDW1 |= 0x08 } If ((CDW3 != Local0)) { CDW1 |= 0x10 } SUPP = CDW2 /* \_SB_.PC0C._OSC.CDW2 */ CTRL = CDW3 /* \_SB_.PC0C._OSC.CDW3 */ CDW3 = Local0 If ((Arg0 == ToUUID ("68f2d50b-c469-4d8a-bd3d-941a103fd3fc") /* Unknown UUID */)) { CreateDWordField (Arg3, 0x0C, CDW4) CreateDWordField (Arg3, 0x10, CDW5) SUPC = CDW4 /* \_SB_.PC0C._OSC.CDW4 */ CTRC = CDW5 /* \_SB_.PC0C._OSC.CDW5 */ CDW5 |= One } Return (Arg3) } Else { CDW1 |= 0x04 Return (Arg3) } Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Message-Id: <20220429144110.25167-25-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/Kconfig | 5 ++ hw/acpi/cxl-stub.c | 12 ++++ hw/acpi/cxl.c | 130 ++++++++++++++++++++++++++++++++++++++++++ hw/acpi/meson.build | 4 +- hw/i386/acpi-build.c | 13 +++-- include/hw/acpi/cxl.h | 23 ++++++++ 6 files changed, 182 insertions(+), 5 deletions(-) create mode 100644 hw/acpi/cxl-stub.c create mode 100644 hw/acpi/cxl.c create mode 100644 include/hw/acpi/cxl.h diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig index 19caebde6c..3703aca212 100644 --- a/hw/acpi/Kconfig +++ b/hw/acpi/Kconfig @@ -5,6 +5,7 @@ config ACPI_X86 bool select ACPI select ACPI_NVDIMM + select ACPI_CXL select ACPI_CPU_HOTPLUG select ACPI_MEMORY_HOTPLUG select ACPI_HMAT @@ -66,3 +67,7 @@ config ACPI_ERST bool default y depends on ACPI && PCI + +config ACPI_CXL + bool + depends on ACPI diff --git a/hw/acpi/cxl-stub.c b/hw/acpi/cxl-stub.c new file mode 100644 index 0000000000..15bc21076b --- /dev/null +++ b/hw/acpi/cxl-stub.c @@ -0,0 +1,12 @@ + +/* + * Stubs for ACPI platforms that don't support CXl + */ +#include "qemu/osdep.h" +#include "hw/acpi/aml-build.h" +#include "hw/acpi/cxl.h" + +void build_cxl_osc_method(Aml *dev) +{ + g_assert_not_reached(); +} diff --git a/hw/acpi/cxl.c b/hw/acpi/cxl.c new file mode 100644 index 0000000000..ca1f04f359 --- /dev/null +++ b/hw/acpi/cxl.c @@ -0,0 +1,130 @@ +/* + * CXL ACPI Implementation + * + * Copyright(C) 2020 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +#include "qemu/osdep.h" +#include "hw/cxl/cxl.h" +#include "hw/acpi/acpi.h" +#include "hw/acpi/aml-build.h" +#include "hw/acpi/bios-linker-loader.h" +#include "hw/acpi/cxl.h" +#include "qapi/error.h" +#include "qemu/uuid.h" + +static Aml *__build_cxl_osc_method(void) +{ + Aml *method, *if_uuid, *else_uuid, *if_arg1_not_1, *if_cxl, *if_caps_masked; + Aml *a_ctrl = aml_local(0); + Aml *a_cdw1 = aml_name("CDW1"); + + method = aml_method("_OSC", 4, AML_NOTSERIALIZED); + /* CDW1 is used for the return value so is present whether or not a match occurs */ + aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1")); + + /* + * Generate shared section between: + * CXL 2.0 - 9.14.2.1.4 and + * PCI Firmware Specification 3.0 + * 4.5.1. _OSC Interface for PCI Host Bridge Devices + * The _OSC interface for a PCI/PCI-X/PCI Express hierarchy is + * identified by the Universal Unique IDentifier (UUID) + * 33DB4D5B-1FF7-401C-9657-7441C03DD766 + * The _OSC interface for a CXL Host bridge is + * identified by the UUID 68F2D50B-C469-4D8A-BD3D-941A103FD3FC + * A CXL Host bridge is compatible with a PCI host bridge so + * for the shared section match both. + */ + if_uuid = aml_if( + aml_lor(aml_equal(aml_arg(0), + aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766")), + aml_equal(aml_arg(0), + aml_touuid("68F2D50B-C469-4D8A-BD3D-941A103FD3FC")))); + aml_append(if_uuid, aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2")); + aml_append(if_uuid, aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3")); + + aml_append(if_uuid, aml_store(aml_name("CDW3"), a_ctrl)); + + /* + * + * Allows OS control for all 5 features: + * PCIeHotplug SHPCHotplug PME AER PCIeCapability + */ + aml_append(if_uuid, aml_and(a_ctrl, aml_int(0x1F), a_ctrl)); + + /* + * Check _OSC revision. + * PCI Firmware specification 3.3 and CXL 2.0 both use revision 1 + * Unknown Revision is CDW1 - BIT (3) + */ + if_arg1_not_1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1)))); + aml_append(if_arg1_not_1, aml_or(a_cdw1, aml_int(0x08), a_cdw1)); + aml_append(if_uuid, if_arg1_not_1); + + if_caps_masked = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl))); + + /* Capability bits were masked */ + aml_append(if_caps_masked, aml_or(a_cdw1, aml_int(0x10), a_cdw1)); + aml_append(if_uuid, if_caps_masked); + + aml_append(if_uuid, aml_store(aml_name("CDW2"), aml_name("SUPP"))); + aml_append(if_uuid, aml_store(aml_name("CDW3"), aml_name("CTRL"))); + + /* Update DWORD3 (the return value) */ + aml_append(if_uuid, aml_store(a_ctrl, aml_name("CDW3"))); + + /* CXL only section as per CXL 2.0 - 9.14.2.1.4 */ + if_cxl = aml_if(aml_equal( + aml_arg(0), aml_touuid("68F2D50B-C469-4D8A-BD3D-941A103FD3FC"))); + /* CXL support field */ + aml_append(if_cxl, aml_create_dword_field(aml_arg(3), aml_int(12), "CDW4")); + /* CXL capabilities */ + aml_append(if_cxl, aml_create_dword_field(aml_arg(3), aml_int(16), "CDW5")); + aml_append(if_cxl, aml_store(aml_name("CDW4"), aml_name("SUPC"))); + aml_append(if_cxl, aml_store(aml_name("CDW5"), aml_name("CTRC"))); + + /* CXL 2.0 Port/Device Register access */ + aml_append(if_cxl, + aml_or(aml_name("CDW5"), aml_int(0x1), aml_name("CDW5"))); + aml_append(if_uuid, if_cxl); + + aml_append(if_uuid, aml_return(aml_arg(3))); + aml_append(method, if_uuid); + + /* + * If no UUID matched, return Unrecognized UUID via Arg3 DWord 1 + * ACPI 6.4 - 6.2.11 + * Unrecognised UUID - BIT(2) + */ + else_uuid = aml_else(); + + aml_append(else_uuid, + aml_or(aml_name("CDW1"), aml_int(0x4), aml_name("CDW1"))); + aml_append(else_uuid, aml_return(aml_arg(3))); + aml_append(method, else_uuid); + + return method; +} + +void build_cxl_osc_method(Aml *dev) +{ + aml_append(dev, aml_name_decl("SUPP", aml_int(0))); + aml_append(dev, aml_name_decl("CTRL", aml_int(0))); + aml_append(dev, aml_name_decl("SUPC", aml_int(0))); + aml_append(dev, aml_name_decl("CTRC", aml_int(0))); + aml_append(dev, __build_cxl_osc_method()); +} diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build index 8bea2e6933..cea2f5f93a 100644 --- a/hw/acpi/meson.build +++ b/hw/acpi/meson.build @@ -13,6 +13,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_MEMORY_HOTPLUG', if_false: files('acpi-mem-hotplu acpi_ss.add(when: 'CONFIG_ACPI_NVDIMM', if_true: files('nvdimm.c')) acpi_ss.add(when: 'CONFIG_ACPI_NVDIMM', if_false: files('acpi-nvdimm-stub.c')) acpi_ss.add(when: 'CONFIG_ACPI_PCI', if_true: files('pci.c')) +acpi_ss.add(when: 'CONFIG_ACPI_CXL', if_true: files('cxl.c'), if_false: files('cxl-stub.c')) acpi_ss.add(when: 'CONFIG_ACPI_VMGENID', if_true: files('vmgenid.c')) acpi_ss.add(when: 'CONFIG_ACPI_HW_REDUCED', if_true: files('generic_event_device.c')) acpi_ss.add(when: 'CONFIG_ACPI_HMAT', if_true: files('hmat.c')) @@ -33,4 +34,5 @@ softmmu_ss.add_all(when: 'CONFIG_ACPI', if_true: acpi_ss) softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('acpi-stub.c', 'aml-build-stub.c', 'acpi-x86-stub.c', 'ipmi-stub.c', 'ghes-stub.c', 'acpi-mem-hotplug-stub.c', 'acpi-cpu-hotplug-stub.c', - 'acpi-pci-hotplug-stub.c', 'acpi-nvdimm-stub.c')) + 'acpi-pci-hotplug-stub.c', 'acpi-nvdimm-stub.c', + 'cxl-stub.c')) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 2d81b0f40c..59ede8b2e9 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -67,6 +67,7 @@ #include "hw/acpi/aml-build.h" #include "hw/acpi/utils.h" #include "hw/acpi/pci.h" +#include "hw/acpi/cxl.h" #include "qom/qom-qobject.h" #include "hw/i386/amd_iommu.h" @@ -1582,11 +1583,15 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dev, aml_name_decl("_UID", aml_int(bus_num))); aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num))); if (pci_bus_is_cxl(bus)) { - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); - aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); + struct Aml *pkg = aml_package(2); - /* Expander bridges do not have ACPI PCI Hot-plug enabled */ - aml_append(dev, build_q35_osc_method(true)); + aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0016"))); + aml_append(pkg, aml_eisaid("PNP0A08")); + aml_append(pkg, aml_eisaid("PNP0A03")); + aml_append(dev, aml_name_decl("_CID", pkg)); + aml_append(dev, aml_name_decl("_ADR", aml_int(0))); + aml_append(dev, aml_name_decl("_UID", aml_int(bus_num))); + build_cxl_osc_method(dev); } else if (pci_bus_is_express(bus)) { aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); diff --git a/include/hw/acpi/cxl.h b/include/hw/acpi/cxl.h new file mode 100644 index 0000000000..7b8f3b8a2e --- /dev/null +++ b/include/hw/acpi/cxl.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef HW_ACPI_CXL_H +#define HW_ACPI_CXL_H + +void build_cxl_osc_method(Aml *dev); + +#endif From 3d6a69b6eb973e5761c8dc489990dcd983f6c099 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:50 +0100 Subject: [PATCH 294/935] acpi/cxl: Create the CEDT (9.14.1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CXL Early Discovery Table is defined in the CXL 2.0 specification as a way for the OS to get CXL specific information from the system firmware. CXL 2.0 specification adds an _HID, ACPI0016, for CXL capable host bridges, with a _CID of PNP0A08 (PCIe host bridge). CXL aware software is able to use this initiate the proper _OSC method, and get the _UID which is referenced by the CEDT. Therefore the existence of an ACPI0016 device allows a CXL aware driver perform the necessary actions. For a CXL capable OS, this works. For a CXL unaware OS, this works. CEDT awaremess requires more. The motivation for ACPI0017 is to provide the possibility of having a Linux CXL module that can work on a legacy Linux kernel. Linux core PCI/ACPI which won't be built as a module, will see the _CID of PNP0A08 and bind a driver to it. If we later loaded a driver for ACPI0016, Linux won't be able to bind it to the hardware because it has already bound the PNP0A08 driver. The ACPI0017 device is an opportunity to have an object to bind a driver will be used by a Linux driver to walk the CXL topology and do everything that we would have preferred to do with ACPI0016. There is another motivation for an ACPI0017 device which isn't implemented here. An operating system needs an attach point for a non-volatile region provider that understands cross-hostbridge interleaving. Since QEMU emulation doesn't support interleaving yet, this is more important on the OS side, for now. As of CXL 2.0 spec, only 1 sub structure is defined, the CXL Host Bridge Structure (CHBS) which is primarily useful for telling the OS exactly where the MMIO for the host bridge is. Link: https://lore.kernel.org/linux-cxl/20210115034911.nkgpzc756d6qmjpl@intel.com/T/#t Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-26-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/cxl.c | 68 +++++++++++++++++++++++++++++ hw/i386/acpi-build.c | 27 ++++++++++++ hw/pci-bridge/pci_expander_bridge.c | 17 -------- include/hw/acpi/cxl.h | 5 +++ include/hw/pci/pci_bridge.h | 20 +++++++++ 5 files changed, 120 insertions(+), 17 deletions(-) diff --git a/hw/acpi/cxl.c b/hw/acpi/cxl.c index ca1f04f359..aa4af86a4c 100644 --- a/hw/acpi/cxl.c +++ b/hw/acpi/cxl.c @@ -18,7 +18,11 @@ */ #include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pci_host.h" #include "hw/cxl/cxl.h" +#include "hw/mem/memory-device.h" #include "hw/acpi/acpi.h" #include "hw/acpi/aml-build.h" #include "hw/acpi/bios-linker-loader.h" @@ -26,6 +30,70 @@ #include "qapi/error.h" #include "qemu/uuid.h" +static void cedt_build_chbs(GArray *table_data, PXBDev *cxl) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(cxl->cxl.cxl_host_bridge); + struct MemoryRegion *mr = sbd->mmio[0].memory; + + /* Type */ + build_append_int_noprefix(table_data, 0, 1); + + /* Reserved */ + build_append_int_noprefix(table_data, 0, 1); + + /* Record Length */ + build_append_int_noprefix(table_data, 32, 2); + + /* UID - currently equal to bus number */ + build_append_int_noprefix(table_data, cxl->bus_nr, 4); + + /* Version */ + build_append_int_noprefix(table_data, 1, 4); + + /* Reserved */ + build_append_int_noprefix(table_data, 0, 4); + + /* Base - subregion within a container that is in PA space */ + build_append_int_noprefix(table_data, mr->container->addr + mr->addr, 8); + + /* Length */ + build_append_int_noprefix(table_data, memory_region_size(mr), 8); +} + +static int cxl_foreach_pxb_hb(Object *obj, void *opaque) +{ + Aml *cedt = opaque; + + if (object_dynamic_cast(obj, TYPE_PXB_CXL_DEVICE)) { + cedt_build_chbs(cedt->buf, PXB_CXL_DEV(obj)); + } + + return 0; +} + +void cxl_build_cedt(MachineState *ms, GArray *table_offsets, GArray *table_data, + BIOSLinker *linker, const char *oem_id, + const char *oem_table_id) +{ + Aml *cedt; + AcpiTable table = { .sig = "CEDT", .rev = 1, .oem_id = oem_id, + .oem_table_id = oem_table_id }; + + acpi_add_table(table_offsets, table_data); + acpi_table_begin(&table, table_data); + cedt = init_aml_allocator(); + + /* reserve space for CEDT header */ + + object_child_foreach_recursive(object_get_root(), cxl_foreach_pxb_hb, cedt); + + /* copy AML table into ACPI tables blob and patch header there */ + g_array_append_vals(table_data, cedt->buf->data, cedt->buf->len); + free_aml_allocator(); + + acpi_table_end(linker, &table); +} + static Aml *__build_cxl_osc_method(void) { Aml *method, *if_uuid, *else_uuid, *if_arg1_not_1, *if_cxl, *if_caps_masked; diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 59ede8b2e9..c125939ed6 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -77,6 +77,7 @@ #include "hw/acpi/ipmi.h" #include "hw/acpi/hmat.h" #include "hw/acpi/viot.h" +#include "hw/acpi/cxl.h" #include CONFIG_DEVICES @@ -1411,6 +1412,22 @@ static void build_smb0(Aml *table, I2CBus *smbus, int devnr, int func) aml_append(table, scope); } +static void build_acpi0017(Aml *table) +{ + Aml *dev, *scope, *method; + + scope = aml_scope("_SB"); + dev = aml_device("CXLM"); + aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0017"))); + + method = aml_method("_STA", 0, AML_NOTSERIALIZED); + aml_append(method, aml_return(aml_int(0x01))); + aml_append(dev, method); + + aml_append(scope, dev); + aml_append(table, scope); +} + static void build_dsdt(GArray *table_data, BIOSLinker *linker, AcpiPmInfo *pm, AcpiMiscInfo *misc, @@ -1430,6 +1447,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, #ifdef CONFIG_TPM TPMIf *tpm = tpm_find(); #endif + bool cxl_present = false; int i; VMBusBridge *vmbus_bridge = vmbus_bridge_find(); AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = x86ms->oem_id, @@ -1618,12 +1636,17 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, MemoryRegion *mr = &machine->cxl_devices_state->host_mr; uint64_t base = mr->addr; + cxl_present = true; crs_range_insert(crs_range_set.mem_ranges, base, base + memory_region_size(mr) - 1); } } } + if (cxl_present) { + build_acpi0017(dsdt); + } + /* * At this point crs_range_set has all the ranges used by pci * busses *other* than PCI0. These ranges will be excluded from @@ -2688,6 +2711,10 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) machine->nvdimms_state, machine->ram_slots, x86ms->oem_id, x86ms->oem_table_id); } + if (machine->cxl_devices_state->is_enabled) { + cxl_build_cedt(machine, table_offsets, tables_blob, tables->linker, + x86ms->oem_id, x86ms->oem_table_id); + } acpi_add_table(table_offsets, tables_blob); build_waet(tables_blob, tables->linker, x86ms->oem_id, x86ms->oem_table_id); diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index 8fb4f2ea91..22feda1ff0 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -57,23 +57,6 @@ DECLARE_INSTANCE_CHECKER(PXBDev, PXB_DEV, DECLARE_INSTANCE_CHECKER(PXBDev, PXB_PCIE_DEV, TYPE_PXB_PCIE_DEVICE) -#define TYPE_PXB_CXL_DEVICE "pxb-cxl" -DECLARE_INSTANCE_CHECKER(PXBDev, PXB_CXL_DEV, - TYPE_PXB_CXL_DEVICE) - -struct PXBDev { - /*< private >*/ - PCIDevice parent_obj; - /*< public >*/ - - uint8_t bus_nr; - uint16_t numa_node; - bool bypass_iommu; - struct cxl_dev { - CXLHost *cxl_host_bridge; - } cxl; -}; - static PXBDev *convert_to_pxb(PCIDevice *dev) { /* A CXL PXB's parent bus is PCIe, so the normal check won't work */ diff --git a/include/hw/acpi/cxl.h b/include/hw/acpi/cxl.h index 7b8f3b8a2e..0c496538c0 100644 --- a/include/hw/acpi/cxl.h +++ b/include/hw/acpi/cxl.h @@ -18,6 +18,11 @@ #ifndef HW_ACPI_CXL_H #define HW_ACPI_CXL_H +#include "hw/acpi/bios-linker-loader.h" + +void cxl_build_cedt(MachineState *ms, GArray *table_offsets, GArray *table_data, + BIOSLinker *linker, const char *oem_id, + const char *oem_table_id); void build_cxl_osc_method(Aml *dev); #endif diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h index 30691a6e57..ba4bafac7c 100644 --- a/include/hw/pci/pci_bridge.h +++ b/include/hw/pci/pci_bridge.h @@ -28,6 +28,7 @@ #include "hw/pci/pci.h" #include "hw/pci/pci_bus.h" +#include "hw/cxl/cxl.h" #include "qom/object.h" typedef struct PCIBridgeWindows PCIBridgeWindows; @@ -80,6 +81,25 @@ struct PCIBridge { #define PCI_BRIDGE_DEV_PROP_CHASSIS_NR "chassis_nr" #define PCI_BRIDGE_DEV_PROP_MSI "msi" #define PCI_BRIDGE_DEV_PROP_SHPC "shpc" +typedef struct CXLHost CXLHost; + +struct PXBDev { + /*< private >*/ + PCIDevice parent_obj; + /*< public >*/ + + uint8_t bus_nr; + uint16_t numa_node; + bool bypass_iommu; + struct cxl_dev { + CXLHost *cxl_host_bridge; /* Pointer to a CXLHost */ + } cxl; +}; + +typedef struct PXBDev PXBDev; +#define TYPE_PXB_CXL_DEVICE "pxb-cxl" +DECLARE_INSTANCE_CHECKER(PXBDev, PXB_CXL_DEV, + TYPE_PXB_CXL_DEVICE) int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset, uint16_t svid, uint16_t ssid, From 829de299d1a4dcac3cd6c494d1c974bdbc608611 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 29 Apr 2022 15:40:51 +0100 Subject: [PATCH 295/935] hw/cxl/component: Add utils for interleave parameter encoding/decoding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both registers and the CFMWS entries in CDAT use simple encodings for the number of interleave ways and the interleave granularity. Introduce simple conversion functions to/from the unencoded number / size. So far the iw decode has not been needed so is it not implemented. Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-27-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-component-utils.c | 34 ++++++++++++++++++++++++++++++++++ include/hw/cxl/cxl_component.h | 8 ++++++++ 2 files changed, 42 insertions(+) diff --git a/hw/cxl/cxl-component-utils.c b/hw/cxl/cxl-component-utils.c index afc97b17c2..69cb07171c 100644 --- a/hw/cxl/cxl-component-utils.c +++ b/hw/cxl/cxl-component-utils.c @@ -9,6 +9,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" +#include "qapi/error.h" #include "hw/pci/pci.h" #include "hw/cxl/cxl.h" @@ -329,3 +330,36 @@ void cxl_component_create_dvsec(CXLComponentState *cxl, range_init_nofail(&cxl->dvsecs[type], cxl->dvsec_offset, length); cxl->dvsec_offset += length; } + +uint8_t cxl_interleave_ways_enc(int iw, Error **errp) +{ + switch (iw) { + case 1: return 0x0; + case 2: return 0x1; + case 4: return 0x2; + case 8: return 0x3; + case 16: return 0x4; + case 3: return 0x8; + case 6: return 0x9; + case 12: return 0xa; + default: + error_setg(errp, "Interleave ways: %d not supported", iw); + return 0; + } +} + +uint8_t cxl_interleave_granularity_enc(uint64_t gran, Error **errp) +{ + switch (gran) { + case 256: return 0; + case 512: return 1; + case 1024: return 2; + case 2048: return 3; + case 4096: return 4; + case 8192: return 5; + case 16384: return 6; + default: + error_setg(errp, "Interleave granularity: %" PRIu64 " invalid", gran); + return 0; + } +} diff --git a/include/hw/cxl/cxl_component.h b/include/hw/cxl/cxl_component.h index 7d8f395cbe..4f69688c47 100644 --- a/include/hw/cxl/cxl_component.h +++ b/include/hw/cxl/cxl_component.h @@ -210,4 +210,12 @@ static inline int cxl_decoder_count_enc(int count) return 0; } +uint8_t cxl_interleave_ways_enc(int iw, Error **errp); +uint8_t cxl_interleave_granularity_enc(uint64_t gran, Error **errp); + +static inline hwaddr cxl_decode_ig(int ig) +{ + return 1 << (ig + 8); +} + #endif From aadfe320919b15e24ac070e9b25085e07599a613 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 29 Apr 2022 15:40:52 +0100 Subject: [PATCH 296/935] hw/cxl/host: Add support for CXL Fixed Memory Windows. The concept of these is introduced in [1] in terms of the description the CEDT ACPI table. The principal is more general. Unlike once traffic hits the CXL root bridges, the host system memory address routing is implementation defined and effectively static once observable by standard / generic system software. Each CXL Fixed Memory Windows (CFMW) is a region of PA space which has fixed system dependent routing configured so that accesses can be routed to the CXL devices below a set of target root bridges. The accesses may be interleaved across multiple root bridges. For QEMU we could have fully specified these regions in terms of a base PA + size, but as the absolute address does not matter it is simpler to let individual platforms place the memory regions. ExampleS: -cxl-fixed-memory-window targets.0=cxl.0,size=128G -cxl-fixed-memory-window targets.0=cxl.1,size=128G -cxl-fixed-memory-window targets.0=cxl0,targets.1=cxl.1,size=256G,interleave-granularity=2k Specifies * 2x 128G regions not interleaved across root bridges, one for each of the root bridges with ids cxl.0 and cxl.1 * 256G region interleaved across root bridges with ids cxl.0 and cxl.1 with a 2k interleave granularity. When system software enumerates the devices below a given root bridge it can then decide which CFMW to use. If non interleave is desired (or possible) it can use the appropriate CFMW for the root bridge in question. If there are suitable devices to interleave across the two root bridges then it may use the 3rd CFMS. A number of other designs were considered but the following constraints made it hard to adapt existing QEMU approaches to this particular problem. 1) The size must be known before a specific architecture / board brings up it's PA memory map. We need to set up an appropriate region. 2) Using links to the host bridges provides a clean command line interface but these links cannot be established until command line devices have been added. Hence the two step process used here of first establishing the size, interleave-ways and granularity + caching the ids of the host bridges and then, once available finding the actual host bridges so they can be used later to support interleave decoding. [1] CXL 2.0 ECN: CEDT CFMWS & QTG DSM (computeexpresslink.org / specifications) Signed-off-by: Jonathan Cameron Acked-by: Markus Armbruster # QAPI Schema Message-Id: <20220429144110.25167-28-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-host-stubs.c | 14 ++++++ hw/cxl/cxl-host.c | 94 +++++++++++++++++++++++++++++++++++++++++ hw/cxl/meson.build | 6 +++ include/hw/cxl/cxl.h | 21 +++++++++ qapi/machine.json | 21 +++++++++ qemu-options.hx | 38 +++++++++++++++++ softmmu/vl.c | 47 +++++++++++++++++++++ 7 files changed, 241 insertions(+) create mode 100644 hw/cxl/cxl-host-stubs.c create mode 100644 hw/cxl/cxl-host.c diff --git a/hw/cxl/cxl-host-stubs.c b/hw/cxl/cxl-host-stubs.c new file mode 100644 index 0000000000..f8fd278d5d --- /dev/null +++ b/hw/cxl/cxl-host-stubs.c @@ -0,0 +1,14 @@ +/* + * CXL host parameter parsing routine stubs + * + * Copyright (c) 2022 Huawei + */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/cxl/cxl.h" + +void cxl_fixed_memory_window_config(MachineState *ms, + CXLFixedMemoryWindowOptions *object, + Error **errp) {}; + +void cxl_fixed_memory_window_link_targets(Error **errp) {}; diff --git a/hw/cxl/cxl-host.c b/hw/cxl/cxl-host.c new file mode 100644 index 0000000000..ec5a75cbf5 --- /dev/null +++ b/hw/cxl/cxl-host.c @@ -0,0 +1,94 @@ +/* + * CXL host parameter parsing routines + * + * Copyright (c) 2022 Huawei + * Modeled loosely on the NUMA options handling in hw/core/numa.c + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qemu/bitmap.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "sysemu/qtest.h" +#include "hw/boards.h" + +#include "qapi/qapi-visit-machine.h" +#include "hw/cxl/cxl.h" + +void cxl_fixed_memory_window_config(MachineState *ms, + CXLFixedMemoryWindowOptions *object, + Error **errp) +{ + CXLFixedWindow *fw = g_malloc0(sizeof(*fw)); + strList *target; + int i; + + for (target = object->targets; target; target = target->next) { + fw->num_targets++; + } + + fw->enc_int_ways = cxl_interleave_ways_enc(fw->num_targets, errp); + if (*errp) { + return; + } + + fw->targets = g_malloc0_n(fw->num_targets, sizeof(*fw->targets)); + for (i = 0, target = object->targets; target; i++, target = target->next) { + /* This link cannot be resolved yet, so stash the name for now */ + fw->targets[i] = g_strdup(target->value); + } + + if (object->size % (256 * MiB)) { + error_setg(errp, + "Size of a CXL fixed memory window must my a multiple of 256MiB"); + return; + } + fw->size = object->size; + + if (object->has_interleave_granularity) { + fw->enc_int_gran = + cxl_interleave_granularity_enc(object->interleave_granularity, + errp); + if (*errp) { + return; + } + } else { + /* Default to 256 byte interleave */ + fw->enc_int_gran = 0; + } + + ms->cxl_devices_state->fixed_windows = + g_list_append(ms->cxl_devices_state->fixed_windows, fw); + + return; +} + +void cxl_fixed_memory_window_link_targets(Error **errp) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + + if (ms->cxl_devices_state && ms->cxl_devices_state->fixed_windows) { + GList *it; + + for (it = ms->cxl_devices_state->fixed_windows; it; it = it->next) { + CXLFixedWindow *fw = it->data; + int i; + + for (i = 0; i < fw->num_targets; i++) { + Object *o; + bool ambig; + + o = object_resolve_path_type(fw->targets[i], + TYPE_PXB_CXL_DEVICE, + &ambig); + if (!o) { + error_setg(errp, "Could not resolve CXLFM target %s", + fw->targets[i]); + return; + } + fw->target_hbs[i] = PXB_CXL_DEV(o); + } + } + } +} diff --git a/hw/cxl/meson.build b/hw/cxl/meson.build index e68eea2358..f117b99949 100644 --- a/hw/cxl/meson.build +++ b/hw/cxl/meson.build @@ -3,4 +3,10 @@ softmmu_ss.add(when: 'CONFIG_CXL', 'cxl-component-utils.c', 'cxl-device-utils.c', 'cxl-mailbox-utils.c', + 'cxl-host.c', + ), + if_false: files( + 'cxl-host-stubs.c', )) + +softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('cxl-host-stubs.c')) diff --git a/include/hw/cxl/cxl.h b/include/hw/cxl/cxl.h index 8d1a7245d0..dce38124db 100644 --- a/include/hw/cxl/cxl.h +++ b/include/hw/cxl/cxl.h @@ -10,6 +10,9 @@ #ifndef CXL_H #define CXL_H + +#include "qapi/qapi-types-machine.h" +#include "hw/pci/pci_bridge.h" #include "hw/pci/pci_host.h" #include "cxl_pci.h" #include "cxl_component.h" @@ -20,10 +23,23 @@ #define CXL_WINDOW_MAX 10 +typedef struct CXLFixedWindow { + uint64_t size; + char **targets; + struct PXBDev *target_hbs[8]; + uint8_t num_targets; + uint8_t enc_int_ways; + uint8_t enc_int_gran; + /* Todo: XOR based interleaving */ + MemoryRegion mr; + hwaddr base; +} CXLFixedWindow; + typedef struct CXLState { bool is_enabled; MemoryRegion host_mr; unsigned int next_mr_idx; + GList *fixed_windows; } CXLState; struct CXLHost { @@ -35,4 +51,9 @@ struct CXLHost { #define TYPE_PXB_CXL_HOST "pxb-cxl-host" OBJECT_DECLARE_SIMPLE_TYPE(CXLHost, PXB_CXL_HOST) +void cxl_fixed_memory_window_config(MachineState *ms, + CXLFixedMemoryWindowOptions *object, + Error **errp); +void cxl_fixed_memory_window_link_targets(Error **errp); + #endif diff --git a/qapi/machine.json b/qapi/machine.json index 92480d4044..3f1eab3482 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -502,6 +502,27 @@ 'dst': 'uint16', 'val': 'uint8' }} +## +# @CXLFixedMemoryWindowOptions: +# +# Create a CXL Fixed Memory Window +# +# @size: Size of the Fixed Memory Window in bytes. Must be a multiple +# of 256MiB. +# @interleave-granularity: Number of contiguous bytes for which +# accesses will go to a given interleave target. +# Accepted values [256, 512, 1k, 2k, 4k, 8k, 16k] +# @targets: Target root bridge IDs from -device ...,id= for each root +# bridge. +# +# Since 7.1 +## +{ 'struct': 'CXLFixedMemoryWindowOptions', + 'data': { + 'size': 'size', + '*interleave-granularity': 'size', + 'targets': ['str'] }} + ## # @X86CPURegister32: # diff --git a/qemu-options.hx b/qemu-options.hx index 796229c433..315bb18595 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -467,6 +467,44 @@ SRST -numa hmat-cache,node-id=1,size=10K,level=1,associativity=direct,policy=write-back,line=8 ERST +DEF("cxl-fixed-memory-window", HAS_ARG, QEMU_OPTION_cxl_fixed_memory_window, + "-cxl-fixed-memory-window targets.0=firsttarget,targets.1=secondtarget,size=size[,interleave-granularity=granularity]\n", + QEMU_ARCH_ALL) +SRST +``-cxl-fixed-memory-window targets.0=firsttarget,targets.1=secondtarget,size=size[,interleave-granularity=granularity]`` + Define a CXL Fixed Memory Window (CFMW). + + Described in the CXL 2.0 ECN: CEDT CFMWS & QTG _DSM. + + They are regions of Host Physical Addresses (HPA) on a system which + may be interleaved across one or more CXL host bridges. The system + software will assign particular devices into these windows and + configure the downstream Host-managed Device Memory (HDM) decoders + in root ports, switch ports and devices appropriately to meet the + interleave requirements before enabling the memory devices. + + ``targets.X=firsttarget`` provides the mapping to CXL host bridges + which may be identified by the id provied in the -device entry. + Multiple entries are needed to specify all the targets when + the fixed memory window represents interleaved memory. X is the + target index from 0. + + ``size=size`` sets the size of the CFMW. This must be a multiple of + 256MiB. The region will be aligned to 256MiB but the location is + platform and configuration dependent. + + ``interleave-granularity=granularity`` sets the granularity of + interleave. Default 256KiB. Only 256KiB, 512KiB, 1024KiB, 2048KiB + 4096KiB, 8192KiB and 16384KiB granularities supported. + + Example: + + :: + + -cxl-fixed-memory-window targets.0=cxl.0,targets.1=cxl.1,size=128G,interleave-granularity=512k + +ERST + DEF("add-fd", HAS_ARG, QEMU_OPTION_add_fd, "-add-fd fd=fd,set=set[,opaque=opaque]\n" " Add 'fd' to fd 'set'\n", QEMU_ARCH_ALL) diff --git a/softmmu/vl.c b/softmmu/vl.c index 817d515783..2390c13fb6 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -93,6 +93,7 @@ #include "qemu/config-file.h" #include "qemu/qemu-options.h" #include "qemu/main-loop.h" +#include "hw/cxl/cxl.h" #ifdef CONFIG_VIRTFS #include "fsdev/qemu-fsdev.h" #endif @@ -118,6 +119,7 @@ #include "qapi/qapi-events-run-state.h" #include "qapi/qapi-visit-block-core.h" #include "qapi/qapi-visit-compat.h" +#include "qapi/qapi-visit-machine.h" #include "qapi/qapi-visit-ui.h" #include "qapi/qapi-commands-block-core.h" #include "qapi/qapi-commands-migration.h" @@ -143,6 +145,12 @@ typedef struct BlockdevOptionsQueueEntry { typedef QSIMPLEQ_HEAD(, BlockdevOptionsQueueEntry) BlockdevOptionsQueue; +typedef struct CXLFMWOptionQueueEntry { + CXLFixedMemoryWindowOptions *opts; + Location loc; + QSIMPLEQ_ENTRY(CXLFMWOptionQueueEntry) entry; +} CXLFMWOptionQueueEntry; + typedef struct ObjectOption { ObjectOptions *opts; QTAILQ_ENTRY(ObjectOption) next; @@ -169,6 +177,8 @@ static int snapshot; static bool preconfig_requested; static QemuPluginList plugin_list = QTAILQ_HEAD_INITIALIZER(plugin_list); static BlockdevOptionsQueue bdo_queue = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue); +static QSIMPLEQ_HEAD(, CXLFMWOptionQueueEntry) CXLFMW_opts = + QSIMPLEQ_HEAD_INITIALIZER(CXLFMW_opts); static bool nographic = false; static int mem_prealloc; /* force preallocation of physical target memory */ static const char *vga_model = NULL; @@ -1153,6 +1163,24 @@ static void parse_display(const char *p) } } +static void parse_cxl_fixed_memory_window(const char *optarg) +{ + CXLFMWOptionQueueEntry *cfmws_entry; + Visitor *v; + + v = qobject_input_visitor_new_str(optarg, "cxl-fixed-memory-window", + &error_fatal); + cfmws_entry = g_new(CXLFMWOptionQueueEntry, 1); + visit_type_CXLFixedMemoryWindowOptions(v, NULL, &cfmws_entry->opts, + &error_fatal); + if (!cfmws_entry->opts) { + exit(1); + } + visit_free(v); + loc_save(&cfmws_entry->loc); + QSIMPLEQ_INSERT_TAIL(&CXLFMW_opts, cfmws_entry, entry); +} + static inline bool nonempty_str(const char *str) { return str && *str; @@ -2015,6 +2043,20 @@ static void qemu_create_late_backends(void) qemu_semihosting_console_init(); } +static void cxl_set_opts(void) +{ + while (!QSIMPLEQ_EMPTY(&CXLFMW_opts)) { + CXLFMWOptionQueueEntry *cfmws_entry = QSIMPLEQ_FIRST(&CXLFMW_opts); + + loc_restore(&cfmws_entry->loc); + QSIMPLEQ_REMOVE_HEAD(&CXLFMW_opts, entry); + cxl_fixed_memory_window_config(current_machine, cfmws_entry->opts, + &error_fatal); + qapi_free_CXLFixedMemoryWindowOptions(cfmws_entry->opts); + g_free(cfmws_entry); + } +} + static void qemu_resolve_machine_memdev(void) { if (ram_memdev_id) { @@ -2661,6 +2703,7 @@ void qmp_x_exit_preconfig(Error **errp) qemu_init_board(); qemu_create_cli_devices(); + cxl_fixed_memory_window_link_targets(errp); qemu_machine_creation_done(); if (loadvm) { @@ -2841,6 +2884,9 @@ void qemu_init(int argc, char **argv, char **envp) exit(1); } break; + case QEMU_OPTION_cxl_fixed_memory_window: + parse_cxl_fixed_memory_window(optarg); + break; case QEMU_OPTION_display: parse_display(optarg); break; @@ -3652,6 +3698,7 @@ void qemu_init(int argc, char **argv, char **envp) qemu_resolve_machine_memdev(); parse_numa_opts(current_machine); + cxl_set_opts(); if (vmstate_dump_file) { /* dump and exit */ From 21df6ab97ff2c0de76ce683808356aaf98d9d1d2 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:53 +0100 Subject: [PATCH 297/935] acpi/cxl: Introduce CFMWS structures in CEDT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CEDT CXL Fixed Window Memory Window Structures (CFMWs) define regions of the host phyiscal address map which (via an impdef means) are configured such that they have a particular interleave setup across one or more CXL Host Bridges. Reported-by: Alison Schofield Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-29-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/cxl.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/hw/acpi/cxl.c b/hw/acpi/cxl.c index aa4af86a4c..31d5235136 100644 --- a/hw/acpi/cxl.c +++ b/hw/acpi/cxl.c @@ -60,6 +60,64 @@ static void cedt_build_chbs(GArray *table_data, PXBDev *cxl) build_append_int_noprefix(table_data, memory_region_size(mr), 8); } +/* + * CFMWS entries in CXL 2.0 ECN: CEDT CFMWS & QTG _DSM. + * Interleave ways encoding in CXL 2.0 ECN: 3, 6, 12 and 16-way memory + * interleaving. + */ +static void cedt_build_cfmws(GArray *table_data, MachineState *ms) +{ + CXLState *cxls = ms->cxl_devices_state; + GList *it; + + for (it = cxls->fixed_windows; it; it = it->next) { + CXLFixedWindow *fw = it->data; + int i; + + /* Type */ + build_append_int_noprefix(table_data, 1, 1); + + /* Reserved */ + build_append_int_noprefix(table_data, 0, 1); + + /* Record Length */ + build_append_int_noprefix(table_data, 36 + 4 * fw->num_targets, 2); + + /* Reserved */ + build_append_int_noprefix(table_data, 0, 4); + + /* Base HPA */ + build_append_int_noprefix(table_data, fw->mr.addr, 8); + + /* Window Size */ + build_append_int_noprefix(table_data, fw->size, 8); + + /* Host Bridge Interleave Ways */ + build_append_int_noprefix(table_data, fw->enc_int_ways, 1); + + /* Host Bridge Interleave Arithmetic */ + build_append_int_noprefix(table_data, 0, 1); + + /* Reserved */ + build_append_int_noprefix(table_data, 0, 2); + + /* Host Bridge Interleave Granularity */ + build_append_int_noprefix(table_data, fw->enc_int_gran, 4); + + /* Window Restrictions */ + build_append_int_noprefix(table_data, 0x0f, 2); /* No restrictions */ + + /* QTG ID */ + build_append_int_noprefix(table_data, 0, 2); + + /* Host Bridge List (list of UIDs - currently bus_nr) */ + for (i = 0; i < fw->num_targets; i++) { + g_assert(fw->target_hbs[i]); + build_append_int_noprefix(table_data, fw->target_hbs[i]->bus_nr, 4); + } + } +} + static int cxl_foreach_pxb_hb(Object *obj, void *opaque) { Aml *cedt = opaque; @@ -86,6 +144,7 @@ void cxl_build_cedt(MachineState *ms, GArray *table_offsets, GArray *table_data, /* reserve space for CEDT header */ object_child_foreach_recursive(object_get_root(), cxl_foreach_pxb_hb, cedt); + cedt_build_cfmws(cedt->buf, ms); /* copy AML table into ACPI tables blob and patch header there */ g_array_append_vals(table_data, cedt->buf->data, cedt->buf->len); From fc1e01e009fd4b1e08399253591b32e01f10808f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 29 Apr 2022 15:40:54 +0100 Subject: [PATCH 298/935] hw/pci-host/gpex-acpi: Add support for dsdt construction for pxb-cxl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds code to instantiate the slightly extended ACPI root port description in DSDT as per the CXL 2.0 specification. Basically a cut and paste job from the i386/pc code. Signed-off-by: Jonathan Cameron Signed-off-by: Ben Widawsky Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-30-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/arm/Kconfig | 1 + hw/pci-host/gpex-acpi.c | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 97f3b38019..219262a8da 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -29,6 +29,7 @@ config ARM_VIRT select ACPI_APEI select ACPI_VIOT select VIRTIO_MEM_SUPPORTED + select ACPI_CXL config CHEETAH bool diff --git a/hw/pci-host/gpex-acpi.c b/hw/pci-host/gpex-acpi.c index e7e162a00a..7c7316bc96 100644 --- a/hw/pci-host/gpex-acpi.c +++ b/hw/pci-host/gpex-acpi.c @@ -5,6 +5,7 @@ #include "hw/pci/pci_bus.h" #include "hw/pci/pci_bridge.h" #include "hw/pci/pcie_host.h" +#include "hw/acpi/cxl.h" static void acpi_dsdt_add_pci_route_table(Aml *dev, uint32_t irq) { @@ -139,6 +140,7 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) QLIST_FOREACH(bus, &bus->child, sibling) { uint8_t bus_num = pci_bus_num(bus); uint8_t numa_node = pci_bus_numa_node(bus); + bool is_cxl = pci_bus_is_cxl(bus); if (!pci_bus_is_root(bus)) { continue; @@ -154,8 +156,16 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) } dev = aml_device("PC%.02X", bus_num); - aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A08"))); - aml_append(dev, aml_name_decl("_CID", aml_string("PNP0A03"))); + if (is_cxl) { + struct Aml *pkg = aml_package(2); + aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0016"))); + aml_append(pkg, aml_eisaid("PNP0A08")); + aml_append(pkg, aml_eisaid("PNP0A03")); + aml_append(dev, aml_name_decl("_CID", pkg)); + } else { + aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A08"))); + aml_append(dev, aml_name_decl("_CID", aml_string("PNP0A03"))); + } aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num))); aml_append(dev, aml_name_decl("_UID", aml_int(bus_num))); aml_append(dev, aml_name_decl("_STR", aml_unicode("pxb Device"))); @@ -175,7 +185,11 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) cfg->pio.base, 0, 0, 0); aml_append(dev, aml_name_decl("_CRS", crs)); - acpi_dsdt_add_pci_osc(dev); + if (is_cxl) { + build_cxl_osc_method(dev); + } else { + acpi_dsdt_add_pci_osc(dev); + } aml_append(scope, dev); } From aa970ed586f9c7f178b813bda2919e329b841e3c Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 29 Apr 2022 15:40:55 +0100 Subject: [PATCH 299/935] pci/pcie_port: Add pci_find_port_by_pn() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simple function to search a PCIBus to find a port by it's port number. CXL interleave decoding uses the port number as a target so it is necessary to locate the port when doing interleave decoding. Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-31-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pcie_port.c | 25 +++++++++++++++++++++++++ include/hw/pci/pcie_port.h | 2 ++ 2 files changed, 27 insertions(+) diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c index e95c1e5519..687e4e763a 100644 --- a/hw/pci/pcie_port.c +++ b/hw/pci/pcie_port.c @@ -136,6 +136,31 @@ static void pcie_port_class_init(ObjectClass *oc, void *data) device_class_set_props(dc, pcie_port_props); } +PCIDevice *pcie_find_port_by_pn(PCIBus *bus, uint8_t pn) +{ + int devfn; + + for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { + PCIDevice *d = bus->devices[devfn]; + PCIEPort *port; + + if (!d || !pci_is_express(d) || !d->exp.exp_cap) { + continue; + } + + if (!object_dynamic_cast(OBJECT(d), TYPE_PCIE_PORT)) { + continue; + } + + port = PCIE_PORT(d); + if (port->port == pn) { + return d; + } + } + + return NULL; +} + static const TypeInfo pcie_port_type_info = { .name = TYPE_PCIE_PORT, .parent = TYPE_PCI_BRIDGE, diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h index e25b289ce8..7b8193061a 100644 --- a/include/hw/pci/pcie_port.h +++ b/include/hw/pci/pcie_port.h @@ -39,6 +39,8 @@ struct PCIEPort { void pcie_port_init_reg(PCIDevice *d); +PCIDevice *pcie_find_port_by_pn(PCIBus *bus, uint8_t pn); + #define TYPE_PCIE_SLOT "pcie-slot" OBJECT_DECLARE_SIMPLE_TYPE(PCIESlot, PCIE_SLOT) From 0b4aec246972f238a22d04403289eee97e8c8be6 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 29 Apr 2022 15:40:56 +0100 Subject: [PATCH 300/935] CXL/cxl_component: Add cxl_get_hb_cstate() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Accessor to get hold of the cxl state for a CXL host bridge without exposing the internals of the implementation. Signed-off-by: Jonathan Cameron Reviewed-by: Alex Bennée Message-Id: <20220429144110.25167-32-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci-bridge/pci_expander_bridge.c | 7 +++++++ include/hw/cxl/cxl_component.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index 22feda1ff0..69244decdb 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -72,6 +72,13 @@ static GList *pxb_dev_list; #define TYPE_PXB_HOST "pxb-host" +CXLComponentState *cxl_get_hb_cstate(PCIHostState *hb) +{ + CXLHost *host = PXB_CXL_HOST(hb); + + return &host->cxl_cstate; +} + static int pxb_bus_num(PCIBus *bus) { PXBDev *pxb = convert_to_pxb(bus->parent_dev); diff --git a/include/hw/cxl/cxl_component.h b/include/hw/cxl/cxl_component.h index 4f69688c47..70b5018156 100644 --- a/include/hw/cxl/cxl_component.h +++ b/include/hw/cxl/cxl_component.h @@ -218,4 +218,6 @@ static inline hwaddr cxl_decode_ig(int ig) return 1 << (ig + 8); } +CXLComponentState *cxl_get_hb_cstate(PCIHostState *hb); + #endif From 5fcc499ee3457709657b23655e385613a437068d Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 29 Apr 2022 15:40:57 +0100 Subject: [PATCH 301/935] mem/cxl_type3: Add read and write functions for associated hostmem. Once a read or write reaches a CXL type 3 device, the HDM decoders on the device are used to establish the Device Physical Address which should be accessed. These functions peform the required maths and then use a device specific address space to access the hostmem->mr to fullfil the actual operation. Note that failed writes are silent, but failed reads return poison. Note this is based loosely on: https://lore.kernel.org/qemu-devel/20200817161853.593247-6-f4bug@amsat.org/ [RFC PATCH 0/9] hw/misc: Add support for interleaved memory accesses Only lightly tested so far. More complex test cases yet to be written. Signed-off-by: Jonathan Cameron Message-Id: <20220429144110.25167-33-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/mem/cxl_type3.c | 91 +++++++++++++++++++++++++++++++++++++ include/hw/cxl/cxl_device.h | 6 +++ 2 files changed, 97 insertions(+) diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index 6c6ed9a776..3bf2869573 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -97,7 +97,9 @@ static void ct3d_reg_write(void *opaque, hwaddr offset, uint64_t value, static bool cxl_setup_memory(CXLType3Dev *ct3d, Error **errp) { + DeviceState *ds = DEVICE(ct3d); MemoryRegion *mr; + char *name; if (!ct3d->hostmem) { error_setg(errp, "memdev property must be set"); @@ -112,6 +114,15 @@ static bool cxl_setup_memory(CXLType3Dev *ct3d, Error **errp) memory_region_set_nonvolatile(mr, true); memory_region_set_enabled(mr, true); host_memory_backend_set_mapped(ct3d->hostmem, true); + + if (ds->id) { + name = g_strdup_printf("cxl-type3-dpa-space:%s", ds->id); + } else { + name = g_strdup("cxl-type3-dpa-space"); + } + address_space_init(&ct3d->hostmem_as, mr, name); + g_free(name); + ct3d->cxl_dstate.pmem_size = ct3d->hostmem->size; if (!ct3d->lsa) { @@ -167,6 +178,86 @@ static void ct3_exit(PCIDevice *pci_dev) ComponentRegisters *regs = &cxl_cstate->crb; g_free(regs->special_ops); + address_space_destroy(&ct3d->hostmem_as); +} + +/* TODO: Support multiple HDM decoders and DPA skip */ +static bool cxl_type3_dpa(CXLType3Dev *ct3d, hwaddr host_addr, uint64_t *dpa) +{ + uint32_t *cache_mem = ct3d->cxl_cstate.crb.cache_mem_registers; + uint64_t decoder_base, decoder_size, hpa_offset; + uint32_t hdm0_ctrl; + int ig, iw; + + decoder_base = (((uint64_t)cache_mem[R_CXL_HDM_DECODER0_BASE_HI] << 32) | + cache_mem[R_CXL_HDM_DECODER0_BASE_LO]); + if ((uint64_t)host_addr < decoder_base) { + return false; + } + + hpa_offset = (uint64_t)host_addr - decoder_base; + + decoder_size = ((uint64_t)cache_mem[R_CXL_HDM_DECODER0_SIZE_HI] << 32) | + cache_mem[R_CXL_HDM_DECODER0_SIZE_LO]; + if (hpa_offset >= decoder_size) { + return false; + } + + hdm0_ctrl = cache_mem[R_CXL_HDM_DECODER0_CTRL]; + iw = FIELD_EX32(hdm0_ctrl, CXL_HDM_DECODER0_CTRL, IW); + ig = FIELD_EX32(hdm0_ctrl, CXL_HDM_DECODER0_CTRL, IG); + + *dpa = (MAKE_64BIT_MASK(0, 8 + ig) & hpa_offset) | + ((MAKE_64BIT_MASK(8 + ig + iw, 64 - 8 - ig - iw) & hpa_offset) >> iw); + + return true; +} + +MemTxResult cxl_type3_read(PCIDevice *d, hwaddr host_addr, uint64_t *data, + unsigned size, MemTxAttrs attrs) +{ + CXLType3Dev *ct3d = CXL_TYPE3(d); + uint64_t dpa_offset; + MemoryRegion *mr; + + /* TODO support volatile region */ + mr = host_memory_backend_get_memory(ct3d->hostmem); + if (!mr) { + return MEMTX_ERROR; + } + + if (!cxl_type3_dpa(ct3d, host_addr, &dpa_offset)) { + return MEMTX_ERROR; + } + + if (dpa_offset > int128_get64(mr->size)) { + return MEMTX_ERROR; + } + + return address_space_read(&ct3d->hostmem_as, dpa_offset, attrs, data, size); +} + +MemTxResult cxl_type3_write(PCIDevice *d, hwaddr host_addr, uint64_t data, + unsigned size, MemTxAttrs attrs) +{ + CXLType3Dev *ct3d = CXL_TYPE3(d); + uint64_t dpa_offset; + MemoryRegion *mr; + + mr = host_memory_backend_get_memory(ct3d->hostmem); + if (!mr) { + return MEMTX_OK; + } + + if (!cxl_type3_dpa(ct3d, host_addr, &dpa_offset)) { + return MEMTX_OK; + } + + if (dpa_offset > int128_get64(mr->size)) { + return MEMTX_OK; + } + return address_space_write(&ct3d->hostmem_as, dpa_offset, attrs, + &data, size); } static void ct3d_reset(DeviceState *dev) diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index 4285fbda08..1e141b6621 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -239,6 +239,7 @@ struct CXLType3Dev { HostMemoryBackend *lsa; /* State */ + AddressSpace hostmem_as; CXLComponentState cxl_cstate; CXLDeviceState cxl_dstate; }; @@ -259,4 +260,9 @@ struct CXLType3Class { uint64_t offset); }; +MemTxResult cxl_type3_read(PCIDevice *d, hwaddr host_addr, uint64_t *data, + unsigned size, MemTxAttrs attrs); +MemTxResult cxl_type3_write(PCIDevice *d, hwaddr host_addr, uint64_t data, + unsigned size, MemTxAttrs attrs); + #endif From eb19d9079efc4e986a37b0c3172ecd9b617fd04a Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 29 Apr 2022 15:40:58 +0100 Subject: [PATCH 302/935] cxl/cxl-host: Add memops for CFMWS region. These memops perform interleave decoding, walking down the CXL topology from CFMWS described host interleave decoder via CXL host bridge HDM decoders, through the CXL root ports and finally call CXL type 3 specific read and write functions. Note that, whilst functional the current implementation does not support: * switches * multiple HDM decoders at a given level. * unaligned accesses across the interleave boundaries Signed-off-by: Jonathan Cameron Message-Id: <20220429144110.25167-34-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-host-stubs.c | 2 + hw/cxl/cxl-host.c | 128 ++++++++++++++++++++++++++++++++++++++++ include/hw/cxl/cxl.h | 2 + 3 files changed, 132 insertions(+) diff --git a/hw/cxl/cxl-host-stubs.c b/hw/cxl/cxl-host-stubs.c index f8fd278d5d..24465a52ab 100644 --- a/hw/cxl/cxl-host-stubs.c +++ b/hw/cxl/cxl-host-stubs.c @@ -12,3 +12,5 @@ void cxl_fixed_memory_window_config(MachineState *ms, Error **errp) {}; void cxl_fixed_memory_window_link_targets(Error **errp) {}; + +const MemoryRegionOps cfmws_ops; diff --git a/hw/cxl/cxl-host.c b/hw/cxl/cxl-host.c index ec5a75cbf5..469b3c4ced 100644 --- a/hw/cxl/cxl-host.c +++ b/hw/cxl/cxl-host.c @@ -15,6 +15,10 @@ #include "qapi/qapi-visit-machine.h" #include "hw/cxl/cxl.h" +#include "hw/pci/pci_bus.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pci_host.h" +#include "hw/pci/pcie_port.h" void cxl_fixed_memory_window_config(MachineState *ms, CXLFixedMemoryWindowOptions *object, @@ -92,3 +96,127 @@ void cxl_fixed_memory_window_link_targets(Error **errp) } } } + +/* TODO: support, multiple hdm decoders */ +static bool cxl_hdm_find_target(uint32_t *cache_mem, hwaddr addr, + uint8_t *target) +{ + uint32_t ctrl; + uint32_t ig_enc; + uint32_t iw_enc; + uint32_t target_reg; + uint32_t target_idx; + + ctrl = cache_mem[R_CXL_HDM_DECODER0_CTRL]; + if (!FIELD_EX32(ctrl, CXL_HDM_DECODER0_CTRL, COMMITTED)) { + return false; + } + + ig_enc = FIELD_EX32(ctrl, CXL_HDM_DECODER0_CTRL, IG); + iw_enc = FIELD_EX32(ctrl, CXL_HDM_DECODER0_CTRL, IW); + target_idx = (addr / cxl_decode_ig(ig_enc)) % (1 << iw_enc); + + if (target_idx > 4) { + target_reg = cache_mem[R_CXL_HDM_DECODER0_TARGET_LIST_LO]; + target_reg >>= target_idx * 8; + } else { + target_reg = cache_mem[R_CXL_HDM_DECODER0_TARGET_LIST_LO]; + target_reg >>= (target_idx - 4) * 8; + } + *target = target_reg & 0xff; + + return true; +} + +static PCIDevice *cxl_cfmws_find_device(CXLFixedWindow *fw, hwaddr addr) +{ + CXLComponentState *hb_cstate; + PCIHostState *hb; + int rb_index; + uint32_t *cache_mem; + uint8_t target; + bool target_found; + PCIDevice *rp, *d; + + /* Address is relative to memory region. Convert to HPA */ + addr += fw->base; + + rb_index = (addr / cxl_decode_ig(fw->enc_int_gran)) % fw->num_targets; + hb = PCI_HOST_BRIDGE(fw->target_hbs[rb_index]->cxl.cxl_host_bridge); + if (!hb || !hb->bus || !pci_bus_is_cxl(hb->bus)) { + return NULL; + } + + hb_cstate = cxl_get_hb_cstate(hb); + if (!hb_cstate) { + return NULL; + } + + cache_mem = hb_cstate->crb.cache_mem_registers; + + target_found = cxl_hdm_find_target(cache_mem, addr, &target); + if (!target_found) { + return NULL; + } + + rp = pcie_find_port_by_pn(hb->bus, target); + if (!rp) { + return NULL; + } + + d = pci_bridge_get_sec_bus(PCI_BRIDGE(rp))->devices[0]; + + if (!d || !object_dynamic_cast(OBJECT(d), TYPE_CXL_TYPE3)) { + return NULL; + } + + return d; +} + +static MemTxResult cxl_read_cfmws(void *opaque, hwaddr addr, uint64_t *data, + unsigned size, MemTxAttrs attrs) +{ + CXLFixedWindow *fw = opaque; + PCIDevice *d; + + d = cxl_cfmws_find_device(fw, addr); + if (d == NULL) { + *data = 0; + /* Reads to invalid address return poison */ + return MEMTX_ERROR; + } + + return cxl_type3_read(d, addr + fw->base, data, size, attrs); +} + +static MemTxResult cxl_write_cfmws(void *opaque, hwaddr addr, + uint64_t data, unsigned size, + MemTxAttrs attrs) +{ + CXLFixedWindow *fw = opaque; + PCIDevice *d; + + d = cxl_cfmws_find_device(fw, addr); + if (d == NULL) { + /* Writes to invalid address are silent */ + return MEMTX_OK; + } + + return cxl_type3_write(d, addr + fw->base, data, size, attrs); +} + +const MemoryRegionOps cfmws_ops = { + .read_with_attrs = cxl_read_cfmws, + .write_with_attrs = cxl_write_cfmws, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = true, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = true, + }, +}; diff --git a/include/hw/cxl/cxl.h b/include/hw/cxl/cxl.h index dce38124db..21d28ca110 100644 --- a/include/hw/cxl/cxl.h +++ b/include/hw/cxl/cxl.h @@ -56,4 +56,6 @@ void cxl_fixed_memory_window_config(MachineState *ms, Error **errp); void cxl_fixed_memory_window_link_targets(Error **errp); +extern const MemoryRegionOps cfmws_ops; + #endif From 3540bf56e47dce55e5035a039db97c0affc66fba Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 29 Apr 2022 15:40:59 +0100 Subject: [PATCH 303/935] hw/cxl/component Add a dumb HDM decoder handler Add a trivial handler for now to cover the root bridge where we could do some error checking in future. Signed-off-by: Ben Widawsky Signed-off-by: Jonathan Cameron Message-Id: <20220429144110.25167-35-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-component-utils.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/hw/cxl/cxl-component-utils.c b/hw/cxl/cxl-component-utils.c index 69cb07171c..7985c9bfca 100644 --- a/hw/cxl/cxl-component-utils.c +++ b/hw/cxl/cxl-component-utils.c @@ -32,6 +32,31 @@ static uint64_t cxl_cache_mem_read_reg(void *opaque, hwaddr offset, } } +static void dumb_hdm_handler(CXLComponentState *cxl_cstate, hwaddr offset, + uint32_t value) +{ + ComponentRegisters *cregs = &cxl_cstate->crb; + uint32_t *cache_mem = cregs->cache_mem_registers; + bool should_commit = false; + + switch (offset) { + case A_CXL_HDM_DECODER0_CTRL: + should_commit = FIELD_EX32(value, CXL_HDM_DECODER0_CTRL, COMMIT); + break; + default: + break; + } + + memory_region_transaction_begin(); + stl_le_p((uint8_t *)cache_mem + offset, value); + if (should_commit) { + ARRAY_FIELD_DP32(cache_mem, CXL_HDM_DECODER0_CTRL, COMMIT, 0); + ARRAY_FIELD_DP32(cache_mem, CXL_HDM_DECODER0_CTRL, ERR, 0); + ARRAY_FIELD_DP32(cache_mem, CXL_HDM_DECODER0_CTRL, COMMITTED, 1); + } + memory_region_transaction_commit(); +} + static void cxl_cache_mem_write_reg(void *opaque, hwaddr offset, uint64_t value, unsigned size) { @@ -50,6 +75,12 @@ static void cxl_cache_mem_write_reg(void *opaque, hwaddr offset, uint64_t value, value |= ~mask & cregs->cache_mem_registers[offset / sizeof(*cregs->cache_mem_registers)]; if (cregs->special_ops && cregs->special_ops->write) { cregs->special_ops->write(cxl_cstate, offset, value, size); + return; + } + + if (offset >= A_CXL_HDM_DECODER_CAPABILITY && + offset <= A_CXL_HDM_DECODER0_TARGET_LIST_HI) { + dumb_hdm_handler(cxl_cstate, offset, value); } else { cregs->cache_mem_registers[offset / sizeof(*cregs->cache_mem_registers)] = value; } From 6d302cf46dfffa85a1a460d4431b1633c9ef2ff3 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 29 Apr 2022 15:41:00 +0100 Subject: [PATCH 304/935] i386/pc: Enable CXL fixed memory windows Add the CFMWs memory regions to the memorymap and adjust the PCI window to avoid hitting the same memory. Signed-off-by: Jonathan Cameron Message-Id: <20220429144110.25167-36-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 03d14f6564..312eb9e400 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -817,7 +817,7 @@ void pc_memory_init(PCMachineState *pcms, MachineClass *mc = MACHINE_GET_CLASS(machine); PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); X86MachineState *x86ms = X86_MACHINE(pcms); - hwaddr cxl_base; + hwaddr cxl_base, cxl_resv_end = 0; assert(machine->ram_size == x86ms->below_4g_mem_size + x86ms->above_4g_mem_size); @@ -925,6 +925,24 @@ void pc_memory_init(PCMachineState *pcms, e820_add_entry(cxl_base, cxl_size, E820_RESERVED); memory_region_init(mr, OBJECT(machine), "cxl_host_reg", cxl_size); memory_region_add_subregion(system_memory, cxl_base, mr); + cxl_resv_end = cxl_base + cxl_size; + if (machine->cxl_devices_state->fixed_windows) { + hwaddr cxl_fmw_base; + GList *it; + + cxl_fmw_base = ROUND_UP(cxl_base + cxl_size, 256 * MiB); + for (it = machine->cxl_devices_state->fixed_windows; it; it = it->next) { + CXLFixedWindow *fw = it->data; + + fw->base = cxl_fmw_base; + memory_region_init_io(&fw->mr, OBJECT(machine), &cfmws_ops, fw, + "cxl-fixed-memory-region", fw->size); + memory_region_add_subregion(system_memory, fw->base, &fw->mr); + e820_add_entry(fw->base, fw->size, E820_RESERVED); + cxl_fmw_base += fw->size; + cxl_resv_end = cxl_fmw_base; + } + } } /* Initialize PC system firmware */ @@ -954,6 +972,10 @@ void pc_memory_init(PCMachineState *pcms, if (!pcmc->broken_reserved_end) { res_mem_end += memory_region_size(&machine->device_memory->mr); } + + if (machine->cxl_devices_state->is_enabled) { + res_mem_end = cxl_resv_end; + } *val = cpu_to_le64(ROUND_UP(res_mem_end, 1 * GiB)); fw_cfg_add_file(fw_cfg, "etc/reserved-memory-end", val, sizeof(*val)); } @@ -990,6 +1012,13 @@ uint64_t pc_pci_hole64_start(void) if (ms->cxl_devices_state->host_mr.addr) { hole64_start = ms->cxl_devices_state->host_mr.addr + memory_region_size(&ms->cxl_devices_state->host_mr); + if (ms->cxl_devices_state->fixed_windows) { + GList *it; + for (it = ms->cxl_devices_state->fixed_windows; it; it = it->next) { + CXLFixedWindow *fw = it->data; + hole64_start = fw->mr.addr + memory_region_size(&fw->mr); + } + } } else if (pcmc->has_reserved_memory && ms->device_memory->base) { hole64_start = ms->device_memory->base; if (!pcmc->broken_reserved_end) { From 502f99abaa58e82b186cc914e7d39d5f2bc0f1b4 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 29 Apr 2022 15:41:01 +0100 Subject: [PATCH 305/935] tests/acpi: q35: Allow addition of a CXL test. Add exceptions for the DSDT and the new CEDT tables specific to a new CXL test in the following patch. Signed-off-by: Jonathan Cameron Message-Id: <20220429144110.25167-37-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/q35/CEDT.cxl | 0 tests/data/acpi/q35/DSDT.cxl | 0 tests/qtest/bios-tables-test-allowed-diff.h | 2 ++ 3 files changed, 2 insertions(+) create mode 100644 tests/data/acpi/q35/CEDT.cxl create mode 100644 tests/data/acpi/q35/DSDT.cxl diff --git a/tests/data/acpi/q35/CEDT.cxl b/tests/data/acpi/q35/CEDT.cxl new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/data/acpi/q35/DSDT.cxl b/tests/data/acpi/q35/DSDT.cxl new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..7c7f9fbc44 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,3 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/q35/DSDT.cxl", +"tests/data/acpi/q35/CEDT.cxl", From 65fc04ff3cf5b91c0490c80714f97ae6a43d7ee8 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 29 Apr 2022 15:41:02 +0100 Subject: [PATCH 306/935] qtests/bios-tables-test: Add a test for CXL emulation. The DSDT includes several CXL specific elements and the CEDT table is only present if we enable CXL. The test exercises all current functionality with several CFMWS, CHBS structures in CEDT and ACPI0016/ACPI00017 and _OSC entries in DSDT. Signed-off-by: Jonathan Cameron Message-Id: <20220429144110.25167-38-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test.c | 44 ++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index 5dddedabcd..a4a46e97f0 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -1536,6 +1536,49 @@ static void test_acpi_q35_viot(void) free_test_data(&data); } +static void test_acpi_q35_cxl(void) +{ + gchar *tmp_path = g_dir_make_tmp("qemu-test-cxl.XXXXXX", NULL); + gchar *params; + + test_data data = { + .machine = MACHINE_Q35, + .variant = ".cxl", + }; + /* + * A complex CXL setup. + */ + params = g_strdup_printf(" -machine cxl=on" + " -object memory-backend-file,id=cxl-mem1,mem-path=%s,size=256M" + " -object memory-backend-file,id=cxl-mem2,mem-path=%s,size=256M" + " -object memory-backend-file,id=cxl-mem3,mem-path=%s,size=256M" + " -object memory-backend-file,id=cxl-mem4,mem-path=%s,size=256M" + " -object memory-backend-file,id=lsa1,mem-path=%s,size=256M" + " -object memory-backend-file,id=lsa2,mem-path=%s,size=256M" + " -object memory-backend-file,id=lsa3,mem-path=%s,size=256M" + " -object memory-backend-file,id=lsa4,mem-path=%s,size=256M" + " -device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1" + " -device pxb-cxl,bus_nr=222,bus=pcie.0,id=cxl.2" + " -device cxl-rp,port=0,bus=cxl.1,id=rp1,chassis=0,slot=2" + " -device cxl-type3,bus=rp1,memdev=cxl-mem1,lsa=lsa1" + " -device cxl-rp,port=1,bus=cxl.1,id=rp2,chassis=0,slot=3" + " -device cxl-type3,bus=rp2,memdev=cxl-mem2,lsa=lsa2" + " -device cxl-rp,port=0,bus=cxl.2,id=rp3,chassis=0,slot=5" + " -device cxl-type3,bus=rp3,memdev=cxl-mem3,lsa=lsa3" + " -device cxl-rp,port=1,bus=cxl.2,id=rp4,chassis=0,slot=6" + " -device cxl-type3,bus=rp4,memdev=cxl-mem4,lsa=lsa4" + " -cxl-fixed-memory-window targets.0=cxl.1,size=4G,interleave-granularity=8k" + " -cxl-fixed-memory-window targets.0=cxl.1,targets.1=cxl.2,size=4G,interleave-granularity=8k", + tmp_path, tmp_path, tmp_path, tmp_path, + tmp_path, tmp_path, tmp_path, tmp_path); + test_acpi_one(params, &data); + + g_free(params); + g_assert(g_rmdir(tmp_path) == 0); + g_free(tmp_path); + free_test_data(&data); +} + static void test_acpi_virt_viot(void) { test_data data = { @@ -1741,6 +1784,7 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/q35/kvm/dmar", test_acpi_q35_kvm_dmar); } qtest_add_func("acpi/q35/viot", test_acpi_q35_viot); + qtest_add_func("acpi/q35/cxl", test_acpi_q35_cxl); qtest_add_func("acpi/q35/slic", test_acpi_q35_slic); } else if (strcmp(arch, "aarch64") == 0) { if (has_tcg) { From aa48799530ad506c311566da5ea8ef654cdb8a4e Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 29 Apr 2022 15:41:03 +0100 Subject: [PATCH 307/935] tests/acpi: Add tables for CXL emulation. Tables that differ from normal Q35 tables when running the CXL test. Signed-off-by: Jonathan Cameron Message-Id: <20220429144110.25167-39-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/q35/CEDT.cxl | Bin 0 -> 184 bytes tests/data/acpi/q35/DSDT.cxl | Bin 0 -> 9615 bytes tests/qtest/bios-tables-test-allowed-diff.h | 2 -- 3 files changed, 2 deletions(-) diff --git a/tests/data/acpi/q35/CEDT.cxl b/tests/data/acpi/q35/CEDT.cxl index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b8fa06b00e65712e91e0a5ea0d9277e0146d1c00 100644 GIT binary patch literal 184 zcmZ>EbqU$Qz`(%x(aGQ0BUr&HBEVSz2pEB4AU23*U{GMV2P7eE5T6mshKVRJ@Sw=U r)I#JL88kqeKtKSd14gp~1^Iy(qF)E31_T6{AT-z>kXmGQAh!SjnYIc6 literal 0 HcmV?d00001 diff --git a/tests/data/acpi/q35/DSDT.cxl b/tests/data/acpi/q35/DSDT.cxl index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c1206defed0154e9024702bba88453b2790a306d 100644 GIT binary patch literal 9615 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 Date: Fri, 29 Apr 2022 15:41:04 +0100 Subject: [PATCH 308/935] qtest/cxl: Add more complex test cases with CFMWs Add CXL Fixed Memory Windows to the CXL tests. Signed-off-by: Ben Widawsky Co-developed-by: Jonathan Cameron Signed-off-by: Jonathan Cameron Message-Id: <20220429144110.25167-40-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/cxl-test.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/qtest/cxl-test.c b/tests/qtest/cxl-test.c index 5f0794e816..079011af6a 100644 --- a/tests/qtest/cxl-test.c +++ b/tests/qtest/cxl-test.c @@ -9,11 +9,13 @@ #include "libqtest-single.h" #define QEMU_PXB_CMD "-machine q35,cxl=on " \ - "-device pxb-cxl,id=cxl.0,bus=pcie.0,bus_nr=52 " + "-device pxb-cxl,id=cxl.0,bus=pcie.0,bus_nr=52 " \ + "-cxl-fixed-memory-window targets.0=cxl.0,size=4G " -#define QEMU_2PXB_CMD "-machine q35,cxl=on " \ +#define QEMU_2PXB_CMD "-machine q35,cxl=on " \ "-device pxb-cxl,id=cxl.0,bus=pcie.0,bus_nr=52 " \ - "-device pxb-cxl,id=cxl.1,bus=pcie.0,bus_nr=53 " + "-device pxb-cxl,id=cxl.1,bus=pcie.0,bus_nr=53 " \ + "-cxl-fixed-memory-window targets.0=cxl.0,targets.1=cxl.1,size=4G " #define QEMU_RP "-device cxl-rp,id=rp0,bus=cxl.0,chassis=0,slot=0 " From aa69abe6e8b0f2dbc3022359a8947fa37bf988b9 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 29 Apr 2022 15:41:07 +0100 Subject: [PATCH 309/935] docs/cxl: Add initial Compute eXpress Link (CXL) documentation. Provide an introduction to the main components of a CXL system, with detailed explanation of memory interleaving, example command lines and kernel configuration. This was a challenging document to write due to the need to extract only that subset of CXL information which is relevant to either users of QEMU emulation of CXL or to those interested in the implementation. Much of CXL is concerned with specific elements of the protocol, management of memory pooling etc which is simply not relevant to what is currently planned for CXL emulation in QEMU. All comments welcome Signed-off-by: Jonathan Cameron Message-Id: <20220429144110.25167-43-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/system/device-emulation.rst | 1 + docs/system/devices/cxl.rst | 302 +++++++++++++++++++++++++++++++ 2 files changed, 303 insertions(+) create mode 100644 docs/system/devices/cxl.rst diff --git a/docs/system/device-emulation.rst b/docs/system/device-emulation.rst index ae8dd233e8..3b729b920d 100644 --- a/docs/system/device-emulation.rst +++ b/docs/system/device-emulation.rst @@ -84,6 +84,7 @@ Emulated Devices devices/can.rst devices/ccid.rst + devices/cxl.rst devices/ivshmem.rst devices/net.rst devices/nvme.rst diff --git a/docs/system/devices/cxl.rst b/docs/system/devices/cxl.rst new file mode 100644 index 0000000000..9293cbf01a --- /dev/null +++ b/docs/system/devices/cxl.rst @@ -0,0 +1,302 @@ +Compute Express Link (CXL) +========================== +From the view of a single host, CXL is an interconnect standard that +targets accelerators and memory devices attached to a CXL host. +This description will focus on those aspects visible either to +software running on a QEMU emulated host or to the internals of +functional emulation. As such, it will skip over many of the +electrical and protocol elements that would be more of interest +for real hardware and will dominate more general introductions to CXL. +It will also completely ignore the fabric management aspects of CXL +by considering only a single host and a static configuration. + +CXL shares many concepts and much of the infrastructure of PCI Express, +with CXL Host Bridges, which have CXL Root Ports which may be directly +attached to CXL or PCI End Points. Alternatively there may be CXL Switches +with CXL and PCI Endpoints attached below them. In many cases additional +control and capabilities are exposed via PCI Express interfaces. +This sharing of interfaces and hence emulation code is is reflected +in how the devices are emulated in QEMU. In most cases the various +CXL elements are built upon an equivalent PCIe devices. + +CXL devices support the following interfaces: + +* Most conventional PCIe interfaces + + - Configuration space access + - BAR mapped memory accesses used for registers and mailboxes. + - MSI/MSI-X + - AER + - DOE mailboxes + - IDE + - Many other PCI express defined interfaces.. + +* Memory operations + + - Equivalent of accessing DRAM / NVDIMMs. Any access / feature + supported by the host for normal memory should also work for + CXL attached memory devices. + +* Cache operations. The are mostly irrelevant to QEMU emulation as + QEMU is not emulating a coherency protocol. Any emulation related + to these will be device specific and is out of the scope of this + document. + +CXL 2.0 Device Types +-------------------- +CXL 2.0 End Points are often categorized into three types. + +**Type 1:** These support coherent caching of host memory. Example might +be a crypto accelerators. May also have device private memory accessible +via means such as PCI memory reads and writes to BARs. + +**Type 2:** These support coherent caching of host memory and host +managed device memory (HDM) for which the coherency protocol is managed +by the host. This is a complex topic, so for more information on CXL +coherency see the CXL 2.0 specification. + +**Type 3 Memory devices:** These devices act as a means of attaching +additional memory (HDM) to a CXL host including both volatile and +persistent memory. The CXL topology may support interleaving across a +number of Type 3 memory devices using HDM Decoders in the host, host +bridge, switch upstream port and endpoints. + +Scope of CXL emulation in QEMU +------------------------------ +The focus of CXL emulation is CXL revision 2.0 and later. Earlier CXL +revisions defined a smaller set of features, leaving much of the control +interface as implementation defined or device specific, making generic +emulation challenging with host specific firmware being responsible +for setup and the Endpoints being presented to operating systems +as Root Complex Integrated End Points. CXL rev 2.0 looks a lot +more like PCI Express, with fully specified discoverability +of the CXL topology. + +CXL System components +---------------------- +A CXL system is made up a Host with a number of 'standard components' +the control and capabilities of which are discoverable by system software +using means described in the CXL 2.0 specification. + +CXL Fixed Memory Windows (CFMW) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +A CFMW consists of a particular range of Host Physical Address space +which is routed to particular CXL Host Bridges. At time of generic +software initialization it will have a particularly interleaving +configuration and associated Quality of Serice Throtling Group (QTG). +This information is available to system software, when making +decisions about how to configure interleave across available CXL +memory devices. It is provide as CFMW Structures (CFMWS) in +the CXL Early Discovery Table, an ACPI table. + +Note: QTG 0 is the only one currently supported in QEMU. + +CXL Host Bridge (CXL HB) +~~~~~~~~~~~~~~~~~~~~~~~~ +A CXL host bridge is similar to the PCIe equivalent, but with a +specification defined register interface called CXL Host Bridge +Component Registers (CHBCR). The location of this CHBCR MMIO +space is described to system software via a CXL Host Bridge +Structure (CHBS) in the CEDT ACPI table. The actual interfaces +are identical to those used for other parts of the CXL heirarchy +as CXL Component Registers in PCI BARs. + +Interfaces provided include: + +* Configuration of HDM Decoders to route CXL Memory accesses with + a particularly Host Physical Address range to the target port + below which the CXL device servicing that address lies. This + may be a mapping to a single Root Port (RP) or across a set of + target RPs. + +CXL Root Ports (CXL RP) +~~~~~~~~~~~~~~~~~~~~~~~ +A CXL Root Port servers te same purpose as a PCIe Root Port. +There are a number of CXL specific Designated Vendor Specific +Extended Capabilities (DVSEC) in PCIe Configuration Space +and associated component register access via PCI bars. + +CXL Switch +~~~~~~~~~~ +Not yet implemented in QEMU. + +Here we consider a simple CXL switch with only a single +virtual hierarchy. Whilst more complex devices exist, their +visibility to a particular host is generally the same as for +a simple switch design. Hosts often have no awareness +of complex rerouting and device pooling, they simply see +devices being hot added or hot removed. + +A CXL switch has a similar architecture to those in PCIe, +with a single upstream port, internal PCI bus and multiple +downstream ports. + +Both the CXL upstream and downstream ports have CXL specific +DVSECs in configuration space, and component registers in PCI +BARs. The Upstream Port has the configuration interfaces for +the HDM decoders which route incoming memory accesses to the +appropriate downstream port. + +CXL Memory Devices - Type 3 +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +CXL type 3 devices use a PCI class code and are intended to be supported +by a generic operating system driver. They have HDM decoders +though in these EP devices, the decoder is reponsible not for +routing but for translation of the incoming host physical address (HPA) +into a Device Physical Address (DPA). + +CXL Memory Interleave +--------------------- +To understand the interaction of different CXL hardware components which +are emulated in QEMU, let us consider a memory read in a fully configured +CXL topology. Note that system software is responsible for configuration +of all components with the exception of the CFMWs. System software is +responsible for allocating appropriate ranges from within the CFMWs +and exposing those via normal memory configurations as would be done +for system RAM. + +Example system Topology. x marks the match in each decoder level:: + + |<------------------SYSTEM PHYSICAL ADDRESS MAP (1)----------------->| + | __________ __________________________________ __________ | + | | | | | | | | + | | CFMW 0 | | CXL Fixed Memory Window 1 | | CFMW 1 | | + | | HB0 only | | Configured to interleave memory | | HB1 only | | + | | | | memory accesses across HB0/HB1 | | | | + | |__________| |_____x____________________________| |__________| | + | | | | + | | | | + | | | | + | Interleave Decoder | | + | Matches this HB | | + \_____________| |_____________/ + __________|__________ _____|_______________ + | | | | + (2) | CXL HB 0 | | CXL HB 1 | + | HB IntLv Decoders | | HB IntLv Decoders | + | PCI/CXL Root Bus 0c | | PCI/CXL Root Bus 0d | + | | | | + |___x_________________| |_____________________| + | | | | + | | | | + A HB 0 HDM Decoder | | | + matches this Port | | | + | | | | + ___________|___ __________|__ __|_________ ___|_________ + (3)| Root Port 0 | | Root Port 1 | | Root Port 2| | Root Port 3 | + | Appears in | | Appears in | | Appears in | | Appear in | + | PCI topology | | PCI Topology| | PCI Topo | | PCI Topo | + | As 0c:00.0 | | as 0c:01.0 | | as de:00.0 | | as de:01.0 | + |_______________| |_____________| |____________| |_____________| + | | | | + | | | | + _____|_________ ______|______ ______|_____ ______|_______ + (4)| x | | | | | | | + | CXL Type3 0 | | CXL Type3 1 | | CXL type3 2| | CLX Type 3 3 | + | | | | | | | | + | PMEM0(Vol LSA)| | PMEM1 (...) | | PMEM2 (...)| | PMEM3 (...) | + | Decoder to go | | | | | | | + | from host PA | | PCI 0e:00.0 | | PCI df:00.0| | PCI e0:00.0 | + | to device PA | | | | | | | + | PCI as 0d:00.0| | | | | | | + |_______________| |_____________| |____________| |______________| + +Notes: + +(1) **3 CXL Fixed Memory Windows (CFMW)** corresponding to different + ranges of the system physical address map. Each CFMW has + particular interleave setup across the CXL Host Bridges (HB) + CFMW0 provides uninterleaved access to HB0, CFW2 provides + uninterleaved acess to HB1. CFW1 provides interleaved memory access + across HB0 and HB1. + +(2) **Two CXL Host Bridges**. Each of these has 2 CXL Root Ports and + programmable HDM decoders to route memory accesses either to + a single port or interleave them across multiple ports. + A complex configuration here, might be to use the following HDM + decoders in HB0. HDM0 routes CFMW0 requests to RP0 and hence + part of CXL Type3 0. HDM1 routes CFMW0 requests from a + different region of the CFMW0 PA range to RP2 and hence part + of CXL Type 3 1. HDM2 routes yet another PA range from within + CFMW0 to be interleaved across RP0 and RP1, providing 2 way + interleave of part of the memory provided by CXL Type3 0 and + CXL Type 3 1. HDM3 routes those interleaved accesses from + CFMW1 that target HB0 to RP 0 and another part of the memory of + CXL Type 3 0 (as part of a 2 way interleave at the system level + across for example CXL Type3 0 and CXL Type3 2. + HDM4 is used to enable system wide 4 way interleave across all + the present CXL type3 devices, by interleaving those (interleaved) + requests that HB0 receives from from CFMW1 across RP 0 and + RP 1 and hence to yet more regions of the memory of the + attached Type3 devices. Note this is a representative subset + of the full range of possible HDM decoder configurations in this + topology. + +(3) **Four CXL Root Ports.** In this case the CXL Type 3 devices are + directly attached to these ports. + +(4) **Four CXL Type3 memory expansion devices.** These will each have + HDM decoders, but in this case rather than performing interleave + they will take the Host Physical Addresses of accesses and map + them to their own local Device Physical Address Space (DPA). + +Example command lines +--------------------- +A very simple setup with just one directly attached CXL Type 3 device:: + + qemu-system-aarch64 -M virt,gic-version=3,cxl=on -m 4g,maxmem=8G,slots=8 -cpu max \ + ... + -object memory-backend-file,id=cxl-mem1,share=on,mem-path=/tmp/cxltest.raw,size=256M \ + -object memory-backend-file,id=cxl-lsa1,share=on,mem-path=/tmp/lsa.raw,size=256M \ + -device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1 \ + -device cxl-rp,port=0,bus=cxl.1,id=root_port13,chassis=0,slot=2 \ + -device cxl-type3,bus=root_port13,memdev=cxl-mem1,lsa=cxl-lsa1,id=cxl-pmem0 \ + -cxl-fixed-memory-window targets.0=cxl.1,size=4G + +A setup suitable for 4 way interleave. Only one fixed window provided, to enable 2 way +interleave across 2 CXL host bridges. Each host bridge has 2 CXL Root Ports, with +the CXL Type3 device directly attached (no switches).:: + + qemu-system-aarch64 -M virt,gic-version=3,cxl=on -m 4g,maxmem=8G,slots=8 -cpu max \ + ... + -object memory-backend-file,id=cxl-mem1,share=on,mem-path=/tmp/cxltest.raw,size=256M \ + -object memory-backend-file,id=cxl-mem2,share=on,mem-path=/tmp/cxltest2.raw,size=256M \ + -object memory-backend-file,id=cxl-mem3,share=on,mem-path=/tmp/cxltest3.raw,size=256M \ + -object memory-backend-file,id=cxl-mem4,share=on,mem-path=/tmp/cxltest4.raw,size=256M \ + -object memory-backend-file,id=cxl-lsa1,share=on,mem-path=/tmp/lsa.raw,size=256M \ + -object memory-backend-file,id=cxl-lsa2,share=on,mem-path=/tmp/lsa2.raw,size=256M \ + -object memory-backend-file,id=cxl-lsa3,share=on,mem-path=/tmp/lsa3.raw,size=256M \ + -object memory-backend-file,id=cxl-lsa4,share=on,mem-path=/tmp/lsa4.raw,size=256M \ + -device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1 \ + -device pxb-cxl,bus_nr=222,bus=pcie.0,id=cxl.2 \ + -device cxl-rp,port=0,bus=cxl.1,id=root_port13,chassis=0,slot=2 \ + -device cxl-type3,bus=root_port13,memdev=cxl-mem1,lsa=cxl-lsa1,id=cxl-pmem0 \ + -device cxl-rp,port=1,bus=cxl.1,id=root_port14,chassis=0,slot=3 \ + -device cxl-type3,bus=root_port14,memdev=cxl-mem2,lsa=cxl-lsa2,id=cxl-pmem1 \ + -device cxl-rp,port=0,bus=cxl.2,id=root_port15,chassis=0,slot=5 \ + -device cxl-type3,bus=root_port15,memdev=cxl-mem3,lsa=cxl-lsa3,id=cxl-pmem2 \ + -device cxl-rp,port=1,bus=cxl.2,id=root_port16,chassis=0,slot=6 \ + -device cxl-type3,bus=root_port16,memdev=cxl-mem4,lsa=cxl-lsa4,id=cxl-pmem3 \ + -cxl-fixed-memory-window targets.0=cxl.1,targets.1=cxl.2,size=4G,interleave-granularity=8k + +Kernel Configuration Options +---------------------------- + +In Linux 5.18 the followings options are necessary to make use of +OS management of CXL memory devices as described here. + +* CONFIG_CXL_BUS +* CONFIG_CXL_PCI +* CONFIG_CXL_ACPI +* CONFIG_CXL_PMEM +* CONFIG_CXL_MEM +* CONFIG_CXL_PORT +* CONFIG_CXL_REGION + +References +---------- + + - Consortium website for specifications etc: + http://www.computeexpresslink.org + - Compute Express link Revision 2 specification, October 2020 + - CEDT CFMWS & QTG _DSM ECN May 2021 From 495fe3a78749c39c0e772c4e1a55d6cb8a7e5292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Thu, 12 May 2022 19:57:42 +0200 Subject: [PATCH 310/935] vhost: Track descriptor chain in private at SVQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The device could have access to modify them, and it definitely have access when we implement packed vq. Harden SVQ maintaining a private copy of the descriptor chain. Other fields like buffer addresses are already maintained sepparatedly. Signed-off-by: Eugenio Pérez Message-Id: <20220512175747.142058-2-eperezma@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-shadow-virtqueue.c | 12 +++++++----- hw/virtio/vhost-shadow-virtqueue.h | 6 ++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c index 1e5cfe2af6..1d6552b0fe 100644 --- a/hw/virtio/vhost-shadow-virtqueue.c +++ b/hw/virtio/vhost-shadow-virtqueue.c @@ -138,6 +138,7 @@ static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, for (n = 0; n < num; n++) { if (more_descs || (n + 1 < num)) { descs[i].flags = flags | cpu_to_le16(VRING_DESC_F_NEXT); + descs[i].next = cpu_to_le16(svq->desc_next[i]); } else { descs[i].flags = flags; } @@ -145,10 +146,10 @@ static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, descs[i].len = cpu_to_le32(iovec[n].iov_len); last = i; - i = cpu_to_le16(descs[i].next); + i = cpu_to_le16(svq->desc_next[i]); } - svq->free_head = le16_to_cpu(descs[last].next); + svq->free_head = le16_to_cpu(svq->desc_next[last]); } static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, @@ -336,7 +337,6 @@ static void vhost_svq_disable_notification(VhostShadowVirtqueue *svq) static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, uint32_t *len) { - vring_desc_t *descs = svq->vring.desc; const vring_used_t *used = svq->vring.used; vring_used_elem_t used_elem; uint16_t last_used; @@ -365,7 +365,7 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, return NULL; } - descs[used_elem.id].next = svq->free_head; + svq->desc_next[used_elem.id] = svq->free_head; svq->free_head = used_elem.id; *len = used_elem.len; @@ -540,8 +540,9 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, svq->vring.used = qemu_memalign(qemu_real_host_page_size(), device_size); memset(svq->vring.used, 0, device_size); svq->ring_id_maps = g_new0(VirtQueueElement *, svq->vring.num); + svq->desc_next = g_new0(uint16_t, svq->vring.num); for (unsigned i = 0; i < svq->vring.num - 1; i++) { - svq->vring.desc[i].next = cpu_to_le16(i + 1); + svq->desc_next[i] = cpu_to_le16(i + 1); } } @@ -574,6 +575,7 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) virtqueue_detach_element(svq->vq, next_avail_elem, 0); } svq->vq = NULL; + g_free(svq->desc_next); g_free(svq->ring_id_maps); qemu_vfree(svq->vring.desc); qemu_vfree(svq->vring.used); diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h index e5e24c536d..c132c994e9 100644 --- a/hw/virtio/vhost-shadow-virtqueue.h +++ b/hw/virtio/vhost-shadow-virtqueue.h @@ -53,6 +53,12 @@ typedef struct VhostShadowVirtqueue { /* Next VirtQueue element that guest made available */ VirtQueueElement *next_guest_avail_elem; + /* + * Backup next field for each descriptor so we can recover securely, not + * needing to trust the device access. + */ + uint16_t *desc_next; + /* Next head to expose to the device */ uint16_t shadow_avail_idx; From 81abfa5724c9a6502d7a1d3a67c55f2a303a1170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Thu, 12 May 2022 19:57:43 +0200 Subject: [PATCH 311/935] vhost: Fix device's used descriptor dequeue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only the first one of them were properly enqueued back. Fixes: 100890f7ca ("vhost: Shadow virtqueue buffers forwarding") Signed-off-by: Eugenio Pérez Message-Id: <20220512175747.142058-3-eperezma@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-shadow-virtqueue.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c index 1d6552b0fe..a8376ef82b 100644 --- a/hw/virtio/vhost-shadow-virtqueue.c +++ b/hw/virtio/vhost-shadow-virtqueue.c @@ -334,12 +334,22 @@ static void vhost_svq_disable_notification(VhostShadowVirtqueue *svq) svq->vring.avail->flags |= cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT); } +static uint16_t vhost_svq_last_desc_of_chain(const VhostShadowVirtqueue *svq, + uint16_t num, uint16_t i) +{ + for (uint16_t j = 0; j < (num - 1); ++j) { + i = le16_to_cpu(svq->desc_next[i]); + } + + return i; +} + static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, uint32_t *len) { const vring_used_t *used = svq->vring.used; vring_used_elem_t used_elem; - uint16_t last_used; + uint16_t last_used, last_used_chain, num; if (!vhost_svq_more_used(svq)) { return NULL; @@ -365,7 +375,10 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, return NULL; } - svq->desc_next[used_elem.id] = svq->free_head; + num = svq->ring_id_maps[used_elem.id]->in_num + + svq->ring_id_maps[used_elem.id]->out_num; + last_used_chain = vhost_svq_last_desc_of_chain(svq, num, used_elem.id); + svq->desc_next[last_used_chain] = svq->free_head; svq->free_head = used_elem.id; *len = used_elem.len; From 639036477ef890958415967e753ca2cbb348c16c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Thu, 12 May 2022 19:57:44 +0200 Subject: [PATCH 312/935] vdpa: Fix bad index calculus at vhost_vdpa_get_vring_base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: 6d0b222666 ("vdpa: Adapt vhost_vdpa_get_vring_base to SVQ") Acked-by: Jason Wang Signed-off-by: Eugenio Pérez Message-Id: <20220512175747.142058-4-eperezma@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-vdpa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index a30510ed17..493269b0b5 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -1172,11 +1172,11 @@ static int vhost_vdpa_get_vring_base(struct vhost_dev *dev, struct vhost_vring_state *ring) { struct vhost_vdpa *v = dev->opaque; + int vdpa_idx = ring->index - dev->vq_index; int ret; if (v->shadow_vqs_enabled) { - VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, - ring->index); + VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, vdpa_idx); /* * Setting base as last used idx, so destination will see as available From 1c82fdfef8a227518ffecae9d419bcada995c202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Thu, 12 May 2022 19:57:45 +0200 Subject: [PATCH 313/935] vdpa: Fix index calculus at vhost_vdpa_svqs_start MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the introduction of MQ the index of the vq needs to be calculated with the device model vq_index. Signed-off-by: Eugenio Pérez Acked-by: Jason Wang Message-Id: <20220512175747.142058-5-eperezma@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-vdpa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 493269b0b5..ed106bff47 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -1018,7 +1018,7 @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) VirtQueue *vq = virtio_get_queue(dev->vdev, dev->vq_index + i); VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); struct vhost_vring_addr addr = { - .index = i, + .index = dev->vq_index + i, }; int r; bool ok = vhost_vdpa_svq_setup(dev, svq, i, &err); From d792199de55ca5cb5334016884039c740290b5c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 12 May 2022 19:57:46 +0200 Subject: [PATCH 314/935] hw/virtio: Replace g_memdup() by g_memdup2() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per https://discourse.gnome.org/t/port-your-module-from-g-memdup-to-g-memdup2-now/5538 The old API took the size of the memory to duplicate as a guint, whereas most memory functions take memory sizes as a gsize. This made it easy to accidentally pass a gsize to g_memdup(). For large values, that would lead to a silent truncation of the size from 64 to 32 bits, and result in a heap area being returned which is significantly smaller than what the caller expects. This can likely be exploited in various modules to cause a heap buffer overflow. Replace g_memdup() by the safer g_memdup2() wrapper. Acked-by: Jason Wang Acked-by: Eugenio Pérez Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20220512175747.142058-6-eperezma@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 3 ++- hw/virtio/virtio-crypto.c | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 1067e72b39..e4748a7e6c 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1443,7 +1443,8 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) } iov_cnt = elem->out_num; - iov2 = iov = g_memdup(elem->out_sg, sizeof(struct iovec) * elem->out_num); + iov2 = iov = g_memdup2(elem->out_sg, + sizeof(struct iovec) * elem->out_num); s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl)); iov_discard_front(&iov, &iov_cnt, sizeof(ctrl)); if (s != sizeof(ctrl)) { diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index dcd80b904d..0e31e3cc04 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -242,7 +242,7 @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) } out_num = elem->out_num; - out_iov_copy = g_memdup(elem->out_sg, sizeof(out_iov[0]) * out_num); + out_iov_copy = g_memdup2(elem->out_sg, sizeof(out_iov[0]) * out_num); out_iov = out_iov_copy; in_num = elem->in_num; @@ -605,11 +605,11 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request) } out_num = elem->out_num; - out_iov_copy = g_memdup(elem->out_sg, sizeof(out_iov[0]) * out_num); + out_iov_copy = g_memdup2(elem->out_sg, sizeof(out_iov[0]) * out_num); out_iov = out_iov_copy; in_num = elem->in_num; - in_iov_copy = g_memdup(elem->in_sg, sizeof(in_iov[0]) * in_num); + in_iov_copy = g_memdup2(elem->in_sg, sizeof(in_iov[0]) * in_num); in_iov = in_iov_copy; if (unlikely(iov_to_buf(out_iov, out_num, 0, &req, sizeof(req)) From 5181db132b587754dda3a520eec923b87a65bbb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Thu, 12 May 2022 19:57:47 +0200 Subject: [PATCH 315/935] vhost: Fix element in vhost_svq_add failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coverity rightly reports that is not free in that case. Fixes: Coverity CID 1487559 Fixes: 100890f7ca ("vhost: Shadow virtqueue buffers forwarding") Signed-off-by: Eugenio Pérez Message-Id: <20220512175747.142058-7-eperezma@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-shadow-virtqueue.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c index a8376ef82b..56c96ebd13 100644 --- a/hw/virtio/vhost-shadow-virtqueue.c +++ b/hw/virtio/vhost-shadow-virtqueue.c @@ -199,11 +199,19 @@ static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, return true; } +/** + * Add an element to a SVQ. + * + * The caller must check that there is enough slots for the new element. It + * takes ownership of the element: In case of failure, it is free and the SVQ + * is considered broken. + */ static bool vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem) { unsigned qemu_head; bool ok = vhost_svq_add_split(svq, elem, &qemu_head); if (unlikely(!ok)) { + g_free(elem); return false; } From e4082063e47e9731dbeb1c26174c17f6038f577f Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 13 May 2022 08:20:08 -0600 Subject: [PATCH 316/935] linux-headers: Update to v5.18-rc6 Update to c5eb0a61238d ("Linux 5.18-rc6"). Mechanical search and replace of vfio defines with white space massaging. Signed-off-by: Alex Williamson --- hw/vfio/common.c | 6 +- hw/vfio/migration.c | 27 +- .../linux/input-event-codes.h | 25 +- .../standard-headers/linux/virtio_config.h | 6 + .../standard-headers/linux/virtio_crypto.h | 82 +++- linux-headers/asm-arm64/kvm.h | 16 + linux-headers/asm-generic/mman-common.h | 2 + linux-headers/asm-mips/mman.h | 2 + linux-headers/linux/kvm.h | 27 +- linux-headers/linux/psci.h | 4 + linux-headers/linux/userfaultfd.h | 8 +- linux-headers/linux/vfio.h | 406 +++++++++--------- linux-headers/linux/vhost.h | 7 + 13 files changed, 383 insertions(+), 235 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 159f910421..29982c7af8 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -355,7 +355,7 @@ static bool vfio_devices_all_dirty_tracking(VFIOContainer *container) } if ((vbasedev->pre_copy_dirty_page_tracking == ON_OFF_AUTO_OFF) - && (migration->device_state & VFIO_DEVICE_STATE_RUNNING)) { + && (migration->device_state & VFIO_DEVICE_STATE_V1_RUNNING)) { return false; } } @@ -381,8 +381,8 @@ static bool vfio_devices_all_running_and_saving(VFIOContainer *container) return false; } - if ((migration->device_state & VFIO_DEVICE_STATE_SAVING) && - (migration->device_state & VFIO_DEVICE_STATE_RUNNING)) { + if ((migration->device_state & VFIO_DEVICE_STATE_V1_SAVING) && + (migration->device_state & VFIO_DEVICE_STATE_V1_RUNNING)) { continue; } else { return false; diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index ff6b45de6b..a6ad1f8945 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -432,7 +432,7 @@ static int vfio_save_setup(QEMUFile *f, void *opaque) } ret = vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_MASK, - VFIO_DEVICE_STATE_SAVING); + VFIO_DEVICE_STATE_V1_SAVING); if (ret) { error_report("%s: Failed to set state SAVING", vbasedev->name); return ret; @@ -531,8 +531,8 @@ static int vfio_save_complete_precopy(QEMUFile *f, void *opaque) uint64_t data_size; int ret; - ret = vfio_migration_set_state(vbasedev, ~VFIO_DEVICE_STATE_RUNNING, - VFIO_DEVICE_STATE_SAVING); + ret = vfio_migration_set_state(vbasedev, ~VFIO_DEVICE_STATE_V1_RUNNING, + VFIO_DEVICE_STATE_V1_SAVING); if (ret) { error_report("%s: Failed to set state STOP and SAVING", vbasedev->name); @@ -569,7 +569,7 @@ static int vfio_save_complete_precopy(QEMUFile *f, void *opaque) return ret; } - ret = vfio_migration_set_state(vbasedev, ~VFIO_DEVICE_STATE_SAVING, 0); + ret = vfio_migration_set_state(vbasedev, ~VFIO_DEVICE_STATE_V1_SAVING, 0); if (ret) { error_report("%s: Failed to set state STOPPED", vbasedev->name); return ret; @@ -609,7 +609,7 @@ static int vfio_load_setup(QEMUFile *f, void *opaque) } ret = vfio_migration_set_state(vbasedev, ~VFIO_DEVICE_STATE_MASK, - VFIO_DEVICE_STATE_RESUMING); + VFIO_DEVICE_STATE_V1_RESUMING); if (ret) { error_report("%s: Failed to set state RESUMING", vbasedev->name); if (migration->region.mmaps) { @@ -717,20 +717,20 @@ static void vfio_vmstate_change(void *opaque, bool running, RunState state) * In both the above cases, set _RUNNING bit. */ mask = ~VFIO_DEVICE_STATE_MASK; - value = VFIO_DEVICE_STATE_RUNNING; + value = VFIO_DEVICE_STATE_V1_RUNNING; } else { /* * Here device state could be either _RUNNING or _SAVING|_RUNNING. Reset * _RUNNING bit */ - mask = ~VFIO_DEVICE_STATE_RUNNING; + mask = ~VFIO_DEVICE_STATE_V1_RUNNING; /* * When VM state transition to stop for savevm command, device should * start saving data. */ if (state == RUN_STATE_SAVE_VM) { - value = VFIO_DEVICE_STATE_SAVING; + value = VFIO_DEVICE_STATE_V1_SAVING; } else { value = 0; } @@ -768,8 +768,9 @@ static void vfio_migration_state_notifier(Notifier *notifier, void *data) case MIGRATION_STATUS_FAILED: bytes_transferred = 0; ret = vfio_migration_set_state(vbasedev, - ~(VFIO_DEVICE_STATE_SAVING | VFIO_DEVICE_STATE_RESUMING), - VFIO_DEVICE_STATE_RUNNING); + ~(VFIO_DEVICE_STATE_V1_SAVING | + VFIO_DEVICE_STATE_V1_RESUMING), + VFIO_DEVICE_STATE_V1_RUNNING); if (ret) { error_report("%s: Failed to set state RUNNING", vbasedev->name); } @@ -864,8 +865,10 @@ int vfio_migration_probe(VFIODevice *vbasedev, Error **errp) goto add_blocker; } - ret = vfio_get_dev_region_info(vbasedev, VFIO_REGION_TYPE_MIGRATION, - VFIO_REGION_SUBTYPE_MIGRATION, &info); + ret = vfio_get_dev_region_info(vbasedev, + VFIO_REGION_TYPE_MIGRATION_DEPRECATED, + VFIO_REGION_SUBTYPE_MIGRATION_DEPRECATED, + &info); if (ret) { goto add_blocker; } diff --git a/include/standard-headers/linux/input-event-codes.h b/include/standard-headers/linux/input-event-codes.h index b5e86b40ab..50790aee5a 100644 --- a/include/standard-headers/linux/input-event-codes.h +++ b/include/standard-headers/linux/input-event-codes.h @@ -278,7 +278,8 @@ #define KEY_PAUSECD 201 #define KEY_PROG3 202 #define KEY_PROG4 203 -#define KEY_DASHBOARD 204 /* AL Dashboard */ +#define KEY_ALL_APPLICATIONS 204 /* AC Desktop Show All Applications */ +#define KEY_DASHBOARD KEY_ALL_APPLICATIONS #define KEY_SUSPEND 205 #define KEY_CLOSE 206 /* AC Close */ #define KEY_PLAY 207 @@ -612,6 +613,7 @@ #define KEY_ASSISTANT 0x247 /* AL Context-aware desktop assistant */ #define KEY_KBD_LAYOUT_NEXT 0x248 /* AC Next Keyboard Layout Select */ #define KEY_EMOJI_PICKER 0x249 /* Show/hide emoji picker (HUTRR101) */ +#define KEY_DICTATE 0x24a /* Start or Stop Voice Dictation Session (HUTRR99) */ #define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */ #define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */ @@ -660,6 +662,27 @@ /* Select an area of screen to be copied */ #define KEY_SELECTIVE_SCREENSHOT 0x27a +/* Move the focus to the next or previous user controllable element within a UI container */ +#define KEY_NEXT_ELEMENT 0x27b +#define KEY_PREVIOUS_ELEMENT 0x27c + +/* Toggle Autopilot engagement */ +#define KEY_AUTOPILOT_ENGAGE_TOGGLE 0x27d + +/* Shortcut Keys */ +#define KEY_MARK_WAYPOINT 0x27e +#define KEY_SOS 0x27f +#define KEY_NAV_CHART 0x280 +#define KEY_FISHING_CHART 0x281 +#define KEY_SINGLE_RANGE_RADAR 0x282 +#define KEY_DUAL_RANGE_RADAR 0x283 +#define KEY_RADAR_OVERLAY 0x284 +#define KEY_TRADITIONAL_SONAR 0x285 +#define KEY_CLEARVU_SONAR 0x286 +#define KEY_SIDEVU_SONAR 0x287 +#define KEY_NAV_INFO 0x288 +#define KEY_BRIGHTNESS_MENU 0x289 + /* * Some keyboards have keys which do not have a defined meaning, these keys * are intended to be programmed / bound to macros by the user. For most diff --git a/include/standard-headers/linux/virtio_config.h b/include/standard-headers/linux/virtio_config.h index 22e3a85f67..7acd8d4abc 100644 --- a/include/standard-headers/linux/virtio_config.h +++ b/include/standard-headers/linux/virtio_config.h @@ -80,6 +80,12 @@ /* This feature indicates support for the packed virtqueue layout. */ #define VIRTIO_F_RING_PACKED 34 +/* + * Inorder feature indicates that all buffers are used by the device + * in the same order in which they have been made available. + */ +#define VIRTIO_F_IN_ORDER 35 + /* * This feature indicates that memory accesses by the driver and the * device are ordered in a way described by the platform. diff --git a/include/standard-headers/linux/virtio_crypto.h b/include/standard-headers/linux/virtio_crypto.h index 5ff0b4ee59..68066dafb6 100644 --- a/include/standard-headers/linux/virtio_crypto.h +++ b/include/standard-headers/linux/virtio_crypto.h @@ -37,6 +37,7 @@ #define VIRTIO_CRYPTO_SERVICE_HASH 1 #define VIRTIO_CRYPTO_SERVICE_MAC 2 #define VIRTIO_CRYPTO_SERVICE_AEAD 3 +#define VIRTIO_CRYPTO_SERVICE_AKCIPHER 4 #define VIRTIO_CRYPTO_OPCODE(service, op) (((service) << 8) | (op)) @@ -57,6 +58,10 @@ struct virtio_crypto_ctrl_header { VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x02) #define VIRTIO_CRYPTO_AEAD_DESTROY_SESSION \ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x03) +#define VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x04) +#define VIRTIO_CRYPTO_AKCIPHER_DESTROY_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x05) uint32_t opcode; uint32_t algo; uint32_t flag; @@ -180,6 +185,58 @@ struct virtio_crypto_aead_create_session_req { uint8_t padding[32]; }; +struct virtio_crypto_rsa_session_para { +#define VIRTIO_CRYPTO_RSA_RAW_PADDING 0 +#define VIRTIO_CRYPTO_RSA_PKCS1_PADDING 1 + uint32_t padding_algo; + +#define VIRTIO_CRYPTO_RSA_NO_HASH 0 +#define VIRTIO_CRYPTO_RSA_MD2 1 +#define VIRTIO_CRYPTO_RSA_MD3 2 +#define VIRTIO_CRYPTO_RSA_MD4 3 +#define VIRTIO_CRYPTO_RSA_MD5 4 +#define VIRTIO_CRYPTO_RSA_SHA1 5 +#define VIRTIO_CRYPTO_RSA_SHA256 6 +#define VIRTIO_CRYPTO_RSA_SHA384 7 +#define VIRTIO_CRYPTO_RSA_SHA512 8 +#define VIRTIO_CRYPTO_RSA_SHA224 9 + uint32_t hash_algo; +}; + +struct virtio_crypto_ecdsa_session_para { +#define VIRTIO_CRYPTO_CURVE_UNKNOWN 0 +#define VIRTIO_CRYPTO_CURVE_NIST_P192 1 +#define VIRTIO_CRYPTO_CURVE_NIST_P224 2 +#define VIRTIO_CRYPTO_CURVE_NIST_P256 3 +#define VIRTIO_CRYPTO_CURVE_NIST_P384 4 +#define VIRTIO_CRYPTO_CURVE_NIST_P521 5 + uint32_t curve_id; + uint32_t padding; +}; + +struct virtio_crypto_akcipher_session_para { +#define VIRTIO_CRYPTO_NO_AKCIPHER 0 +#define VIRTIO_CRYPTO_AKCIPHER_RSA 1 +#define VIRTIO_CRYPTO_AKCIPHER_DSA 2 +#define VIRTIO_CRYPTO_AKCIPHER_ECDSA 3 + uint32_t algo; + +#define VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC 1 +#define VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE 2 + uint32_t keytype; + uint32_t keylen; + + union { + struct virtio_crypto_rsa_session_para rsa; + struct virtio_crypto_ecdsa_session_para ecdsa; + } u; +}; + +struct virtio_crypto_akcipher_create_session_req { + struct virtio_crypto_akcipher_session_para para; + uint8_t padding[36]; +}; + struct virtio_crypto_alg_chain_session_para { #define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER 1 #define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH 2 @@ -247,6 +304,8 @@ struct virtio_crypto_op_ctrl_req { mac_create_session; struct virtio_crypto_aead_create_session_req aead_create_session; + struct virtio_crypto_akcipher_create_session_req + akcipher_create_session; struct virtio_crypto_destroy_session_req destroy_session; uint8_t padding[56]; @@ -266,6 +325,14 @@ struct virtio_crypto_op_header { VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x00) #define VIRTIO_CRYPTO_AEAD_DECRYPT \ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x01) +#define VIRTIO_CRYPTO_AKCIPHER_ENCRYPT \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x00) +#define VIRTIO_CRYPTO_AKCIPHER_DECRYPT \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x01) +#define VIRTIO_CRYPTO_AKCIPHER_SIGN \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x02) +#define VIRTIO_CRYPTO_AKCIPHER_VERIFY \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x03) uint32_t opcode; /* algo should be service-specific algorithms */ uint32_t algo; @@ -390,6 +457,16 @@ struct virtio_crypto_aead_data_req { uint8_t padding[32]; }; +struct virtio_crypto_akcipher_para { + uint32_t src_data_len; + uint32_t dst_data_len; +}; + +struct virtio_crypto_akcipher_data_req { + struct virtio_crypto_akcipher_para para; + uint8_t padding[40]; +}; + /* The request of the data virtqueue's packet */ struct virtio_crypto_op_data_req { struct virtio_crypto_op_header header; @@ -399,6 +476,7 @@ struct virtio_crypto_op_data_req { struct virtio_crypto_hash_data_req hash_req; struct virtio_crypto_mac_data_req mac_req; struct virtio_crypto_aead_data_req aead_req; + struct virtio_crypto_akcipher_data_req akcipher_req; uint8_t padding[48]; } u; }; @@ -408,6 +486,8 @@ struct virtio_crypto_op_data_req { #define VIRTIO_CRYPTO_BADMSG 2 #define VIRTIO_CRYPTO_NOTSUPP 3 #define VIRTIO_CRYPTO_INVSESS 4 /* Invalid session id */ +#define VIRTIO_CRYPTO_NOSPC 5 /* no free session ID */ +#define VIRTIO_CRYPTO_KEY_REJECTED 6 /* Signature verification failed */ /* The accelerator hardware is ready */ #define VIRTIO_CRYPTO_S_HW_READY (1 << 0) @@ -438,7 +518,7 @@ struct virtio_crypto_config { uint32_t max_cipher_key_len; /* Maximum length of authenticated key */ uint32_t max_auth_key_len; - uint32_t reserve; + uint32_t akcipher_algo; /* Maximum size of each crypto request's content */ uint64_t max_size; }; diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h index 3d2ce9912d..5c28a9737a 100644 --- a/linux-headers/asm-arm64/kvm.h +++ b/linux-headers/asm-arm64/kvm.h @@ -281,6 +281,11 @@ struct kvm_arm_copy_mte_tags { #define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED 3 #define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED (1U << 4) +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3 KVM_REG_ARM_FW_REG(3) +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL 0 +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL 1 +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED 2 + /* SVE registers */ #define KVM_REG_ARM64_SVE (0x15 << KVM_REG_ARM_COPROC_SHIFT) @@ -362,6 +367,7 @@ struct kvm_arm_copy_mte_tags { #define KVM_ARM_VCPU_PMU_V3_IRQ 0 #define KVM_ARM_VCPU_PMU_V3_INIT 1 #define KVM_ARM_VCPU_PMU_V3_FILTER 2 +#define KVM_ARM_VCPU_PMU_V3_SET_PMU 3 #define KVM_ARM_VCPU_TIMER_CTRL 1 #define KVM_ARM_VCPU_TIMER_IRQ_VTIMER 0 #define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1 @@ -411,6 +417,16 @@ struct kvm_arm_copy_mte_tags { #define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS #define KVM_PSCI_RET_DENIED PSCI_RET_DENIED +/* arm64-specific kvm_run::system_event flags */ +/* + * Reset caused by a PSCI v1.1 SYSTEM_RESET2 call. + * Valid only when the system event has a type of KVM_SYSTEM_EVENT_RESET. + */ +#define KVM_SYSTEM_EVENT_RESET_FLAG_PSCI_RESET2 (1ULL << 0) + +/* run->fail_entry.hardware_entry_failure_reason codes. */ +#define KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED (1ULL << 0) + #endif #endif /* __ARM_KVM_H__ */ diff --git a/linux-headers/asm-generic/mman-common.h b/linux-headers/asm-generic/mman-common.h index 1567a3294c..6c1aa92a92 100644 --- a/linux-headers/asm-generic/mman-common.h +++ b/linux-headers/asm-generic/mman-common.h @@ -75,6 +75,8 @@ #define MADV_POPULATE_READ 22 /* populate (prefault) page tables readable */ #define MADV_POPULATE_WRITE 23 /* populate (prefault) page tables writable */ +#define MADV_DONTNEED_LOCKED 24 /* like DONTNEED, but drop locked pages too */ + /* compatibility flags */ #define MAP_FILE 0 diff --git a/linux-headers/asm-mips/mman.h b/linux-headers/asm-mips/mman.h index 40b210c65a..1be428663c 100644 --- a/linux-headers/asm-mips/mman.h +++ b/linux-headers/asm-mips/mman.h @@ -101,6 +101,8 @@ #define MADV_POPULATE_READ 22 /* populate (prefault) page tables readable */ #define MADV_POPULATE_WRITE 23 /* populate (prefault) page tables writable */ +#define MADV_DONTNEED_LOCKED 24 /* like DONTNEED, but drop locked pages too */ + /* compatibility flags */ #define MAP_FILE 0 diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index d232feaae9..0d05d02ee4 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -445,7 +445,11 @@ struct kvm_run { #define KVM_SYSTEM_EVENT_RESET 2 #define KVM_SYSTEM_EVENT_CRASH 3 __u32 type; - __u64 flags; + __u32 ndata; + union { + __u64 flags; + __u64 data[16]; + }; } system_event; /* KVM_EXIT_S390_STSI */ struct { @@ -562,9 +566,12 @@ struct kvm_s390_mem_op { __u32 op; /* type of operation */ __u64 buf; /* buffer in userspace */ union { - __u8 ar; /* the access register number */ + struct { + __u8 ar; /* the access register number */ + __u8 key; /* access key, ignored if flag unset */ + }; __u32 sida_offset; /* offset into the sida */ - __u8 reserved[32]; /* should be set to 0 */ + __u8 reserved[32]; /* ignored */ }; }; /* types for kvm_s390_mem_op->op */ @@ -572,9 +579,12 @@ struct kvm_s390_mem_op { #define KVM_S390_MEMOP_LOGICAL_WRITE 1 #define KVM_S390_MEMOP_SIDA_READ 2 #define KVM_S390_MEMOP_SIDA_WRITE 3 +#define KVM_S390_MEMOP_ABSOLUTE_READ 4 +#define KVM_S390_MEMOP_ABSOLUTE_WRITE 5 /* flags for kvm_s390_mem_op->flags */ #define KVM_S390_MEMOP_F_CHECK_ONLY (1ULL << 0) #define KVM_S390_MEMOP_F_INJECT_EXCEPTION (1ULL << 1) +#define KVM_S390_MEMOP_F_SKEY_PROTECTION (1ULL << 2) /* for KVM_INTERRUPT */ struct kvm_interrupt { @@ -1134,6 +1144,12 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_VM_GPA_BITS 207 #define KVM_CAP_XSAVE2 208 #define KVM_CAP_SYS_ATTRIBUTES 209 +#define KVM_CAP_PPC_AIL_MODE_3 210 +#define KVM_CAP_S390_MEM_OP_EXTENSION 211 +#define KVM_CAP_PMU_CAPABILITY 212 +#define KVM_CAP_DISABLE_QUIRKS2 213 +/* #define KVM_CAP_VM_TSC_CONTROL 214 */ +#define KVM_CAP_SYSTEM_EVENT_DATA 215 #ifdef KVM_CAP_IRQ_ROUTING @@ -1624,9 +1640,6 @@ struct kvm_enc_region { #define KVM_S390_NORMAL_RESET _IO(KVMIO, 0xc3) #define KVM_S390_CLEAR_RESET _IO(KVMIO, 0xc4) -/* Available with KVM_CAP_XSAVE2 */ -#define KVM_GET_XSAVE2 _IOR(KVMIO, 0xcf, struct kvm_xsave) - struct kvm_s390_pv_sec_parm { __u64 origin; __u64 length; @@ -1973,6 +1986,8 @@ struct kvm_dirty_gfn { #define KVM_BUS_LOCK_DETECTION_OFF (1 << 0) #define KVM_BUS_LOCK_DETECTION_EXIT (1 << 1) +#define KVM_PMU_CAP_DISABLE (1 << 0) + /** * struct kvm_stats_header - Header of per vm/vcpu binary statistics data. * @flags: Some extra information for header, always 0 for now. diff --git a/linux-headers/linux/psci.h b/linux-headers/linux/psci.h index a6772d508b..213b2a0f70 100644 --- a/linux-headers/linux/psci.h +++ b/linux-headers/linux/psci.h @@ -82,6 +82,10 @@ #define PSCI_0_2_TOS_UP_NO_MIGRATE 1 #define PSCI_0_2_TOS_MP 2 +/* PSCI v1.1 reset type encoding for SYSTEM_RESET2 */ +#define PSCI_1_1_RESET_TYPE_SYSTEM_WARM_RESET 0 +#define PSCI_1_1_RESET_TYPE_VENDOR_START 0x80000000U + /* PSCI version decoding (independent of PSCI version) */ #define PSCI_VERSION_MAJOR_SHIFT 16 #define PSCI_VERSION_MINOR_MASK \ diff --git a/linux-headers/linux/userfaultfd.h b/linux-headers/linux/userfaultfd.h index 8479af5f4c..769b8379e4 100644 --- a/linux-headers/linux/userfaultfd.h +++ b/linux-headers/linux/userfaultfd.h @@ -32,7 +32,8 @@ UFFD_FEATURE_SIGBUS | \ UFFD_FEATURE_THREAD_ID | \ UFFD_FEATURE_MINOR_HUGETLBFS | \ - UFFD_FEATURE_MINOR_SHMEM) + UFFD_FEATURE_MINOR_SHMEM | \ + UFFD_FEATURE_EXACT_ADDRESS) #define UFFD_API_IOCTLS \ ((__u64)1 << _UFFDIO_REGISTER | \ (__u64)1 << _UFFDIO_UNREGISTER | \ @@ -189,6 +190,10 @@ struct uffdio_api { * * UFFD_FEATURE_MINOR_SHMEM indicates the same support as * UFFD_FEATURE_MINOR_HUGETLBFS, but for shmem-backed pages instead. + * + * UFFD_FEATURE_EXACT_ADDRESS indicates that the exact address of page + * faults would be provided and the offset within the page would not be + * masked. */ #define UFFD_FEATURE_PAGEFAULT_FLAG_WP (1<<0) #define UFFD_FEATURE_EVENT_FORK (1<<1) @@ -201,6 +206,7 @@ struct uffdio_api { #define UFFD_FEATURE_THREAD_ID (1<<8) #define UFFD_FEATURE_MINOR_HUGETLBFS (1<<9) #define UFFD_FEATURE_MINOR_SHMEM (1<<10) +#define UFFD_FEATURE_EXACT_ADDRESS (1<<11) __u64 features; __u64 ioctls; diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index e680594f27..e9f7795c39 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -323,7 +323,7 @@ struct vfio_region_info_cap_type { #define VFIO_REGION_TYPE_PCI_VENDOR_MASK (0xffff) #define VFIO_REGION_TYPE_GFX (1) #define VFIO_REGION_TYPE_CCW (2) -#define VFIO_REGION_TYPE_MIGRATION (3) +#define VFIO_REGION_TYPE_MIGRATION_DEPRECATED (3) /* sub-types for VFIO_REGION_TYPE_PCI_* */ @@ -405,225 +405,29 @@ struct vfio_region_gfx_edid { #define VFIO_REGION_SUBTYPE_CCW_CRW (3) /* sub-types for VFIO_REGION_TYPE_MIGRATION */ -#define VFIO_REGION_SUBTYPE_MIGRATION (1) - -/* - * The structure vfio_device_migration_info is placed at the 0th offset of - * the VFIO_REGION_SUBTYPE_MIGRATION region to get and set VFIO device related - * migration information. Field accesses from this structure are only supported - * at their native width and alignment. Otherwise, the result is undefined and - * vendor drivers should return an error. - * - * device_state: (read/write) - * - The user application writes to this field to inform the vendor driver - * about the device state to be transitioned to. - * - The vendor driver should take the necessary actions to change the - * device state. After successful transition to a given state, the - * vendor driver should return success on write(device_state, state) - * system call. If the device state transition fails, the vendor driver - * should return an appropriate -errno for the fault condition. - * - On the user application side, if the device state transition fails, - * that is, if write(device_state, state) returns an error, read - * device_state again to determine the current state of the device from - * the vendor driver. - * - The vendor driver should return previous state of the device unless - * the vendor driver has encountered an internal error, in which case - * the vendor driver may report the device_state VFIO_DEVICE_STATE_ERROR. - * - The user application must use the device reset ioctl to recover the - * device from VFIO_DEVICE_STATE_ERROR state. If the device is - * indicated to be in a valid device state by reading device_state, the - * user application may attempt to transition the device to any valid - * state reachable from the current state or terminate itself. - * - * device_state consists of 3 bits: - * - If bit 0 is set, it indicates the _RUNNING state. If bit 0 is clear, - * it indicates the _STOP state. When the device state is changed to - * _STOP, driver should stop the device before write() returns. - * - If bit 1 is set, it indicates the _SAVING state, which means that the - * driver should start gathering device state information that will be - * provided to the VFIO user application to save the device's state. - * - If bit 2 is set, it indicates the _RESUMING state, which means that - * the driver should prepare to resume the device. Data provided through - * the migration region should be used to resume the device. - * Bits 3 - 31 are reserved for future use. To preserve them, the user - * application should perform a read-modify-write operation on this - * field when modifying the specified bits. - * - * +------- _RESUMING - * |+------ _SAVING - * ||+----- _RUNNING - * ||| - * 000b => Device Stopped, not saving or resuming - * 001b => Device running, which is the default state - * 010b => Stop the device & save the device state, stop-and-copy state - * 011b => Device running and save the device state, pre-copy state - * 100b => Device stopped and the device state is resuming - * 101b => Invalid state - * 110b => Error state - * 111b => Invalid state - * - * State transitions: - * - * _RESUMING _RUNNING Pre-copy Stop-and-copy _STOP - * (100b) (001b) (011b) (010b) (000b) - * 0. Running or default state - * | - * - * 1. Normal Shutdown (optional) - * |------------------------------------->| - * - * 2. Save the state or suspend - * |------------------------->|---------->| - * - * 3. Save the state during live migration - * |----------->|------------>|---------->| - * - * 4. Resuming - * |<---------| - * - * 5. Resumed - * |--------->| - * - * 0. Default state of VFIO device is _RUNNING when the user application starts. - * 1. During normal shutdown of the user application, the user application may - * optionally change the VFIO device state from _RUNNING to _STOP. This - * transition is optional. The vendor driver must support this transition but - * must not require it. - * 2. When the user application saves state or suspends the application, the - * device state transitions from _RUNNING to stop-and-copy and then to _STOP. - * On state transition from _RUNNING to stop-and-copy, driver must stop the - * device, save the device state and send it to the application through the - * migration region. The sequence to be followed for such transition is given - * below. - * 3. In live migration of user application, the state transitions from _RUNNING - * to pre-copy, to stop-and-copy, and to _STOP. - * On state transition from _RUNNING to pre-copy, the driver should start - * gathering the device state while the application is still running and send - * the device state data to application through the migration region. - * On state transition from pre-copy to stop-and-copy, the driver must stop - * the device, save the device state and send it to the user application - * through the migration region. - * Vendor drivers must support the pre-copy state even for implementations - * where no data is provided to the user before the stop-and-copy state. The - * user must not be required to consume all migration data before the device - * transitions to a new state, including the stop-and-copy state. - * The sequence to be followed for above two transitions is given below. - * 4. To start the resuming phase, the device state should be transitioned from - * the _RUNNING to the _RESUMING state. - * In the _RESUMING state, the driver should use the device state data - * received through the migration region to resume the device. - * 5. After providing saved device data to the driver, the application should - * change the state from _RESUMING to _RUNNING. - * - * reserved: - * Reads on this field return zero and writes are ignored. - * - * pending_bytes: (read only) - * The number of pending bytes still to be migrated from the vendor driver. - * - * data_offset: (read only) - * The user application should read data_offset field from the migration - * region. The user application should read the device data from this - * offset within the migration region during the _SAVING state or write - * the device data during the _RESUMING state. See below for details of - * sequence to be followed. - * - * data_size: (read/write) - * The user application should read data_size to get the size in bytes of - * the data copied in the migration region during the _SAVING state and - * write the size in bytes of the data copied in the migration region - * during the _RESUMING state. - * - * The format of the migration region is as follows: - * ------------------------------------------------------------------ - * |vfio_device_migration_info| data section | - * | | /////////////////////////////// | - * ------------------------------------------------------------------ - * ^ ^ - * offset 0-trapped part data_offset - * - * The structure vfio_device_migration_info is always followed by the data - * section in the region, so data_offset will always be nonzero. The offset - * from where the data is copied is decided by the kernel driver. The data - * section can be trapped, mmapped, or partitioned, depending on how the kernel - * driver defines the data section. The data section partition can be defined - * as mapped by the sparse mmap capability. If mmapped, data_offset must be - * page aligned, whereas initial section which contains the - * vfio_device_migration_info structure, might not end at the offset, which is - * page aligned. The user is not required to access through mmap regardless - * of the capabilities of the region mmap. - * The vendor driver should determine whether and how to partition the data - * section. The vendor driver should return data_offset accordingly. - * - * The sequence to be followed while in pre-copy state and stop-and-copy state - * is as follows: - * a. Read pending_bytes, indicating the start of a new iteration to get device - * data. Repeated read on pending_bytes at this stage should have no side - * effects. - * If pending_bytes == 0, the user application should not iterate to get data - * for that device. - * If pending_bytes > 0, perform the following steps. - * b. Read data_offset, indicating that the vendor driver should make data - * available through the data section. The vendor driver should return this - * read operation only after data is available from (region + data_offset) - * to (region + data_offset + data_size). - * c. Read data_size, which is the amount of data in bytes available through - * the migration region. - * Read on data_offset and data_size should return the offset and size of - * the current buffer if the user application reads data_offset and - * data_size more than once here. - * d. Read data_size bytes of data from (region + data_offset) from the - * migration region. - * e. Process the data. - * f. Read pending_bytes, which indicates that the data from the previous - * iteration has been read. If pending_bytes > 0, go to step b. - * - * The user application can transition from the _SAVING|_RUNNING - * (pre-copy state) to the _SAVING (stop-and-copy) state regardless of the - * number of pending bytes. The user application should iterate in _SAVING - * (stop-and-copy) until pending_bytes is 0. - * - * The sequence to be followed while _RESUMING device state is as follows: - * While data for this device is available, repeat the following steps: - * a. Read data_offset from where the user application should write data. - * b. Write migration data starting at the migration region + data_offset for - * the length determined by data_size from the migration source. - * c. Write data_size, which indicates to the vendor driver that data is - * written in the migration region. Vendor driver must return this write - * operations on consuming data. Vendor driver should apply the - * user-provided migration region data to the device resume state. - * - * If an error occurs during the above sequences, the vendor driver can return - * an error code for next read() or write() operation, which will terminate the - * loop. The user application should then take the next necessary action, for - * example, failing migration or terminating the user application. - * - * For the user application, data is opaque. The user application should write - * data in the same order as the data is received and the data should be of - * same transaction size at the source. - */ +#define VFIO_REGION_SUBTYPE_MIGRATION_DEPRECATED (1) struct vfio_device_migration_info { __u32 device_state; /* VFIO device state */ -#define VFIO_DEVICE_STATE_STOP (0) -#define VFIO_DEVICE_STATE_RUNNING (1 << 0) -#define VFIO_DEVICE_STATE_SAVING (1 << 1) -#define VFIO_DEVICE_STATE_RESUMING (1 << 2) -#define VFIO_DEVICE_STATE_MASK (VFIO_DEVICE_STATE_RUNNING | \ - VFIO_DEVICE_STATE_SAVING | \ - VFIO_DEVICE_STATE_RESUMING) +#define VFIO_DEVICE_STATE_V1_STOP (0) +#define VFIO_DEVICE_STATE_V1_RUNNING (1 << 0) +#define VFIO_DEVICE_STATE_V1_SAVING (1 << 1) +#define VFIO_DEVICE_STATE_V1_RESUMING (1 << 2) +#define VFIO_DEVICE_STATE_MASK (VFIO_DEVICE_STATE_V1_RUNNING | \ + VFIO_DEVICE_STATE_V1_SAVING | \ + VFIO_DEVICE_STATE_V1_RESUMING) #define VFIO_DEVICE_STATE_VALID(state) \ - (state & VFIO_DEVICE_STATE_RESUMING ? \ - (state & VFIO_DEVICE_STATE_MASK) == VFIO_DEVICE_STATE_RESUMING : 1) + (state & VFIO_DEVICE_STATE_V1_RESUMING ? \ + (state & VFIO_DEVICE_STATE_MASK) == VFIO_DEVICE_STATE_V1_RESUMING : 1) #define VFIO_DEVICE_STATE_IS_ERROR(state) \ - ((state & VFIO_DEVICE_STATE_MASK) == (VFIO_DEVICE_STATE_SAVING | \ - VFIO_DEVICE_STATE_RESUMING)) + ((state & VFIO_DEVICE_STATE_MASK) == (VFIO_DEVICE_STATE_V1_SAVING | \ + VFIO_DEVICE_STATE_V1_RESUMING)) #define VFIO_DEVICE_STATE_SET_ERROR(state) \ - ((state & ~VFIO_DEVICE_STATE_MASK) | VFIO_DEVICE_SATE_SAVING | \ - VFIO_DEVICE_STATE_RESUMING) + ((state & ~VFIO_DEVICE_STATE_MASK) | VFIO_DEVICE_STATE_V1_SAVING | \ + VFIO_DEVICE_STATE_V1_RESUMING) __u32 reserved; __u64 pending_bytes; @@ -1002,6 +806,186 @@ struct vfio_device_feature { */ #define VFIO_DEVICE_FEATURE_PCI_VF_TOKEN (0) +/* + * Indicates the device can support the migration API through + * VFIO_DEVICE_FEATURE_MIG_DEVICE_STATE. If this GET succeeds, the RUNNING and + * ERROR states are always supported. Support for additional states is + * indicated via the flags field; at least VFIO_MIGRATION_STOP_COPY must be + * set. + * + * VFIO_MIGRATION_STOP_COPY means that STOP, STOP_COPY and + * RESUMING are supported. + * + * VFIO_MIGRATION_STOP_COPY | VFIO_MIGRATION_P2P means that RUNNING_P2P + * is supported in addition to the STOP_COPY states. + * + * Other combinations of flags have behavior to be defined in the future. + */ +struct vfio_device_feature_migration { + __aligned_u64 flags; +#define VFIO_MIGRATION_STOP_COPY (1 << 0) +#define VFIO_MIGRATION_P2P (1 << 1) +}; +#define VFIO_DEVICE_FEATURE_MIGRATION 1 + +/* + * Upon VFIO_DEVICE_FEATURE_SET, execute a migration state change on the VFIO + * device. The new state is supplied in device_state, see enum + * vfio_device_mig_state for details + * + * The kernel migration driver must fully transition the device to the new state + * value before the operation returns to the user. + * + * The kernel migration driver must not generate asynchronous device state + * transitions outside of manipulation by the user or the VFIO_DEVICE_RESET + * ioctl as described above. + * + * If this function fails then current device_state may be the original + * operating state or some other state along the combination transition path. + * The user can then decide if it should execute a VFIO_DEVICE_RESET, attempt + * to return to the original state, or attempt to return to some other state + * such as RUNNING or STOP. + * + * If the new_state starts a new data transfer session then the FD associated + * with that session is returned in data_fd. The user is responsible to close + * this FD when it is finished. The user must consider the migration data stream + * carried over the FD to be opaque and must preserve the byte order of the + * stream. The user is not required to preserve buffer segmentation when writing + * the data stream during the RESUMING operation. + * + * Upon VFIO_DEVICE_FEATURE_GET, get the current migration state of the VFIO + * device, data_fd will be -1. + */ +struct vfio_device_feature_mig_state { + __u32 device_state; /* From enum vfio_device_mig_state */ + __s32 data_fd; +}; +#define VFIO_DEVICE_FEATURE_MIG_DEVICE_STATE 2 + +/* + * The device migration Finite State Machine is described by the enum + * vfio_device_mig_state. Some of the FSM arcs will create a migration data + * transfer session by returning a FD, in this case the migration data will + * flow over the FD using read() and write() as discussed below. + * + * There are 5 states to support VFIO_MIGRATION_STOP_COPY: + * RUNNING - The device is running normally + * STOP - The device does not change the internal or external state + * STOP_COPY - The device internal state can be read out + * RESUMING - The device is stopped and is loading a new internal state + * ERROR - The device has failed and must be reset + * + * And 1 optional state to support VFIO_MIGRATION_P2P: + * RUNNING_P2P - RUNNING, except the device cannot do peer to peer DMA + * + * The FSM takes actions on the arcs between FSM states. The driver implements + * the following behavior for the FSM arcs: + * + * RUNNING_P2P -> STOP + * STOP_COPY -> STOP + * While in STOP the device must stop the operation of the device. The device + * must not generate interrupts, DMA, or any other change to external state. + * It must not change its internal state. When stopped the device and kernel + * migration driver must accept and respond to interaction to support external + * subsystems in the STOP state, for example PCI MSI-X and PCI config space. + * Failure by the user to restrict device access while in STOP must not result + * in error conditions outside the user context (ex. host system faults). + * + * The STOP_COPY arc will terminate a data transfer session. + * + * RESUMING -> STOP + * Leaving RESUMING terminates a data transfer session and indicates the + * device should complete processing of the data delivered by write(). The + * kernel migration driver should complete the incorporation of data written + * to the data transfer FD into the device internal state and perform + * final validity and consistency checking of the new device state. If the + * user provided data is found to be incomplete, inconsistent, or otherwise + * invalid, the migration driver must fail the SET_STATE ioctl and + * optionally go to the ERROR state as described below. + * + * While in STOP the device has the same behavior as other STOP states + * described above. + * + * To abort a RESUMING session the device must be reset. + * + * RUNNING_P2P -> RUNNING + * While in RUNNING the device is fully operational, the device may generate + * interrupts, DMA, respond to MMIO, all vfio device regions are functional, + * and the device may advance its internal state. + * + * RUNNING -> RUNNING_P2P + * STOP -> RUNNING_P2P + * While in RUNNING_P2P the device is partially running in the P2P quiescent + * state defined below. + * + * STOP -> STOP_COPY + * This arc begin the process of saving the device state and will return a + * new data_fd. + * + * While in the STOP_COPY state the device has the same behavior as STOP + * with the addition that the data transfers session continues to stream the + * migration state. End of stream on the FD indicates the entire device + * state has been transferred. + * + * The user should take steps to restrict access to vfio device regions while + * the device is in STOP_COPY or risk corruption of the device migration data + * stream. + * + * STOP -> RESUMING + * Entering the RESUMING state starts a process of restoring the device state + * and will return a new data_fd. The data stream fed into the data_fd should + * be taken from the data transfer output of a single FD during saving from + * a compatible device. The migration driver may alter/reset the internal + * device state for this arc if required to prepare the device to receive the + * migration data. + * + * any -> ERROR + * ERROR cannot be specified as a device state, however any transition request + * can be failed with an errno return and may then move the device_state into + * ERROR. In this case the device was unable to execute the requested arc and + * was also unable to restore the device to any valid device_state. + * To recover from ERROR VFIO_DEVICE_RESET must be used to return the + * device_state back to RUNNING. + * + * The optional peer to peer (P2P) quiescent state is intended to be a quiescent + * state for the device for the purposes of managing multiple devices within a + * user context where peer-to-peer DMA between devices may be active. The + * RUNNING_P2P states must prevent the device from initiating + * any new P2P DMA transactions. If the device can identify P2P transactions + * then it can stop only P2P DMA, otherwise it must stop all DMA. The migration + * driver must complete any such outstanding operations prior to completing the + * FSM arc into a P2P state. For the purpose of specification the states + * behave as though the device was fully running if not supported. Like while in + * STOP or STOP_COPY the user must not touch the device, otherwise the state + * can be exited. + * + * The remaining possible transitions are interpreted as combinations of the + * above FSM arcs. As there are multiple paths through the FSM arcs the path + * should be selected based on the following rules: + * - Select the shortest path. + * Refer to vfio_mig_get_next_state() for the result of the algorithm. + * + * The automatic transit through the FSM arcs that make up the combination + * transition is invisible to the user. When working with combination arcs the + * user may see any step along the path in the device_state if SET_STATE + * fails. When handling these types of errors users should anticipate future + * revisions of this protocol using new states and those states becoming + * visible in this case. + * + * The optional states cannot be used with SET_STATE if the device does not + * support them. The user can discover if these states are supported by using + * VFIO_DEVICE_FEATURE_MIGRATION. By using combination transitions the user can + * avoid knowing about these optional states if the kernel driver supports them. + */ +enum vfio_device_mig_state { + VFIO_DEVICE_STATE_ERROR = 0, + VFIO_DEVICE_STATE_STOP = 1, + VFIO_DEVICE_STATE_RUNNING = 2, + VFIO_DEVICE_STATE_STOP_COPY = 3, + VFIO_DEVICE_STATE_RESUMING = 4, + VFIO_DEVICE_STATE_RUNNING_P2P = 5, +}; + /* -------- API for Type1 VFIO IOMMU -------- */ /** diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h index c998860d7b..5d99e7c242 100644 --- a/linux-headers/linux/vhost.h +++ b/linux-headers/linux/vhost.h @@ -150,4 +150,11 @@ /* Get the valid iova range */ #define VHOST_VDPA_GET_IOVA_RANGE _IOR(VHOST_VIRTIO, 0x78, \ struct vhost_vdpa_iova_range) + +/* Get the config size */ +#define VHOST_VDPA_GET_CONFIG_SIZE _IOR(VHOST_VIRTIO, 0x79, __u32) + +/* Get the count of all virtqueues */ +#define VHOST_VDPA_GET_VQS_COUNT _IOR(VHOST_VIRTIO, 0x80, __u32) + #endif From f000bc74589247244943085b210cee32bac28c89 Mon Sep 17 00:00:00 2001 From: Ivan Shcherbakov Date: Sat, 14 May 2022 07:50:21 +0200 Subject: [PATCH 317/935] WHPX: fixed TPR/CR8 translation issues affecting VM debugging This patch fixes the following error that would occur when trying to resume a WHPX-accelerated VM from a breakpoint: qemu: WHPX: Failed to set interrupt state registers, hr=c0350005 The error arises from an incorrect CR8 value being passed to WHvSetVirtualProcessorRegisters() that doesn't match the value set via WHvSetVirtualProcessorInterruptControllerState2(). Signed-off-by: Ivan Shcherbakov Signed-off-by: Paolo Bonzini --- target/i386/whpx/whpx-all.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index 23ae639b23..b22a3314b4 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -373,6 +373,8 @@ static int whpx_set_tsc(CPUState *cpu) * * This mechanism is described in section 10.8.6.1 of Volume 3 of Intel 64 * and IA-32 Architectures Software Developer's Manual. + * + * The functions below translate the value of CR8 to TPR and vice versa. */ static uint64_t whpx_apic_tpr_to_cr8(uint64_t tpr) @@ -380,6 +382,11 @@ static uint64_t whpx_apic_tpr_to_cr8(uint64_t tpr) return tpr >> 4; } +static uint64_t whpx_cr8_to_apic_tpr(uint64_t cr8) +{ + return cr8 << 4; +} + static void whpx_set_registers(CPUState *cpu, int level) { struct whpx_state *whpx = &whpx_global; @@ -687,7 +694,7 @@ static void whpx_get_registers(CPUState *cpu) tpr = vcxt.values[idx++].Reg64; if (tpr != vcpu->tpr) { vcpu->tpr = tpr; - cpu_set_apic_tpr(x86_cpu->apic_state, tpr); + cpu_set_apic_tpr(x86_cpu->apic_state, whpx_cr8_to_apic_tpr(tpr)); } /* 8 Debug Registers - Skipped */ @@ -1547,7 +1554,7 @@ static void whpx_vcpu_pre_run(CPUState *cpu) } /* Sync the TPR to the CR8 if was modified during the intercept */ - tpr = cpu_get_apic_tpr(x86_cpu->apic_state); + tpr = whpx_apic_tpr_to_cr8(cpu_get_apic_tpr(x86_cpu->apic_state)); if (tpr != vcpu->tpr) { vcpu->tpr = tpr; reg_values[reg_count].Reg64 = tpr; @@ -1596,7 +1603,7 @@ static void whpx_vcpu_post_run(CPUState *cpu) if (vcpu->tpr != tpr) { vcpu->tpr = tpr; qemu_mutex_lock_iothread(); - cpu_set_apic_tpr(x86_cpu->apic_state, vcpu->tpr); + cpu_set_apic_tpr(x86_cpu->apic_state, whpx_cr8_to_apic_tpr(vcpu->tpr)); qemu_mutex_unlock_iothread(); } From 580ea136eb37b9a059bdba9c20260dc825bcc2de Mon Sep 17 00:00:00 2001 From: Konstantin Kostiuk Date: Thu, 12 May 2022 18:49:06 +0300 Subject: [PATCH 318/935] qga-vss: Add auto generated headers to dependencies Signed-off-by: Konstantin Kostiuk Message-Id: <20220512154906.331399-1-kkostiuk@redhat.com> Signed-off-by: Paolo Bonzini --- qga/vss-win32/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qga/vss-win32/meson.build b/qga/vss-win32/meson.build index 26c5dd6e0e..9483ccd3b8 100644 --- a/qga/vss-win32/meson.build +++ b/qga/vss-win32/meson.build @@ -7,7 +7,7 @@ link_args = cc.get_supported_link_arguments([ qga_vss = shared_module( 'qga-vss', - ['requester.cpp', 'provider.cpp', 'install.cpp'], + ['requester.cpp', 'provider.cpp', 'install.cpp', genh], name_prefix: '', cpp_args: ['-Wno-unknown-pragmas', '-Wno-delete-non-virtual-dtor', '-Wno-non-virtual-dtor'], link_args: link_args, From 6c1d88c72bd740cc431a13a02145168cf87866fc Mon Sep 17 00:00:00 2001 From: Konstantin Kostiuk Date: Thu, 12 May 2022 18:49:09 +0300 Subject: [PATCH 319/935] qga-vss: Use the proper operator to free memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit volume_name_wchar is allocated by 'void* operator new [](long long unsigned int) Signed-off-by: Konstantin Kostiuk Reviewed-by: Marc-André Lureau Message-Id: <20220512154909.331481-1-kkostiuk@redhat.com> Signed-off-by: Paolo Bonzini --- qga/vss-win32/requester.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qga/vss-win32/requester.cpp b/qga/vss-win32/requester.cpp index 4513324dd2..b371affeab 100644 --- a/qga/vss-win32/requester.cpp +++ b/qga/vss-win32/requester.cpp @@ -354,12 +354,12 @@ void requester_freeze(int *num_vols, void *mountpoints, ErrorSet *errset) if (FAILED(hr)) { err_set(errset, hr, "failed to add %S to snapshot set", volume_name_wchar); - delete volume_name_wchar; + delete[] volume_name_wchar; goto out; } num_mount_points++; - delete volume_name_wchar; + delete[] volume_name_wchar; } if (num_mount_points == 0) { From 6df39f5e583ca0f67bd934d1327f9ead2e3bd49c Mon Sep 17 00:00:00 2001 From: Robert Hoo Date: Mon, 14 Mar 2022 16:50:59 +0800 Subject: [PATCH 320/935] i386/cpu: Remove the deprecated cpu model 'Icelake-Client' Icelake, is the codename for Intel 3rd generation Xeon Scalable server processors. There isn't ever client variants. This "Icelake-Client" CPU model was added wrongly and imaginarily. It has been deprecated since v5.2, now it's time to remove it completely from code. Signed-off-by: Robert Hoo Reviewed-by: Igor Mammedov Message-Id: <1647247859-4947-1-git-send-email-robert.hu@linux.intel.com> Signed-off-by: Paolo Bonzini --- docs/about/deprecated.rst | 6 -- docs/about/removed-features.rst | 6 ++ target/i386/cpu.c | 122 -------------------------------- 3 files changed, 6 insertions(+), 128 deletions(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 896e5a97ab..44f52c172d 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -270,12 +270,6 @@ from Linux upstream kernel, declare it deprecated. System emulator CPUS -------------------- -``Icelake-Client`` CPU Model (since 5.2) -'''''''''''''''''''''''''''''''''''''''' - -``Icelake-Client`` CPU Models are deprecated. Use ``Icelake-Server`` CPU -Models instead. - MIPS ``I7200`` CPU Model (since 5.2) '''''''''''''''''''''''''''''''''''' diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 4a0b270296..ba78bc1a19 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -557,6 +557,12 @@ Support for this CPU was removed from the upstream Linux kernel, and there is no available upstream toolchain to build binaries for it. Removed without replacement. +x86 ``Icelake-Client`` CPU (removed in 7.1) +''''''''''''''''''''''''''''''''''''''''''' + +There isn't ever Icelake Client CPU, it is some wrong and imaginary one. +Use ``Icelake-Server`` instead. + System emulator machines ------------------------ diff --git a/target/i386/cpu.c b/target/i386/cpu.c index c4a17c93f6..6083e556f5 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -3258,128 +3258,6 @@ static const X86CPUDefinition builtin_x86_defs[] = { { /* end of list */ } } }, - { - .name = "Icelake-Client", - .level = 0xd, - .vendor = CPUID_VENDOR_INTEL, - .family = 6, - .model = 126, - .stepping = 0, - .features[FEAT_1_EDX] = - CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | - CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | - CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | - CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | - CPUID_DE | CPUID_FP87, - .features[FEAT_1_ECX] = - CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | - CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | - CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | - CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 | - CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE | - CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND, - .features[FEAT_8000_0001_EDX] = - CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX | - CPUID_EXT2_SYSCALL, - .features[FEAT_8000_0001_ECX] = - CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH, - .features[FEAT_8000_0008_EBX] = - CPUID_8000_0008_EBX_WBNOINVD, - .features[FEAT_7_0_EBX] = - CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | - CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | - CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | - CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | - CPUID_7_0_EBX_SMAP, - .features[FEAT_7_0_ECX] = - CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | - CPUID_7_0_ECX_AVX512_VBMI2 | CPUID_7_0_ECX_GFNI | - CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ | - CPUID_7_0_ECX_AVX512VNNI | CPUID_7_0_ECX_AVX512BITALG | - CPUID_7_0_ECX_AVX512_VPOPCNTDQ, - .features[FEAT_7_0_EDX] = - CPUID_7_0_EDX_SPEC_CTRL | CPUID_7_0_EDX_SPEC_CTRL_SSBD, - /* XSAVES is added in version 3 */ - .features[FEAT_XSAVE] = - CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | - CPUID_XSAVE_XGETBV1, - .features[FEAT_6_EAX] = - CPUID_6_EAX_ARAT, - /* Missing: Mode-based execute control (XS/XU), processor tracing, TSC scaling */ - .features[FEAT_VMX_BASIC] = MSR_VMX_BASIC_INS_OUTS | - MSR_VMX_BASIC_TRUE_CTLS, - .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE | - VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | VMX_VM_ENTRY_LOAD_IA32_PAT | - VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_LOAD_IA32_EFER, - .features[FEAT_VMX_EPT_VPID_CAPS] = MSR_VMX_EPT_EXECONLY | - MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | - MSR_VMX_EPT_1GB | MSR_VMX_EPT_INVEPT | - MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | - MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | - MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | MSR_VMX_EPT_INVVPID_ALL_CONTEXT | - MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS | MSR_VMX_EPT_AD_BITS, - .features[FEAT_VMX_EXIT_CTLS] = - VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | - VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | - VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_LOAD_IA32_EFER | - VMX_VM_EXIT_SAVE_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | - VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, - .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT | - MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_VMWRITE_VMEXIT, - .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | - VMX_PIN_BASED_NMI_EXITING | VMX_PIN_BASED_VIRTUAL_NMIS | - VMX_PIN_BASED_VMX_PREEMPTION_TIMER, - .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | - VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | - VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | - VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | - VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | - VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | - VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | - VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING | - VMX_CPU_BASED_VIRTUAL_NMI_PENDING | VMX_CPU_BASED_USE_MSR_BITMAPS | - VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | - VMX_CPU_BASED_MONITOR_TRAP_FLAG | - VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, - .features[FEAT_VMX_SECONDARY_CTLS] = - VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | - VMX_SECONDARY_EXEC_WBINVD_EXITING | VMX_SECONDARY_EXEC_ENABLE_EPT | - VMX_SECONDARY_EXEC_DESC | VMX_SECONDARY_EXEC_RDTSCP | - VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | - VMX_SECONDARY_EXEC_RDRAND_EXITING | VMX_SECONDARY_EXEC_ENABLE_INVPCID | - VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | - VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML, - .features[FEAT_VMX_VMFUNC] = MSR_VMX_VMFUNC_EPT_SWITCHING, - .xlevel = 0x80000008, - .model_id = "Intel Core Processor (Icelake)", - .versions = (X86CPUVersionDefinition[]) { - { - .version = 1, - .note = "deprecated" - }, - { - .version = 2, - .note = "no TSX, deprecated", - .alias = "Icelake-Client-noTSX", - .props = (PropValue[]) { - { "hle", "off" }, - { "rtm", "off" }, - { /* end of list */ } - }, - }, - { - .version = 3, - .note = "no TSX, XSAVES, deprecated", - .props = (PropValue[]) { - { "xsaves", "on" }, - { "vmx-xsaves", "on" }, - { /* end of list */ } - }, - }, - { /* end of list */ } - }, - .deprecation_note = "use Icelake-Server instead" - }, { .name = "Icelake-Server", .level = 0xd, From 18c22d7112a76fabeee5022a3bdd9e8c3a37c8d2 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Tue, 15 Feb 2022 14:52:51 -0500 Subject: [PATCH 321/935] qdev-properties: Add a new macro with bitmask check for uint64_t property The DEFINE_PROP_UINT64_CHECKMASK maro applies certain mask check agaist user-supplied property value, reject the value if it violates the bitmask. Co-developed-by: Like Xu Signed-off-by: Like Xu Signed-off-by: Yang Weijiang Message-Id: <20220215195258.29149-2-weijiang.yang@intel.com> Signed-off-by: Paolo Bonzini --- hw/core/qdev-properties.c | 19 +++++++++++++++++++ include/hw/qdev-properties.h | 12 ++++++++++++ 2 files changed, 31 insertions(+) diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index c34aac6ebc..357b8761b5 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -428,6 +428,25 @@ const PropertyInfo qdev_prop_int64 = { .set_default_value = qdev_propinfo_set_default_value_int, }; +static void set_uint64_checkmask(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + Property *prop = opaque; + uint64_t *ptr = object_field_prop_ptr(obj, prop); + + visit_type_uint64(v, name, ptr, errp); + if (*ptr & ~prop->bitmask) { + error_setg(errp, "Property value for '%s' has bits outside mask '0x%" PRIx64 "'", + name, prop->bitmask); + } +} + +const PropertyInfo qdev_prop_uint64_checkmask = { + .name = "uint64", + .get = get_uint64, + .set = set_uint64_checkmask, +}; + /* --- string --- */ static void release_string(Object *obj, const char *name, void *opaque) diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index f7925f67d0..e1df08876c 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -17,6 +17,7 @@ struct Property { const PropertyInfo *info; ptrdiff_t offset; uint8_t bitnr; + uint64_t bitmask; bool set_default; union { int64_t i; @@ -54,6 +55,7 @@ extern const PropertyInfo qdev_prop_uint16; extern const PropertyInfo qdev_prop_uint32; extern const PropertyInfo qdev_prop_int32; extern const PropertyInfo qdev_prop_uint64; +extern const PropertyInfo qdev_prop_uint64_checkmask; extern const PropertyInfo qdev_prop_int64; extern const PropertyInfo qdev_prop_size; extern const PropertyInfo qdev_prop_string; @@ -103,6 +105,16 @@ extern const PropertyInfo qdev_prop_link; .set_default = true, \ .defval.u = (bool)_defval) +/** + * The DEFINE_PROP_UINT64_CHECKMASK macro checks a user-supplied value + * against corresponding bitmask, rejects the value if it violates. + * The default value is set in instance_init(). + */ +#define DEFINE_PROP_UINT64_CHECKMASK(_name, _state, _field, _bitmask) \ + DEFINE_PROP(_name, _state, _field, qdev_prop_uint64_checkmask, uint64_t, \ + .bitmask = (_bitmask), \ + .set_default = false) + #define PROP_ARRAY_LEN_PREFIX "len-" /** From f06d8a18abc9d29d052f628eefd1d4a86c99fcea Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Tue, 15 Feb 2022 14:52:52 -0500 Subject: [PATCH 322/935] target/i386: Add lbr-fmt vPMU option to support guest LBR The Last Branch Recording (LBR) is a performance monitor unit (PMU) feature on Intel processors which records a running trace of the most recent branches taken by the processor in the LBR stack. This option indicates the LBR format to enable for guest perf. The LBR feature is enabled if below conditions are met: 1) KVM is enabled and the PMU is enabled. 2) msr-based-feature IA32_PERF_CAPABILITIES is supporterd on KVM. 3) Supported returned value for lbr_fmt from above msr is non-zero. 4) Guest vcpu model does support FEAT_1_ECX.CPUID_EXT_PDCM. 5) User-provided lbr-fmt value doesn't violate its bitmask (0x3f). 6) Target guest LBR format matches that of host. Co-developed-by: Like Xu Signed-off-by: Like Xu Signed-off-by: Yang Weijiang Message-Id: <20220215195258.29149-3-weijiang.yang@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 40 ++++++++++++++++++++++++++++++++++++++++ target/i386/cpu.h | 10 ++++++++++ 2 files changed, 50 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 6083e556f5..856a8659e8 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6275,6 +6275,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) CPUX86State *env = &cpu->env; Error *local_err = NULL; static bool ht_warned; + unsigned requested_lbr_fmt; if (cpu->apic_id == UNASSIGNED_APIC_ID) { error_setg(errp, "apic-id property was not initialized properly"); @@ -6292,6 +6293,42 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) goto out; } + /* + * Override env->features[FEAT_PERF_CAPABILITIES].LBR_FMT + * with user-provided setting. + */ + if (cpu->lbr_fmt != ~PERF_CAP_LBR_FMT) { + if ((cpu->lbr_fmt & PERF_CAP_LBR_FMT) != cpu->lbr_fmt) { + error_setg(errp, "invalid lbr-fmt"); + return; + } + env->features[FEAT_PERF_CAPABILITIES] &= ~PERF_CAP_LBR_FMT; + env->features[FEAT_PERF_CAPABILITIES] |= cpu->lbr_fmt; + } + + /* + * vPMU LBR is supported when 1) KVM is enabled 2) Option pmu=on and + * 3)vPMU LBR format matches that of host setting. + */ + requested_lbr_fmt = + env->features[FEAT_PERF_CAPABILITIES] & PERF_CAP_LBR_FMT; + if (requested_lbr_fmt && kvm_enabled()) { + uint64_t host_perf_cap = + x86_cpu_get_supported_feature_word(FEAT_PERF_CAPABILITIES, false); + unsigned host_lbr_fmt = host_perf_cap & PERF_CAP_LBR_FMT; + + if (!cpu->enable_pmu) { + error_setg(errp, "vPMU: LBR is unsupported without pmu=on"); + return; + } + if (requested_lbr_fmt != host_lbr_fmt) { + error_setg(errp, "vPMU: the lbr-fmt value (0x%x) does not match " + "the host value (0x%x).", + requested_lbr_fmt, host_lbr_fmt); + return; + } + } + x86_cpu_filter_features(cpu, cpu->check_cpuid || cpu->enforce_cpuid); if (cpu->enforce_cpuid && x86_cpu_have_filtered_features(cpu)) { @@ -6644,6 +6681,8 @@ static void x86_cpu_initfn(Object *obj) object_property_add_alias(obj, "sse4_2", obj, "sse4.2"); object_property_add_alias(obj, "hv-apicv", obj, "hv-avic"); + cpu->lbr_fmt = ~PERF_CAP_LBR_FMT; + object_property_add_alias(obj, "lbr_fmt", obj, "lbr-fmt"); if (xcc->model) { x86_cpu_load_model(cpu, xcc->model); @@ -6798,6 +6837,7 @@ static Property x86_cpu_properties[] = { #endif DEFINE_PROP_INT32("node-id", X86CPU, node_id, CPU_UNSET_NUMA_NODE_ID), DEFINE_PROP_BOOL("pmu", X86CPU, enable_pmu, false), + DEFINE_PROP_UINT64_CHECKMASK("lbr-fmt", X86CPU, lbr_fmt, PERF_CAP_LBR_FMT), DEFINE_PROP_UINT32("hv-spinlocks", X86CPU, hyperv_spinlock_attempts, HYPERV_SPINLOCK_NEVER_NOTIFY), diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 9661f9fbd1..6730df5dbf 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -386,6 +386,7 @@ typedef enum X86Seg { #define ARCH_CAP_TSX_CTRL_MSR (1<<7) #define MSR_IA32_PERF_CAPABILITIES 0x345 +#define PERF_CAP_LBR_FMT 0x3f #define MSR_IA32_TSX_CTRL 0x122 #define MSR_IA32_TSCDEADLINE 0x6e0 @@ -1810,6 +1811,15 @@ struct ArchCPU { */ bool enable_pmu; + /* + * Enable LBR_FMT bits of IA32_PERF_CAPABILITIES MSR. + * This can't be initialized with a default because it doesn't have + * stable ABI support yet. It is only allowed to pass all LBR_FMT bits + * returned by kvm_arch_get_supported_msr_feature()(which depends on both + * host CPU and kernel capabilities) to the guest. + */ + uint64_t lbr_fmt; + /* LMCE support can be enabled/disabled via cpu option 'lmce=on/off'. It is * disabled by default to avoid breaking migration between QEMU with * different LMCE configurations. From 5a778a5f820fdd907b95e93560637a61f6ea3c71 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Tue, 15 Feb 2022 14:52:53 -0500 Subject: [PATCH 323/935] target/i386: Add kvm_get_one_msr helper When try to get one msr from KVM, I found there's no such kind of existing interface while kvm_put_one_msr() is there. So here comes the patch. It'll remove redundant preparation code before finally call KVM_GET_MSRS IOCTL. No functional change intended. Signed-off-by: Yang Weijiang Message-Id: <20220215195258.29149-4-weijiang.yang@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/kvm/kvm.c | 46 ++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index c885763a5b..536cbe5fad 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -141,6 +141,7 @@ static struct kvm_msr_list *kvm_feature_msrs; #define BUS_LOCK_SLICE_TIME 1000000000ULL /* ns */ static RateLimit bus_lock_ratelimit_ctrl; +static int kvm_get_one_msr(X86CPU *cpu, int index, uint64_t *value); int kvm_has_pit_state2(void) { @@ -211,28 +212,21 @@ static int kvm_get_tsc(CPUState *cs) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; - struct { - struct kvm_msrs info; - struct kvm_msr_entry entries[1]; - } msr_data = {}; + uint64_t value; int ret; if (env->tsc_valid) { return 0; } - memset(&msr_data, 0, sizeof(msr_data)); - msr_data.info.nmsrs = 1; - msr_data.entries[0].index = MSR_IA32_TSC; env->tsc_valid = !runstate_is_running(); - ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, &msr_data); + ret = kvm_get_one_msr(cpu, MSR_IA32_TSC, &value); if (ret < 0) { return ret; } - assert(ret == 1); - env->tsc = msr_data.entries[0].data; + env->tsc = value; return 0; } @@ -1566,21 +1560,14 @@ static int hyperv_init_vcpu(X86CPU *cpu) * the kernel doesn't support setting vp_index; assert that its value * is in sync */ - struct { - struct kvm_msrs info; - struct kvm_msr_entry entries[1]; - } msr_data = { - .info.nmsrs = 1, - .entries[0].index = HV_X64_MSR_VP_INDEX, - }; + uint64_t value; - ret = kvm_vcpu_ioctl(cs, KVM_GET_MSRS, &msr_data); + ret = kvm_get_one_msr(cpu, HV_X64_MSR_VP_INDEX, &value); if (ret < 0) { return ret; } - assert(ret == 1); - if (msr_data.entries[0].data != hyperv_vp_index(CPU(cpu))) { + if (value != hyperv_vp_index(CPU(cpu))) { error_report("kernel's vp_index != QEMU's vp_index"); return -ENXIO; } @@ -2839,6 +2826,25 @@ static int kvm_put_one_msr(X86CPU *cpu, int index, uint64_t value) return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MSRS, cpu->kvm_msr_buf); } +static int kvm_get_one_msr(X86CPU *cpu, int index, uint64_t *value) +{ + int ret; + struct { + struct kvm_msrs info; + struct kvm_msr_entry entries[1]; + } msr_data = { + .info.nmsrs = 1, + .entries[0].index = index, + }; + + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, &msr_data); + if (ret < 0) { + return ret; + } + assert(ret == 1); + *value = msr_data.entries[0].data; + return ret; +} void kvm_put_apicbase(X86CPU *cpu, uint64_t value) { int ret; From 301e90675c3fed6cdc48682021a1ab42bc0e0d76 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Tue, 15 Feb 2022 14:52:54 -0500 Subject: [PATCH 324/935] target/i386: Enable support for XSAVES based features There're some new features, including Arch LBR, depending on XSAVES/XRSTORS support, the new instructions will save/restore data based on feature bits enabled in XCR0 | XSS. This patch adds the basic support for related CPUID enumeration and meanwhile changes the name from FEAT_XSAVE_COMP_{LO|HI} to FEAT_XSAVE_XCR0_{LO|HI} to differentiate clearly the feature bits in XCR0 and those in XSS. Signed-off-by: Yang Weijiang Message-Id: <20220215195258.29149-5-weijiang.yang@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 104 +++++++++++++++++++++++++++++++++++----------- target/i386/cpu.h | 14 ++++++- 2 files changed, 92 insertions(+), 26 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 856a8659e8..643536d05d 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -937,6 +937,34 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { }, .tcg_features = TCG_XSAVE_FEATURES, }, + [FEAT_XSAVE_XSS_LO] = { + .type = CPUID_FEATURE_WORD, + .feat_names = { + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, + .cpuid = { + .eax = 0xD, + .needs_ecx = true, + .ecx = 1, + .reg = R_ECX, + }, + }, + [FEAT_XSAVE_XSS_HI] = { + .type = CPUID_FEATURE_WORD, + .cpuid = { + .eax = 0xD, + .needs_ecx = true, + .ecx = 1, + .reg = R_EDX + }, + }, [FEAT_6_EAX] = { .type = CPUID_FEATURE_WORD, .feat_names = { @@ -952,7 +980,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { .cpuid = { .eax = 6, .reg = R_EAX, }, .tcg_features = TCG_6_EAX_FEATURES, }, - [FEAT_XSAVE_COMP_LO] = { + [FEAT_XSAVE_XCR0_LO] = { .type = CPUID_FEATURE_WORD, .cpuid = { .eax = 0xD, @@ -965,7 +993,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { XSTATE_OPMASK_MASK | XSTATE_ZMM_Hi256_MASK | XSTATE_Hi16_ZMM_MASK | XSTATE_PKRU_MASK, }, - [FEAT_XSAVE_COMP_HI] = { + [FEAT_XSAVE_XCR0_HI] = { .type = CPUID_FEATURE_WORD, .cpuid = { .eax = 0xD, @@ -1382,6 +1410,9 @@ static const X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = { }; #undef REGISTER +/* CPUID feature bits available in XSS */ +#define CPUID_XSTATE_XSS_MASK (0) + ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT] = { [XSTATE_FP_BIT] = { /* x87 FP state component is always enabled if XSAVE is supported */ @@ -1424,15 +1455,18 @@ ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT] = { }, }; -static uint32_t xsave_area_size(uint64_t mask) +static uint32_t xsave_area_size(uint64_t mask, bool compacted) { + uint64_t ret = x86_ext_save_areas[0].size; + const ExtSaveArea *esa; + uint32_t offset = 0; int i; - uint64_t ret = 0; - for (i = 0; i < ARRAY_SIZE(x86_ext_save_areas); i++) { - const ExtSaveArea *esa = &x86_ext_save_areas[i]; + for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) { + esa = &x86_ext_save_areas[i]; if ((mask >> i) & 1) { - ret = MAX(ret, esa->offset + esa->size); + offset = compacted ? ret : esa->offset; + ret = MAX(ret, offset + esa->size); } } return ret; @@ -1443,10 +1477,10 @@ static inline bool accel_uses_host_cpuid(void) return kvm_enabled() || hvf_enabled(); } -static inline uint64_t x86_cpu_xsave_components(X86CPU *cpu) +static inline uint64_t x86_cpu_xsave_xcr0_components(X86CPU *cpu) { - return ((uint64_t)cpu->env.features[FEAT_XSAVE_COMP_HI]) << 32 | - cpu->env.features[FEAT_XSAVE_COMP_LO]; + return ((uint64_t)cpu->env.features[FEAT_XSAVE_XCR0_HI]) << 32 | + cpu->env.features[FEAT_XSAVE_XCR0_LO]; } /* Return name of 32-bit register, from a R_* constant */ @@ -1458,6 +1492,12 @@ static const char *get_register_name_32(unsigned int reg) return x86_reg_info_32[reg].name; } +static inline uint64_t x86_cpu_xsave_xss_components(X86CPU *cpu) +{ + return ((uint64_t)cpu->env.features[FEAT_XSAVE_XSS_HI]) << 32 | + cpu->env.features[FEAT_XSAVE_XSS_LO]; +} + /* * Returns the set of feature flags that are supported and migratable by * QEMU, for a given FeatureWord. @@ -4511,8 +4551,8 @@ static const char *x86_cpu_feature_name(FeatureWord w, int bitnr) /* XSAVE components are automatically enabled by other features, * so return the original feature name instead */ - if (w == FEAT_XSAVE_COMP_LO || w == FEAT_XSAVE_COMP_HI) { - int comp = (w == FEAT_XSAVE_COMP_HI) ? bitnr + 32 : bitnr; + if (w == FEAT_XSAVE_XCR0_LO || w == FEAT_XSAVE_XCR0_HI) { + int comp = (w == FEAT_XSAVE_XCR0_HI) ? bitnr + 32 : bitnr; if (comp < ARRAY_SIZE(x86_ext_save_areas) && x86_ext_save_areas[comp].bits) { @@ -5408,25 +5448,36 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, } if (count == 0) { - *ecx = xsave_area_size(x86_cpu_xsave_components(cpu)); - *eax = env->features[FEAT_XSAVE_COMP_LO]; - *edx = env->features[FEAT_XSAVE_COMP_HI]; + *ecx = xsave_area_size(x86_cpu_xsave_xcr0_components(cpu), false); + *eax = env->features[FEAT_XSAVE_XCR0_LO]; + *edx = env->features[FEAT_XSAVE_XCR0_HI]; /* * The initial value of xcr0 and ebx == 0, On host without kvm * commit 412a3c41(e.g., CentOS 6), the ebx's value always == 0 * even through guest update xcr0, this will crash some legacy guest * (e.g., CentOS 6), So set ebx == ecx to workaroud it. */ - *ebx = kvm_enabled() ? *ecx : xsave_area_size(env->xcr0); + *ebx = kvm_enabled() ? *ecx : xsave_area_size(env->xcr0, false); } else if (count == 1) { + uint64_t xstate = x86_cpu_xsave_xcr0_components(cpu) | + x86_cpu_xsave_xss_components(cpu); + *eax = env->features[FEAT_XSAVE]; + *ebx = xsave_area_size(xstate, true); + *ecx = env->features[FEAT_XSAVE_XSS_LO]; + *edx = env->features[FEAT_XSAVE_XSS_HI]; } else if (count < ARRAY_SIZE(x86_ext_save_areas)) { - if ((x86_cpu_xsave_components(cpu) >> count) & 1) { - const ExtSaveArea *esa = &x86_ext_save_areas[count]; + const ExtSaveArea *esa = &x86_ext_save_areas[count]; + + if (x86_cpu_xsave_xcr0_components(cpu) & (1ULL << count)) { *eax = esa->size; *ebx = esa->offset; *ecx = esa->ecx & (ESA_FEATURE_ALIGN64_MASK | ESA_FEATURE_XFD_MASK); + } else if (x86_cpu_xsave_xss_components(cpu) & (1ULL << count)) { + *eax = esa->size; + *ebx = 0; + *ecx = 1; } } break; @@ -5477,8 +5528,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, } else { *eax &= env->features[FEAT_SGX_12_1_EAX]; *ebx &= 0; /* ebx reserve */ - *ecx &= env->features[FEAT_XSAVE_COMP_LO]; - *edx &= env->features[FEAT_XSAVE_COMP_HI]; + *ecx &= env->features[FEAT_XSAVE_XSS_LO]; + *edx &= env->features[FEAT_XSAVE_XSS_HI]; /* FP and SSE are always allowed regardless of XSAVE/XCR0. */ *ecx |= XSTATE_FP_MASK | XSTATE_SSE_MASK; @@ -5874,6 +5925,9 @@ static void x86_cpu_reset(DeviceState *dev) } for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) { const ExtSaveArea *esa = &x86_ext_save_areas[i]; + if (!((1 << i) & CPUID_XSTATE_XCR0_MASK)) { + continue; + } if (env->features[esa->feature] & esa->bits) { xcr0 |= 1ull << i; } @@ -5988,8 +6042,8 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu) static bool request_perm; if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) { - env->features[FEAT_XSAVE_COMP_LO] = 0; - env->features[FEAT_XSAVE_COMP_HI] = 0; + env->features[FEAT_XSAVE_XCR0_LO] = 0; + env->features[FEAT_XSAVE_XCR0_HI] = 0; return; } @@ -6007,8 +6061,10 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu) request_perm = true; } - env->features[FEAT_XSAVE_COMP_LO] = mask; - env->features[FEAT_XSAVE_COMP_HI] = mask >> 32; + env->features[FEAT_XSAVE_XCR0_LO] = mask & CPUID_XSTATE_XCR0_MASK; + env->features[FEAT_XSAVE_XCR0_HI] = mask >> 32; + env->features[FEAT_XSAVE_XSS_LO] = mask & CPUID_XSTATE_XSS_MASK; + env->features[FEAT_XSAVE_XSS_HI] = mask >> 32; } /***** Steps involved on loading and filtering CPUID data diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 6730df5dbf..453b80eae2 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -568,6 +568,14 @@ typedef enum X86Seg { #define ESA_FEATURE_XFD_MASK (1U << ESA_FEATURE_XFD_BIT) +/* CPUID feature bits available in XCR0 */ +#define CPUID_XSTATE_XCR0_MASK (XSTATE_FP_MASK | XSTATE_SSE_MASK | \ + XSTATE_YMM_MASK | XSTATE_BNDREGS_MASK | \ + XSTATE_BNDCSR_MASK | XSTATE_OPMASK_MASK | \ + XSTATE_ZMM_Hi256_MASK | \ + XSTATE_Hi16_ZMM_MASK | XSTATE_PKRU_MASK | \ + XSTATE_XTILE_CFG_MASK | XSTATE_XTILE_DATA_MASK) + /* CPUID feature words */ typedef enum FeatureWord { FEAT_1_EDX, /* CPUID[1].EDX */ @@ -586,8 +594,8 @@ typedef enum FeatureWord { FEAT_SVM, /* CPUID[8000_000A].EDX */ FEAT_XSAVE, /* CPUID[EAX=0xd,ECX=1].EAX */ FEAT_6_EAX, /* CPUID[6].EAX */ - FEAT_XSAVE_COMP_LO, /* CPUID[EAX=0xd,ECX=0].EAX */ - FEAT_XSAVE_COMP_HI, /* CPUID[EAX=0xd,ECX=0].EDX */ + FEAT_XSAVE_XCR0_LO, /* CPUID[EAX=0xd,ECX=0].EAX */ + FEAT_XSAVE_XCR0_HI, /* CPUID[EAX=0xd,ECX=0].EDX */ FEAT_ARCH_CAPABILITIES, FEAT_CORE_CAPABILITY, FEAT_PERF_CAPABILITIES, @@ -604,6 +612,8 @@ typedef enum FeatureWord { FEAT_SGX_12_0_EAX, /* CPUID[EAX=0x12,ECX=0].EAX (SGX) */ FEAT_SGX_12_0_EBX, /* CPUID[EAX=0x12,ECX=0].EBX (SGX MISCSELECT[31:0]) */ FEAT_SGX_12_1_EAX, /* CPUID[EAX=0x12,ECX=1].EAX (SGX ATTRIBUTES[31:0]) */ + FEAT_XSAVE_XSS_LO, /* CPUID[EAX=0xd,ECX=1].ECX */ + FEAT_XSAVE_XSS_HI, /* CPUID[EAX=0xd,ECX=1].EDX */ FEATURE_WORDS, } FeatureWord; From 10f0abcb3b8a74a4db1412e844b9192dc9768e94 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Tue, 15 Feb 2022 14:52:55 -0500 Subject: [PATCH 325/935] target/i386: Add XSAVES support for Arch LBR Define Arch LBR bit in XSS and save/restore structure for XSAVE area size calculation. Signed-off-by: Yang Weijiang Message-Id: <20220215195258.29149-6-weijiang.yang@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 6 +++++- target/i386/cpu.h | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 643536d05d..1816c37852 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -1411,7 +1411,7 @@ static const X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = { #undef REGISTER /* CPUID feature bits available in XSS */ -#define CPUID_XSTATE_XSS_MASK (0) +#define CPUID_XSTATE_XSS_MASK (XSTATE_ARCH_LBR_MASK) ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT] = { [XSTATE_FP_BIT] = { @@ -1445,6 +1445,10 @@ ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT] = { [XSTATE_PKRU_BIT] = { .feature = FEAT_7_0_ECX, .bits = CPUID_7_0_ECX_PKU, .size = sizeof(XSavePKRU) }, + [XSTATE_ARCH_LBR_BIT] = { + .feature = FEAT_7_0_EDX, .bits = CPUID_7_0_EDX_ARCH_LBR, + .offset = 0 /*supervisor mode component, offset = 0 */, + .size = sizeof(XSavesArchLBR) }, [XSTATE_XTILE_CFG_BIT] = { .feature = FEAT_7_0_EDX, .bits = CPUID_7_0_EDX_AMX_TILE, .size = sizeof(XSaveXTILECFG), diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 453b80eae2..dba92936a2 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -544,6 +544,7 @@ typedef enum X86Seg { #define XSTATE_ZMM_Hi256_BIT 6 #define XSTATE_Hi16_ZMM_BIT 7 #define XSTATE_PKRU_BIT 9 +#define XSTATE_ARCH_LBR_BIT 15 #define XSTATE_XTILE_CFG_BIT 17 #define XSTATE_XTILE_DATA_BIT 18 @@ -556,6 +557,7 @@ typedef enum X86Seg { #define XSTATE_ZMM_Hi256_MASK (1ULL << XSTATE_ZMM_Hi256_BIT) #define XSTATE_Hi16_ZMM_MASK (1ULL << XSTATE_Hi16_ZMM_BIT) #define XSTATE_PKRU_MASK (1ULL << XSTATE_PKRU_BIT) +#define XSTATE_ARCH_LBR_MASK (1ULL << XSTATE_ARCH_LBR_BIT) #define XSTATE_XTILE_CFG_MASK (1ULL << XSTATE_XTILE_CFG_BIT) #define XSTATE_XTILE_DATA_MASK (1ULL << XSTATE_XTILE_DATA_BIT) @@ -870,6 +872,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, #define CPUID_7_0_EDX_SERIALIZE (1U << 14) /* TSX Suspend Load Address Tracking instruction */ #define CPUID_7_0_EDX_TSX_LDTRK (1U << 16) +/* Architectural LBRs */ +#define CPUID_7_0_EDX_ARCH_LBR (1U << 19) /* AVX512_FP16 instruction */ #define CPUID_7_0_EDX_AVX512_FP16 (1U << 23) /* AMX tile (two-dimensional register) */ @@ -1376,6 +1380,24 @@ typedef struct XSaveXTILEDATA { uint8_t xtiledata[8][1024]; } XSaveXTILEDATA; +typedef struct { + uint64_t from; + uint64_t to; + uint64_t info; +} LBREntry; + +#define ARCH_LBR_NR_ENTRIES 32 + +/* Ext. save area 19: Supervisor mode Arch LBR state */ +typedef struct XSavesArchLBR { + uint64_t lbr_ctl; + uint64_t lbr_depth; + uint64_t ler_from; + uint64_t ler_to; + uint64_t ler_info; + LBREntry lbr_records[ARCH_LBR_NR_ENTRIES]; +} XSavesArchLBR; + QEMU_BUILD_BUG_ON(sizeof(XSaveAVX) != 0x100); QEMU_BUILD_BUG_ON(sizeof(XSaveBNDREG) != 0x40); QEMU_BUILD_BUG_ON(sizeof(XSaveBNDCSR) != 0x40); @@ -1385,6 +1407,7 @@ QEMU_BUILD_BUG_ON(sizeof(XSaveHi16_ZMM) != 0x400); QEMU_BUILD_BUG_ON(sizeof(XSavePKRU) != 0x8); QEMU_BUILD_BUG_ON(sizeof(XSaveXTILECFG) != 0x40); QEMU_BUILD_BUG_ON(sizeof(XSaveXTILEDATA) != 0x2000); +QEMU_BUILD_BUG_ON(sizeof(XSavesArchLBR) != 0x328); typedef struct ExtSaveArea { uint32_t feature, bits; From 12703d4e7523a7841764200e1a7838736495da10 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Tue, 15 Feb 2022 14:52:56 -0500 Subject: [PATCH 326/935] target/i386: Add MSR access interface for Arch LBR In the first generation of Arch LBR, the max support Arch LBR depth is 32, both host and guest use the value to set depth MSR. This can simplify the implementation of patch given the side-effect of mismatch of host/guest depth MSR: XRSTORS will reset all recording MSRs to 0s if the saved depth mismatches MSR_ARCH_LBR_DEPTH. In most of the cases Arch LBR is not in active status, so check the control bit before save/restore the big chunck of Arch LBR MSRs. Signed-off-by: Yang Weijiang Message-Id: <20220215195258.29149-7-weijiang.yang@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 10 +++++++ target/i386/kvm/kvm.c | 67 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index dba92936a2..0d528ac58f 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -391,6 +391,11 @@ typedef enum X86Seg { #define MSR_IA32_TSX_CTRL 0x122 #define MSR_IA32_TSCDEADLINE 0x6e0 #define MSR_IA32_PKRS 0x6e1 +#define MSR_ARCH_LBR_CTL 0x000014ce +#define MSR_ARCH_LBR_DEPTH 0x000014cf +#define MSR_ARCH_LBR_FROM_0 0x00001500 +#define MSR_ARCH_LBR_TO_0 0x00001600 +#define MSR_ARCH_LBR_INFO_0 0x00001200 #define FEATURE_CONTROL_LOCKED (1<<0) #define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX (1ULL << 1) @@ -1650,6 +1655,11 @@ typedef struct CPUArchState { uint64_t msr_xfd; uint64_t msr_xfd_err; + /* Per-VCPU Arch LBR MSRs */ + uint64_t msr_lbr_ctl; + uint64_t msr_lbr_depth; + LBREntry lbr_records[ARCH_LBR_NR_ENTRIES]; + /* exception/interrupt handling */ int error_code; int exception_is_int; diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 536cbe5fad..a9ee8eebd7 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -3367,6 +3367,38 @@ static int kvm_put_msrs(X86CPU *cpu, int level) env->msr_xfd_err); } + if (kvm_enabled() && cpu->enable_pmu && + (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR)) { + uint64_t depth; + int i, ret; + + /* + * Only migrate Arch LBR states when: 1) Arch LBR is enabled + * for migrated vcpu. 2) the host Arch LBR depth equals that + * of source guest's, this is to avoid mismatch of guest/host + * config for the msr hence avoid unexpected misbehavior. + */ + ret = kvm_get_one_msr(cpu, MSR_ARCH_LBR_DEPTH, &depth); + + if (ret == 1 && (env->msr_lbr_ctl & 0x1) && !!depth && + depth == env->msr_lbr_depth) { + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_CTL, env->msr_lbr_ctl); + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_DEPTH, env->msr_lbr_depth); + + for (i = 0; i < ARCH_LBR_NR_ENTRIES; i++) { + if (!env->lbr_records[i].from) { + continue; + } + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_FROM_0 + i, + env->lbr_records[i].from); + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_TO_0 + i, + env->lbr_records[i].to); + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_INFO_0 + i, + env->lbr_records[i].info); + } + } + } + /* Note: MSR_IA32_FEATURE_CONTROL is written separately, see * kvm_put_msr_feature_control. */ } @@ -3767,6 +3799,26 @@ static int kvm_get_msrs(X86CPU *cpu) kvm_msr_entry_add(cpu, MSR_IA32_XFD_ERR, 0); } + if (kvm_enabled() && cpu->enable_pmu && + (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR)) { + uint64_t ctl, depth; + int i, ret2; + + ret = kvm_get_one_msr(cpu, MSR_ARCH_LBR_CTL, &ctl); + ret2 = kvm_get_one_msr(cpu, MSR_ARCH_LBR_DEPTH, &depth); + if (ret == 1 && ret2 == 1 && (ctl & 0x1) && + depth == ARCH_LBR_NR_ENTRIES) { + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_CTL, 0); + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_DEPTH, 0); + + for (i = 0; i < ARCH_LBR_NR_ENTRIES; i++) { + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_FROM_0 + i, 0); + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_TO_0 + i, 0); + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_INFO_0 + i, 0); + } + } + } + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, cpu->kvm_msr_buf); if (ret < 0) { return ret; @@ -4072,6 +4124,21 @@ static int kvm_get_msrs(X86CPU *cpu) case MSR_IA32_XFD_ERR: env->msr_xfd_err = msrs[i].data; break; + case MSR_ARCH_LBR_CTL: + env->msr_lbr_ctl = msrs[i].data; + break; + case MSR_ARCH_LBR_DEPTH: + env->msr_lbr_depth = msrs[i].data; + break; + case MSR_ARCH_LBR_FROM_0 ... MSR_ARCH_LBR_FROM_0 + 31: + env->lbr_records[index - MSR_ARCH_LBR_FROM_0].from = msrs[i].data; + break; + case MSR_ARCH_LBR_TO_0 ... MSR_ARCH_LBR_TO_0 + 31: + env->lbr_records[index - MSR_ARCH_LBR_TO_0].to = msrs[i].data; + break; + case MSR_ARCH_LBR_INFO_0 ... MSR_ARCH_LBR_INFO_0 + 31: + env->lbr_records[index - MSR_ARCH_LBR_INFO_0].info = msrs[i].data; + break; } } From f2e7c2fc8945943699f745c405be82ac7e698275 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Tue, 15 Feb 2022 14:52:57 -0500 Subject: [PATCH 327/935] target/i386: Enable Arch LBR migration states in vmstate The Arch LBR record MSRs and control MSRs will be migrated to destination guest if the vcpus were running with Arch LBR active. Signed-off-by: Yang Weijiang Message-Id: <20220215195258.29149-8-weijiang.yang@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/machine.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/target/i386/machine.c b/target/i386/machine.c index 7c54bada81..cecd476e98 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -136,6 +136,22 @@ static const VMStateDescription vmstate_mtrr_var = { #define VMSTATE_MTRR_VARS(_field, _state, _n, _v) \ VMSTATE_STRUCT_ARRAY(_field, _state, _n, _v, vmstate_mtrr_var, MTRRVar) +static const VMStateDescription vmstate_lbr_records_var = { + .name = "lbr_records_var", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(from, LBREntry), + VMSTATE_UINT64(to, LBREntry), + VMSTATE_UINT64(info, LBREntry), + VMSTATE_END_OF_LIST() + } +}; + +#define VMSTATE_LBR_VARS(_field, _state, _n, _v) \ + VMSTATE_STRUCT_ARRAY(_field, _state, _n, _v, vmstate_lbr_records_var, \ + LBREntry) + typedef struct x86_FPReg_tmp { FPReg *parent; uint64_t tmp_mant; @@ -1525,6 +1541,27 @@ static const VMStateDescription vmstate_amx_xtile = { }; #endif +static bool arch_lbr_needed(void *opaque) +{ + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; + + return !!(env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR); +} + +static const VMStateDescription vmstate_arch_lbr = { + .name = "cpu/arch_lbr", + .version_id = 1, + .minimum_version_id = 1, + .needed = arch_lbr_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT64(env.msr_lbr_ctl, X86CPU), + VMSTATE_UINT64(env.msr_lbr_depth, X86CPU), + VMSTATE_LBR_VARS(env.lbr_records, X86CPU, ARCH_LBR_NR_ENTRIES, 1), + VMSTATE_END_OF_LIST() + } +}; + const VMStateDescription vmstate_x86_cpu = { .name = "cpu", .version_id = 12, @@ -1668,6 +1705,7 @@ const VMStateDescription vmstate_x86_cpu = { #ifdef TARGET_X86_64 &vmstate_amx_xtile, #endif + &vmstate_arch_lbr, NULL } }; From d19d6ffa07100f5015dc1c708d6c811354a13d7f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 29 Apr 2022 20:52:52 +0200 Subject: [PATCH 328/935] target/i386: introduce helper to access supported CPUID Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 1816c37852..dcc770ecea 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -4944,6 +4944,28 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, return r; } +static void x86_cpu_get_supported_cpuid(uint32_t func, uint32_t index, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + if (kvm_enabled()) { + *eax = kvm_arch_get_supported_cpuid(kvm_state, func, index, R_EAX); + *ebx = kvm_arch_get_supported_cpuid(kvm_state, func, index, R_EBX); + *ecx = kvm_arch_get_supported_cpuid(kvm_state, func, index, R_ECX); + *edx = kvm_arch_get_supported_cpuid(kvm_state, func, index, R_EDX); + } else if (hvf_enabled()) { + *eax = hvf_get_supported_cpuid(func, index, R_EAX); + *ebx = hvf_get_supported_cpuid(func, index, R_EBX); + *ecx = hvf_get_supported_cpuid(func, index, R_ECX); + *edx = hvf_get_supported_cpuid(func, index, R_EDX); + } else { + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; + } +} + static void x86_cpu_get_cache_cpuid(uint32_t func, uint32_t index, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) @@ -5359,18 +5381,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, break; case 0xA: /* Architectural Performance Monitoring Leaf */ - if (kvm_enabled() && cpu->enable_pmu) { - KVMState *s = cs->kvm_state; - - *eax = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EAX); - *ebx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EBX); - *ecx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_ECX); - *edx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EDX); - } else if (hvf_enabled() && cpu->enable_pmu) { - *eax = hvf_get_supported_cpuid(0xA, count, R_EAX); - *ebx = hvf_get_supported_cpuid(0xA, count, R_EBX); - *ecx = hvf_get_supported_cpuid(0xA, count, R_ECX); - *edx = hvf_get_supported_cpuid(0xA, count, R_EDX); + if (accel_uses_host_cpuid() && cpu->enable_pmu) { + x86_cpu_get_supported_cpuid(0xA, count, eax, ebx, ecx, edx); } else { *eax = 0; *ebx = 0; @@ -5521,10 +5533,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, * supports. Features can be further restricted by userspace, but not * made more permissive. */ - *eax = kvm_arch_get_supported_cpuid(cs->kvm_state, 0x12, count, R_EAX); - *ebx = kvm_arch_get_supported_cpuid(cs->kvm_state, 0x12, count, R_EBX); - *ecx = kvm_arch_get_supported_cpuid(cs->kvm_state, 0x12, count, R_ECX); - *edx = kvm_arch_get_supported_cpuid(cs->kvm_state, 0x12, count, R_EDX); + x86_cpu_get_supported_cpuid(0x12, index, eax, ebx, ecx, edx); if (count == 0) { *eax &= env->features[FEAT_SGX_12_0_EAX]; From c3c67679f65903b7d1fe25da8fc4e163878ab2b9 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Tue, 15 Feb 2022 14:52:58 -0500 Subject: [PATCH 329/935] target/i386: Support Arch LBR in CPUID enumeration If CPUID.(EAX=07H, ECX=0):EDX[19] is set to 1, the processor supports Architectural LBRs. In this case, CPUID leaf 01CH indicates details of the Architectural LBRs capabilities. XSAVE support for Architectural LBRs is enumerated in CPUID.(EAX=0DH, ECX=0FH). Signed-off-by: Yang Weijiang Message-Id: <20220215195258.29149-9-weijiang.yang@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index dcc770ecea..35c3475e6c 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -855,7 +855,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { "fsrm", NULL, NULL, NULL, "avx512-vp2intersect", NULL, "md-clear", NULL, NULL, NULL, "serialize", NULL, - "tsx-ldtrk", NULL, NULL /* pconfig */, NULL, + "tsx-ldtrk", NULL, NULL /* pconfig */, "arch-lbr", NULL, NULL, "amx-bf16", "avx512-fp16", "amx-tile", "amx-int8", "spec-ctrl", "stibp", NULL, "arch-capabilities", "core-capability", "ssbd", @@ -5420,6 +5420,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, assert(!(*eax & ~0x1f)); *ebx &= 0xffff; /* The count doesn't need to be reliable. */ break; + case 0x1C: + if (accel_uses_host_cpuid() && cpu->enable_pmu && + (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR)) { + x86_cpu_get_supported_cpuid(0x1C, 0, eax, ebx, ecx, edx); + *edx = 0; + } + break; case 0x1F: /* V2 Extended Topology Enumeration Leaf */ if (env->nr_dies < 2) { @@ -5482,6 +5489,17 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *ebx = xsave_area_size(xstate, true); *ecx = env->features[FEAT_XSAVE_XSS_LO]; *edx = env->features[FEAT_XSAVE_XSS_HI]; + if (kvm_enabled() && cpu->enable_pmu && + (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR) && + (*eax & CPUID_XSAVE_XSAVES)) { + *ecx |= XSTATE_ARCH_LBR_MASK; + } else { + *ecx &= ~XSTATE_ARCH_LBR_MASK; + } + } else if (count == 0xf && + accel_uses_host_cpuid() && cpu->enable_pmu && + (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR)) { + x86_cpu_get_supported_cpuid(0xD, count, eax, ebx, ecx, edx); } else if (count < ARRAY_SIZE(x86_ext_save_areas)) { const ExtSaveArea *esa = &x86_ext_save_areas[count]; From 0310641c06dd5f7ea031b2b6170cb2edc63e4cea Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 9 May 2022 11:42:23 +0200 Subject: [PATCH 330/935] crypto: make loaded property read-only The ``loaded=on`` option in the command line or QMP ``object-add`` either had no effect (if ``loaded`` was the last option) or caused options to be effectively ignored as if they were not given. The property is therefore useless and was deprecated in 6.0; make it read-only now. The patch is best reviewed with "-b". Signed-off-by: Paolo Bonzini --- crypto/secret_common.c | 84 ++++++++++++++------------------- crypto/tlscredsanon.c | 20 ++------ crypto/tlscredspsk.c | 20 ++------ crypto/tlscredsx509.c | 20 ++------ docs/about/deprecated.rst | 10 ---- docs/about/removed-features.rst | 9 ++++ 6 files changed, 56 insertions(+), 107 deletions(-) diff --git a/crypto/secret_common.c b/crypto/secret_common.c index 714a15d5e5..3441c44ca8 100644 --- a/crypto/secret_common.c +++ b/crypto/secret_common.c @@ -138,36 +138,44 @@ static void qcrypto_secret_decode(const uint8_t *input, static void -qcrypto_secret_prop_set_loaded(Object *obj, - bool value, - Error **errp) +qcrypto_secret_complete(UserCreatable *uc, Error **errp) { - QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); + QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(uc); QCryptoSecretCommonClass *sec_class - = QCRYPTO_SECRET_COMMON_GET_CLASS(obj); + = QCRYPTO_SECRET_COMMON_GET_CLASS(uc); - if (value) { - Error *local_err = NULL; - uint8_t *input = NULL; - size_t inputlen = 0; - uint8_t *output = NULL; - size_t outputlen = 0; + Error *local_err = NULL; + uint8_t *input = NULL; + size_t inputlen = 0; + uint8_t *output = NULL; + size_t outputlen = 0; - if (sec_class->load_data) { - sec_class->load_data(secret, &input, &inputlen, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - } else { - error_setg(errp, "%s provides no 'load_data' method'", - object_get_typename(obj)); + if (sec_class->load_data) { + sec_class->load_data(secret, &input, &inputlen, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } + } else { + error_setg(errp, "%s provides no 'load_data' method'", + object_get_typename(OBJECT(uc))); + return; + } - if (secret->keyid) { - qcrypto_secret_decrypt(secret, input, inputlen, - &output, &outputlen, &local_err); + if (secret->keyid) { + qcrypto_secret_decrypt(secret, input, inputlen, + &output, &outputlen, &local_err); + g_free(input); + if (local_err) { + error_propagate(errp, local_err); + return; + } + input = output; + inputlen = outputlen; + } else { + if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) { + qcrypto_secret_decode(input, inputlen, + &output, &outputlen, &local_err); g_free(input); if (local_err) { error_propagate(errp, local_err); @@ -175,26 +183,11 @@ qcrypto_secret_prop_set_loaded(Object *obj, } input = output; inputlen = outputlen; - } else { - if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) { - qcrypto_secret_decode(input, inputlen, - &output, &outputlen, &local_err); - g_free(input); - if (local_err) { - error_propagate(errp, local_err); - return; - } - input = output; - inputlen = outputlen; - } } - - secret->rawdata = input; - secret->rawlen = inputlen; - } else if (secret->rawdata) { - error_setg(errp, "Cannot unload secret"); - return; } + + secret->rawdata = input; + secret->rawlen = inputlen; } @@ -268,13 +261,6 @@ qcrypto_secret_prop_get_keyid(Object *obj, } -static void -qcrypto_secret_complete(UserCreatable *uc, Error **errp) -{ - object_property_set_bool(OBJECT(uc), "loaded", true, errp); -} - - static void qcrypto_secret_finalize(Object *obj) { @@ -294,7 +280,7 @@ qcrypto_secret_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "loaded", qcrypto_secret_prop_get_loaded, - qcrypto_secret_prop_set_loaded); + NULL); object_class_property_add_enum(oc, "format", "QCryptoSecretFormat", &QCryptoSecretFormat_lookup, diff --git a/crypto/tlscredsanon.c b/crypto/tlscredsanon.c index 6fb83639ec..c0d23a0ef3 100644 --- a/crypto/tlscredsanon.c +++ b/crypto/tlscredsanon.c @@ -119,16 +119,11 @@ qcrypto_tls_creds_anon_unload(QCryptoTLSCredsAnon *creds G_GNUC_UNUSED) static void -qcrypto_tls_creds_anon_prop_set_loaded(Object *obj, - bool value, - Error **errp) +qcrypto_tls_creds_anon_complete(UserCreatable *uc, Error **errp) { - QCryptoTLSCredsAnon *creds = QCRYPTO_TLS_CREDS_ANON(obj); + QCryptoTLSCredsAnon *creds = QCRYPTO_TLS_CREDS_ANON(uc); - qcrypto_tls_creds_anon_unload(creds); - if (value) { - qcrypto_tls_creds_anon_load(creds, errp); - } + qcrypto_tls_creds_anon_load(creds, errp); } @@ -163,13 +158,6 @@ qcrypto_tls_creds_anon_prop_get_loaded(Object *obj G_GNUC_UNUSED, #endif /* ! CONFIG_GNUTLS */ -static void -qcrypto_tls_creds_anon_complete(UserCreatable *uc, Error **errp) -{ - object_property_set_bool(OBJECT(uc), "loaded", true, errp); -} - - static void qcrypto_tls_creds_anon_finalize(Object *obj) { @@ -188,7 +176,7 @@ qcrypto_tls_creds_anon_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "loaded", qcrypto_tls_creds_anon_prop_get_loaded, - qcrypto_tls_creds_anon_prop_set_loaded); + NULL); } diff --git a/crypto/tlscredspsk.c b/crypto/tlscredspsk.c index 752f2d92be..a4f9891274 100644 --- a/crypto/tlscredspsk.c +++ b/crypto/tlscredspsk.c @@ -188,16 +188,11 @@ qcrypto_tls_creds_psk_unload(QCryptoTLSCredsPSK *creds G_GNUC_UNUSED) static void -qcrypto_tls_creds_psk_prop_set_loaded(Object *obj, - bool value, - Error **errp) +qcrypto_tls_creds_psk_complete(UserCreatable *uc, Error **errp) { - QCryptoTLSCredsPSK *creds = QCRYPTO_TLS_CREDS_PSK(obj); + QCryptoTLSCredsPSK *creds = QCRYPTO_TLS_CREDS_PSK(uc); - qcrypto_tls_creds_psk_unload(creds); - if (value) { - qcrypto_tls_creds_psk_load(creds, errp); - } + qcrypto_tls_creds_psk_load(creds, errp); } @@ -232,13 +227,6 @@ qcrypto_tls_creds_psk_prop_get_loaded(Object *obj G_GNUC_UNUSED, #endif /* ! CONFIG_GNUTLS */ -static void -qcrypto_tls_creds_psk_complete(UserCreatable *uc, Error **errp) -{ - object_property_set_bool(OBJECT(uc), "loaded", true, errp); -} - - static void qcrypto_tls_creds_psk_finalize(Object *obj) { @@ -276,7 +264,7 @@ qcrypto_tls_creds_psk_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "loaded", qcrypto_tls_creds_psk_prop_get_loaded, - qcrypto_tls_creds_psk_prop_set_loaded); + NULL); object_class_property_add_str(oc, "username", qcrypto_tls_creds_psk_prop_get_username, qcrypto_tls_creds_psk_prop_set_username); diff --git a/crypto/tlscredsx509.c b/crypto/tlscredsx509.c index 32948a6bdc..d14313925d 100644 --- a/crypto/tlscredsx509.c +++ b/crypto/tlscredsx509.c @@ -687,16 +687,11 @@ qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED) static void -qcrypto_tls_creds_x509_prop_set_loaded(Object *obj, - bool value, - Error **errp) +qcrypto_tls_creds_x509_complete(UserCreatable *uc, Error **errp) { - QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); + QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(uc); - qcrypto_tls_creds_x509_unload(creds); - if (value) { - qcrypto_tls_creds_x509_load(creds, errp); - } + qcrypto_tls_creds_x509_load(creds, errp); } @@ -814,13 +809,6 @@ qcrypto_tls_creds_x509_reload(QCryptoTLSCreds *creds, Error **errp) #endif /* ! CONFIG_GNUTLS */ -static void -qcrypto_tls_creds_x509_complete(UserCreatable *uc, Error **errp) -{ - object_property_set_bool(OBJECT(uc), "loaded", true, errp); -} - - static void qcrypto_tls_creds_x509_init(Object *obj) { @@ -852,7 +840,7 @@ qcrypto_tls_creds_x509_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "loaded", qcrypto_tls_creds_x509_prop_get_loaded, - qcrypto_tls_creds_x509_prop_set_loaded); + NULL); object_class_property_add_bool(oc, "sanity-check", qcrypto_tls_creds_x509_prop_get_sanity, qcrypto_tls_creds_x509_prop_set_sanity); diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 44f52c172d..2a022f2300 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -99,16 +99,6 @@ other options have been processed. This will either have no effect (if ``opened`` was the last option) or cause errors. The property is therefore useless and should not be specified. -``loaded`` property of ``secret`` and ``secret_keyring`` objects (since 6.0) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -The only effect of specifying ``loaded=on`` in the command line or QMP -``object-add`` is that the secret is loaded immediately, possibly before all -other options have been processed. This will either have no effect (if -``loaded`` was the last option) or cause options to be effectively ignored as -if they were not given. The property is therefore useless and should not be -specified. - ``-display sdl,window_close=...`` (since 6.1) ''''''''''''''''''''''''''''''''''''''''''''' diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index ba78bc1a19..81ceeb9000 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -355,6 +355,15 @@ The ``-writeconfig`` option was not able to serialize the entire contents of the QEMU command line. It is thus considered a failed experiment and removed without a replacement. +``loaded`` property of ``secret`` and ``secret_keyring`` objects (removed in 7.1) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The ``loaded=on`` option in the command line or QMP ``object-add`` either had +no effect (if ``loaded`` was the last option) or caused options to be +effectively ignored as if they were not given. The property is therefore +useless and should simply be removed. + + QEMU Machine Protocol (QMP) commands ------------------------------------ From 6e577937485080f2dcebc6a3e5a4a9e8db841762 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 9 May 2022 11:46:03 +0200 Subject: [PATCH 331/935] rng: make opened property read-only The ``opened=on`` option in the command line or QMP ``object-add`` either had no effect (if ``opened`` was the last option) or caused errors. The property is therefore useless and was deprecated in 6.0; make it read-only now. Signed-off-by: Paolo Bonzini --- backends/rng.c | 18 ++---------------- docs/about/deprecated.rst | 9 --------- docs/about/removed-features.rst | 6 ++++++ 3 files changed, 8 insertions(+), 25 deletions(-) diff --git a/backends/rng.c b/backends/rng.c index 3757b04485..6c7bf64426 100644 --- a/backends/rng.c +++ b/backends/rng.c @@ -48,24 +48,10 @@ static bool rng_backend_prop_get_opened(Object *obj, Error **errp) static void rng_backend_complete(UserCreatable *uc, Error **errp) { - object_property_set_bool(OBJECT(uc), "opened", true, errp); -} - -static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp) -{ - RngBackend *s = RNG_BACKEND(obj); + RngBackend *s = RNG_BACKEND(uc); RngBackendClass *k = RNG_BACKEND_GET_CLASS(s); Error *local_err = NULL; - if (value == s->opened) { - return; - } - - if (!value && s->opened) { - error_setg(errp, QERR_PERMISSION_DENIED); - return; - } - if (k->opened) { k->opened(s, &local_err); if (local_err) { @@ -122,7 +108,7 @@ static void rng_backend_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "opened", rng_backend_prop_get_opened, - rng_backend_prop_set_opened); + NULL); } static const TypeInfo rng_backend_info = { diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 2a022f2300..1f961b9e6e 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -90,15 +90,6 @@ the process listing. This is replaced by the new ``password-secret`` option which lets the password be securely provided on the command line using a ``secret`` object instance. -``opened`` property of ``rng-*`` objects (since 6.0) -'''''''''''''''''''''''''''''''''''''''''''''''''''' - -The only effect of specifying ``opened=on`` in the command line or QMP -``object-add`` is that the device is opened immediately, possibly before all -other options have been processed. This will either have no effect (if -``opened`` was the last option) or cause errors. The property is therefore -useless and should not be specified. - ``-display sdl,window_close=...`` (since 6.1) ''''''''''''''''''''''''''''''''''''''''''''' diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 81ceeb9000..69498efd51 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -363,6 +363,12 @@ no effect (if ``loaded`` was the last option) or caused options to be effectively ignored as if they were not given. The property is therefore useless and should simply be removed. +``opened`` property of ``rng-*`` objects (removed in 7.1) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The ``opened=on`` option in the command line or QMP ``object-add`` either had +no effect (if ``opened`` was the last option) or caused errors. The property +is therefore useless and should simply be removed. QEMU Machine Protocol (QMP) commands ------------------------------------ From 9c50b8aae2b411b253edaee77d76d297e5fa2fab Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 27 Apr 2022 12:04:47 +0200 Subject: [PATCH 332/935] soundhw: remove ability to create multiple soundcards The usefulness of enabling a dozen soundcards is dubious. Simplify the code by allowing a single instance of -soundhw, with no support for parsing either comma-separated values or 'soundhw all'. Signed-off-by: Paolo Bonzini --- hw/audio/soundhw.c | 88 +++++++++++++++++----------------------------- 1 file changed, 32 insertions(+), 56 deletions(-) diff --git a/hw/audio/soundhw.c b/hw/audio/soundhw.c index f7d94d7dfa..097501fee1 100644 --- a/hw/audio/soundhw.c +++ b/hw/audio/soundhw.c @@ -25,6 +25,7 @@ #include "qemu/option.h" #include "qemu/help_option.h" #include "qemu/error-report.h" +#include "qapi/error.h" #include "qom/object.h" #include "hw/isa/isa.h" #include "hw/pci/pci.h" @@ -34,7 +35,6 @@ struct soundhw { const char *name; const char *descr; const char *typename; - int enabled; int isa; int (*init_pci) (PCIBus *bus); }; @@ -64,10 +64,16 @@ void deprecated_register_soundhw(const char *name, const char *descr, soundhw_count++; } +static struct soundhw *selected = NULL; + void select_soundhw(const char *optarg) { struct soundhw *c; + if (selected) { + error_setg(&error_fatal, "only one -soundhw option is allowed"); + } + if (is_help_option(optarg)) { show_valid_cards: @@ -84,44 +90,15 @@ void select_soundhw(const char *optarg) exit(!is_help_option(optarg)); } else { - size_t l; - const char *p; - char *e; - int bad_card = 0; - - if (!strcmp(optarg, "all")) { - for (c = soundhw; c->name; ++c) { - c->enabled = 1; + for (c = soundhw; c->name; ++c) { + if (g_str_equal(c->name, optarg)) { + selected = c; + break; } - return; } - p = optarg; - while (*p) { - e = strchr(p, ','); - l = !e ? strlen(p) : (size_t) (e - p); - - for (c = soundhw; c->name; ++c) { - if (!strncmp(c->name, p, l) && !c->name[l]) { - c->enabled = 1; - break; - } - } - - if (!c->name) { - if (l > 80) { - error_report("Unknown sound card name (too big to show)"); - } - else { - error_report("Unknown sound card name `%.*s'", - (int) l, p); - } - bad_card = 1; - } - p += l + (e != NULL); - } - - if (bad_card) { + if (!c->name) { + error_report("Unknown sound card name `%s'", optarg); goto show_valid_cards; } } @@ -129,30 +106,29 @@ void select_soundhw(const char *optarg) void soundhw_init(void) { - struct soundhw *c; + struct soundhw *c = selected; ISABus *isa_bus = (ISABus *) object_resolve_path_type("", TYPE_ISA_BUS, NULL); PCIBus *pci_bus = (PCIBus *) object_resolve_path_type("", TYPE_PCI_BUS, NULL); - for (c = soundhw; c->name; ++c) { - if (c->enabled) { - if (c->typename) { - warn_report("'-soundhw %s' is deprecated, " - "please use '-device %s' instead", - c->name, c->typename); - if (c->isa) { - isa_create_simple(isa_bus, c->typename); - } else { - pci_create_simple(pci_bus, -1, c->typename); - } - } else { - assert(!c->isa); - if (!pci_bus) { - error_report("PCI bus not available for %s", c->name); - exit(1); - } - c->init_pci(pci_bus); - } + if (!c) { + return; + } + if (c->typename) { + warn_report("'-soundhw %s' is deprecated, " + "please use '-device %s' instead", + c->name, c->typename); + if (c->isa) { + isa_create_simple(isa_bus, c->typename); + } else { + pci_create_simple(pci_bus, -1, c->typename); } + } else { + assert(!c->isa); + if (!pci_bus) { + error_report("PCI bus not available for %s", c->name); + exit(1); + } + c->init_pci(pci_bus); } } From eef5fdf3d57dccc25505179f717adf636764ba02 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 27 Apr 2022 12:26:48 +0200 Subject: [PATCH 333/935] soundhw: extract soundhw help to a separate function Signed-off-by: Paolo Bonzini --- hw/audio/soundhw.c | 33 +++++++++++++++++++-------------- include/hw/audio/soundhw.h | 1 + 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/hw/audio/soundhw.c b/hw/audio/soundhw.c index 097501fee1..0fb64bdc8f 100644 --- a/hw/audio/soundhw.c +++ b/hw/audio/soundhw.c @@ -64,6 +64,21 @@ void deprecated_register_soundhw(const char *name, const char *descr, soundhw_count++; } +void show_valid_soundhw(void) +{ + struct soundhw *c; + + if (soundhw_count) { + printf("Valid sound card names (comma separated):\n"); + for (c = soundhw; c->name; ++c) { + printf ("%-11s %s\n", c->name, c->descr); + } + } else { + printf("Machine has no user-selectable audio hardware " + "(it may or may not have always-present audio hardware).\n"); + } +} + static struct soundhw *selected = NULL; void select_soundhw(const char *optarg) @@ -75,19 +90,8 @@ void select_soundhw(const char *optarg) } if (is_help_option(optarg)) { - show_valid_cards: - - if (soundhw_count) { - printf("Valid sound card names (comma separated):\n"); - for (c = soundhw; c->name; ++c) { - printf ("%-11s %s\n", c->name, c->descr); - } - printf("\n-soundhw all will enable all of the above\n"); - } else { - printf("Machine has no user-selectable audio hardware " - "(it may or may not have always-present audio hardware).\n"); - } - exit(!is_help_option(optarg)); + show_valid_soundhw(); + exit(0); } else { for (c = soundhw; c->name; ++c) { @@ -99,7 +103,8 @@ void select_soundhw(const char *optarg) if (!c->name) { error_report("Unknown sound card name `%s'", optarg); - goto show_valid_cards; + show_valid_soundhw(); + exit(1); } } } diff --git a/include/hw/audio/soundhw.h b/include/hw/audio/soundhw.h index e68685fcda..dec5c0cdca 100644 --- a/include/hw/audio/soundhw.h +++ b/include/hw/audio/soundhw.h @@ -7,6 +7,7 @@ void deprecated_register_soundhw(const char *name, const char *descr, int isa, const char *typename); void soundhw_init(void); +void show_valid_soundhw(void); void select_soundhw(const char *optarg); #endif From bf521c5655f7f821603d921e6de77e4e05fa44b9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 27 Apr 2022 12:06:59 +0200 Subject: [PATCH 334/935] soundhw: unify initialization for ISA and PCI soundhw Use qdev_new instead of distinguishing isa_create_simple/pci_create_simple. Signed-off-by: Paolo Bonzini --- hw/audio/soundhw.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/hw/audio/soundhw.c b/hw/audio/soundhw.c index 0fb64bdc8f..a1558dab3a 100644 --- a/hw/audio/soundhw.c +++ b/hw/audio/soundhw.c @@ -114,25 +114,30 @@ void soundhw_init(void) struct soundhw *c = selected; ISABus *isa_bus = (ISABus *) object_resolve_path_type("", TYPE_ISA_BUS, NULL); PCIBus *pci_bus = (PCIBus *) object_resolve_path_type("", TYPE_PCI_BUS, NULL); + BusState *bus; if (!c) { return; } - if (c->typename) { - warn_report("'-soundhw %s' is deprecated, " - "please use '-device %s' instead", - c->name, c->typename); - if (c->isa) { - isa_create_simple(isa_bus, c->typename); - } else { - pci_create_simple(pci_bus, -1, c->typename); + if (c->isa) { + if (!isa_bus) { + error_report("ISA bus not available for %s", c->name); + exit(1); } + bus = BUS(isa_bus); } else { - assert(!c->isa); if (!pci_bus) { error_report("PCI bus not available for %s", c->name); exit(1); } + bus = BUS(pci_bus); + } + + if (c->typename) { + DeviceState *dev = qdev_new(c->typename); + qdev_realize_and_unref(dev, bus, &error_fatal); + } else { + assert(!c->isa); c->init_pci(pci_bus); } } From 67aaa96ae451913ffd25766dc59341fe6b63619d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 27 Apr 2022 13:15:23 +0200 Subject: [PATCH 335/935] soundhw: move help handling to vl.c This will allow processing "-audio model=help" even if the backend part of the option is missing. Signed-off-by: Paolo Bonzini --- hw/audio/soundhw.c | 24 +++++++++--------------- softmmu/vl.c | 4 ++++ 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/hw/audio/soundhw.c b/hw/audio/soundhw.c index a1558dab3a..ebbd0958ba 100644 --- a/hw/audio/soundhw.c +++ b/hw/audio/soundhw.c @@ -89,23 +89,17 @@ void select_soundhw(const char *optarg) error_setg(&error_fatal, "only one -soundhw option is allowed"); } - if (is_help_option(optarg)) { - show_valid_soundhw(); - exit(0); + for (c = soundhw; c->name; ++c) { + if (g_str_equal(c->name, optarg)) { + selected = c; + break; + } } - else { - for (c = soundhw; c->name; ++c) { - if (g_str_equal(c->name, optarg)) { - selected = c; - break; - } - } - if (!c->name) { - error_report("Unknown sound card name `%s'", optarg); - show_valid_soundhw(); - exit(1); - } + if (!c->name) { + error_report("Unknown sound card name `%s'", optarg); + show_valid_soundhw(); + exit(1); } } diff --git a/softmmu/vl.c b/softmmu/vl.c index 817d515783..0363cbd9b4 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2931,6 +2931,10 @@ void qemu_init(int argc, char **argv, char **envp) audio_parse_option(optarg); break; case QEMU_OPTION_soundhw: + if (is_help_option(optarg)) { + show_valid_soundhw(); + exit(0); + } select_soundhw (optarg); break; case QEMU_OPTION_h: From 039a68373c4544ff94871f945a733928b6dcfe93 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 27 Apr 2022 12:27:46 +0200 Subject: [PATCH 336/935] introduce -audio as a replacement for -soundhw -audio is used like "-audio pa,model=sb16". It is almost as simple as -soundhw, but it reuses the -audiodev parsing machinery and attaches an audiodev to the newly-created device. The main 'feature' is that it knows about adding the codec device for model=intel-hda, and adding the audiodev to the codec device. In the future, it could be extended to support default models or builtin devices, just like -nic, or even a default backend. For now, keep it simple. Signed-off-by: Paolo Bonzini --- audio/audio.c | 8 +++++- audio/audio.h | 1 + docs/about/deprecated.rst | 9 ------ docs/about/removed-features.rst | 7 +++++ hw/audio/intel-hda.c | 5 ++-- hw/audio/soundhw.c | 12 +++++--- include/hw/audio/soundhw.h | 4 +-- qemu-options.hx | 51 ++++++++++++++++----------------- softmmu/vl.c | 28 ++++++++++++++++-- 9 files changed, 76 insertions(+), 49 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 9e91a5a4f2..a02f3ce5c6 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -2099,13 +2099,19 @@ static void audio_validate_opts(Audiodev *dev, Error **errp) void audio_parse_option(const char *opt) { - AudiodevListEntry *e; Audiodev *dev = NULL; Visitor *v = qobject_input_visitor_new_str(opt, "driver", &error_fatal); visit_type_Audiodev(v, NULL, &dev, &error_fatal); visit_free(v); + audio_define(dev); +} + +void audio_define(Audiodev *dev) +{ + AudiodevListEntry *e; + audio_validate_opts(dev, &error_fatal); e = g_new0(AudiodevListEntry, 1); diff --git a/audio/audio.h b/audio/audio.h index 3d5ecdecd5..b5e17cd218 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -168,6 +168,7 @@ void audio_sample_to_uint64(const void *samples, int pos, void audio_sample_from_uint64(void *samples, int pos, uint64_t left, uint64_t right); +void audio_define(Audiodev *audio); void audio_parse_option(const char *opt); void audio_init_audiodevs(void); void audio_legacy_help(void); diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 1f961b9e6e..a92ae0f162 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -39,15 +39,6 @@ should specify an ``audiodev=`` property. Additionally, when using vnc, you should specify an ``audiodev=`` property if you plan to transmit audio through the VNC protocol. -Creating sound card devices using ``-soundhw`` (since 5.1) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -Sound card devices should be created using ``-device`` instead. The -names are the same for most devices. The exceptions are ``hda`` which -needs two devices (``-device intel-hda -device hda-duplex``) and -``pcspk`` which can be activated using ``-machine -pcspk-audiodev=``. - ``-chardev`` backend aliases ``tty`` and ``parport`` (since 6.0) '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 69498efd51..eb76974347 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -654,6 +654,13 @@ tripped up the CI testing and was suspected to be quite broken. For that reason the maintainers strongly suspected no one actually used it. +Creating sound card devices using ``-soundhw`` (removed in 7.1) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Sound card devices should be created using ``-device`` or ``-audio``. +The exception is ``pcspk`` which can be activated using ``-machine +pcspk-audiodev=``. + TCG introspection features -------------------------- diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index bc77e3d8c9..f38117057b 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -1311,17 +1311,16 @@ static const TypeInfo hda_codec_device_type_info = { * create intel hda controller with codec attached to it, * so '-soundhw hda' works. */ -static int intel_hda_and_codec_init(PCIBus *bus) +static int intel_hda_and_codec_init(PCIBus *bus, const char *audiodev) { DeviceState *controller; BusState *hdabus; DeviceState *codec; - warn_report("'-soundhw hda' is deprecated, " - "please use '-device intel-hda -device hda-duplex' instead"); controller = DEVICE(pci_create_simple(bus, -1, "intel-hda")); hdabus = QLIST_FIRST(&controller->child_bus); codec = qdev_new("hda-duplex"); + qdev_prop_set_string(codec, "audiodev", audiodev); qdev_realize_and_unref(codec, hdabus, &error_fatal); return 0; } diff --git a/hw/audio/soundhw.c b/hw/audio/soundhw.c index ebbd0958ba..94d9463e42 100644 --- a/hw/audio/soundhw.c +++ b/hw/audio/soundhw.c @@ -27,6 +27,7 @@ #include "qemu/error-report.h" #include "qapi/error.h" #include "qom/object.h" +#include "hw/qdev-properties.h" #include "hw/isa/isa.h" #include "hw/pci/pci.h" #include "hw/audio/soundhw.h" @@ -36,14 +37,14 @@ struct soundhw { const char *descr; const char *typename; int isa; - int (*init_pci) (PCIBus *bus); + int (*init_pci) (PCIBus *bus, const char *audiodev); }; static struct soundhw soundhw[9]; static int soundhw_count; void pci_register_soundhw(const char *name, const char *descr, - int (*init_pci)(PCIBus *bus)) + int (*init_pci)(PCIBus *bus, const char *audiodev)) { assert(soundhw_count < ARRAY_SIZE(soundhw) - 1); soundhw[soundhw_count].name = name; @@ -80,8 +81,9 @@ void show_valid_soundhw(void) } static struct soundhw *selected = NULL; +static const char *audiodev_id; -void select_soundhw(const char *optarg) +void select_soundhw(const char *optarg, const char *audiodev) { struct soundhw *c; @@ -92,6 +94,7 @@ void select_soundhw(const char *optarg) for (c = soundhw; c->name; ++c) { if (g_str_equal(c->name, optarg)) { selected = c; + audiodev_id = audiodev; break; } } @@ -129,10 +132,11 @@ void soundhw_init(void) if (c->typename) { DeviceState *dev = qdev_new(c->typename); + qdev_prop_set_string(dev, "audiodev", audiodev_id); qdev_realize_and_unref(dev, bus, &error_fatal); } else { assert(!c->isa); - c->init_pci(pci_bus); + c->init_pci(pci_bus, audiodev_id); } } diff --git a/include/hw/audio/soundhw.h b/include/hw/audio/soundhw.h index dec5c0cdca..270717a06a 100644 --- a/include/hw/audio/soundhw.h +++ b/include/hw/audio/soundhw.h @@ -2,12 +2,12 @@ #define HW_SOUNDHW_H void pci_register_soundhw(const char *name, const char *descr, - int (*init_pci)(PCIBus *bus)); + int (*init_pci)(PCIBus *bus, const char *audiodev)); void deprecated_register_soundhw(const char *name, const char *descr, int isa, const char *typename); void soundhw_init(void); void show_valid_soundhw(void); -void select_soundhw(const char *optarg); +void select_soundhw(const char *optarg, const char *audiodev); #endif diff --git a/qemu-options.hx b/qemu-options.hx index 796229c433..60d2d728d6 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -661,6 +661,30 @@ SRST (deprecated) environment variables. ERST +DEF("audio", HAS_ARG, QEMU_OPTION_audio, + "-audio [driver=]driver,model=value[,prop[=value][,...]]\n" + " specifies the audio backend and device to use;\n" + " apart from 'model', options are the same as for -audiodev.\n" + " use '-audio model=help' to show possible devices.\n", + QEMU_ARCH_ALL) +SRST +``-audio [driver=]driver,model=value[,prop[=value][,...]]`` + This option is a shortcut for configuring both the guest audio + hardware and the host audio backend in one go. + The host backend options are the same as with the corresponding + ``-audiodev`` options below. The guest hardware model can be set with + ``model=modelname``. Use ``model=help`` to list the available device + types. + + The following two example do exactly the same, to show how ``-audio`` + can be used to shorten the command line length: + + .. parsed-literal:: + + |qemu_system| -audiodev pa,id=pa -device sb16,audiodev=pa + |qemu_system| -audio pa,model=sb16 +ERST + DEF("audiodev", HAS_ARG, QEMU_OPTION_audiodev, "-audiodev [driver=]driver,id=id[,prop[=value][,...]]\n" " specifies the audio backend to use\n" @@ -892,33 +916,6 @@ SRST ``qemu.wav``. ERST -DEF("soundhw", HAS_ARG, QEMU_OPTION_soundhw, - "-soundhw c1,... enable audio support\n" - " and only specified sound cards (comma separated list)\n" - " use '-soundhw help' to get the list of supported cards\n" - " use '-soundhw all' to enable all of them\n", QEMU_ARCH_ALL) -SRST -``-soundhw card1[,card2,...] or -soundhw all`` - Enable audio and selected sound hardware. Use 'help' to print all - available sound hardware. For example: - - .. parsed-literal:: - - |qemu_system_x86| -soundhw sb16,adlib disk.img - |qemu_system_x86| -soundhw es1370 disk.img - |qemu_system_x86| -soundhw ac97 disk.img - |qemu_system_x86| -soundhw hda disk.img - |qemu_system_x86| -soundhw all disk.img - |qemu_system_x86| -soundhw help - - Note that Linux's i810\_audio OSS kernel (for AC97) module might - require manually specifying clocking. - - :: - - modprobe i810_audio clocking=48000 -ERST - DEF("device", HAS_ARG, QEMU_OPTION_device, "-device driver[,prop[=value][,...]]\n" " add device (based on driver)\n" diff --git a/softmmu/vl.c b/softmmu/vl.c index 0363cbd9b4..219b23a573 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -116,6 +116,8 @@ #include "crypto/init.h" #include "sysemu/replay.h" #include "qapi/qapi-events-run-state.h" +#include "qapi/qapi-types-audio.h" +#include "qapi/qapi-visit-audio.h" #include "qapi/qapi-visit-block-core.h" #include "qapi/qapi-visit-compat.h" #include "qapi/qapi-visit-ui.h" @@ -2930,13 +2932,33 @@ void qemu_init(int argc, char **argv, char **envp) case QEMU_OPTION_audiodev: audio_parse_option(optarg); break; - case QEMU_OPTION_soundhw: - if (is_help_option(optarg)) { + case QEMU_OPTION_audio: { + QDict *dict = keyval_parse(optarg, "driver", NULL, &error_fatal); + char *model; + Audiodev *dev = NULL; + Visitor *v; + + if (!qdict_haskey(dict, "id")) { + qdict_put_str(dict, "id", "audiodev0"); + } + if (!qdict_haskey(dict, "model")) { + error_setg(&error_fatal, "Parameter 'model' is missing"); + } + model = g_strdup(qdict_get_str(dict, "model")); + qdict_del(dict, "model"); + if (is_help_option(model)) { show_valid_soundhw(); exit(0); } - select_soundhw (optarg); + v = qobject_input_visitor_new_keyval(QOBJECT(dict)); + qobject_unref(dict); + visit_type_Audiodev(v, NULL, &dev, &error_fatal); + visit_free(v); + audio_define(dev); + select_soundhw(model, dev->id); + g_free(model); break; + } case QEMU_OPTION_h: help(0); break; From 40b3ea76425435ee18395d619e4b3f8f652e25b0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 13 May 2022 18:06:29 +0200 Subject: [PATCH 337/935] build: remove useless dependency qemu-plugins.symbols is now processed in Meson. Signed-off-by: Paolo Bonzini --- Makefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/Makefile b/Makefile index e5fd1ebdf6..b842dbccdb 100644 --- a/Makefile +++ b/Makefile @@ -165,10 +165,7 @@ ifneq ($(filter $(ninja-targets), $(ninja-cmd-goals)),) endif endif -# Force configure to re-run if the API symbols are updated ifeq ($(CONFIG_PLUGIN),y) -config-host.mak: $(SRC_PATH)/plugins/qemu-plugins.symbols - .PHONY: plugins plugins: $(call quiet-command,\ From 008f6f20a544cbffe6152aacb69b2774978b49e0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 13 May 2022 18:06:37 +0200 Subject: [PATCH 338/935] configure: remove another dead variable Signed-off-by: Paolo Bonzini --- configure | 1 - 1 file changed, 1 deletion(-) diff --git a/configure b/configure index c8b5b99532..dda25f05bf 100755 --- a/configure +++ b/configure @@ -1992,7 +1992,6 @@ fi if test "$static" = "yes" ; then echo "CONFIG_STATIC=y" >> $config_host_mak fi -qemu_version=$(head $source_path/VERSION) echo "SRC_PATH=$source_path" >> $config_host_mak echo "TARGET_DIRS=$target_list" >> $config_host_mak if test "$modules" = "yes"; then From 8eccdb9eb84615291faef1257d5779ebfef7a0d0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 13 May 2022 11:37:57 +0200 Subject: [PATCH 339/935] configure: remove duplicate help messages These messages are already emitted by scripts/meson-parse-buildoptions.sh. Signed-off-by: Paolo Bonzini --- configure | 4 ---- 1 file changed, 4 deletions(-) diff --git a/configure b/configure index dda25f05bf..0cc8c876f7 100755 --- a/configure +++ b/configure @@ -1043,10 +1043,6 @@ Advanced options (experts only): --enable-tsan enable thread sanitizer --disable-werror disable compilation abort on warning --disable-stack-protector disable compiler-provided stack protection - --audio-drv-list=LIST set audio drivers to try if -audiodev is not used - --block-drv-whitelist=L Same as --block-drv-rw-whitelist=L - --with-trace-file=NAME Full PATH,NAME of file to store traces - Default:trace- --cpu=CPU Build for host CPU [$cpu] --with-coroutine=BACKEND coroutine backend. Supported options: ucontext, sigaltstack, windows From 777784bda46847fc0587d711c3aacff8fff3c3f9 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 3 May 2022 01:20:56 +0200 Subject: [PATCH 340/935] hw/openrisc: support 4 serial ports in or1ksim The 8250 serial controller supports 4 serial ports, so wire them all up, so that we can have more than one basic I/O channel. Cc: Stafford Horne Signed-off-by: Jason A. Donenfeld [smh:Fixup indentation and lines over 80 chars] Signed-off-by: Stafford Horne --- hw/openrisc/openrisc_sim.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 99b14940f4..6873124f74 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -71,6 +71,10 @@ enum { OR1KSIM_ETHOC_IRQ = 4, }; +enum { + OR1KSIM_UART_COUNT = 4 +}; + static const struct MemmapEntry { hwaddr base; hwaddr size; @@ -239,11 +243,13 @@ static void openrisc_sim_ompic_init(Or1ksimState *state, hwaddr base, static void openrisc_sim_serial_init(Or1ksimState *state, hwaddr base, hwaddr size, int num_cpus, - OpenRISCCPU *cpus[], int irq_pin) + OpenRISCCPU *cpus[], int irq_pin, + int uart_idx) { void *fdt = state->fdt; char *nodename; qemu_irq serial_irq; + char alias[sizeof("uart0")]; int i; if (num_cpus > 1) { @@ -258,7 +264,8 @@ static void openrisc_sim_serial_init(Or1ksimState *state, hwaddr base, serial_irq = get_cpu_irq(cpus, 0, irq_pin); } serial_mm_init(get_system_memory(), base, 0, serial_irq, 115200, - serial_hd(0), DEVICE_NATIVE_ENDIAN); + serial_hd(OR1KSIM_UART_COUNT - uart_idx - 1), + DEVICE_NATIVE_ENDIAN); /* Add device tree node for serial. */ nodename = g_strdup_printf("/serial@%" HWADDR_PRIx, base); @@ -271,7 +278,8 @@ static void openrisc_sim_serial_init(Or1ksimState *state, hwaddr base, /* The /chosen node is created during fdt creation. */ qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename); - qemu_fdt_setprop_string(fdt, "/aliases", "uart0", nodename); + snprintf(alias, sizeof(alias), "uart%d", uart_idx); + qemu_fdt_setprop_string(fdt, "/aliases", alias, nodename); g_free(nodename); } @@ -414,9 +422,11 @@ static void openrisc_sim_init(MachineState *machine) smp_cpus, cpus, OR1KSIM_OMPIC_IRQ); } - openrisc_sim_serial_init(state, or1ksim_memmap[OR1KSIM_UART].base, - or1ksim_memmap[OR1KSIM_UART].size, smp_cpus, cpus, - OR1KSIM_UART_IRQ); + for (n = 0; n < OR1KSIM_UART_COUNT; ++n) + openrisc_sim_serial_init(state, or1ksim_memmap[OR1KSIM_UART].base + + or1ksim_memmap[OR1KSIM_UART].size * n, + or1ksim_memmap[OR1KSIM_UART].size, + smp_cpus, cpus, OR1KSIM_UART_IRQ, n); load_addr = openrisc_load_kernel(ram_size, kernel_filename); if (load_addr > 0) { From a92162f4f1dfc2daf1bc8f2bbc3cad3c9d1ea729 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 3 May 2022 11:45:33 +0200 Subject: [PATCH 341/935] hw/openrisc: use right OMPIC size variable This appears to be a copy and paste error. The UART size was used instead of the much smaller OMPIC size. But actually that smaller OMPIC size is wrong too and doesn't allow the IPI to work in Linux. So set it to the old value. Signed-off-by: Jason A. Donenfeld [smh:Updated OR1KSIM_OMPIC size to use OR1KSIM_CPUS_MAX] Signed-off-by: Stafford Horne --- hw/openrisc/openrisc_sim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 6873124f74..35adce17ac 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -82,7 +82,7 @@ static const struct MemmapEntry { [OR1KSIM_DRAM] = { 0x00000000, 0 }, [OR1KSIM_UART] = { 0x90000000, 0x100 }, [OR1KSIM_ETHOC] = { 0x92000000, 0x800 }, - [OR1KSIM_OMPIC] = { 0x98000000, 16 }, + [OR1KSIM_OMPIC] = { 0x98000000, OR1KSIM_CPUS_MAX * 8 }, }; static struct openrisc_boot_info { @@ -418,7 +418,7 @@ static void openrisc_sim_init(MachineState *machine) if (smp_cpus > 1) { openrisc_sim_ompic_init(state, or1ksim_memmap[OR1KSIM_OMPIC].base, - or1ksim_memmap[OR1KSIM_UART].size, + or1ksim_memmap[OR1KSIM_OMPIC].size, smp_cpus, cpus, OR1KSIM_OMPIC_IRQ); } From e8f0ab0cd674241cbab7231ce05ac1bfa0b4f5ed Mon Sep 17 00:00:00 2001 From: Stafford Horne Date: Wed, 11 May 2022 20:47:50 +0900 Subject: [PATCH 342/935] target/openrisc: Do not reset delay slot flag on early tb exit This was found when running linux crypto algorithm selftests used by wireguard. We found that randomly the tests would fail. We found through investigation that a combination of a tick timer interrupt, raised when executing a delay slot instruction at a page boundary caused the issue. This was caused when handling the TB_EXIT_REQUESTED case in cpu_tb_exec. On OpenRISC, which doesn't implement synchronize_from_tb, set_pc was being used as a fallback. The OpenRISC set_pc implementation clears dflag, which caused the exception handling logic to not account for the delay slot. This was the bug, because it meant when execution resumed after the interrupt was handling it resumed in the wrong place. Fix this by implementing synchronize_from_tb which simply updates pc, and not clear the delay slot flag. Reported-by: Jason A. Donenfeld Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- target/openrisc/cpu.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index dfbafc5236..41d1b2a24a 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -21,6 +21,7 @@ #include "qapi/error.h" #include "qemu/qemu-print.h" #include "cpu.h" +#include "exec/exec-all.h" static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) { @@ -30,6 +31,15 @@ static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.dflag = 0; } +static void openrisc_cpu_synchronize_from_tb(CPUState *cs, + const TranslationBlock *tb) +{ + OpenRISCCPU *cpu = OPENRISC_CPU(cs); + + cpu->env.pc = tb->pc; +} + + static bool openrisc_cpu_has_work(CPUState *cs) { return cs->interrupt_request & (CPU_INTERRUPT_HARD | @@ -186,6 +196,7 @@ static const struct SysemuCPUOps openrisc_sysemu_ops = { static const struct TCGCPUOps openrisc_tcg_ops = { .initialize = openrisc_translate_init, + .synchronize_from_tb = openrisc_cpu_synchronize_from_tb, #ifndef CONFIG_USER_ONLY .tlb_fill = openrisc_cpu_tlb_fill, From 433a4fdc42042e3d5a6c3dc741215f78b43b3a2e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 22 Apr 2022 15:28:07 +0200 Subject: [PATCH 343/935] qapi: Fix malformed "Since:" section tags "Since X.Y" is not recognized as a tagged section, and therefore not formatted as such in generated documentation. Fix by adding the required colon. Signed-off-by: Markus Armbruster Message-Id: <20220422132807.1704411-1-armbru@redhat.com> Reviewed-by: Andrea Bolognani --- qapi/crypto.json | 3 +-- qapi/machine.json | 2 +- qapi/misc.json | 2 +- qga/qapi-schema.json | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/qapi/crypto.json b/qapi/crypto.json index 1ec54c15ca..8e0b4764e5 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -357,8 +357,7 @@ # password to use to retrieve current master key. # Defaults to the same secret that was used to open the image # -# -# Since 5.1 +# Since: 5.1 ## { 'struct': 'QCryptoBlockAmendOptionsLUKS', 'data': { 'state': 'QCryptoBlockLUKSKeyslotState', diff --git a/qapi/machine.json b/qapi/machine.json index 92480d4044..c9bdae40eb 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -972,7 +972,7 @@ # preconfigure stage to configure numa mapping before initializing # machine. # -# Since 3.0 +# Since: 3.0 ## { 'command': 'set-numa-node', 'boxed': true, 'data': 'NumaOptions', diff --git a/qapi/misc.json b/qapi/misc.json index b83cc39029..f8a9feda30 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -188,7 +188,7 @@ # Features: # @unstable: This command is experimental. # -# Since 3.0 +# Since: 3.0 # # Returns: nothing # diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index 4d8e506c9e..f989597b0c 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -950,7 +950,7 @@ # by device mapper # @smart: disk smart information (Since 7.1) # -# Since 5.2 +# Since: 5.2 ## { 'struct': 'GuestDiskInfo', 'data': {'name': 'str', 'partition': 'bool', '*dependencies': ['str'], From f39057d58b9edc37fd82e3ea8a034fc7353c46e8 Mon Sep 17 00:00:00 2001 From: Andrea Bolognani Date: Tue, 3 May 2022 09:37:30 +0200 Subject: [PATCH 344/935] qapi: Drop stray trailing symbol Signed-off-by: Andrea Bolognani Reviewed-by: Markus Armbruster Message-Id: <20220503073737.84223-2-abologna@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- qapi/run-state.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qapi/run-state.json b/qapi/run-state.json index 8124220bd9..15d6c9a2ed 100644 --- a/qapi/run-state.json +++ b/qapi/run-state.json @@ -348,7 +348,7 @@ # # @poweroff: Shutdown the VM and exit # -# @pause: pause the VM# +# @pause: pause the VM # # Since: 6.0 ## From 406dfba614edc8629f60f03eb7c26bf4e426137d Mon Sep 17 00:00:00 2001 From: Andrea Bolognani Date: Tue, 3 May 2022 09:37:31 +0200 Subject: [PATCH 345/935] qapi: Fix comment indentation It should start on the very first column. Signed-off-by: Andrea Bolognani Reviewed-by: Markus Armbruster Message-Id: <20220503073737.84223-3-abologna@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- qapi/ui.json | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/qapi/ui.json b/qapi/ui.json index 059302a5ef..43e62efd76 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -1250,21 +1250,21 @@ '*p2p': 'bool', '*audiodev': 'str' } } - ## - # @DisplayGLMode: - # - # Display OpenGL mode. - # - # @off: Disable OpenGL (default). - # @on: Use OpenGL, pick context type automatically. - # Would better be named 'auto' but is called 'on' for backward - # compatibility with bool type. - # @core: Use OpenGL with Core (desktop) Context. - # @es: Use OpenGL with ES (embedded systems) Context. - # - # Since: 3.0 - # - ## +## +# @DisplayGLMode: +# +# Display OpenGL mode. +# +# @off: Disable OpenGL (default). +# @on: Use OpenGL, pick context type automatically. +# Would better be named 'auto' but is called 'on' for backward +# compatibility with bool type. +# @core: Use OpenGL with Core (desktop) Context. +# @es: Use OpenGL with ES (embedded systems) Context. +# +# Since: 3.0 +# +## { 'enum' : 'DisplayGLMode', 'data' : [ 'off', 'on', 'core', 'es' ] } From 4ae65a52658c264caebcb3a31effccf582822a6d Mon Sep 17 00:00:00 2001 From: Andrea Bolognani Date: Tue, 3 May 2022 09:37:32 +0200 Subject: [PATCH 346/935] qapi: Add missing separators between sections This only affects readability. The generated documentation doesn't change. Signed-off-by: Andrea Bolognani Reviewed-by: Markus Armbruster Message-Id: <20220503073737.84223-4-abologna@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- qapi/block-core.json | 5 +++++ qapi/block.json | 1 + qapi/crypto.json | 7 +++++++ qapi/machine.json | 1 + qapi/migration.json | 4 ++++ 5 files changed, 18 insertions(+) diff --git a/qapi/block-core.json b/qapi/block-core.json index b66494e8c5..34dae298ee 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1744,6 +1744,7 @@ # Since: 2.3 # # Example: +# # -> { "execute": "blockdev-backup", # "arguments": { "device": "src-id", # "sync": "full", @@ -2008,6 +2009,7 @@ # @on-target-error: the action to take on an error on the target, # default 'report' (no limitations, since this applies to # a different block device than @device). +# # @unmap: Whether to try to unmap target sectors where source has # only zero. If true, and target unallocated sectors will read as zero, # target image sectors will be unmapped; otherwise, zeroes will be @@ -2029,6 +2031,7 @@ # When true, this job will automatically disappear from the query # list without user intervention. # Defaults to true. (Since 3.1) +# # Since: 1.3 ## { 'struct': 'DriveMirror', @@ -2342,6 +2345,7 @@ # When true, this job will automatically disappear from the query # list without user intervention. # Defaults to true. (Since 3.1) +# # Returns: nothing on success. # # Since: 2.6 @@ -4139,6 +4143,7 @@ # @throttle-group: the name of the throttle-group object to use. It # must already exist. # @file: reference to or definition of the data source block device +# # Since: 2.11 ## { 'struct': 'BlockdevOptionsThrottle', diff --git a/qapi/block.json b/qapi/block.json index 3f100d4887..e0f7898ed1 100644 --- a/qapi/block.json +++ b/qapi/block.json @@ -105,6 +105,7 @@ # # Returns: - Nothing on success # - If @device is not a valid block device, DeviceNotFound +# # Notes: Ejecting a device with no media results in success # # Since: 0.14 diff --git a/qapi/crypto.json b/qapi/crypto.json index 8e0b4764e5..21c670eefa 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -32,6 +32,7 @@ # # @raw: raw bytes. When encoded in JSON only valid UTF-8 sequences can be used # @base64: arbitrary base64 encoded binary data +# # Since: 2.6 ## { 'enum': 'QCryptoSecretFormat', @@ -51,6 +52,7 @@ # @sha384: SHA-384. (since 2.7) # @sha512: SHA-512. (since 2.7) # @ripemd160: RIPEMD-160. (since 2.7) +# # Since: 2.6 ## { 'enum': 'QCryptoHashAlgorithm', @@ -75,6 +77,7 @@ # @twofish-128: Twofish with 128 bit / 16 byte keys # @twofish-192: Twofish with 192 bit / 24 byte keys # @twofish-256: Twofish with 256 bit / 32 byte keys +# # Since: 2.6 ## { 'enum': 'QCryptoCipherAlgorithm', @@ -95,6 +98,7 @@ # @cbc: Cipher Block Chaining # @xts: XEX with tweaked code book and ciphertext stealing # @ctr: Counter (Since 2.8) +# # Since: 2.6 ## { 'enum': 'QCryptoCipherMode', @@ -114,6 +118,7 @@ # @plain: 64-bit sector number truncated to 32-bits # @plain64: 64-bit sector number # @essiv: 64-bit sector number encrypted with a hash of the encryption key +# # Since: 2.6 ## { 'enum': 'QCryptoIVGenAlgorithm', @@ -170,6 +175,7 @@ # @key-secret: the ID of a QCryptoSecret object providing the # decryption key. Mandatory except when probing image for # metadata only. +# # Since: 2.6 ## { 'struct': 'QCryptoBlockOptionsLUKS', @@ -194,6 +200,7 @@ # @iter-time: number of milliseconds to spend in # PBKDF passphrase processing. Currently defaults # to 2000. (since 2.8) +# # Since: 2.6 ## { 'struct': 'QCryptoBlockCreateOptionsLUKS', diff --git a/qapi/machine.json b/qapi/machine.json index c9bdae40eb..79901e1c09 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -299,6 +299,7 @@ # returning does not indicate that a guest has accepted the request or # that it has shut down. Many guests will respond to this command by # prompting the user in some way. +# # Example: # # -> { "execute": "system_powerdown" } diff --git a/qapi/migration.json b/qapi/migration.json index 409eb086a2..fc1c157d3f 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -1422,7 +1422,9 @@ # @state: The state the migration is currently expected to be in # # Returns: nothing on success +# # Since: 2.11 +# # Example: # # -> { "execute": "migrate-continue" , "arguments": @@ -1736,6 +1738,7 @@ # Since: 4.2 # # Example: +# # <- { "event": "UNPLUG_PRIMARY", # "data": { "device-id": "hostdev0" }, # "timestamp": { "seconds": 1265044230, "microseconds": 450486 } } @@ -1845,6 +1848,7 @@ # Since: 5.2 # # Example: +# # {"execute": "calc-dirty-rate", "arguments": {"calc-time": 1, # 'sample-pages': 512} } # From c6487a88871ed299f78641f81f2c0aaff9b6c8bb Mon Sep 17 00:00:00 2001 From: Andrea Bolognani Date: Tue, 3 May 2022 09:37:33 +0200 Subject: [PATCH 347/935] qapi: Drop unnecessary empty lines in comments Signed-off-by: Andrea Bolognani Reviewed-by: Markus Armbruster Message-Id: <20220503073737.84223-5-abologna@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- qapi/block-core.json | 4 ---- qapi/block.json | 1 - qapi/char.json | 1 - qapi/common.json | 2 -- qapi/control.json | 2 -- qapi/machine.json | 2 -- qapi/migration.json | 7 ------- qapi/misc-target.json | 3 --- qapi/replay.json | 1 - qapi/run-state.json | 3 --- qapi/ui.json | 22 ---------------------- 11 files changed, 48 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index 34dae298ee..27832a1244 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -237,7 +237,6 @@ # information (since 1.7) # # Since: 1.3 -# ## { 'struct': 'ImageInfo', 'data': {'filename': 'str', 'format': 'str', '*dirty-flag': 'bool', @@ -288,7 +287,6 @@ # supports it # # Since: 1.4 -# ## { 'struct': 'ImageCheck', 'data': {'filename': 'str', 'format': 'str', 'check-errors': 'int', @@ -328,7 +326,6 @@ # @filename: filename that is referred to by @offset # # Since: 2.6 -# ## { 'struct': 'MapEntry', 'data': {'start': 'int', 'length': 'int', 'data': 'bool', @@ -445,7 +442,6 @@ # has one or more dirty bitmaps) (Since 4.2) # # Since: 0.14 -# ## { 'struct': 'BlockDeviceInfo', 'data': { 'file': 'str', '*node-name': 'str', 'ro': 'bool', 'drv': 'str', diff --git a/qapi/block.json b/qapi/block.json index e0f7898ed1..5de15c6070 100644 --- a/qapi/block.json +++ b/qapi/block.json @@ -300,7 +300,6 @@ # @read-write: Makes the device writable # # Since: 2.3 -# ## { 'enum': 'BlockdevChangeReadOnlyMode', 'data': ['retain', 'read-only', 'read-write'] } diff --git a/qapi/char.json b/qapi/char.json index 7b42151575..f0fd0d1c9f 100644 --- a/qapi/char.json +++ b/qapi/char.json @@ -413,7 +413,6 @@ # @clipboard: enable/disable clipboard, default is disabled. # # Since: 6.1 -# ## { 'struct': 'ChardevQemuVDAgent', 'data': { '*mouse': 'bool', diff --git a/qapi/common.json b/qapi/common.json index 412cc4f5ae..356db3f670 100644 --- a/qapi/common.json +++ b/qapi/common.json @@ -192,7 +192,6 @@ # Keys to toggle input-linux between host and guest. # # Since: 4.0 -# ## { 'enum': 'GrabToggleKeys', 'data': [ 'ctrl-ctrl', 'alt-alt', 'shift-shift','meta-meta', 'scrolllock', @@ -204,7 +203,6 @@ # @human-readable-text: Formatted output intended for humans. # # Since: 6.2 -# ## { 'struct': 'HumanReadableText', 'data': { 'human-readable-text': 'str' } } diff --git a/qapi/control.json b/qapi/control.json index 71a838d49e..8c9122ef7a 100644 --- a/qapi/control.json +++ b/qapi/control.json @@ -33,7 +33,6 @@ # all the QMP capabilities will be turned off by default. # # Since: 0.13 -# ## { 'command': 'qmp_capabilities', 'data': { '*enable': [ 'QMPCapability' ] }, @@ -49,7 +48,6 @@ # (Please refer to qmp-spec.txt for more information on OOB) # # Since: 2.12 -# ## { 'enum': 'QMPCapability', 'data': [ 'oob' ] } diff --git a/qapi/machine.json b/qapi/machine.json index 79901e1c09..c8f07c43cd 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -77,7 +77,6 @@ # additional fields will be listed (since 3.0) # # Since: 2.12 -# ## { 'union' : 'CpuInfoFast', 'base' : { 'cpu-index' : 'int', @@ -1022,7 +1021,6 @@ # Formula used: logical_vm_size = vm_ram_size - balloon_size # # Since: 0.14 -# ## { 'struct': 'BalloonInfo', 'data': {'actual': 'int' } } diff --git a/qapi/migration.json b/qapi/migration.json index fc1c157d3f..dd4dde6361 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -151,7 +151,6 @@ # (since 4.2) # # Since: 2.3 -# ## { 'enum': 'MigrationStatus', 'data': [ 'none', 'setup', 'cancelling', 'cancelled', @@ -166,7 +165,6 @@ # @transferred: amount of bytes transferred to the target VM by VFIO devices # # Since: 5.2 -# ## { 'struct': 'VfioStats', 'data': {'transferred': 'int' } } @@ -546,7 +544,6 @@ # @zstd: use zstd compression method. # # Since: 5.0 -# ## { 'enum': 'MultiFDCompression', 'data': [ 'none', 'zlib', @@ -1757,7 +1754,6 @@ # @dirty-rate: dirty rate. # # Since: 6.2 -# ## { 'struct': 'DirtyRateVcpu', 'data': { 'id': 'int', 'dirty-rate': 'int64' } } @@ -1774,7 +1770,6 @@ # @measured: the dirtyrate thread has measured and results are available. # # Since: 5.2 -# ## { 'enum': 'DirtyRateStatus', 'data': [ 'unstarted', 'measuring', 'measured'] } @@ -1791,7 +1786,6 @@ # @dirty-bitmap: calculate dirtyrate by dirty bitmap. # # Since: 6.2 -# ## { 'enum': 'DirtyRateMeasureMode', 'data': ['page-sampling', 'dirty-ring', 'dirty-bitmap'] } @@ -1821,7 +1815,6 @@ # mode specified (Since 6.2) # # Since: 5.2 -# ## { 'struct': 'DirtyRateInfo', 'data': {'*dirty-rate': 'int64', diff --git a/qapi/misc-target.json b/qapi/misc-target.json index ed4a468aab..ae2c483a68 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -110,7 +110,6 @@ # @data: the measurement value encoded in base64 # # Since: 2.12 -# ## { 'struct': 'SevLaunchMeasureInfo', 'data': {'data': 'str'}, 'if': 'TARGET_I386' } @@ -194,7 +193,6 @@ # @gpa: the guest physical address where secret will be injected. # # Since: 6.0 -# ## { 'command': 'sev-inject-launch-secret', 'data': { 'packet-header': 'str', 'secret': 'str', '*gpa': 'uint64' }, @@ -208,7 +206,6 @@ # # @data: guest attestation report (base64 encoded) # -# # Since: 6.1 ## { 'struct': 'SevAttestationReport', diff --git a/qapi/replay.json b/qapi/replay.json index 351898f60d..729470300d 100644 --- a/qapi/replay.json +++ b/qapi/replay.json @@ -40,7 +40,6 @@ # @icount: current number of executed instructions. # # Since: 5.2 -# ## { 'struct': 'ReplayInfo', 'data': { 'mode': 'ReplayMode', '*filename': 'str', 'icount': 'int' } } diff --git a/qapi/run-state.json b/qapi/run-state.json index 15d6c9a2ed..a5d2db3b91 100644 --- a/qapi/run-state.json +++ b/qapi/run-state.json @@ -592,7 +592,6 @@ # @guest: memory failure at guest memory, # # Since: 5.2 -# ## { 'enum': 'MemoryFailureRecipient', 'data': [ 'hypervisor', @@ -619,7 +618,6 @@ # to handle memory failures. # # Since: 5.2 -# ## { 'enum': 'MemoryFailureAction', 'data': [ 'ignore', @@ -639,7 +637,6 @@ # failure was still in progress. # # Since: 5.2 -# ## { 'struct': 'MemoryFailureFlags', 'data': { 'action-required': 'bool', diff --git a/qapi/ui.json b/qapi/ui.json index 43e62efd76..0e903340fc 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -15,7 +15,6 @@ # Display protocols which support changing password options. # # Since: 7.0 -# ## { 'enum': 'DisplayProtocol', 'data': [ 'vnc', 'spice' ] } @@ -32,7 +31,6 @@ # @disconnect: disconnect existing clients # # Since: 7.0 -# ## { 'enum': 'SetPasswordAction', 'data': [ 'keep', 'fail', 'disconnect' ] } @@ -52,7 +50,6 @@ # For VNC, only 'keep' is currently implemented. # # Since: 7.0 -# ## { 'union': 'SetPasswordOptions', 'base': { 'protocol': 'DisplayProtocol', @@ -70,7 +67,6 @@ # Defaults to the first. # # Since: 7.0 -# ## { 'struct': 'SetPasswordOptionsVnc', 'data': { '*display': 'str' } } @@ -115,7 +111,6 @@ # sure you are on the same machine as the QEMU instance. # # Since: 7.0 -# ## { 'union': 'ExpirePasswordOptions', 'base': { 'protocol': 'DisplayProtocol', @@ -132,7 +127,6 @@ # Defaults to the first. # # Since: 7.0 -# ## { 'struct': 'ExpirePasswordOptionsVnc', @@ -167,7 +161,6 @@ # @ppm: PPM format # # Since: 7.1 -# ## { 'enum': 'ImageFormat', 'data': ['ppm', 'png'] } @@ -902,7 +895,6 @@ # are effectively synonyms. # # Since: 1.3 -# ## { 'enum': 'QKeyCode', 'data': [ 'unmapped', @@ -1206,7 +1198,6 @@ # Since 3.1 # # Since: 2.12 -# ## { 'struct' : 'DisplayGTK', 'data' : { '*grab-on-hover' : 'bool', @@ -1221,7 +1212,6 @@ # available node on the host. # # Since: 3.1 -# ## { 'struct' : 'DisplayEGLHeadless', 'data' : { '*rendernode' : 'str' } } @@ -1242,7 +1232,6 @@ # @audiodev: Use the specified DBus audiodev to export audio. # # Since: 7.0 -# ## { 'struct' : 'DisplayDBus', 'data' : { '*rendernode' : 'str', @@ -1263,7 +1252,6 @@ # @es: Use OpenGL with ES (embedded systems) Context. # # Since: 3.0 -# ## { 'enum' : 'DisplayGLMode', 'data' : [ 'off', 'on', 'core', 'es' ] } @@ -1276,7 +1264,6 @@ # @charset: Font charset used by guest (default: CP437). # # Since: 4.0 -# ## { 'struct' : 'DisplayCurses', 'data' : { '*charset' : 'str' } } @@ -1346,7 +1333,6 @@ # @dbus: Start a D-Bus service for the display. (Since 7.0) # # Since: 2.12 -# ## { 'enum' : 'DisplayType', 'data' : [ @@ -1376,7 +1362,6 @@ # @gl: Enable OpenGL support (default: off). # # Since: 2.12 -# ## { 'union' : 'DisplayOptions', 'base' : { 'type' : 'DisplayType', @@ -1403,7 +1388,6 @@ # Returns: @DisplayOptions # # Since: 3.1 -# ## { 'command': 'query-display-options', 'returns': 'DisplayOptions' } @@ -1416,7 +1400,6 @@ # @vnc: VNC display # # Since: 6.0 -# ## { 'enum': 'DisplayReloadType', 'data': ['vnc'] } @@ -1429,7 +1412,6 @@ # @tls-certs: reload tls certs or not. # # Since: 6.0 -# ## { 'struct': 'DisplayReloadOptionsVNC', 'data': { '*tls-certs': 'bool' } } @@ -1442,7 +1424,6 @@ # @type: Specify the display type. # # Since: 6.0 -# ## { 'union': 'DisplayReloadOptions', 'base': {'type': 'DisplayReloadType'}, @@ -1477,7 +1458,6 @@ # @vnc: VNC display # # Since: 7.1 -# ## { 'enum': 'DisplayUpdateType', 'data': ['vnc'] } @@ -1492,7 +1472,6 @@ # for websockets are not touched. # # Since: 7.1 -# ## { 'struct': 'DisplayUpdateOptionsVNC', 'data': { '*addresses': ['SocketAddress'] } } @@ -1505,7 +1484,6 @@ # @type: Specify the display type. # # Since: 7.1 -# ## { 'union': 'DisplayUpdateOptions', 'base': {'type': 'DisplayUpdateType'}, From 15cc783cfbd8949c5477c134f66f1fdc599a129e Mon Sep 17 00:00:00 2001 From: Andrea Bolognani Date: Tue, 3 May 2022 09:37:34 +0200 Subject: [PATCH 348/935] qapi: Drop unnecessary empty lines outside of comments Signed-off-by: Andrea Bolognani Reviewed-by: Markus Armbruster Message-Id: <20220503073737.84223-6-abologna@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- qapi/audio.json | 1 - qapi/block-core.json | 11 ----------- qapi/block.json | 3 --- qapi/char.json | 1 - qapi/control.json | 1 - qapi/crypto.json | 12 ------------ qapi/job.json | 1 - qapi/machine-target.json | 1 - qapi/machine.json | 1 - qapi/misc-target.json | 4 ---- qapi/run-state.json | 1 - qapi/ui.json | 1 - 12 files changed, 38 deletions(-) diff --git a/qapi/audio.json b/qapi/audio.json index 0785e70a50..8099e3d7f1 100644 --- a/qapi/audio.json +++ b/qapi/audio.json @@ -352,7 +352,6 @@ '*out': 'AudiodevPerDirectionOptions', '*path': 'str' } } - ## # @AudioFormat: # diff --git a/qapi/block-core.json b/qapi/block-core.json index 27832a1244..2bce5bb0ae 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -739,7 +739,6 @@ ## { 'command': 'query-block', 'returns': ['BlockInfo'] } - ## # @BlockDeviceTimedStats: # @@ -1512,7 +1511,6 @@ { 'command': 'blockdev-snapshot-sync', 'data': 'BlockdevSnapshotSync' } - ## # @blockdev-snapshot: # @@ -1751,7 +1749,6 @@ { 'command': 'blockdev-backup', 'boxed': true, 'data': 'BlockdevBackup' } - ## # @query-named-block-nodes: # @@ -3067,7 +3064,6 @@ 'base': 'BlockdevOptionsGenericFormat', 'data': { '*key-secret': 'str' } } - ## # @BlockdevOptionsGenericCOWFormat: # @@ -3182,8 +3178,6 @@ 'base': 'BlockdevOptionsGenericCOWFormat', 'data': { '*encrypt': 'BlockdevQcowEncryption' } } - - ## # @BlockdevQcow2EncryptionFormat: # @@ -3357,7 +3351,6 @@ '*user': 'str', '*host-key-check': 'SshHostKeyCheck' } } - ## # @BlkdebugEvent: # @@ -3721,7 +3714,6 @@ '*header-digest': 'IscsiHeaderDigest', '*timeout': 'int' } } - ## # @RbdAuthMode: # @@ -4564,7 +4556,6 @@ { 'enum': 'BlockdevQcow2Version', 'data': [ 'v2', 'v3' ] } - ## # @Qcow2CompressionType: # @@ -4738,7 +4729,6 @@ '*toolsversion': 'str', '*zeroed-grain': 'bool' } } - ## # @BlockdevCreateOptionsSsh: # @@ -4973,7 +4963,6 @@ { 'enum': 'BlockErrorAction', 'data': [ 'ignore', 'report', 'stop' ] } - ## # @BLOCK_IMAGE_CORRUPTED: # diff --git a/qapi/block.json b/qapi/block.json index 5de15c6070..41b73c9934 100644 --- a/qapi/block.json +++ b/qapi/block.json @@ -286,7 +286,6 @@ 'data': { 'id': 'str', 'node-name': 'str'} } - ## # @BlockdevChangeReadOnlyMode: # @@ -304,7 +303,6 @@ { 'enum': 'BlockdevChangeReadOnlyMode', 'data': ['retain', 'read-only', 'read-write'] } - ## # @blockdev-change-medium: # @@ -375,7 +373,6 @@ '*force': 'bool', '*read-only-mode': 'BlockdevChangeReadOnlyMode' } } - ## # @DEVICE_TRAY_MOVED: # diff --git a/qapi/char.json b/qapi/char.json index f0fd0d1c9f..8414ef2bc2 100644 --- a/qapi/char.json +++ b/qapi/char.json @@ -329,7 +329,6 @@ 'data': { '*signal': 'bool' }, 'base': 'ChardevCommon' } - ## # @ChardevSpiceChannel: # diff --git a/qapi/control.json b/qapi/control.json index 8c9122ef7a..53461cec05 100644 --- a/qapi/control.json +++ b/qapi/control.json @@ -68,7 +68,6 @@ { 'struct': 'VersionTriple', 'data': {'major': 'int', 'minor': 'int', 'micro': 'int'} } - ## # @VersionInfo: # diff --git a/qapi/crypto.json b/qapi/crypto.json index 21c670eefa..9ec0aca1c6 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -24,7 +24,6 @@ 'prefix': 'QCRYPTO_TLS_CREDS_ENDPOINT', 'data': ['client', 'server']} - ## # @QCryptoSecretFormat: # @@ -39,7 +38,6 @@ 'prefix': 'QCRYPTO_SECRET_FORMAT', 'data': ['raw', 'base64']} - ## # @QCryptoHashAlgorithm: # @@ -59,7 +57,6 @@ 'prefix': 'QCRYPTO_HASH_ALG', 'data': ['md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'ripemd160']} - ## # @QCryptoCipherAlgorithm: # @@ -88,7 +85,6 @@ 'serpent-128', 'serpent-192', 'serpent-256', 'twofish-128', 'twofish-192', 'twofish-256']} - ## # @QCryptoCipherMode: # @@ -105,7 +101,6 @@ 'prefix': 'QCRYPTO_CIPHER_MODE', 'data': ['ecb', 'cbc', 'xts', 'ctr']} - ## # @QCryptoIVGenAlgorithm: # @@ -181,7 +176,6 @@ { 'struct': 'QCryptoBlockOptionsLUKS', 'data': { '*key-secret': 'str' }} - ## # @QCryptoBlockCreateOptionsLUKS: # @@ -212,7 +206,6 @@ '*hash-alg': 'QCryptoHashAlgorithm', '*iter-time': 'int'}} - ## # @QCryptoBlockOpenOptions: # @@ -227,7 +220,6 @@ 'data': { 'qcow': 'QCryptoBlockOptionsQCow', 'luks': 'QCryptoBlockOptionsLUKS' } } - ## # @QCryptoBlockCreateOptions: # @@ -242,7 +234,6 @@ 'data': { 'qcow': 'QCryptoBlockOptionsQCow', 'luks': 'QCryptoBlockCreateOptionsLUKS' } } - ## # @QCryptoBlockInfoBase: # @@ -256,7 +247,6 @@ { 'struct': 'QCryptoBlockInfoBase', 'data': { 'format': 'QCryptoBlockFormat' }} - ## # @QCryptoBlockInfoLUKSSlot: # @@ -276,7 +266,6 @@ '*stripes': 'int', 'key-offset': 'int' } } - ## # @QCryptoBlockInfoLUKS: # @@ -330,7 +319,6 @@ { 'enum': 'QCryptoBlockLUKSKeyslotState', 'data': [ 'active', 'inactive' ] } - ## # @QCryptoBlockAmendOptionsLUKS: # diff --git a/qapi/job.json b/qapi/job.json index 1a6ef03451..d5f84e9615 100644 --- a/qapi/job.json +++ b/qapi/job.json @@ -173,7 +173,6 @@ ## { 'command': 'job-cancel', 'data': { 'id': 'str' } } - ## # @job-complete: # diff --git a/qapi/machine-target.json b/qapi/machine-target.json index f5ec4bc172..06b0d2ca61 100644 --- a/qapi/machine-target.json +++ b/qapi/machine-target.json @@ -54,7 +54,6 @@ { 'enum': 'CpuModelExpansionType', 'data': [ 'static', 'full' ] } - ## # @CpuModelCompareResult: # diff --git a/qapi/machine.json b/qapi/machine.json index c8f07c43cd..3fe977e903 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -1365,7 +1365,6 @@ { 'event': 'MEMORY_DEVICE_SIZE_CHANGE', 'data': { '*id': 'str', 'size': 'size', 'qom-path' : 'str'} } - ## # @MEM_UNPLUG_ERROR: # diff --git a/qapi/misc-target.json b/qapi/misc-target.json index ae2c483a68..2fa68a6796 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -21,7 +21,6 @@ { 'command': 'rtc-reset-reinjection', 'if': 'TARGET_I386' } - ## # @SevState: # @@ -101,7 +100,6 @@ { 'command': 'query-sev', 'returns': 'SevInfo', 'if': 'TARGET_I386' } - ## # @SevLaunchMeasureInfo: # @@ -132,7 +130,6 @@ { 'command': 'query-sev-launch-measure', 'returns': 'SevLaunchMeasureInfo', 'if': 'TARGET_I386' } - ## # @SevCapability: # @@ -304,7 +301,6 @@ { 'command': 'query-gic-capabilities', 'returns': ['GICCapability'], 'if': 'TARGET_ARM' } - ## # @SGXEPCSection: # diff --git a/qapi/run-state.json b/qapi/run-state.json index a5d2db3b91..30a2f5231d 100644 --- a/qapi/run-state.json +++ b/qapi/run-state.json @@ -597,7 +597,6 @@ 'data': [ 'hypervisor', 'guest' ] } - ## # @MemoryFailureAction: # diff --git a/qapi/ui.json b/qapi/ui.json index 0e903340fc..9f19beea6d 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -128,7 +128,6 @@ # # Since: 7.0 ## - { 'struct': 'ExpirePasswordOptionsVnc', 'data': { '*display': 'str' } } From 23e46452589d8c62d69ae993d16e6d15fd15f526 Mon Sep 17 00:00:00 2001 From: Andrea Bolognani Date: Tue, 3 May 2022 09:37:35 +0200 Subject: [PATCH 349/935] qapi: Drop unnecessary whitespace in comments The only instances that get changed are those in which the additional whitespace was not (or couldn't possibly be) used for alignment purposes. Signed-off-by: Andrea Bolognani Message-Id: <20220503073737.84223-7-abologna@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- qapi/block-core.json | 24 ++++++++++++------------ qapi/block-export.json | 2 +- qapi/block.json | 2 +- qapi/char.json | 2 +- qapi/dump.json | 4 ++-- qapi/machine.json | 8 ++++---- qapi/misc-target.json | 6 +++--- qapi/misc.json | 6 +++--- qapi/run-state.json | 4 ++-- qapi/sockets.json | 2 +- qapi/ui.json | 2 +- 11 files changed, 31 insertions(+), 31 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index 2bce5bb0ae..e110af2f1d 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -604,7 +604,7 @@ # @inserted: @BlockDeviceInfo describing the device if media is # present # -# Since: 0.14 +# Since: 0.14 ## { 'struct': 'BlockInfo', 'data': {'device': 'str', '*qdev': 'str', 'type': 'str', 'removable': 'bool', @@ -795,9 +795,9 @@ # # Statistics of a virtual block device or a block backing device. # -# @rd_bytes: The number of bytes read by the device. +# @rd_bytes: The number of bytes read by the device. # -# @wr_bytes: The number of bytes written by the device. +# @wr_bytes: The number of bytes written by the device. # # @unmap_bytes: The number of bytes unmapped by the device (Since 4.2) # @@ -970,7 +970,7 @@ # @qdev: The qdev ID, or if no ID is assigned, the QOM path of the block # device. (since 3.0) # -# @stats: A @BlockDeviceStats for the device. +# @stats: A @BlockDeviceStats for the device. # # @driver-specific: Optional driver-specific stats. (Since 4.2) # @@ -1275,7 +1275,7 @@ # # @node-name: graph node name to get the image resized (Since 2.0) # -# @size: new image size in bytes +# @size: new image size in bytes # # Returns: - nothing on success # - If @device is not a valid block device, DeviceNotFound @@ -1960,8 +1960,8 @@ # @job-id: identifier for the newly-created block job. If # omitted, the device name will be used. (Since 2.7) # -# @device: the device name or node-name of a root node whose writes should be -# mirrored. +# @device: the device name or node-name of a root node whose writes should be +# mirrored. # # @target: the target of the new image. If the file exists, or if it # is a device, the existing file/device will be used as the new @@ -1981,7 +1981,7 @@ # @mode: whether and how QEMU should create a new image, default is # 'absolute-paths'. # -# @speed: the maximum speed, in bytes per second +# @speed: the maximum speed, in bytes per second # # @sync: what parts of the disk image should be copied to the destination # (all the disk, only the sectors allocated in the topmost image, or @@ -2296,7 +2296,7 @@ # broken Quorum files. By default, @device is replaced, although # implicitly created filters on it are kept. # -# @speed: the maximum speed, in bytes per second +# @speed: the maximum speed, in bytes per second # # @sync: what parts of the disk image should be copied to the destination # (all the disk, only the sectors allocated in the topmost image, or @@ -4548,8 +4548,8 @@ ## # @BlockdevQcow2Version: # -# @v2: The original QCOW2 format as introduced in qemu 0.10 (version 2) -# @v3: The extended QCOW2 format as introduced in qemu 1.1 (version 3) +# @v2: The original QCOW2 format as introduced in qemu 0.10 (version 2) +# @v3: The extended QCOW2 format as introduced in qemu 1.1 (version 3) # # Since: 2.12 ## @@ -4905,7 +4905,7 @@ # # Options for amending an image format # -# @driver: Block driver of the node to amend. +# @driver: Block driver of the node to amend. # # Since: 5.1 ## diff --git a/qapi/block-export.json b/qapi/block-export.json index 7776248435..0685cb8b9a 100644 --- a/qapi/block-export.json +++ b/qapi/block-export.json @@ -391,7 +391,7 @@ # block-export-del command, but before the shutdown has # completed) # -# Since: 5.2 +# Since: 5.2 ## { 'struct': 'BlockExportInfo', 'data': { 'id': 'str', diff --git a/qapi/block.json b/qapi/block.json index 41b73c9934..96f557b3bb 100644 --- a/qapi/block.json +++ b/qapi/block.json @@ -106,7 +106,7 @@ # Returns: - Nothing on success # - If @device is not a valid block device, DeviceNotFound # -# Notes: Ejecting a device with no media results in success +# Notes: Ejecting a device with no media results in success # # Since: 0.14 # diff --git a/qapi/char.json b/qapi/char.json index 8414ef2bc2..a40fe4b7bd 100644 --- a/qapi/char.json +++ b/qapi/char.json @@ -216,7 +216,7 @@ # # Configuration info for file chardevs. # -# @in: The name of the input file +# @in: The name of the input file # @out: The name of the output file # @append: Open the file in append mode (default false to # truncate) (Since 2.6) diff --git a/qapi/dump.json b/qapi/dump.json index 29441af9d8..90859c5483 100644 --- a/qapi/dump.json +++ b/qapi/dump.json @@ -186,8 +186,8 @@ # # Returns the available formats for dump-guest-memory # -# Returns: A @DumpGuestMemoryCapability object listing available formats for -# dump-guest-memory +# Returns: A @DumpGuestMemoryCapability object listing available formats for +# dump-guest-memory # # Since: 2.0 # diff --git a/qapi/machine.json b/qapi/machine.json index 3fe977e903..1e5bf02480 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -315,9 +315,9 @@ # query-current-machine), wake-up guest from suspend if the guest is # in SUSPENDED state. Return an error otherwise. # -# Since: 1.1 +# Since: 1.1 # -# Returns: nothing. +# Returns: nothing. # # Note: prior to 4.0, this command does nothing in case the guest # isn't suspended. @@ -368,9 +368,9 @@ # Injects a Non-Maskable Interrupt into the default CPU (x86/s390) or all CPUs (ppc64). # The command fails when the guest doesn't support injecting. # -# Returns: If successful, nothing +# Returns: If successful, nothing # -# Since: 0.14 +# Since: 0.14 # # Note: prior to 2.1, this command was only supported for x86 and s390 VMs # diff --git a/qapi/misc-target.json b/qapi/misc-target.json index 2fa68a6796..4944c0528f 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -136,9 +136,9 @@ # The struct describes capability for a Secure Encrypted Virtualization # feature. # -# @pdh: Platform Diffie-Hellman key (base64 encoded) +# @pdh: Platform Diffie-Hellman key (base64 encoded) # -# @cert-chain: PDH certificate chain (base64 encoded) +# @cert-chain: PDH certificate chain (base64 encoded) # # @cpu0-id: Unique ID of CPU0 (base64 encoded) (since 7.1) # @@ -201,7 +201,7 @@ # The struct describes attestation report for a Secure Encrypted # Virtualization feature. # -# @data: guest attestation report (base64 encoded) +# @data: guest attestation report (base64 encoded) # # Since: 6.1 ## diff --git a/qapi/misc.json b/qapi/misc.json index f8a9feda30..45344483cd 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -136,7 +136,7 @@ # # Stop all guest VCPU execution. # -# Since: 0.14 +# Since: 0.14 # # Notes: This function will succeed even if the guest is already in the stopped # state. In "inmigrate" state, it will ensure that the guest @@ -156,9 +156,9 @@ # # Resume guest VCPU execution. # -# Since: 0.14 +# Since: 0.14 # -# Returns: If successful, nothing +# Returns: If successful, nothing # # Notes: This command will succeed if the guest is currently running. It # will also succeed if the guest is in the "inmigrate" state; in diff --git a/qapi/run-state.json b/qapi/run-state.json index 30a2f5231d..6e2162d7b3 100644 --- a/qapi/run-state.json +++ b/qapi/run-state.json @@ -104,7 +104,7 @@ # # @status: the virtual machine @RunState # -# Since: 0.14 +# Since: 0.14 # # Notes: @singlestep is enabled through the GDB stub ## @@ -118,7 +118,7 @@ # # Returns: @StatusInfo reflecting all VCPUs # -# Since: 0.14 +# Since: 0.14 # # Example: # diff --git a/qapi/sockets.json b/qapi/sockets.json index fccc38584b..b4f84d3334 100644 --- a/qapi/sockets.json +++ b/qapi/sockets.json @@ -189,7 +189,7 @@ # Captures the address of a socket, which could also be a named file # descriptor # -# @type: Transport type +# @type: Transport type # # Since: 2.9 ## diff --git a/qapi/ui.json b/qapi/ui.json index 9f19beea6d..c844237434 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -1260,7 +1260,7 @@ # # Curses display options. # -# @charset: Font charset used by guest (default: CP437). +# @charset: Font charset used by guest (default: CP437). # # Since: 4.0 ## From c0ac533b6f97fe978a9d9b33078ee36dd54cedb2 Mon Sep 17 00:00:00 2001 From: Andrea Bolognani Date: Tue, 3 May 2022 09:37:36 +0200 Subject: [PATCH 350/935] qapi: Stop using whitespace for alignment in comments Perfectly aligned things look pretty, but keeping them that way as the schema evolves requires churn, and in some cases newly-added lines are not aligned properly. Overall, trying to align things is just not worth the trouble. Signed-off-by: Andrea Bolognani Message-Id: <20220503073737.84223-8-abologna@redhat.com> Message-Id: <20220503073737.84223-9-abologna@redhat.com> Reviewed-by: Eric Blake Reviewed-by: Markus Armbruster [Two patches squashed together] Signed-off-by: Markus Armbruster --- qapi/block-core.json | 53 ++++++++++++++++++++++---------------------- qapi/block.json | 6 ++--- qapi/char.json | 6 ++--- qapi/control.json | 10 ++++----- qapi/crypto.json | 42 +++++++++++++++++------------------ qapi/migration.json | 8 +++---- qapi/sockets.json | 4 ++-- qapi/ui.json | 17 +++++++------- 8 files changed, 72 insertions(+), 74 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index e110af2f1d..f0383c7925 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -337,9 +337,9 @@ # # Cache mode information for a block device # -# @writeback: true if writeback mode is enabled -# @direct: true if the host page cache is bypassed (O_DIRECT) -# @no-flush: true if flush requests are ignored for the device +# @writeback: true if writeback mode is enabled +# @direct: true if the host page cache is bypassed (O_DIRECT) +# @no-flush: true if flush requests are ignored for the device # # Since: 2.3 ## @@ -3333,15 +3333,14 @@ ## # @BlockdevOptionsSsh: # -# @server: host address +# @server: host address # -# @path: path to the image on the host +# @path: path to the image on the host # -# @user: user as which to connect, defaults to current -# local user name +# @user: user as which to connect, defaults to current local user name # -# @host-key-check: Defines how and what to check the host key against -# (default: known_hosts) +# @host-key-check: Defines how and what to check the host key against +# (default: known_hosts) # # Since: 2.9 ## @@ -4662,18 +4661,18 @@ # # Subformat options for VMDK images # -# @monolithicSparse: Single file image with sparse cluster allocation +# @monolithicSparse: Single file image with sparse cluster allocation # -# @monolithicFlat: Single flat data image and a descriptor file +# @monolithicFlat: Single flat data image and a descriptor file # # @twoGbMaxExtentSparse: Data is split into 2GB (per virtual LBA) sparse extent # files, in addition to a descriptor file # -# @twoGbMaxExtentFlat: Data is split into 2GB (per virtual LBA) flat extent -# files, in addition to a descriptor file +# @twoGbMaxExtentFlat: Data is split into 2GB (per virtual LBA) flat extent +# files, in addition to a descriptor file # -# @streamOptimized: Single file image sparse cluster allocation, optimized -# for streaming over network. +# @streamOptimized: Single file image sparse cluster allocation, optimized +# for streaming over network. # # Since: 4.0 ## @@ -4764,7 +4763,7 @@ # @BlockdevVhdxSubformat: # # @dynamic: Growing image file -# @fixed: Preallocated fixed-size image file +# @fixed: Preallocated fixed-size image file # # Since: 2.12 ## @@ -4802,7 +4801,7 @@ # @BlockdevVpcSubformat: # # @dynamic: Growing image file -# @fixed: Preallocated fixed-size image file +# @fixed: Preallocated fixed-size image file # # Since: 2.12 ## @@ -4865,9 +4864,9 @@ # Starts a job to create an image format on a given node. The job is # automatically finalized, but a manual job-dismiss is required. # -# @job-id: Identifier for the newly created job. +# @job-id: Identifier for the newly created job. # -# @options: Options for the image creation. +# @options: Options for the image creation. # # Since: 3.0 ## @@ -4923,17 +4922,17 @@ # Starts a job to amend format specific options of an existing open block device # The job is automatically finalized, but a manual job-dismiss is required. # -# @job-id: Identifier for the newly created job. +# @job-id: Identifier for the newly created job. # -# @node-name: Name of the block node to work on +# @node-name: Name of the block node to work on # -# @options: Options (driver specific) +# @options: Options (driver specific) # -# @force: Allow unsafe operations, format specific -# For luks that allows erase of the last active keyslot -# (permanent loss of data), -# and replacement of an active keyslot -# (possible loss of data if IO error happens) +# @force: Allow unsafe operations, format specific +# For luks that allows erase of the last active keyslot +# (permanent loss of data), +# and replacement of an active keyslot +# (possible loss of data if IO error happens) # # Features: # @unstable: This command is experimental. diff --git a/qapi/block.json b/qapi/block.json index 96f557b3bb..19326641ac 100644 --- a/qapi/block.json +++ b/qapi/block.json @@ -50,9 +50,9 @@ # # Type of Floppy drive to be emulated by the Floppy Disk Controller. # -# @144: 1.44MB 3.5" drive -# @288: 2.88MB 3.5" drive -# @120: 1.2MB 5.25" drive +# @144: 1.44MB 3.5" drive +# @288: 2.88MB 3.5" drive +# @120: 1.2MB 5.25" drive # @none: No drive connected # @auto: Automatically determined by inserted media at boot # diff --git a/qapi/char.json b/qapi/char.json index a40fe4b7bd..923dc5056d 100644 --- a/qapi/char.json +++ b/qapi/char.json @@ -376,10 +376,10 @@ # # Configuration info for virtual console chardevs. # -# @width: console width, in pixels +# @width: console width, in pixels # @height: console height, in pixels -# @cols: console width, in chars -# @rows: console height, in chars +# @cols: console width, in chars +# @rows: console height, in chars # # Since: 1.5 ## diff --git a/qapi/control.json b/qapi/control.json index 53461cec05..afca2043af 100644 --- a/qapi/control.json +++ b/qapi/control.json @@ -192,14 +192,14 @@ # # Options to be used for adding a new monitor. # -# @id: Name of the monitor +# @id: Name of the monitor # -# @mode: Selects the monitor mode (default: readline in the system -# emulator, control in qemu-storage-daemon) +# @mode: Selects the monitor mode (default: readline in the system +# emulator, control in qemu-storage-daemon) # -# @pretty: Enables pretty printing (QMP only) +# @pretty: Enables pretty printing (QMP only) # -# @chardev: Name of a character device to expose the monitor on +# @chardev: Name of a character device to expose the monitor on # # Since: 5.0 ## diff --git a/qapi/crypto.json b/qapi/crypto.json index 9ec0aca1c6..15c24f0078 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -311,8 +311,8 @@ # # Defines state of keyslots that are affected by the update # -# @active: The slots contain the given password and marked as active -# @inactive: The slots are erased (contain garbage) and marked as inactive +# @active: The slots contain the given password and marked as active +# @inactive: The slots are erased (contain garbage) and marked as inactive # # Since: 5.1 ## @@ -327,30 +327,30 @@ # # @state: the desired state of the keyslots # -# @new-secret: The ID of a QCryptoSecret object providing the password to be -# written into added active keyslots +# @new-secret: The ID of a QCryptoSecret object providing the password to be +# written into added active keyslots # -# @old-secret: Optional (for deactivation only) -# If given will deactivate all keyslots that -# match password located in QCryptoSecret with this ID +# @old-secret: Optional (for deactivation only) +# If given will deactivate all keyslots that +# match password located in QCryptoSecret with this ID # -# @iter-time: Optional (for activation only) -# Number of milliseconds to spend in -# PBKDF passphrase processing for the newly activated keyslot. -# Currently defaults to 2000. +# @iter-time: Optional (for activation only) +# Number of milliseconds to spend in +# PBKDF passphrase processing for the newly activated keyslot. +# Currently defaults to 2000. # -# @keyslot: Optional. ID of the keyslot to activate/deactivate. -# For keyslot activation, keyslot should not be active already -# (this is unsafe to update an active keyslot), -# but possible if 'force' parameter is given. -# If keyslot is not given, first free keyslot will be written. +# @keyslot: Optional. ID of the keyslot to activate/deactivate. +# For keyslot activation, keyslot should not be active already +# (this is unsafe to update an active keyslot), +# but possible if 'force' parameter is given. +# If keyslot is not given, first free keyslot will be written. # -# For keyslot deactivation, this parameter specifies the exact -# keyslot to deactivate +# For keyslot deactivation, this parameter specifies the exact +# keyslot to deactivate # -# @secret: Optional. The ID of a QCryptoSecret object providing the -# password to use to retrieve current master key. -# Defaults to the same secret that was used to open the image +# @secret: Optional. The ID of a QCryptoSecret object providing the +# password to use to retrieve current master key. +# Defaults to the same secret that was used to open the image # # Since: 5.1 ## diff --git a/qapi/migration.json b/qapi/migration.json index dd4dde6361..1ff4d7eaff 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -1191,10 +1191,10 @@ # ask the client to automatically reconnect using the new parameters # once migration finished successfully. Only implemented for SPICE. # -# @protocol: must be "spice" -# @hostname: migration target hostname -# @port: spice tcp port for plaintext channels -# @tls-port: spice tcp port for tls-secured channels +# @protocol: must be "spice" +# @hostname: migration target hostname +# @port: spice tcp port for plaintext channels +# @tls-port: spice tcp port for tls-secured channels # @cert-subject: server certificate subject # # Since: 0.14 diff --git a/qapi/sockets.json b/qapi/sockets.json index b4f84d3334..bad74e34d3 100644 --- a/qapi/sockets.json +++ b/qapi/sockets.json @@ -167,9 +167,9 @@ # # Available SocketAddress types # -# @inet: Internet address +# @inet: Internet address # -# @unix: Unix domain socket +# @unix: Unix domain socket # # @vsock: VMCI address # diff --git a/qapi/ui.json b/qapi/ui.json index c844237434..11a827d10f 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -1018,8 +1018,8 @@ # # Keyboard input event. # -# @key: Which key this event is for. -# @down: True for key-down and false for key-up events. +# @key: Which key this event is for. +# @down: True for key-down and false for key-up events. # # Since: 2.0 ## @@ -1033,7 +1033,7 @@ # Pointer button input event. # # @button: Which button this event is for. -# @down: True for key-down and false for key-up events. +# @down: True for key-down and false for key-up events. # # Since: 2.0 ## @@ -1353,12 +1353,11 @@ # # Display (user interface) options. # -# @type: Which DisplayType qemu should use. -# @full-screen: Start user interface in fullscreen mode (default: off). -# @window-close: Allow to quit qemu with window close button (default: on). -# @show-cursor: Force showing the mouse cursor (default: off). -# (since: 5.0) -# @gl: Enable OpenGL support (default: off). +# @type: Which DisplayType qemu should use. +# @full-screen: Start user interface in fullscreen mode (default: off). +# @window-close: Allow to quit qemu with window close button (default: on). +# @show-cursor: Force showing the mouse cursor (default: off). (since: 5.0) +# @gl: Enable OpenGL support (default: off). # # Since: 2.12 ## From 9e191d33688125c0cadff96b389126664054046f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 10 May 2022 08:16:44 +0200 Subject: [PATCH 351/935] qapi/expr: Enforce feature naming rules again Commit e42648dccd "qapi/expr.py: Remove single-letter variable" accidentally removed the check for "only lower case letters and hyphens". Restore it. Fixes: e42648dccdd1defe8f35f247966cd7283f865cd6 Signed-off-by: Markus Armbruster Message-Id: <20220510061645.3209195-2-armbru@redhat.com> --- scripts/qapi/expr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 48578e1698..5a1782b57e 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -443,7 +443,7 @@ def check_features(features: Optional[object], check_keys(feat, info, source, ['name'], ['if']) check_name_is_str(feat['name'], info, source) source = "%s '%s'" % (source, feat['name']) - check_name_str(feat['name'], info, source) + check_name_lower(feat['name'], info, source) check_if(feat, info, source) From 1524559f58b1fe14e9b1c9b5be09a82696867eb1 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 10 May 2022 08:16:45 +0200 Subject: [PATCH 352/935] docs/devel/qapi-code-gen: Belatedly document feature naming rules Signed-off-by: Markus Armbruster Message-Id: <20220510061645.3209195-3-armbru@redhat.com> --- docs/devel/qapi-code-gen.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/devel/qapi-code-gen.rst b/docs/devel/qapi-code-gen.rst index 7b968433a6..cd9b544376 100644 --- a/docs/devel/qapi-code-gen.rst +++ b/docs/devel/qapi-code-gen.rst @@ -739,10 +739,11 @@ Type names ending with ``Kind`` or ``List`` are reserved for the generator, which uses them for implicit union enums and array types, respectively. -Command names, and member names within a type, should be all lower -case with words separated by a hyphen. However, some existing older -commands and complex types use underscore; when extending them, -consistency is preferred over blindly avoiding underscore. +Command names, member names within a type, and feature names should be +all lower case with words separated by a hyphen. However, some +existing older commands and complex types use underscore; when +extending them, consistency is preferred over blindly avoiding +underscore. Event names should be ALL_CAPS with words separated by underscore. From dd8f0f332f34a2466d855d1067386b04ff2eb6d9 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 10 May 2022 10:14:33 +0200 Subject: [PATCH 353/935] qapi/pragma: Tidy up comments Commit 05ebf841ef "qapi: Enforce command naming rules" inserted new code between a comment and the code it applies to. Move the comment back to its code, and add one for the new code. Signed-off-by: Markus Armbruster Message-Id: <20220510081433.3289762-1-armbru@redhat.com> --- qapi/pragma.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qapi/pragma.json b/qapi/pragma.json index e6a021c19c..7f810b0e97 100644 --- a/qapi/pragma.json +++ b/qapi/pragma.json @@ -6,7 +6,7 @@ # Whitelists to permit QAPI rule violations; think twice before you # add to them! { 'pragma': { - # Commands allowed to return a non-dictionary: + # Command names containing '_' 'command-name-exceptions': [ 'add_client', 'block_resize', @@ -24,6 +24,7 @@ 'system_powerdown', 'system_reset', 'system_wakeup' ], + # Commands allowed to return a non-dictionary 'command-returns-exceptions': [ 'human-monitor-command', 'qom-get', From dc89f32d92bba795b0665f075b78d8881cf67ab3 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 14 Mar 2022 14:25:41 +0000 Subject: [PATCH 354/935] target/i386: Fix sanity check on max APIC ID / X2APIC enablement The check on x86ms->apic_id_limit in pc_machine_done() had two problems. Firstly, we need KVM to support the X2APIC API in order to allow IRQ delivery to APICs >= 255. So we need to call/check kvm_enable_x2apic(), which was done elsewhere in *some* cases but not all. Secondly, microvm needs the same check. So move it from pc_machine_done() to x86_cpus_init() where it will work for both. The check in kvm_cpu_instance_init() is now redundant and can be dropped. Signed-off-by: David Woodhouse Acked-by: Claudio Fontana Message-Id: <20220314142544.150555-1-dwmw2@infradead.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 8 -------- hw/i386/x86.c | 16 ++++++++++++++++ target/i386/kvm/kvm-cpu.c | 2 +- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 312eb9e400..15f37d8dc6 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -744,14 +744,6 @@ void pc_machine_done(Notifier *notifier, void *data) /* update FW_CFG_NB_CPUS to account for -device added CPUs */ fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus); } - - - if (x86ms->apic_id_limit > 255 && !xen_enabled() && - !kvm_irqchip_in_kernel()) { - error_report("current -smp configuration requires kernel " - "irqchip support."); - exit(EXIT_FAILURE); - } } void pc_guest_info_init(PCMachineState *pcms) diff --git a/hw/i386/x86.c b/hw/i386/x86.c index 79ebdface6..f79e720cc2 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -38,6 +38,7 @@ #include "sysemu/replay.h" #include "sysemu/sysemu.h" #include "sysemu/cpu-timers.h" +#include "sysemu/xen.h" #include "trace.h" #include "hw/i386/x86.h" @@ -122,6 +123,21 @@ void x86_cpus_init(X86MachineState *x86ms, int default_cpu_version) */ x86ms->apic_id_limit = x86_cpu_apic_id_from_index(x86ms, ms->smp.max_cpus - 1) + 1; + + /* + * Can we support APIC ID 255 or higher? + * + * Under Xen: yes. + * With userspace emulated lapic: no + * With KVM's in-kernel lapic: only if X2APIC API is enabled. + */ + if (x86ms->apic_id_limit > 255 && !xen_enabled() && + (!kvm_irqchip_in_kernel() || !kvm_enable_x2apic())) { + error_report("current -smp configuration requires kernel " + "irqchip and X2APIC API support."); + exit(EXIT_FAILURE); + } + possible_cpus = mc->possible_cpu_arch_ids(ms); for (i = 0; i < ms->smp.cpus; i++) { x86_cpu_new(x86ms, possible_cpus->cpus[i].arch_id, &error_fatal); diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c index 5eb955ce9a..7237378a7d 100644 --- a/target/i386/kvm/kvm-cpu.c +++ b/target/i386/kvm/kvm-cpu.c @@ -171,7 +171,7 @@ static void kvm_cpu_instance_init(CPUState *cs) /* only applies to builtin_x86_defs cpus */ if (!kvm_irqchip_in_kernel()) { x86_cpu_change_kvm_default("x2apic", "off"); - } else if (kvm_irqchip_is_split() && kvm_enable_x2apic()) { + } else if (kvm_irqchip_is_split()) { x86_cpu_change_kvm_default("kvm-msi-ext-dest-id", "on"); } From 8646d9c773d88c3f9a20919a96afa35e6230c1ee Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 14 Mar 2022 14:25:42 +0000 Subject: [PATCH 355/935] intel_iommu: Support IR-only mode without DMA translation By setting none of the SAGAW bits we can indicate to a guest that DMA translation isn't supported. Tested by booting Windows 10, as well as Linux guests with the fix at https://git.kernel.org/torvalds/c/c40aaaac10 Signed-off-by: David Woodhouse Reviewed-by: Peter Xu Acked-by: Jason Wang Message-Id: <20220314142544.150555-2-dwmw2@infradead.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 14 ++++++++++---- include/hw/i386/intel_iommu.h | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index e05d69a2c0..b22376a45d 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2214,7 +2214,7 @@ static void vtd_handle_gcmd_write(IntelIOMMUState *s) uint32_t changed = status ^ val; trace_vtd_reg_write_gcmd(status, val); - if (changed & VTD_GCMD_TE) { + if ((changed & VTD_GCMD_TE) && s->dma_translation) { /* Translation enable/disable */ vtd_handle_gcmd_te(s, val & VTD_GCMD_TE); } @@ -3122,6 +3122,7 @@ static Property vtd_properties[] = { DEFINE_PROP_BOOL("x-scalable-mode", IntelIOMMUState, scalable_mode, FALSE), DEFINE_PROP_BOOL("snoop-control", IntelIOMMUState, snoop_control, false), DEFINE_PROP_BOOL("dma-drain", IntelIOMMUState, dma_drain, true), + DEFINE_PROP_BOOL("dma-translation", IntelIOMMUState, dma_translation, true), DEFINE_PROP_END_OF_LIST(), }; @@ -3627,12 +3628,17 @@ static void vtd_init(IntelIOMMUState *s) s->next_frcd_reg = 0; s->cap = VTD_CAP_FRO | VTD_CAP_NFR | VTD_CAP_ND | VTD_CAP_MAMV | VTD_CAP_PSI | VTD_CAP_SLLPS | - VTD_CAP_SAGAW_39bit | VTD_CAP_MGAW(s->aw_bits); + VTD_CAP_MGAW(s->aw_bits); if (s->dma_drain) { s->cap |= VTD_CAP_DRAIN; } - if (s->aw_bits == VTD_HOST_AW_48BIT) { - s->cap |= VTD_CAP_SAGAW_48bit; + if (s->dma_translation) { + if (s->aw_bits >= VTD_HOST_AW_39BIT) { + s->cap |= VTD_CAP_SAGAW_39bit; + } + if (s->aw_bits >= VTD_HOST_AW_48BIT) { + s->cap |= VTD_CAP_SAGAW_48bit; + } } s->ecap = VTD_ECAP_QI | VTD_ECAP_IRO; diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index bfa982a419..67653b0f9b 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -267,6 +267,7 @@ struct IntelIOMMUState { bool buggy_eim; /* Force buggy EIM unless eim=off */ uint8_t aw_bits; /* Host/IOVA address width (in bits) */ bool dma_drain; /* Whether DMA r/w draining enabled */ + bool dma_translation; /* Whether DMA translation supported */ /* * Protects IOMMU states in general. Currently it protects the From 175f3a59863d7263597011ae86bc57108539ba35 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 14 Mar 2022 14:25:43 +0000 Subject: [PATCH 356/935] intel_iommu: Only allow interrupt remapping to be enabled if it's supported We should probably check if we were meant to be exposing IR, before letting the guest turn the IRE bit on. Signed-off-by: David Woodhouse Reviewed-by: Peter Xu Acked-by: Jason Wang Message-Id: <20220314142544.150555-3-dwmw2@infradead.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index b22376a45d..d3361c8313 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2209,6 +2209,7 @@ static void vtd_handle_gcmd_ire(IntelIOMMUState *s, bool en) /* Handle write to Global Command Register */ static void vtd_handle_gcmd_write(IntelIOMMUState *s) { + X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s); uint32_t status = vtd_get_long_raw(s, DMAR_GSTS_REG); uint32_t val = vtd_get_long_raw(s, DMAR_GCMD_REG); uint32_t changed = status ^ val; @@ -2230,7 +2231,8 @@ static void vtd_handle_gcmd_write(IntelIOMMUState *s) /* Set/update the interrupt remapping root-table pointer */ vtd_handle_gcmd_sirtp(s); } - if (changed & VTD_GCMD_IRE) { + if ((changed & VTD_GCMD_IRE) && + x86_iommu_ir_supported(x86_iommu)) { /* Interrupt remap enable/disable */ vtd_handle_gcmd_ire(s, val & VTD_GCMD_IRE); } From 77250171bdc02aee106083fd2a068147befa1a38 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 14 Mar 2022 14:25:44 +0000 Subject: [PATCH 357/935] intel_iommu: Fix irqchip / X2APIC configuration checks We don't need to check kvm_enable_x2apic(). It's perfectly OK to support interrupt remapping even if we can't address CPUs above 254. Kind of pointless, but still functional. The check on kvm_enable_x2apic() needs to happen *anyway* in order to allow CPUs above 254 even without an IOMMU, so allow that to happen elsewhere. However, we do require the *split* irqchip in order to rewrite I/OAPIC destinations. So fix that check while we're here. Signed-off-by: David Woodhouse Acked-by: Claudio Fontana Message-Id: <20220314142544.150555-4-dwmw2@infradead.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index d3361c8313..d310532108 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3786,15 +3786,10 @@ static bool vtd_decide_config(IntelIOMMUState *s, Error **errp) ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; } if (s->intr_eim == ON_OFF_AUTO_ON && !s->buggy_eim) { - if (!kvm_irqchip_in_kernel()) { + if (!kvm_irqchip_is_split()) { error_setg(errp, "eim=on requires accel=kvm,kernel-irqchip=split"); return false; } - if (!kvm_enable_x2apic()) { - error_setg(errp, "eim=on requires support on the KVM side" - "(X2APIC_API, first shipped in v4.7)"); - return false; - } } /* Currently only address widths supported are 39 and 48 bits */ From a48a5bcd641773dca66840908d2c6d9552e3d1c6 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 10 Feb 2022 17:28:14 +0800 Subject: [PATCH 358/935] intel-iommu: remove VTD_FR_RESERVED_ERR This fault reason is not used and is duplicated with SPT.2 condition code. So let's remove it. Signed-off-by: Jason Wang Message-Id: <20220210092815.45174-1-jasowang@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Peter Xu --- hw/i386/intel_iommu.c | 6 ------ hw/i386/intel_iommu_internal.h | 5 ----- 2 files changed, 11 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index d310532108..8af2e39151 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -469,11 +469,6 @@ static void vtd_report_dmar_fault(IntelIOMMUState *s, uint16_t source_id, assert(fault < VTD_FR_MAX); - if (fault == VTD_FR_RESERVED_ERR) { - /* This is not a normal fault reason case. Drop it. */ - return; - } - trace_vtd_dmar_fault(source_id, fault, addr, is_write); if (fsts_reg & VTD_FSTS_PFO) { @@ -1637,7 +1632,6 @@ static const bool vtd_qualified_faults[] = { [VTD_FR_PAGING_ENTRY_RSVD] = true, [VTD_FR_CONTEXT_ENTRY_TT] = true, [VTD_FR_PASID_TABLE_INV] = false, - [VTD_FR_RESERVED_ERR] = false, [VTD_FR_MAX] = false, }; diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index 1ff13b40f9..b6a2da8e83 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -304,11 +304,6 @@ typedef enum VTDFaultReason { VTD_FR_PASID_TABLE_INV = 0x58, /*Invalid PASID table entry */ - /* This is not a normal fault reason. We use this to indicate some faults - * that are not referenced by the VT-d specification. - * Fault event with such reason should not be recorded. - */ - VTD_FR_RESERVED_ERR, VTD_FR_MAX, /* Guard */ } VTDFaultReason; From ea97a1bde7b7940bb2100b645b6f1abc7330e248 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 10 Feb 2022 17:28:15 +0800 Subject: [PATCH 359/935] intel-iommu: block output address in interrupt address range According to vtd spec v3.3 3.14: """ Software must not program paging-structure entries to remap any address to the interrupt address range. Untranslated requests and translation requests that result in an address in the interrupt range will be blocked with condition code LGN.4 or SGN.8. """ This patch blocks the request that result in interrupt address range. Signed-off-by: Jason Wang Message-Id: <20220210092815.45174-2-jasowang@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Peter Xu --- hw/i386/intel_iommu.c | 27 ++++++++++++++++++++++++++- hw/i386/intel_iommu_internal.h | 4 ++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 8af2e39151..695dd51dc3 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -1020,6 +1020,7 @@ static int vtd_iova_to_slpte(IntelIOMMUState *s, VTDContextEntry *ce, uint32_t offset; uint64_t slpte; uint64_t access_right_check; + uint64_t xlat, size; if (!vtd_iova_range_check(s, iova, ce, aw_bits)) { error_report_once("%s: detected IOVA overflow (iova=0x%" PRIx64 ")", @@ -1064,11 +1065,33 @@ static int vtd_iova_to_slpte(IntelIOMMUState *s, VTDContextEntry *ce, if (vtd_is_last_slpte(slpte, level)) { *slptep = slpte; *slpte_level = level; - return 0; + break; } addr = vtd_get_slpte_addr(slpte, aw_bits); level--; } + + xlat = vtd_get_slpte_addr(*slptep, aw_bits); + size = ~vtd_slpt_level_page_mask(level) + 1; + + /* + * From VT-d spec 3.14: Untranslated requests and translation + * requests that result in an address in the interrupt range will be + * blocked with condition code LGN.4 or SGN.8. + */ + if ((xlat > VTD_INTERRUPT_ADDR_LAST || + xlat + size - 1 < VTD_INTERRUPT_ADDR_FIRST)) { + return 0; + } else { + error_report_once("%s: xlat address is in interrupt range " + "(iova=0x%" PRIx64 ", level=0x%" PRIx32 ", " + "slpte=0x%" PRIx64 ", write=%d, " + "xlat=0x%" PRIx64 ", size=0x%" PRIx64 ")", + __func__, iova, level, slpte, is_write, + xlat, size); + return s->scalable_mode ? -VTD_FR_SM_INTERRUPT_ADDR : + -VTD_FR_INTERRUPT_ADDR; + } } typedef int (*vtd_page_walk_hook)(IOMMUTLBEvent *event, void *private); @@ -1628,10 +1651,12 @@ static const bool vtd_qualified_faults[] = { [VTD_FR_PAGING_ENTRY_INV] = true, [VTD_FR_ROOT_TABLE_INV] = false, [VTD_FR_CONTEXT_TABLE_INV] = false, + [VTD_FR_INTERRUPT_ADDR] = true, [VTD_FR_ROOT_ENTRY_RSVD] = false, [VTD_FR_PAGING_ENTRY_RSVD] = true, [VTD_FR_CONTEXT_ENTRY_TT] = true, [VTD_FR_PASID_TABLE_INV] = false, + [VTD_FR_SM_INTERRUPT_ADDR] = true, [VTD_FR_MAX] = false, }; diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index b6a2da8e83..930ce61feb 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -289,6 +289,8 @@ typedef enum VTDFaultReason { * context-entry. */ VTD_FR_CONTEXT_ENTRY_TT, + /* Output address in the interrupt address range */ + VTD_FR_INTERRUPT_ADDR = 0xE, /* Interrupt remapping transition faults */ VTD_FR_IR_REQ_RSVD = 0x20, /* One or more IR request reserved @@ -304,6 +306,8 @@ typedef enum VTDFaultReason { VTD_FR_PASID_TABLE_INV = 0x58, /*Invalid PASID table entry */ + /* Output address in the interrupt address range for scalable mode */ + VTD_FR_SM_INTERRUPT_ADDR = 0x87, VTD_FR_MAX, /* Guard */ } VTDFaultReason; From ceb058955ab529937498acfd3c9259a2a64b2d4e Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 17 Mar 2022 16:05:21 +0800 Subject: [PATCH 360/935] intel-iommu: update root_scalable before switching as during post_load We need check whether passthrough is enabled during vtd_switch_address_space() by checking the context entries. This requires the root_scalable to be set correctly otherwise we may try to check legacy rsvd bits instead of scalable ones. Fixing this by updating root_scalable before switching the address spaces during post_load. Fixes: fb43cf739e ("intel_iommu: scalable mode emulation") Signed-off-by: Jason Wang Message-Id: <20220317080522.14621-1-jasowang@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Peter Xu --- hw/i386/intel_iommu.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 695dd51dc3..53e3f5035d 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3073,13 +3073,6 @@ static int vtd_post_load(void *opaque, int version_id) { IntelIOMMUState *iommu = opaque; - /* - * Memory regions are dynamically turned on/off depending on - * context entry configurations from the guest. After migration, - * we need to make sure the memory regions are still correct. - */ - vtd_switch_address_space_all(iommu); - /* * We don't need to migrate the root_scalable because we can * simply do the calculation after the loading is complete. We @@ -3089,6 +3082,13 @@ static int vtd_post_load(void *opaque, int version_id) */ vtd_update_scalable_state(iommu); + /* + * Memory regions are dynamically turned on/off depending on + * context entry configurations from the guest. After migration, + * we need to make sure the memory regions are still correct. + */ + vtd_switch_address_space_all(iommu); + return 0; } From 147a372e7580dc5cf4310d159db2f374e38ac30e Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 17 Mar 2022 16:05:22 +0800 Subject: [PATCH 361/935] intel-iommu: update iq_dw during post load We need to update iq_dw according to the DMA_IRQ_REG during post load. Otherwise we may get wrong IOTLB invalidation descriptor after migration. Fixes: fb43cf739e ("intel_iommu: scalable mode emulation") Signed-off-by: Jason Wang Message-Id: <20220317080522.14621-2-jasowang@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Peter Xu --- hw/i386/intel_iommu.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 53e3f5035d..2162394e08 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -181,6 +181,18 @@ static void vtd_update_scalable_state(IntelIOMMUState *s) } } +static void vtd_update_iq_dw(IntelIOMMUState *s) +{ + uint64_t val = vtd_get_quad_raw(s, DMAR_IQA_REG); + + if (s->ecap & VTD_ECAP_SMTS && + val & VTD_IQA_DW_MASK) { + s->iq_dw = true; + } else { + s->iq_dw = false; + } +} + /* Whether the address space needs to notify new mappings */ static inline gboolean vtd_as_has_map_notifier(VTDAddressSpace *as) { @@ -2904,12 +2916,7 @@ static void vtd_mem_write(void *opaque, hwaddr addr, } else { vtd_set_quad(s, addr, val); } - if (s->ecap & VTD_ECAP_SMTS && - val & VTD_IQA_DW_MASK) { - s->iq_dw = true; - } else { - s->iq_dw = false; - } + vtd_update_iq_dw(s); break; case DMAR_IQA_REG_HI: @@ -3082,6 +3089,8 @@ static int vtd_post_load(void *opaque, int version_id) */ vtd_update_scalable_state(iommu); + vtd_update_iq_dw(iommu); + /* * Memory regions are dynamically turned on/off depending on * context entry configurations from the guest. After migration, From 1eed051c8c8cd84e69f619b0adc22df543ed7f06 Mon Sep 17 00:00:00 2001 From: Ilya Maximets Date: Fri, 18 Mar 2022 15:04:40 +0100 Subject: [PATCH 362/935] vhost_net: Print feature masks in hex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "0x200000000" is much more readable than "8589934592". The change saves one step (conversion) while debugging. Signed-off-by: Ilya Maximets Message-Id: <20220318140440.596019-1-i.maximets@ovn.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Philippe Mathieu-Daudé --- hw/net/vhost_net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 30379d2ca4..df0f050548 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -201,7 +201,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options) net->dev.features &= ~(1ULL << VIRTIO_NET_F_MRG_RXBUF); } if (~net->dev.features & net->dev.backend_features) { - fprintf(stderr, "vhost lacks feature mask %" PRIu64 + fprintf(stderr, "vhost lacks feature mask 0x%" PRIx64 " for backend\n", (uint64_t)(~net->dev.features & net->dev.backend_features)); goto fail; @@ -213,7 +213,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options) if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) { features = vhost_user_get_acked_features(net->nc); if (~net->dev.features & features) { - fprintf(stderr, "vhost lacks feature mask %" PRIu64 + fprintf(stderr, "vhost lacks feature mask 0x%" PRIx64 " for backend\n", (uint64_t)(~net->dev.features & features)); goto fail; From e1b1f5341a860e87c6f208e2eea7a3b2bab454dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 21 Mar 2022 15:30:25 +0000 Subject: [PATCH 363/935] hw/virtio: move virtio-pci.h into shared include space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows other device classes that will be exposed via PCI to be able to do so in the appropriate hw/ directory. I resisted the temptation to re-order headers to be more aesthetically pleasing. Signed-off-by: Alex Bennée Message-Id: <20200925125147.26943-4-alex.bennee@linaro.org> Message-Id: <20220321153037.3622127-2-alex.bennee@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-scsi-pci.c | 2 +- hw/virtio/vhost-user-blk-pci.c | 2 +- hw/virtio/vhost-user-fs-pci.c | 2 +- hw/virtio/vhost-user-i2c-pci.c | 2 +- hw/virtio/vhost-user-input-pci.c | 2 +- hw/virtio/vhost-user-rng-pci.c | 2 +- hw/virtio/vhost-user-scsi-pci.c | 2 +- hw/virtio/vhost-user-vsock-pci.c | 2 +- hw/virtio/vhost-vsock-pci.c | 2 +- hw/virtio/virtio-9p-pci.c | 2 +- hw/virtio/virtio-balloon-pci.c | 2 +- hw/virtio/virtio-blk-pci.c | 2 +- hw/virtio/virtio-input-host-pci.c | 2 +- hw/virtio/virtio-input-pci.c | 2 +- hw/virtio/virtio-iommu-pci.c | 2 +- hw/virtio/virtio-net-pci.c | 2 +- hw/virtio/virtio-pci.c | 2 +- hw/virtio/virtio-rng-pci.c | 2 +- hw/virtio/virtio-scsi-pci.c | 2 +- hw/virtio/virtio-serial-pci.c | 2 +- {hw => include/hw}/virtio/virtio-pci.h | 0 21 files changed, 20 insertions(+), 20 deletions(-) rename {hw => include/hw}/virtio/virtio-pci.h (100%) diff --git a/hw/virtio/vhost-scsi-pci.c b/hw/virtio/vhost-scsi-pci.c index cb71a294fa..08980bc23b 100644 --- a/hw/virtio/vhost-scsi-pci.c +++ b/hw/virtio/vhost-scsi-pci.c @@ -21,7 +21,7 @@ #include "hw/virtio/vhost-scsi.h" #include "qapi/error.h" #include "qemu/module.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qom/object.h" typedef struct VHostSCSIPCI VHostSCSIPCI; diff --git a/hw/virtio/vhost-user-blk-pci.c b/hw/virtio/vhost-user-blk-pci.c index 33b404d8a2..eef8641a98 100644 --- a/hw/virtio/vhost-user-blk-pci.c +++ b/hw/virtio/vhost-user-blk-pci.c @@ -26,7 +26,7 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/module.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qom/object.h" typedef struct VHostUserBlkPCI VHostUserBlkPCI; diff --git a/hw/virtio/vhost-user-fs-pci.c b/hw/virtio/vhost-user-fs-pci.c index 2ed8492b3f..6829b8b743 100644 --- a/hw/virtio/vhost-user-fs-pci.c +++ b/hw/virtio/vhost-user-fs-pci.c @@ -14,7 +14,7 @@ #include "qemu/osdep.h" #include "hw/qdev-properties.h" #include "hw/virtio/vhost-user-fs.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qom/object.h" struct VHostUserFSPCI { diff --git a/hw/virtio/vhost-user-i2c-pci.c b/hw/virtio/vhost-user-i2c-pci.c index 70b7b65fd9..00ac10941f 100644 --- a/hw/virtio/vhost-user-i2c-pci.c +++ b/hw/virtio/vhost-user-i2c-pci.c @@ -9,7 +9,7 @@ #include "qemu/osdep.h" #include "hw/qdev-properties.h" #include "hw/virtio/vhost-user-i2c.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" struct VHostUserI2CPCI { VirtIOPCIProxy parent_obj; diff --git a/hw/virtio/vhost-user-input-pci.c b/hw/virtio/vhost-user-input-pci.c index c9d3e9113a..b858898a36 100644 --- a/hw/virtio/vhost-user-input-pci.c +++ b/hw/virtio/vhost-user-input-pci.c @@ -9,7 +9,7 @@ #include "hw/virtio/virtio-input.h" #include "qapi/error.h" #include "qemu/error-report.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qom/object.h" typedef struct VHostUserInputPCI VHostUserInputPCI; diff --git a/hw/virtio/vhost-user-rng-pci.c b/hw/virtio/vhost-user-rng-pci.c index c83dc86813..f64935453b 100644 --- a/hw/virtio/vhost-user-rng-pci.c +++ b/hw/virtio/vhost-user-rng-pci.c @@ -9,7 +9,7 @@ #include "qemu/osdep.h" #include "hw/qdev-properties.h" #include "hw/virtio/vhost-user-rng.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" struct VHostUserRNGPCI { VirtIOPCIProxy parent_obj; diff --git a/hw/virtio/vhost-user-scsi-pci.c b/hw/virtio/vhost-user-scsi-pci.c index d5343412a1..75882e3cf9 100644 --- a/hw/virtio/vhost-user-scsi-pci.c +++ b/hw/virtio/vhost-user-scsi-pci.c @@ -30,7 +30,7 @@ #include "hw/pci/msix.h" #include "hw/loader.h" #include "sysemu/kvm.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qom/object.h" typedef struct VHostUserSCSIPCI VHostUserSCSIPCI; diff --git a/hw/virtio/vhost-user-vsock-pci.c b/hw/virtio/vhost-user-vsock-pci.c index 72a96199cd..e5a86e8013 100644 --- a/hw/virtio/vhost-user-vsock-pci.c +++ b/hw/virtio/vhost-user-vsock-pci.c @@ -10,7 +10,7 @@ #include "qemu/osdep.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "hw/qdev-properties.h" #include "hw/virtio/vhost-user-vsock.h" #include "qom/object.h" diff --git a/hw/virtio/vhost-vsock-pci.c b/hw/virtio/vhost-vsock-pci.c index 205da8d1f5..9f34414d38 100644 --- a/hw/virtio/vhost-vsock-pci.c +++ b/hw/virtio/vhost-vsock-pci.c @@ -13,7 +13,7 @@ #include "qemu/osdep.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "hw/qdev-properties.h" #include "hw/virtio/vhost-vsock.h" #include "qemu/module.h" diff --git a/hw/virtio/virtio-9p-pci.c b/hw/virtio/virtio-9p-pci.c index e07adcd9ea..94c14f0b98 100644 --- a/hw/virtio/virtio-9p-pci.c +++ b/hw/virtio/virtio-9p-pci.c @@ -15,7 +15,7 @@ #include "qemu/osdep.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "hw/9pfs/virtio-9p.h" #include "hw/qdev-properties.h" #include "qemu/module.h" diff --git a/hw/virtio/virtio-balloon-pci.c b/hw/virtio/virtio-balloon-pci.c index 79a3ba979a..ce2645ba71 100644 --- a/hw/virtio/virtio-balloon-pci.c +++ b/hw/virtio/virtio-balloon-pci.c @@ -14,7 +14,7 @@ #include "qemu/osdep.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "hw/qdev-properties.h" #include "hw/virtio/virtio-balloon.h" #include "qapi/error.h" diff --git a/hw/virtio/virtio-blk-pci.c b/hw/virtio/virtio-blk-pci.c index 9d5795810c..9743bee965 100644 --- a/hw/virtio/virtio-blk-pci.c +++ b/hw/virtio/virtio-blk-pci.c @@ -19,7 +19,7 @@ #include "hw/qdev-properties.h" #include "hw/virtio/virtio-blk.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qapi/error.h" #include "qemu/module.h" #include "qom/object.h" diff --git a/hw/virtio/virtio-input-host-pci.c b/hw/virtio/virtio-input-host-pci.c index 0ac360de4f..cf8a9cf9e8 100644 --- a/hw/virtio/virtio-input-host-pci.c +++ b/hw/virtio/virtio-input-host-pci.c @@ -8,7 +8,7 @@ #include "qemu/osdep.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "hw/virtio/virtio-input.h" #include "qemu/module.h" #include "qom/object.h" diff --git a/hw/virtio/virtio-input-pci.c b/hw/virtio/virtio-input-pci.c index 48e9ff38e2..a9d0992389 100644 --- a/hw/virtio/virtio-input-pci.c +++ b/hw/virtio/virtio-input-pci.c @@ -8,7 +8,7 @@ #include "qemu/osdep.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "hw/qdev-properties.h" #include "hw/virtio/virtio-input.h" #include "qemu/module.h" diff --git a/hw/virtio/virtio-iommu-pci.c b/hw/virtio/virtio-iommu-pci.c index 6a1df7fe50..844d647704 100644 --- a/hw/virtio/virtio-iommu-pci.c +++ b/hw/virtio/virtio-iommu-pci.c @@ -11,7 +11,7 @@ #include "qemu/osdep.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "hw/virtio/virtio-iommu.h" #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" diff --git a/hw/virtio/virtio-net-pci.c b/hw/virtio/virtio-net-pci.c index aa0b3caecb..e03543a70a 100644 --- a/hw/virtio/virtio-net-pci.c +++ b/hw/virtio/virtio-net-pci.c @@ -19,7 +19,7 @@ #include "hw/qdev-properties.h" #include "hw/virtio/virtio-net.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qapi/error.h" #include "qemu/module.h" #include "qom/object.h" diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 7cf1231c1c..602be7f83d 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -33,7 +33,7 @@ #include "hw/pci/msix.h" #include "hw/loader.h" #include "sysemu/kvm.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qemu/range.h" #include "hw/virtio/virtio-bus.h" #include "qapi/visitor.h" diff --git a/hw/virtio/virtio-rng-pci.c b/hw/virtio/virtio-rng-pci.c index c1f916268b..151ece6f94 100644 --- a/hw/virtio/virtio-rng-pci.c +++ b/hw/virtio/virtio-rng-pci.c @@ -11,7 +11,7 @@ #include "qemu/osdep.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "hw/virtio/virtio-rng.h" #include "qapi/error.h" #include "qemu/module.h" diff --git a/hw/virtio/virtio-scsi-pci.c b/hw/virtio/virtio-scsi-pci.c index 97fab74236..e8e3442f38 100644 --- a/hw/virtio/virtio-scsi-pci.c +++ b/hw/virtio/virtio-scsi-pci.c @@ -18,7 +18,7 @@ #include "hw/qdev-properties.h" #include "hw/virtio/virtio-scsi.h" #include "qemu/module.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qom/object.h" typedef struct VirtIOSCSIPCI VirtIOSCSIPCI; diff --git a/hw/virtio/virtio-serial-pci.c b/hw/virtio/virtio-serial-pci.c index 35bcd961c9..cea31adcc4 100644 --- a/hw/virtio/virtio-serial-pci.c +++ b/hw/virtio/virtio-serial-pci.c @@ -20,7 +20,7 @@ #include "hw/qdev-properties.h" #include "hw/virtio/virtio-serial.h" #include "qemu/module.h" -#include "virtio-pci.h" +#include "hw/virtio/virtio-pci.h" #include "qom/object.h" typedef struct VirtIOSerialPCI VirtIOSerialPCI; diff --git a/hw/virtio/virtio-pci.h b/include/hw/virtio/virtio-pci.h similarity index 100% rename from hw/virtio/virtio-pci.h rename to include/hw/virtio/virtio-pci.h From 31cc62bb5bd43b6c36b1f42d5bde6baca4dffaee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 21 Mar 2022 15:30:26 +0000 Subject: [PATCH 364/935] virtio-pci: add notification trace points MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200925125147.26943-6-alex.bennee@linaro.org> Signed-off-by: Alex Bennée Message-Id: <20220321153037.3622127-3-alex.bennee@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/trace-events | 7 ++++++- hw/virtio/virtio-pci.c | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 333348d9d5..7a6576d833 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -89,7 +89,12 @@ virtio_mmio_guest_page(uint64_t size, int shift) "guest page size 0x%" PRIx64 " virtio_mmio_queue_write(uint64_t value, int max_size) "mmio_queue write 0x%" PRIx64 " max %d" virtio_mmio_setting_irq(int level) "virtio_mmio setting IRQ %d" -# virtio-iommu.c +# virtio-pci.c +virtio_pci_notify(uint16_t vector) "virtio_pci_notify vec 0x%x" +virtio_pci_notify_write(uint64_t addr, uint64_t val, unsigned int size) "0x%" PRIx64" = 0x%" PRIx64 " (%d)" +virtio_pci_notify_write_pio(uint64_t addr, uint64_t val, unsigned int size) "0x%" PRIx64" = 0x%" PRIx64 " (%d)" + +# hw/virtio/virtio-iommu.c virtio_iommu_device_reset(void) "reset!" virtio_iommu_system_reset(void) "system reset!" virtio_iommu_get_features(uint64_t features) "device supports features=0x%"PRIx64 diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 602be7f83d..0566ad7d00 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -38,6 +38,7 @@ #include "hw/virtio/virtio-bus.h" #include "qapi/visitor.h" #include "sysemu/replay.h" +#include "trace.h" #define VIRTIO_PCI_REGION_SIZE(dev) VIRTIO_PCI_CONFIG_OFF(msix_present(dev)) @@ -1380,6 +1381,7 @@ static void virtio_pci_notify_write(void *opaque, hwaddr addr, unsigned queue = addr / virtio_pci_queue_mem_mult(proxy); if (vdev != NULL && queue < VIRTIO_QUEUE_MAX) { + trace_virtio_pci_notify_write(addr, val, size); virtio_queue_notify(vdev, queue); } } @@ -1393,6 +1395,7 @@ static void virtio_pci_notify_write_pio(void *opaque, hwaddr addr, unsigned queue = val; if (vdev != NULL && queue < VIRTIO_QUEUE_MAX) { + trace_virtio_pci_notify_write_pio(addr, val, size); virtio_queue_notify(vdev, queue); } } From 6ca6d8ee9dd053eaa625aad48d95d12f4418ef4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 21 Mar 2022 15:30:27 +0000 Subject: [PATCH 365/935] hw/virtio: add vhost_user_[read|write] trace points MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These are useful when trying to debug the initial vhost-user negotiation, especially when it hard to get logging from the low level library on the other side. Signed-off-by: Alex Bennée Message-Id: <20220321153037.3622127-4-alex.bennee@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Philippe Mathieu-Daudé --- hw/virtio/trace-events | 2 ++ hw/virtio/vhost-user.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 7a6576d833..65e3b704ec 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -21,6 +21,8 @@ vhost_user_set_mem_table_withfd(int index, const char *name, uint64_t memory_siz vhost_user_postcopy_waker(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64 vhost_user_postcopy_waker_found(uint64_t client_addr) "0x%"PRIx64 vhost_user_postcopy_waker_nomatch(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64 +vhost_user_read(uint32_t req, uint32_t flags) "req:%d flags:0x%"PRIx32"" +vhost_user_write(uint32_t req, uint32_t flags) "req:%d flags:0x%"PRIx32"" # vhost-vdpa.c vhost_vdpa_dma_map(void *vdpa, int fd, uint32_t msg_type, uint64_t iova, uint64_t size, uint64_t uaddr, uint8_t perm, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" uaddr: 0x%"PRIx64" perm: 0x%"PRIx8" type: %"PRIu8 diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index afd51f79b3..6c8f722262 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -489,6 +489,8 @@ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg, return ret < 0 ? -saved_errno : -EIO; } + trace_vhost_user_write(msg->hdr.request, msg->hdr.flags); + return 0; } @@ -542,6 +544,8 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, } } + trace_vhost_user_read(msg.hdr.request, msg.hdr.flags); + return 0; } From 43725d4844cc516e8c1b92c7903aeb0e88360f1b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 21 Mar 2022 15:30:28 +0000 Subject: [PATCH 366/935] docs: vhost-user: clean up request/reply description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is not necessary to mention which side is sending/receiving each payload; it is more interesting to say which is the request and which is the reply. This also matches what vhost-user-gpu.rst already does. While at it, ensure that all messages list both the request and the reply payload. Signed-off-by: Paolo Bonzini Message-Id: <20210226143413.188046-2-pbonzini@redhat.com> Message-Id: <20220321153037.3622127-5-alex.bennee@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Philippe Mathieu-Daudé --- docs/interop/vhost-user.rst | 163 +++++++++++++++++++++--------------- 1 file changed, 95 insertions(+), 68 deletions(-) diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst index f9e721ba5f..1039e7a34e 100644 --- a/docs/interop/vhost-user.rst +++ b/docs/interop/vhost-user.rst @@ -866,8 +866,8 @@ Master message types ``VHOST_USER_GET_FEATURES`` :id: 1 :equivalent ioctl: ``VHOST_GET_FEATURES`` - :master payload: N/A - :slave payload: ``u64`` + :request payload: N/A + :reply payload: ``u64`` Get from the underlying vhost implementation the features bitmask. Feature bit ``VHOST_USER_F_PROTOCOL_FEATURES`` signals slave support @@ -877,7 +877,8 @@ Master message types ``VHOST_USER_SET_FEATURES`` :id: 2 :equivalent ioctl: ``VHOST_SET_FEATURES`` - :master payload: ``u64`` + :request payload: ``u64`` + :reply payload: N/A Enable features in the underlying vhost implementation using a bitmask. Feature bit ``VHOST_USER_F_PROTOCOL_FEATURES`` signals @@ -887,8 +888,8 @@ Master message types ``VHOST_USER_GET_PROTOCOL_FEATURES`` :id: 15 :equivalent ioctl: ``VHOST_GET_FEATURES`` - :master payload: N/A - :slave payload: ``u64`` + :request payload: N/A + :reply payload: ``u64`` Get the protocol feature bitmask from the underlying vhost implementation. Only legal if feature bit @@ -903,7 +904,8 @@ Master message types ``VHOST_USER_SET_PROTOCOL_FEATURES`` :id: 16 :equivalent ioctl: ``VHOST_SET_FEATURES`` - :master payload: ``u64`` + :request payload: ``u64`` + :reply payload: N/A Enable protocol features in the underlying vhost implementation. @@ -917,7 +919,8 @@ Master message types ``VHOST_USER_SET_OWNER`` :id: 3 :equivalent ioctl: ``VHOST_SET_OWNER`` - :master payload: N/A + :request payload: N/A + :reply payload: N/A Issued when a new connection is established. It sets the current *master* as an owner of the session. This can be used on the *slave* @@ -925,7 +928,8 @@ Master message types ``VHOST_USER_RESET_OWNER`` :id: 4 - :master payload: N/A + :request payload: N/A + :reply payload: N/A .. admonition:: Deprecated @@ -938,8 +942,8 @@ Master message types ``VHOST_USER_SET_MEM_TABLE`` :id: 5 :equivalent ioctl: ``VHOST_SET_MEM_TABLE`` - :master payload: memory regions description - :slave payload: (postcopy only) memory regions description + :request payload: memory regions description + :reply payload: (postcopy only) memory regions description Sets the memory map regions on the slave so it can translate the vring addresses. In the ancillary data there is an array of file @@ -962,8 +966,8 @@ Master message types ``VHOST_USER_SET_LOG_BASE`` :id: 6 :equivalent ioctl: ``VHOST_SET_LOG_BASE`` - :master payload: u64 - :slave payload: N/A + :request payload: u64 + :reply payload: N/A Sets logging shared memory space. @@ -975,44 +979,48 @@ Master message types ``VHOST_USER_SET_LOG_FD`` :id: 7 :equivalent ioctl: ``VHOST_SET_LOG_FD`` - :master payload: N/A + :request payload: N/A + :reply payload: N/A Sets the logging file descriptor, which is passed as ancillary data. ``VHOST_USER_SET_VRING_NUM`` :id: 8 :equivalent ioctl: ``VHOST_SET_VRING_NUM`` - :master payload: vring state description + :request payload: vring state description + :reply payload: N/A Set the size of the queue. ``VHOST_USER_SET_VRING_ADDR`` :id: 9 :equivalent ioctl: ``VHOST_SET_VRING_ADDR`` - :master payload: vring address description - :slave payload: N/A + :request payload: vring address description + :reply payload: N/A Sets the addresses of the different aspects of the vring. ``VHOST_USER_SET_VRING_BASE`` :id: 10 :equivalent ioctl: ``VHOST_SET_VRING_BASE`` - :master payload: vring state description + :request payload: vring state description + :reply payload: N/A Sets the base offset in the available vring. ``VHOST_USER_GET_VRING_BASE`` :id: 11 :equivalent ioctl: ``VHOST_USER_GET_VRING_BASE`` - :master payload: vring state description - :slave payload: vring state description + :request payload: vring state description + :reply payload: vring state description Get the available vring base offset. ``VHOST_USER_SET_VRING_KICK`` :id: 12 :equivalent ioctl: ``VHOST_SET_VRING_KICK`` - :master payload: ``u64`` + :request payload: ``u64`` + :reply payload: N/A Set the event file descriptor for adding buffers to the vring. It is passed in the ancillary data. @@ -1030,7 +1038,8 @@ Master message types ``VHOST_USER_SET_VRING_CALL`` :id: 13 :equivalent ioctl: ``VHOST_SET_VRING_CALL`` - :master payload: ``u64`` + :request payload: ``u64`` + :reply payload: N/A Set the event file descriptor to signal when buffers are used. It is passed in the ancillary data. @@ -1048,7 +1057,8 @@ Master message types ``VHOST_USER_SET_VRING_ERR`` :id: 14 :equivalent ioctl: ``VHOST_SET_VRING_ERR`` - :master payload: ``u64`` + :request payload: ``u64`` + :reply payload: N/A Set the event file descriptor to signal when error occurs. It is passed in the ancillary data. @@ -1065,8 +1075,8 @@ Master message types ``VHOST_USER_GET_QUEUE_NUM`` :id: 17 :equivalent ioctl: N/A - :master payload: N/A - :slave payload: u64 + :request payload: N/A + :reply payload: u64 Query how many queues the backend supports. @@ -1077,7 +1087,8 @@ Master message types ``VHOST_USER_SET_VRING_ENABLE`` :id: 18 :equivalent ioctl: N/A - :master payload: vring state description + :request payload: vring state description + :reply payload: N/A Signal slave to enable or disable corresponding vring. @@ -1087,7 +1098,8 @@ Master message types ``VHOST_USER_SEND_RARP`` :id: 19 :equivalent ioctl: N/A - :master payload: ``u64`` + :request payload: ``u64`` + :reply payload: N/A Ask vhost user backend to broadcast a fake RARP to notify the migration is terminated for guest that does not support GUEST_ANNOUNCE. @@ -1102,7 +1114,8 @@ Master message types ``VHOST_USER_NET_SET_MTU`` :id: 20 :equivalent ioctl: N/A - :master payload: ``u64`` + :request payload: ``u64`` + :reply payload: N/A Set host MTU value exposed to the guest. @@ -1119,7 +1132,8 @@ Master message types ``VHOST_USER_SET_SLAVE_REQ_FD`` :id: 21 :equivalent ioctl: N/A - :master payload: N/A + :request payload: N/A + :reply payload: N/A Set the socket file descriptor for slave initiated requests. It is passed in the ancillary data. @@ -1134,8 +1148,8 @@ Master message types ``VHOST_USER_IOTLB_MSG`` :id: 22 :equivalent ioctl: N/A (equivalent to ``VHOST_IOTLB_MSG`` message type) - :master payload: ``struct vhost_iotlb_msg`` - :slave payload: ``u64`` + :request payload: ``struct vhost_iotlb_msg`` + :reply payload: ``u64`` Send IOTLB messages with ``struct vhost_iotlb_msg`` as payload. @@ -1149,7 +1163,8 @@ Master message types ``VHOST_USER_SET_VRING_ENDIAN`` :id: 23 :equivalent ioctl: ``VHOST_SET_VRING_ENDIAN`` - :master payload: vring state description + :request payload: vring state description + :reply payload: N/A Set the endianness of a VQ for legacy devices. Little-endian is indicated with state.num set to 0 and big-endian is indicated with @@ -1164,8 +1179,8 @@ Master message types ``VHOST_USER_GET_CONFIG`` :id: 24 :equivalent ioctl: N/A - :master payload: virtio device config space - :slave payload: virtio device config space + :request payload: virtio device config space + :reply payload: virtio device config space When ``VHOST_USER_PROTOCOL_F_CONFIG`` is negotiated, this message is submitted by the vhost-user master to fetch the contents of the @@ -1178,8 +1193,8 @@ Master message types ``VHOST_USER_SET_CONFIG`` :id: 25 :equivalent ioctl: N/A - :master payload: virtio device config space - :slave payload: N/A + :request payload: virtio device config space + :reply payload: N/A When ``VHOST_USER_PROTOCOL_F_CONFIG`` is negotiated, this message is submitted by the vhost-user master when the Guest changes the virtio @@ -1191,8 +1206,8 @@ Master message types ``VHOST_USER_CREATE_CRYPTO_SESSION`` :id: 26 :equivalent ioctl: N/A - :master payload: crypto session description - :slave payload: crypto session description + :request payload: crypto session description + :reply payload: crypto session description Create a session for crypto operation. The server side must return the session id, 0 or positive for success, negative for failure. @@ -1204,7 +1219,8 @@ Master message types ``VHOST_USER_CLOSE_CRYPTO_SESSION`` :id: 27 :equivalent ioctl: N/A - :master payload: ``u64`` + :request payload: ``u64`` + :reply payload: N/A Close a session for crypto operation which was previously created by ``VHOST_USER_CREATE_CRYPTO_SESSION``. @@ -1216,8 +1232,8 @@ Master message types ``VHOST_USER_POSTCOPY_ADVISE`` :id: 28 - :master payload: N/A - :slave payload: userfault fd + :request payload: N/A + :reply payload: userfault fd When ``VHOST_USER_PROTOCOL_F_PAGEFAULT`` is supported, the master advises slave that a migration with postcopy enabled is underway, @@ -1226,7 +1242,8 @@ Master message types ``VHOST_USER_POSTCOPY_LISTEN`` :id: 29 - :master payload: N/A + :request payload: N/A + :reply payload: N/A Master advises slave that a transition to postcopy mode has happened. The slave must ensure that shared memory is registered @@ -1237,10 +1254,11 @@ Master message types ``VHOST_USER_POSTCOPY_END`` :id: 30 - :slave payload: ``u64`` + :request payload: N/A + :reply payload: ``u64`` Master advises that postcopy migration has now completed. The slave - must disable the userfaultfd. The response is an acknowledgement + must disable the userfaultfd. The reply is an acknowledgement only. When ``VHOST_USER_PROTOCOL_F_PAGEFAULT`` is supported, this message @@ -1252,7 +1270,8 @@ Master message types ``VHOST_USER_GET_INFLIGHT_FD`` :id: 31 :equivalent ioctl: N/A - :master payload: inflight description + :request payload: inflight description + :reply payload: N/A When ``VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD`` protocol feature has been successfully negotiated, this message is submitted by master to @@ -1263,7 +1282,8 @@ Master message types ``VHOST_USER_SET_INFLIGHT_FD`` :id: 32 :equivalent ioctl: N/A - :master payload: inflight description + :request payload: inflight description + :reply payload: N/A When ``VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD`` protocol feature has been successfully negotiated, this message is submitted by master to @@ -1273,7 +1293,8 @@ Master message types ``VHOST_USER_GPU_SET_SOCKET`` :id: 33 :equivalent ioctl: N/A - :master payload: N/A + :request payload: N/A + :reply payload: N/A Sets the GPU protocol socket file descriptor, which is passed as ancillary data. The GPU protocol is used to inform the master of @@ -1282,8 +1303,8 @@ Master message types ``VHOST_USER_RESET_DEVICE`` :id: 34 :equivalent ioctl: N/A - :master payload: N/A - :slave payload: N/A + :request payload: N/A + :reply payload: N/A Ask the vhost user backend to disable all rings and reset all internal device state to the initial state, ready to be @@ -1296,8 +1317,8 @@ Master message types ``VHOST_USER_VRING_KICK`` :id: 35 :equivalent ioctl: N/A - :slave payload: vring state description - :master payload: N/A + :request payload: vring state description + :reply payload: N/A When the ``VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS`` protocol feature has been successfully negotiated, this message may be @@ -1310,7 +1331,8 @@ Master message types ``VHOST_USER_GET_MAX_MEM_SLOTS`` :id: 36 :equivalent ioctl: N/A - :slave payload: u64 + :request payload: N/A + :reply payload: u64 When the ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol feature has been successfully negotiated, this message is submitted @@ -1323,7 +1345,8 @@ Master message types ``VHOST_USER_ADD_MEM_REG`` :id: 37 :equivalent ioctl: N/A - :slave payload: single memory region description + :request payload: N/A + :reply payload: single memory region description When the ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol feature has been successfully negotiated, this message is submitted @@ -1346,7 +1369,8 @@ Master message types ``VHOST_USER_REM_MEM_REG`` :id: 38 :equivalent ioctl: N/A - :slave payload: single memory region description + :request payload: N/A + :reply payload: single memory region description When the ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol feature has been successfully negotiated, this message is submitted @@ -1369,8 +1393,8 @@ Master message types ``VHOST_USER_SET_STATUS`` :id: 39 :equivalent ioctl: VHOST_VDPA_SET_STATUS - :slave payload: N/A - :master payload: ``u64`` + :request payload: ``u64`` + :reply payload: N/A When the ``VHOST_USER_PROTOCOL_F_STATUS`` protocol feature has been successfully negotiated, this message is submitted by the master to @@ -1380,8 +1404,8 @@ Master message types ``VHOST_USER_GET_STATUS`` :id: 40 :equivalent ioctl: VHOST_VDPA_GET_STATUS - :slave payload: ``u64`` - :master payload: N/A + :request payload: N/A + :reply payload: ``u64`` When the ``VHOST_USER_PROTOCOL_F_STATUS`` protocol feature has been successfully negotiated, this message is submitted by the master to @@ -1392,11 +1416,14 @@ Master message types Slave message types ------------------- +For this type of message, the request is sent by the slave and the reply +is sent by the master. + ``VHOST_USER_SLAVE_IOTLB_MSG`` :id: 1 :equivalent ioctl: N/A (equivalent to ``VHOST_IOTLB_MSG`` message type) - :slave payload: ``struct vhost_iotlb_msg`` - :master payload: N/A + :request payload: ``struct vhost_iotlb_msg`` + :reply payload: N/A Send IOTLB messages with ``struct vhost_iotlb_msg`` as payload. Slave sends such requests to notify of an IOTLB miss, or an IOTLB @@ -1410,8 +1437,8 @@ Slave message types ``VHOST_USER_SLAVE_CONFIG_CHANGE_MSG`` :id: 2 :equivalent ioctl: N/A - :slave payload: N/A - :master payload: N/A + :request payload: N/A + :reply payload: N/A When ``VHOST_USER_PROTOCOL_F_CONFIG`` is negotiated, vhost-user slave sends such messages to notify that the virtio device's @@ -1425,8 +1452,8 @@ Slave message types ``VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG`` :id: 3 :equivalent ioctl: N/A - :slave payload: vring area description - :master payload: N/A + :request payload: vring area description + :reply payload: N/A Sets host notifier for a specified queue. The queue index is contained in the ``u64`` field of the vring area description. The @@ -1448,8 +1475,8 @@ Slave message types ``VHOST_USER_SLAVE_VRING_CALL`` :id: 4 :equivalent ioctl: N/A - :slave payload: vring state description - :master payload: N/A + :request payload: vring state description + :reply payload: N/A When the ``VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS`` protocol feature has been successfully negotiated, this message may be @@ -1462,8 +1489,8 @@ Slave message types ``VHOST_USER_SLAVE_VRING_ERR`` :id: 5 :equivalent ioctl: N/A - :slave payload: vring state description - :master payload: N/A + :request payload: vring state description + :reply payload: N/A When the ``VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS`` protocol feature has been successfully negotiated, this message may be @@ -1489,7 +1516,7 @@ client MUST respond with a Payload ``VhostUserMsg`` indicating success or failure. The payload should be set to zero on success or non-zero on failure, unless the message already has an explicit reply body. -The response payload gives QEMU a deterministic indication of the result +The reply payload gives QEMU a deterministic indication of the result of the command. Today, QEMU is expected to terminate the main vhost-user loop upon receiving such errors. In future, qemu could be taught to be more resilient for selective requests. From 0647098d2ed69171b8bdce495cfdd1c5223010f1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 21 Mar 2022 15:30:29 +0000 Subject: [PATCH 367/935] docs: vhost-user: rewrite section on ring state machine This section is using the word "back-end" to refer to the "slave's back-end", and talking about the "client" for what the rest of the document calls the "slave". Rework it to free the use of the term "back-end", which in the next patch will replace "slave". Signed-off-by: Paolo Bonzini Message-Id: <20210226143413.188046-3-pbonzini@redhat.com> Message-Id: <20220321153037.3622127-6-alex.bennee@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/interop/vhost-user.rst | 46 +++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst index 1039e7a34e..1151326d6f 100644 --- a/docs/interop/vhost-user.rst +++ b/docs/interop/vhost-user.rst @@ -332,40 +332,36 @@ bit was dedicated for this purpose:: #define VHOST_USER_F_PROTOCOL_FEATURES 30 -Starting and stopping rings ---------------------------- +Ring states +----------- -Client must only process each ring when it is started. +Rings can be in one of three states: -Client must only pass data between the ring and the backend, when the -ring is enabled. +* stopped: the slave must not process the ring at all. -If ring is started but disabled, client must process the ring without -talking to the backend. +* started but disabled: the slave must process the ring without + causing any side effects. For example, for a networking device, + in the disabled state the slave must not supply any new RX packets, + but must process and discard any TX packets. -For example, for a networking device, in the disabled state client -must not supply any new RX packets, but must process and discard any -TX packets. +* started and enabled. + +Each ring is initialized in a stopped state. The slave must start +ring upon receiving a kick (that is, detecting that file descriptor is +readable) on the descriptor specified by ``VHOST_USER_SET_VRING_KICK`` +or receiving the in-band message ``VHOST_USER_VRING_KICK`` if negotiated, +and stop ring upon receiving ``VHOST_USER_GET_VRING_BASE``. + +Rings can be enabled or disabled by ``VHOST_USER_SET_VRING_ENABLE``. If ``VHOST_USER_F_PROTOCOL_FEATURES`` has not been negotiated, the -ring is initialized in an enabled state. +ring starts directly in the enabled state. If ``VHOST_USER_F_PROTOCOL_FEATURES`` has been negotiated, the ring is -initialized in a disabled state. Client must not pass data to/from the -backend until ring is enabled by ``VHOST_USER_SET_VRING_ENABLE`` with -parameter 1, or after it has been disabled by -``VHOST_USER_SET_VRING_ENABLE`` with parameter 0. +initialized in a disabled state and is enabled by +``VHOST_USER_SET_VRING_ENABLE`` with parameter 1. -Each ring is initialized in a stopped state, client must not process -it until ring is started, or after it has been stopped. - -Client must start ring upon receiving a kick (that is, detecting that -file descriptor is readable) on the descriptor specified by -``VHOST_USER_SET_VRING_KICK`` or receiving the in-band message -``VHOST_USER_VRING_KICK`` if negotiated, and stop ring upon receiving -``VHOST_USER_GET_VRING_BASE``. - -While processing the rings (whether they are enabled or not), client +While processing the rings (whether they are enabled or not), the slave must support changing some configuration aspects on the fly. Multiple queue support From bd59f2a1823a458ac27c09e1f27f30098745381e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 21 Mar 2022 15:30:30 +0000 Subject: [PATCH 368/935] docs: vhost-user: replace master/slave with front-end/back-end This matches the nomenclature that is generally used. Also commonly used is client/server, but it is not as clear because sometimes the front-end exposes a passive (server) socket that the back-end connects to. Signed-off-by: Paolo Bonzini Message-Id: <20210226143413.188046-4-pbonzini@redhat.com> Message-Id: <20220321153037.3622127-7-alex.bennee@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/interop/vhost-user-gpu.rst | 10 +- docs/interop/vhost-user.rst | 350 ++++++++++++++++---------------- 2 files changed, 180 insertions(+), 180 deletions(-) diff --git a/docs/interop/vhost-user-gpu.rst b/docs/interop/vhost-user-gpu.rst index 71a2c52b31..1640553729 100644 --- a/docs/interop/vhost-user-gpu.rst +++ b/docs/interop/vhost-user-gpu.rst @@ -13,10 +13,10 @@ Introduction ============ The vhost-user-gpu protocol is aiming at sharing the rendering result -of a virtio-gpu, done from a vhost-user slave process to a vhost-user -master process (such as QEMU). It bears a resemblance to a display +of a virtio-gpu, done from a vhost-user back-end process to a vhost-user +front-end process (such as QEMU). It bears a resemblance to a display server protocol, if you consider QEMU as the display server and the -slave as the client, but in a very limited way. Typically, it will +back-end as the client, but in a very limited way. Typically, it will work by setting a scanout/display configuration, before sending flush events for the display updates. It will also update the cursor shape and position. @@ -26,8 +26,8 @@ socket ancillary data to share opened file descriptors (DMABUF fds or shared memory). The socket is usually obtained via ``VHOST_USER_GPU_SET_SOCKET``. -Requests are sent by the *slave*, and the optional replies by the -*master*. +Requests are sent by the *back-end*, and the optional replies by the +*front-end*. Wire format =========== diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst index 1151326d6f..9159476678 100644 --- a/docs/interop/vhost-user.rst +++ b/docs/interop/vhost-user.rst @@ -23,19 +23,19 @@ space process on the same host. It uses communication over a Unix domain socket to share file descriptors in the ancillary data of the message. -The protocol defines 2 sides of the communication, *master* and -*slave*. *Master* is the application that shares its virtqueues, in -our case QEMU. *Slave* is the consumer of the virtqueues. +The protocol defines 2 sides of the communication, *front-end* and +*back-end*. The *front-end* is the application that shares its virtqueues, in +our case QEMU. The *back-end* is the consumer of the virtqueues. -In the current implementation QEMU is the *master*, and the *slave* is -the external process consuming the virtio queues, for example a +In the current implementation QEMU is the *front-end*, and the *back-end* +is the external process consuming the virtio queues, for example a software Ethernet switch running in user space, such as Snabbswitch, -or a block device backend processing read & write to a virtual -disk. In order to facilitate interoperability between various backend +or a block device back-end processing read & write to a virtual +disk. In order to facilitate interoperability between various back-end implementations, it is recommended to follow the :ref:`Backend program conventions `. -*Master* and *slave* can be either a client (i.e. connecting) or +The *front-end* and *back-end* can be either a client (i.e. connecting) or server (listening) in the socket communication. Support for platforms other than Linux @@ -77,7 +77,7 @@ Header :flags: 32-bit bit field - Lower 2 bits are the version (currently 0x01) -- Bit 2 is the reply flag - needs to be sent on each reply from the slave +- Bit 2 is the reply flag - needs to be sent on each reply from the back-end - Bit 3 is the need_reply flag - see :ref:`REPLY_ACK ` for details. @@ -222,8 +222,8 @@ Virtio device config space :size: a 32-bit configuration space access size in bytes :flags: a 32-bit value: - - 0: Vhost master messages used for writeable fields - - 1: Vhost master messages used for live migration + - 0: Vhost front-end messages used for writeable fields + - 1: Vhost front-end messages used for live migration :payload: Size bytes array holding the contents of the virtio device's configuration space @@ -290,8 +290,8 @@ vhost for the Linux Kernel. Most messages that can be sent via the Unix domain socket implementing vhost-user have an equivalent ioctl to the kernel implementation. -The communication consists of *master* sending message requests and -*slave* sending message replies. Most of the requests don't require +The communication consists of the *front-end* sending message requests and +the *back-end* sending message replies. Most of the requests don't require replies. Here is a list of the ones that do: * ``VHOST_USER_GET_FEATURES`` @@ -305,7 +305,7 @@ replies. Here is a list of the ones that do: :ref:`REPLY_ACK ` The section on ``REPLY_ACK`` protocol extension. -There are several messages that the master sends with file descriptors passed +There are several messages that the front-end sends with file descriptors passed in the ancillary data: * ``VHOST_USER_ADD_MEM_REG`` @@ -318,16 +318,16 @@ in the ancillary data: * ``VHOST_USER_SET_SLAVE_REQ_FD`` * ``VHOST_USER_SET_INFLIGHT_FD`` (if ``VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD``) -If *master* is unable to send the full message or receives a wrong +If *front-end* is unable to send the full message or receives a wrong reply it will close the connection. An optional reconnection mechanism can be implemented. -If *slave* detects some error such as incompatible features, it may also +If *back-end* detects some error such as incompatible features, it may also close the connection. This should only happen in exceptional circumstances. Any protocol extensions are gated by protocol feature bits, which -allows full backwards compatibility on both master and slave. As -older slaves don't support negotiating protocol features, a feature +allows full backwards compatibility on both front-end and back-end. As +older back-ends don't support negotiating protocol features, a feature bit was dedicated for this purpose:: #define VHOST_USER_F_PROTOCOL_FEATURES 30 @@ -337,16 +337,16 @@ Ring states Rings can be in one of three states: -* stopped: the slave must not process the ring at all. +* stopped: the back-end must not process the ring at all. -* started but disabled: the slave must process the ring without +* started but disabled: the back-end must process the ring without causing any side effects. For example, for a networking device, - in the disabled state the slave must not supply any new RX packets, + in the disabled state the back-end must not supply any new RX packets, but must process and discard any TX packets. * started and enabled. -Each ring is initialized in a stopped state. The slave must start +Each ring is initialized in a stopped state. The back-end must start ring upon receiving a kick (that is, detecting that file descriptor is readable) on the descriptor specified by ``VHOST_USER_SET_VRING_KICK`` or receiving the in-band message ``VHOST_USER_VRING_KICK`` if negotiated, @@ -361,53 +361,53 @@ If ``VHOST_USER_F_PROTOCOL_FEATURES`` has been negotiated, the ring is initialized in a disabled state and is enabled by ``VHOST_USER_SET_VRING_ENABLE`` with parameter 1. -While processing the rings (whether they are enabled or not), the slave +While processing the rings (whether they are enabled or not), the back-end must support changing some configuration aspects on the fly. Multiple queue support ---------------------- -Many devices have a fixed number of virtqueues. In this case the master +Many devices have a fixed number of virtqueues. In this case the front-end already knows the number of available virtqueues without communicating with the -slave. +back-end. Some devices do not have a fixed number of virtqueues. Instead the maximum -number of virtqueues is chosen by the slave. The number can depend on host -resource availability or slave implementation details. Such devices are called +number of virtqueues is chosen by the back-end. The number can depend on host +resource availability or back-end implementation details. Such devices are called multiple queue devices. -Multiple queue support allows the slave to advertise the maximum number of -queues. This is treated as a protocol extension, hence the slave has to +Multiple queue support allows the back-end to advertise the maximum number of +queues. This is treated as a protocol extension, hence the back-end has to implement protocol features first. The multiple queues feature is supported only when the protocol feature ``VHOST_USER_PROTOCOL_F_MQ`` (bit 0) is set. -The max number of queues the slave supports can be queried with message -``VHOST_USER_GET_QUEUE_NUM``. Master should stop when the number of requested +The max number of queues the back-end supports can be queried with message +``VHOST_USER_GET_QUEUE_NUM``. Front-end should stop when the number of requested queues is bigger than that. -As all queues share one connection, the master uses a unique index for each +As all queues share one connection, the front-end uses a unique index for each queue in the sent message to identify a specified queue. -The master enables queues by sending message ``VHOST_USER_SET_VRING_ENABLE``. +The front-end enables queues by sending message ``VHOST_USER_SET_VRING_ENABLE``. vhost-user-net has historically automatically enabled the first queue pair. -Slaves should always implement the ``VHOST_USER_PROTOCOL_F_MQ`` protocol +Back-ends should always implement the ``VHOST_USER_PROTOCOL_F_MQ`` protocol feature, even for devices with a fixed number of virtqueues, since it is simple to implement and offers a degree of introspection. -Masters must not rely on the ``VHOST_USER_PROTOCOL_F_MQ`` protocol feature for +Front-ends must not rely on the ``VHOST_USER_PROTOCOL_F_MQ`` protocol feature for devices with a fixed number of virtqueues. Only true multiqueue devices require this protocol feature. Migration --------- -During live migration, the master may need to track the modifications -the slave makes to the memory mapped regions. The client should mark +During live migration, the front-end may need to track the modifications +the back-end makes to the memory mapped regions. The front-end should mark the dirty pages in a log. Once it complies to this logging, it may declare the ``VHOST_F_LOG_ALL`` vhost feature. -To start/stop logging of data/used ring writes, server may send +To start/stop logging of data/used ring writes, the front-end may send messages ``VHOST_USER_SET_FEATURES`` with ``VHOST_F_LOG_ALL`` and ``VHOST_USER_SET_VRING_ADDR`` with ``VHOST_VRING_F_LOG`` in ring's flags set to 1/0, respectively. @@ -421,7 +421,7 @@ Dirty pages are of size:: #define VHOST_LOG_PAGE 0x1000 The log memory fd is provided in the ancillary data of -``VHOST_USER_SET_LOG_BASE`` message when the slave has +``VHOST_USER_SET_LOG_BASE`` message when the back-end has ``VHOST_USER_PROTOCOL_F_LOG_SHMFD`` protocol feature. The size of the log is supplied as part of ``VhostUserMsg`` which @@ -447,26 +447,26 @@ the bit offset of the last byte of the ring must fall within the size supplied by ``VhostUserLog``. ``VHOST_USER_SET_LOG_FD`` is an optional message with an eventfd in -ancillary data, it may be used to inform the master that the log has +ancillary data, it may be used to inform the front-end that the log has been modified. Once the source has finished migration, rings will be stopped by the source. No further update must be done before rings are restarted. -In postcopy migration the slave is started before all the memory has +In postcopy migration the back-end is started before all the memory has been received from the source host, and care must be taken to avoid -accessing pages that have yet to be received. The slave opens a +accessing pages that have yet to be received. The back-end opens a 'userfault'-fd and registers the memory with it; this fd is then -passed back over to the master. The master services requests on the +passed back over to the front-end. The front-end services requests on the userfaultfd for pages that are accessed and when the page is available it performs WAKE ioctl's on the userfaultfd to wake the stalled -slave. The client indicates support for this via the +back-end. The front-end indicates support for this via the ``VHOST_USER_PROTOCOL_F_PAGEFAULT`` feature. Memory access ------------- -The master sends a list of vhost memory regions to the slave using the +The front-end sends a list of vhost memory regions to the back-end using the ``VHOST_USER_SET_MEM_TABLE`` message. Each region has two base addresses: a guest address and a user address. @@ -491,60 +491,60 @@ IOMMU support ------------- When the ``VIRTIO_F_IOMMU_PLATFORM`` feature has been negotiated, the -master sends IOTLB entries update & invalidation by sending -``VHOST_USER_IOTLB_MSG`` requests to the slave with a ``struct +front-end sends IOTLB entries update & invalidation by sending +``VHOST_USER_IOTLB_MSG`` requests to the back-end with a ``struct vhost_iotlb_msg`` as payload. For update events, the ``iotlb`` payload has to be filled with the update message type (2), the I/O virtual address, the size, the user virtual address, and the permissions flags. Addresses and size must be within vhost memory regions set via the ``VHOST_USER_SET_MEM_TABLE`` request. For invalidation events, the ``iotlb`` payload has to be filled with the invalidation message type -(3), the I/O virtual address and the size. On success, the slave is +(3), the I/O virtual address and the size. On success, the back-end is expected to reply with a zero payload, non-zero otherwise. -The slave relies on the slave communication channel (see :ref:`Slave -communication ` section below) to send IOTLB miss +The back-end relies on the back-end communication channel (see :ref:`Back-end +communication ` section below) to send IOTLB miss and access failure events, by sending ``VHOST_USER_SLAVE_IOTLB_MSG`` -requests to the master with a ``struct vhost_iotlb_msg`` as +requests to the front-end with a ``struct vhost_iotlb_msg`` as payload. For miss events, the iotlb payload has to be filled with the miss message type (1), the I/O virtual address and the permissions flags. For access failure event, the iotlb payload has to be filled with the access failure message type (4), the I/O virtual address and -the permissions flags. For synchronization purpose, the slave may -rely on the reply-ack feature, so the master may send a reply when +the permissions flags. For synchronization purpose, the back-end may +rely on the reply-ack feature, so the front-end may send a reply when operation is completed if the reply-ack feature is negotiated and -slaves requests a reply. For miss events, completed operation means -either master sent an update message containing the IOTLB entry -containing requested address and permission, or master sent nothing if +back-ends requests a reply. For miss events, completed operation means +either front-end sent an update message containing the IOTLB entry +containing requested address and permission, or front-end sent nothing if the IOTLB miss message is invalid (invalid IOVA or permission). -The master isn't expected to take the initiative to send IOTLB update -messages, as the slave sends IOTLB miss messages for the guest virtual +The front-end isn't expected to take the initiative to send IOTLB update +messages, as the back-end sends IOTLB miss messages for the guest virtual memory areas it needs to access. -.. _slave_communication: +.. _backend_communication: -Slave communication -------------------- +Back-end communication +---------------------- -An optional communication channel is provided if the slave declares +An optional communication channel is provided if the back-end declares ``VHOST_USER_PROTOCOL_F_SLAVE_REQ`` protocol feature, to allow the -slave to make requests to the master. +back-end to make requests to the front-end. The fd is provided via ``VHOST_USER_SET_SLAVE_REQ_FD`` ancillary data. -A slave may then send ``VHOST_USER_SLAVE_*`` messages to the master +A back-end may then send ``VHOST_USER_SLAVE_*`` messages to the front-end using this fd communication channel. If ``VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD`` protocol feature is -negotiated, slave can send file descriptors (at most 8 descriptors in -each message) to master via ancillary data using this fd communication +negotiated, back-end can send file descriptors (at most 8 descriptors in +each message) to front-end via ancillary data using this fd communication channel. Inflight I/O tracking --------------------- -To support reconnecting after restart or crash, slave may need to +To support reconnecting after restart or crash, back-end may need to resubmit inflight I/Os. If virtqueue is processed in order, we can easily achieve that by getting the inflight descriptors from descriptor table (split virtqueue) or descriptor ring (packed @@ -552,18 +552,18 @@ virtqueue). However, it can't work when we process descriptors out-of-order because some entries which store the information of inflight descriptors in available ring (split virtqueue) or descriptor ring (packed virtqueue) might be overridden by new entries. To solve -this problem, slave need to allocate an extra buffer to store this -information of inflight descriptors and share it with master for +this problem, the back-end need to allocate an extra buffer to store this +information of inflight descriptors and share it with front-end for persistent. ``VHOST_USER_GET_INFLIGHT_FD`` and ``VHOST_USER_SET_INFLIGHT_FD`` are used to transfer this buffer -between master and slave. And the format of this buffer is described +between front-end and back-end. And the format of this buffer is described below: +---------------+---------------+-----+---------------+ | queue0 region | queue1 region | ... | queueN region | +---------------+---------------+-----+---------------+ -N is the number of available virtqueues. Slave could get it from num +N is the number of available virtqueues. The back-end could get it from num queues field of ``VhostUserInflight``. For split virtqueue, queue region can be implemented as: @@ -595,8 +595,8 @@ For split virtqueue, queue region can be implemented as: * Zero value indicates an uninitialized buffer */ uint16_t version; - /* The size of DescStateSplit array. It's equal to the virtqueue - * size. Slave could get it from queue size field of VhostUserInflight. */ + /* The size of DescStateSplit array. It's equal to the virtqueue size. + * The back-end could get it from queue size field of VhostUserInflight. */ uint16_t desc_num; /* The head of list that track the last batch of used descriptors. */ @@ -702,8 +702,8 @@ For packed virtqueue, queue region can be implemented as: * Zero value indicates an uninitialized buffer */ uint16_t version; - /* The size of DescStatePacked array. It's equal to the virtqueue - * size. Slave could get it from queue size field of VhostUserInflight. */ + /* The size of DescStatePacked array. It's equal to the virtqueue size. + * The back-end could get it from queue size field of VhostUserInflight. */ uint16_t desc_num; /* The head of free DescStatePacked entry list */ @@ -795,7 +795,7 @@ When reconnecting: #. Use ``old_used_wrap_counter`` to calculate the available flags #. If ``d.flags`` is not equal to the calculated flags value (means - slave has submitted the buffer to guest driver before crash, so + back-end has submitted the buffer to guest driver before crash, so it has to commit the in-progres update), set ``old_free_head``, ``old_used_idx``, ``old_used_wrap_counter`` to ``free_head``, ``used_idx``, ``used_wrap_counter`` @@ -824,11 +824,11 @@ cause the sending application(s) to block, it is not advised to use this feature unless absolutely necessary. It is also considered an error to negotiate this feature without also negotiating ``VHOST_USER_PROTOCOL_F_SLAVE_REQ`` and ``VHOST_USER_PROTOCOL_F_REPLY_ACK``, -the former is necessary for getting a message channel from the slave -to the master, while the latter needs to be used with the in-band +the former is necessary for getting a message channel from the back-end +to the front-end, while the latter needs to be used with the in-band notification messages to block until they are processed, both to avoid blocking later and for proper processing (at least in the simulation -use case.) As it has no other way of signalling this error, the slave +use case.) As it has no other way of signalling this error, the back-end should close the connection as a response to a ``VHOST_USER_SET_PROTOCOL_FEATURES`` message that sets the in-band notifications feature flag without the other two. @@ -856,8 +856,8 @@ Protocol features #define VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS 15 #define VHOST_USER_PROTOCOL_F_STATUS 16 -Master message types --------------------- +Front-end message types +----------------------- ``VHOST_USER_GET_FEATURES`` :id: 1 @@ -866,7 +866,7 @@ Master message types :reply payload: ``u64`` Get from the underlying vhost implementation the features bitmask. - Feature bit ``VHOST_USER_F_PROTOCOL_FEATURES`` signals slave support + Feature bit ``VHOST_USER_F_PROTOCOL_FEATURES`` signals back-end support for ``VHOST_USER_GET_PROTOCOL_FEATURES`` and ``VHOST_USER_SET_PROTOCOL_FEATURES``. @@ -878,7 +878,7 @@ Master message types Enable features in the underlying vhost implementation using a bitmask. Feature bit ``VHOST_USER_F_PROTOCOL_FEATURES`` signals - slave support for ``VHOST_USER_GET_PROTOCOL_FEATURES`` and + back-end support for ``VHOST_USER_GET_PROTOCOL_FEATURES`` and ``VHOST_USER_SET_PROTOCOL_FEATURES``. ``VHOST_USER_GET_PROTOCOL_FEATURES`` @@ -893,7 +893,7 @@ Master message types ``VHOST_USER_GET_FEATURES``. .. Note:: - Slave that reported ``VHOST_USER_F_PROTOCOL_FEATURES`` must + Back-ends that report ``VHOST_USER_F_PROTOCOL_FEATURES`` must support this message even before ``VHOST_USER_SET_FEATURES`` was called. @@ -909,7 +909,7 @@ Master message types ``VHOST_USER_GET_FEATURES``. .. Note:: - Slave that reported ``VHOST_USER_F_PROTOCOL_FEATURES`` must support + Back-ends that report ``VHOST_USER_F_PROTOCOL_FEATURES`` must support this message even before ``VHOST_USER_SET_FEATURES`` was called. ``VHOST_USER_SET_OWNER`` @@ -918,8 +918,8 @@ Master message types :request payload: N/A :reply payload: N/A - Issued when a new connection is established. It sets the current - *master* as an owner of the session. This can be used on the *slave* + Issued when a new connection is established. It marks the sender + as the front-end that owns of the session. This can be used on the *back-end* as a "session start" flag. ``VHOST_USER_RESET_OWNER`` @@ -930,9 +930,9 @@ Master message types .. admonition:: Deprecated This is no longer used. Used to be sent to request disabling all - rings, but some clients interpreted it to also discard connection + rings, but some back-ends interpreted it to also discard connection state (this interpretation would lead to bugs). It is recommended - that clients either ignore this message, or use it to disable all + that back-ends either ignore this message, or use it to disable all rings. ``VHOST_USER_SET_MEM_TABLE`` @@ -941,14 +941,14 @@ Master message types :request payload: memory regions description :reply payload: (postcopy only) memory regions description - Sets the memory map regions on the slave so it can translate the + Sets the memory map regions on the back-end so it can translate the vring addresses. In the ancillary data there is an array of file descriptors for each memory mapped region. The size and ordering of the fds matches the number and ordering of memory regions. When ``VHOST_USER_POSTCOPY_LISTEN`` has been received, ``SET_MEM_TABLE`` replies with the bases of the memory mapped - regions to the master. The slave must have mmap'd the regions but + regions to the front-end. The back-end must have mmap'd the regions but not yet accessed them and should not yet generate a userfault event. @@ -967,7 +967,7 @@ Master message types Sets logging shared memory space. - When slave has ``VHOST_USER_PROTOCOL_F_LOG_SHMFD`` protocol feature, + When the back-end has ``VHOST_USER_PROTOCOL_F_LOG_SHMFD`` protocol feature, the log memory fd is provided in the ancillary data of ``VHOST_USER_SET_LOG_BASE`` message, the size and offset of shared memory area provided in the message. @@ -1074,7 +1074,7 @@ Master message types :request payload: N/A :reply payload: u64 - Query how many queues the backend supports. + Query how many queues the back-end supports. This request should be sent only when ``VHOST_USER_PROTOCOL_F_MQ`` is set in queried protocol features by @@ -1086,7 +1086,7 @@ Master message types :request payload: vring state description :reply payload: N/A - Signal slave to enable or disable corresponding vring. + Signal the back-end to enable or disable corresponding vring. This request should be sent only when ``VHOST_USER_F_PROTOCOL_FEATURES`` has been negotiated. @@ -1097,7 +1097,7 @@ Master message types :request payload: ``u64`` :reply payload: N/A - Ask vhost user backend to broadcast a fake RARP to notify the migration + Ask vhost user back-end to broadcast a fake RARP to notify the migration is terminated for guest that does not support GUEST_ANNOUNCE. Only legal if feature bit ``VHOST_USER_F_PROTOCOL_FEATURES`` is @@ -1105,7 +1105,7 @@ Master message types ``VHOST_USER_PROTOCOL_F_RARP`` is present in ``VHOST_USER_GET_PROTOCOL_FEATURES``. The first 6 bytes of the payload contain the mac address of the guest to allow the vhost user - backend to construct and broadcast the fake RARP. + back-end to construct and broadcast the fake RARP. ``VHOST_USER_NET_SET_MTU`` :id: 20 @@ -1121,7 +1121,7 @@ Master message types ``VHOST_USER_PROTOCOL_F_NET_MTU`` is present in ``VHOST_USER_GET_PROTOCOL_FEATURES``. - If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, slave must + If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, the back-end must respond with zero in case the specified MTU is valid, or non-zero otherwise. @@ -1131,14 +1131,14 @@ Master message types :request payload: N/A :reply payload: N/A - Set the socket file descriptor for slave initiated requests. It is passed + Set the socket file descriptor for back-end initiated requests. It is passed in the ancillary data. This request should be sent only when ``VHOST_USER_F_PROTOCOL_FEATURES`` has been negotiated, and protocol feature bit ``VHOST_USER_PROTOCOL_F_SLAVE_REQ`` bit is present in ``VHOST_USER_GET_PROTOCOL_FEATURES``. If - ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, slave must + ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, the back-end must respond with zero for success, non-zero otherwise. ``VHOST_USER_IOTLB_MSG`` @@ -1149,8 +1149,8 @@ Master message types Send IOTLB messages with ``struct vhost_iotlb_msg`` as payload. - Master sends such requests to update and invalidate entries in the - device IOTLB. The slave has to acknowledge the request with sending + The front-end sends such requests to update and invalidate entries in the + device IOTLB. The back-end has to acknowledge the request with sending zero as ``u64`` payload for success, non-zero otherwise. This request should be send only when ``VIRTIO_F_IOMMU_PLATFORM`` @@ -1170,7 +1170,7 @@ Master message types ``VHOST_USER_PROTOCOL_F_CROSS_ENDIAN`` has been negotiated. Backends that negotiated this feature should handle both endiannesses and expect this message once (per VQ) during device - configuration (ie. before the master starts the VQ). + configuration (ie. before the front-end starts the VQ). ``VHOST_USER_GET_CONFIG`` :id: 24 @@ -1179,11 +1179,11 @@ Master message types :reply payload: virtio device config space When ``VHOST_USER_PROTOCOL_F_CONFIG`` is negotiated, this message is - submitted by the vhost-user master to fetch the contents of the - virtio device configuration space, vhost-user slave's payload size - MUST match master's request, vhost-user slave uses zero length of - payload to indicate an error to vhost-user master. The vhost-user - master may cache the contents to avoid repeated + submitted by the vhost-user front-end to fetch the contents of the + virtio device configuration space, vhost-user back-end's payload size + MUST match the front-end's request, vhost-user back-end uses zero length of + payload to indicate an error to the vhost-user front-end. The vhost-user + front-end may cache the contents to avoid repeated ``VHOST_USER_GET_CONFIG`` calls. ``VHOST_USER_SET_CONFIG`` @@ -1193,10 +1193,10 @@ Master message types :reply payload: N/A When ``VHOST_USER_PROTOCOL_F_CONFIG`` is negotiated, this message is - submitted by the vhost-user master when the Guest changes the virtio + submitted by the vhost-user front-end when the Guest changes the virtio device configuration space and also can be used for live migration - on the destination host. The vhost-user slave must check the flags - field, and slaves MUST NOT accept SET_CONFIG for read-only + on the destination host. The vhost-user back-end must check the flags + field, and back-ends MUST NOT accept SET_CONFIG for read-only configuration space fields unless the live migration bit is set. ``VHOST_USER_CREATE_CRYPTO_SESSION`` @@ -1205,7 +1205,7 @@ Master message types :request payload: crypto session description :reply payload: crypto session description - Create a session for crypto operation. The server side must return + Create a session for crypto operation. The back-end must return the session id, 0 or positive for success, negative for failure. This request should be sent only when ``VHOST_USER_PROTOCOL_F_CRYPTO_SESSION`` feature has been @@ -1231,9 +1231,9 @@ Master message types :request payload: N/A :reply payload: userfault fd - When ``VHOST_USER_PROTOCOL_F_PAGEFAULT`` is supported, the master - advises slave that a migration with postcopy enabled is underway, - the slave must open a userfaultfd for later use. Note that at this + When ``VHOST_USER_PROTOCOL_F_PAGEFAULT`` is supported, the front-end + advises back-end that a migration with postcopy enabled is underway, + the back-end must open a userfaultfd for later use. Note that at this stage the migration is still in precopy mode. ``VHOST_USER_POSTCOPY_LISTEN`` @@ -1241,8 +1241,8 @@ Master message types :request payload: N/A :reply payload: N/A - Master advises slave that a transition to postcopy mode has - happened. The slave must ensure that shared memory is registered + The front-end advises back-end that a transition to postcopy mode has + happened. The back-end must ensure that shared memory is registered with userfaultfd to cause faulting of non-present pages. This is always sent sometime after a ``VHOST_USER_POSTCOPY_ADVISE``, @@ -1253,7 +1253,7 @@ Master message types :request payload: N/A :reply payload: ``u64`` - Master advises that postcopy migration has now completed. The slave + The front-end advises that postcopy migration has now completed. The back-end must disable the userfaultfd. The reply is an acknowledgement only. @@ -1270,9 +1270,9 @@ Master message types :reply payload: N/A When ``VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD`` protocol feature has - been successfully negotiated, this message is submitted by master to - get a shared buffer from slave. The shared buffer will be used to - track inflight I/O by slave. QEMU should retrieve a new one when vm + been successfully negotiated, this message is submitted by the front-end to + get a shared buffer from back-end. The shared buffer will be used to + track inflight I/O by back-end. QEMU should retrieve a new one when vm reset. ``VHOST_USER_SET_INFLIGHT_FD`` @@ -1282,9 +1282,9 @@ Master message types :reply payload: N/A When ``VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD`` protocol feature has - been successfully negotiated, this message is submitted by master to - send the shared inflight buffer back to slave so that slave could - get inflight I/O after a crash or restart. + been successfully negotiated, this message is submitted by the front-end to + send the shared inflight buffer back to the back-end so that the back-end + could get inflight I/O after a crash or restart. ``VHOST_USER_GPU_SET_SOCKET`` :id: 33 @@ -1293,7 +1293,7 @@ Master message types :reply payload: N/A Sets the GPU protocol socket file descriptor, which is passed as - ancillary data. The GPU protocol is used to inform the master of + ancillary data. The GPU protocol is used to inform the front-end of rendering state and updates. See vhost-user-gpu.rst for details. ``VHOST_USER_RESET_DEVICE`` @@ -1302,13 +1302,13 @@ Master message types :request payload: N/A :reply payload: N/A - Ask the vhost user backend to disable all rings and reset all + Ask the vhost user back-end to disable all rings and reset all internal device state to the initial state, ready to be - reinitialized. The backend retains ownership of the device + reinitialized. The back-end retains ownership of the device throughout the reset operation. Only valid if the ``VHOST_USER_PROTOCOL_F_RESET_DEVICE`` protocol - feature is set by the backend. + feature is set by the back-end. ``VHOST_USER_VRING_KICK`` :id: 35 @@ -1318,9 +1318,9 @@ Master message types When the ``VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS`` protocol feature has been successfully negotiated, this message may be - submitted by the master to indicate that a buffer was added to + submitted by the front-end to indicate that a buffer was added to the vring instead of signalling it using the vring's kick file - descriptor or having the slave rely on polling. + descriptor or having the back-end rely on polling. The state.num field is currently reserved and must be set to 0. @@ -1332,9 +1332,9 @@ Master message types When the ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol feature has been successfully negotiated, this message is submitted - by master to the slave. The slave should return the message with a + by the front-end to the back-end. The back-end should return the message with a u64 payload containing the maximum number of memory slots for - QEMU to expose to the guest. The value returned by the backend + QEMU to expose to the guest. The value returned by the back-end will be capped at the maximum number of ram slots which can be supported by the target platform. @@ -1346,19 +1346,19 @@ Master message types When the ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol feature has been successfully negotiated, this message is submitted - by the master to the slave. The message payload contains a memory + by the front-end to the back-end. The message payload contains a memory region descriptor struct, describing a region of guest memory which - the slave device must map in. When the + the back-end device must map in. When the ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol feature has been successfully negotiated, along with the ``VHOST_USER_REM_MEM_REG`` message, this message is used to set and - update the memory tables of the slave device. + update the memory tables of the back-end device. Exactly one file descriptor from which the memory is mapped is passed in the ancillary data. - In postcopy mode (see ``VHOST_USER_POSTCOPY_LISTEN``), the slave - replies with the bases of the memory mapped region to the master. + In postcopy mode (see ``VHOST_USER_POSTCOPY_LISTEN``), the back-end + replies with the bases of the memory mapped region to the front-end. For further details on postcopy, see ``VHOST_USER_SET_MEM_TABLE``. They apply to ``VHOST_USER_ADD_MEM_REG`` accordingly. @@ -1370,21 +1370,21 @@ Master message types When the ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol feature has been successfully negotiated, this message is submitted - by the master to the slave. The message payload contains a memory + by the front-end to the back-end. The message payload contains a memory region descriptor struct, describing a region of guest memory which - the slave device must unmap. When the + the back-end device must unmap. When the ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol feature has been successfully negotiated, along with the ``VHOST_USER_ADD_MEM_REG`` message, this message is used to set and - update the memory tables of the slave device. + update the memory tables of the back-end device. The memory region to be removed is identified by its guest address, user address and size. The mmap offset is ignored. No file descriptors SHOULD be passed in the ancillary data. For - compatibility with existing incorrect implementations, the slave MAY + compatibility with existing incorrect implementations, the back-end MAY accept messages with one file descriptor. If a file descriptor is - passed, the slave MUST close it without using it otherwise. + passed, the back-end MUST close it without using it otherwise. ``VHOST_USER_SET_STATUS`` :id: 39 @@ -1393,8 +1393,8 @@ Master message types :reply payload: N/A When the ``VHOST_USER_PROTOCOL_F_STATUS`` protocol feature has been - successfully negotiated, this message is submitted by the master to - notify the backend with updated device status as defined in the Virtio + successfully negotiated, this message is submitted by the front-end to + notify the back-end with updated device status as defined in the Virtio specification. ``VHOST_USER_GET_STATUS`` @@ -1404,16 +1404,16 @@ Master message types :reply payload: ``u64`` When the ``VHOST_USER_PROTOCOL_F_STATUS`` protocol feature has been - successfully negotiated, this message is submitted by the master to - query the backend for its device status as defined in the Virtio + successfully negotiated, this message is submitted by the front-end to + query the back-end for its device status as defined in the Virtio specification. -Slave message types -------------------- +Back-end message types +---------------------- -For this type of message, the request is sent by the slave and the reply -is sent by the master. +For this type of message, the request is sent by the back-end and the reply +is sent by the front-end. ``VHOST_USER_SLAVE_IOTLB_MSG`` :id: 1 @@ -1422,9 +1422,9 @@ is sent by the master. :reply payload: N/A Send IOTLB messages with ``struct vhost_iotlb_msg`` as payload. - Slave sends such requests to notify of an IOTLB miss, or an IOTLB + The back-end sends such requests to notify of an IOTLB miss, or an IOTLB access failure. If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is - negotiated, and slave set the ``VHOST_USER_NEED_REPLY`` flag, master + negotiated, and back-end set the ``VHOST_USER_NEED_REPLY`` flag, the front-end must respond with zero when operation is successfully completed, or non-zero otherwise. This request should be send only when ``VIRTIO_F_IOMMU_PLATFORM`` feature has been successfully @@ -1437,12 +1437,12 @@ is sent by the master. :reply payload: N/A When ``VHOST_USER_PROTOCOL_F_CONFIG`` is negotiated, vhost-user - slave sends such messages to notify that the virtio device's + back-end sends such messages to notify that the virtio device's configuration space has changed, for those host devices which can support such feature, host driver can send ``VHOST_USER_GET_CONFIG`` - message to slave to get the latest content. If - ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and slave set the - ``VHOST_USER_NEED_REPLY`` flag, master must respond with zero when + message to the back-end to get the latest content. If + ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and the back-end sets the + ``VHOST_USER_NEED_REPLY`` flag, the front-end must respond with zero when operation is successfully completed, or non-zero otherwise. ``VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG`` @@ -1460,7 +1460,7 @@ is sent by the master. description. QEMU can mmap the file descriptor based on the size and offset to get a memory range. Registering a host notifier means mapping this memory range to the VM as the specified queue's notify - MMIO region. Slave sends this request to tell QEMU to de-register + MMIO region. The back-end sends this request to tell QEMU to de-register the existing notifier if any and register the new notifier if the request is sent with a file descriptor. @@ -1476,9 +1476,9 @@ is sent by the master. When the ``VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS`` protocol feature has been successfully negotiated, this message may be - submitted by the slave to indicate that a buffer was used from + submitted by the back-end to indicate that a buffer was used from the vring instead of signalling this using the vring's call file - descriptor or having the master relying on polling. + descriptor or having the front-end relying on polling. The state.num field is currently reserved and must be set to 0. @@ -1490,9 +1490,9 @@ is sent by the master. When the ``VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS`` protocol feature has been successfully negotiated, this message may be - submitted by the slave to indicate that an error occurred on the + submitted by the back-end to indicate that an error occurred on the specific vring, instead of signalling the error file descriptor - set by the master via ``VHOST_USER_SET_VRING_ERR``. + set by the front-end via ``VHOST_USER_SET_VRING_ERR``. The state.num field is currently reserved and must be set to 0. @@ -1503,12 +1503,12 @@ VHOST_USER_PROTOCOL_F_REPLY_ACK The original vhost-user specification only demands replies for certain commands. This differs from the vhost protocol implementation where -commands are sent over an ``ioctl()`` call and block until the client +commands are sent over an ``ioctl()`` call and block until the back-end has completed. With this protocol extension negotiated, the sender (QEMU) can set the ``need_reply`` [Bit 3] flag to any command. This indicates that the -client MUST respond with a Payload ``VhostUserMsg`` indicating success +back-end MUST respond with a Payload ``VhostUserMsg`` indicating success or failure. The payload should be set to zero on success or non-zero on failure, unless the message already has an explicit reply body. @@ -1517,7 +1517,7 @@ of the command. Today, QEMU is expected to terminate the main vhost-user loop upon receiving such errors. In future, qemu could be taught to be more resilient for selective requests. -For the message types that already solicit a reply from the client, +For the message types that already solicit a reply from the back-end, the presence of ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` or need_reply bit being set brings no behavioural change. (See the Communication_ section for details.) @@ -1527,26 +1527,26 @@ section for details.) Backend program conventions =========================== -vhost-user backends can provide various devices & services and may +vhost-user back-ends can provide various devices & services and may need to be configured manually depending on the use case. However, it is a good idea to follow the conventions listed here when possible. Users, QEMU or libvirt, can then rely on some common behaviour to avoid heterogeneous configuration and management of the -backend programs and facilitate interoperability. +back-end programs and facilitate interoperability. -Each backend installed on a host system should come with at least one +Each back-end installed on a host system should come with at least one JSON file that conforms to the vhost-user.json schema. Each file -informs the management applications about the backend type, and binary +informs the management applications about the back-end type, and binary location. In addition, it defines rules for management apps for -picking the highest priority backend when multiple match the search +picking the highest priority back-end when multiple match the search criteria (see ``@VhostUserBackend`` documentation in the schema file). -If the backend is not capable of enabling a requested feature on the +If the back-end is not capable of enabling a requested feature on the host (such as 3D acceleration with virgl), or the initialization -failed, the backend should fail to start early and exit with a status +failed, the back-end should fail to start early and exit with a status != 0. It may also print a message to stderr for further details. -The backend program must not daemonize itself, but it may be +The back-end program must not daemonize itself, but it may be daemonized by the management layer. It may also have a restricted access to the system. @@ -1554,7 +1554,7 @@ File descriptors 0, 1 and 2 will exist, and have regular stdin/stdout/stderr usage (they may have been redirected to /dev/null by the management layer, or to a log handler). -The backend program must end (as quickly and cleanly as possible) when +The back-end program must end (as quickly and cleanly as possible) when the SIGTERM signal is received. Eventually, it may receive SIGKILL by the management layer after a few seconds. @@ -1568,15 +1568,15 @@ are mandatory, unless explicitly said differently: --fd=FDNUM - When this argument is given, the backend program is started with the + When this argument is given, the back-end program is started with the vhost-user socket as file descriptor FDNUM. It is incompatible with --socket-path. --print-capabilities - Output to stdout the backend capabilities in JSON format, and then + Output to stdout the back-end capabilities in JSON format, and then exit successfully. Other options and arguments should be ignored, and - the backend program should not perform its normal function. The + the back-end program should not perform its normal function. The capabilities can be reported dynamically depending on the host capabilities. From fa9972662ce5b6d50fe7190efeb48a5a9fecca91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 21 Mar 2022 15:30:31 +0000 Subject: [PATCH 369/935] vhost-user.rst: add clarifying language about protocol negotiation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the language about feature negotiation explicitly clear about the handling of the VHOST_USER_F_PROTOCOL_FEATURES feature bit. Try and avoid the sort of bug introduced in vhost.rs REPLY_ACK processing: https://github.com/rust-vmm/vhost/pull/24 Signed-off-by: Alex Bennée Cc: Jiang Liu Message-Id: <20210226111619.21178-1-alex.bennee@linaro.org> Message-Id: <20220321153037.3622127-8-alex.bennee@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/interop/vhost-user.rst | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst index 9159476678..73e710fe32 100644 --- a/docs/interop/vhost-user.rst +++ b/docs/interop/vhost-user.rst @@ -332,6 +332,18 @@ bit was dedicated for this purpose:: #define VHOST_USER_F_PROTOCOL_FEATURES 30 +Note that VHOST_USER_F_PROTOCOL_FEATURES is the UNUSED (30) feature +bit defined in `VIRTIO 1.1 6.3 Legacy Interface: Reserved Feature Bits +`_. +VIRTIO devices do not advertise this feature bit and therefore VIRTIO +drivers cannot negotiate it. + +This reserved feature bit was reused by the vhost-user protocol to add +vhost-user protocol feature negotiation in a backwards compatible +fashion. Old vhost-user master and slave implementations continue to +work even though they are not aware of vhost-user protocol feature +negotiation. + Ring states ----------- @@ -890,7 +902,8 @@ Front-end message types Get the protocol feature bitmask from the underlying vhost implementation. Only legal if feature bit ``VHOST_USER_F_PROTOCOL_FEATURES`` is present in - ``VHOST_USER_GET_FEATURES``. + ``VHOST_USER_GET_FEATURES``. It does not need to be acknowledged by + ``VHOST_USER_SET_FEATURES``. .. Note:: Back-ends that report ``VHOST_USER_F_PROTOCOL_FEATURES`` must @@ -906,7 +919,8 @@ Front-end message types Enable protocol features in the underlying vhost implementation. Only legal if feature bit ``VHOST_USER_F_PROTOCOL_FEATURES`` is present in - ``VHOST_USER_GET_FEATURES``. + ``VHOST_USER_GET_FEATURES``. It does not need to be acknowledged by + ``VHOST_USER_SET_FEATURES``. .. Note:: Back-ends that report ``VHOST_USER_F_PROTOCOL_FEATURES`` must support From 467eeb0f80798457ba83040f7adb1e6b29c7c6a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 21 Mar 2022 15:30:32 +0000 Subject: [PATCH 370/935] libvhost-user: expose vu_request_to_string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is useful for more human readable debug messages in vhost-user programs. Signed-off-by: Alex Bennée Message-Id: <20220321153037.3622127-9-alex.bennee@linaro.org> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- subprojects/libvhost-user/libvhost-user.c | 2 +- subprojects/libvhost-user/libvhost-user.h | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c index d0041c864b..b4cc3c2d68 100644 --- a/subprojects/libvhost-user/libvhost-user.c +++ b/subprojects/libvhost-user/libvhost-user.c @@ -99,7 +99,7 @@ static inline bool vu_has_protocol_feature(VuDev *dev, unsigned int fbit) return has_feature(dev->protocol_features, fbit); } -static const char * +const char * vu_request_to_string(unsigned int req) { #define REQ(req) [req] = #req diff --git a/subprojects/libvhost-user/libvhost-user.h b/subprojects/libvhost-user/libvhost-user.h index cde9f07bb3..aea7ec5061 100644 --- a/subprojects/libvhost-user/libvhost-user.h +++ b/subprojects/libvhost-user/libvhost-user.h @@ -473,6 +473,15 @@ bool vu_init(VuDev *dev, */ void vu_deinit(VuDev *dev); + +/** + * vu_request_to_string: return string for vhost message request + * @req: VhostUserMsg request + * + * Returns a const string, do not free. + */ +const char *vu_request_to_string(unsigned int req); + /** * vu_dispatch: * @dev: a VuDev context From bcf317f8591083fc11c3167f8048c826475efc39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 21 Mar 2022 15:30:33 +0000 Subject: [PATCH 371/935] docs/devel: start documenting writing VirtIO devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While writing my own VirtIO devices I've gotten confused with how things are structured and what sort of shared infrastructure there is. If we can document how everything is supposed to work we can then maybe start cleaning up inconsistencies in the code. Signed-off-by: Alex Bennée Cc: Stefan Hajnoczi Cc: "Michael S. Tsirkin" Cc: Gerd Hoffmann Cc: Marc-André Lureau Cc: Viresh Kumar Cc: Mathieu Poirier Cc: Dr. David Alan Gilbert Message-Id: <20220309164929.19395-1-alex.bennee@linaro.org> Message-Id: <20220321153037.3622127-10-alex.bennee@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/devel/index-internals.rst | 1 + docs/devel/virtio-backends.rst | 214 +++++++++++++++++++++++++++++++++ 2 files changed, 215 insertions(+) create mode 100644 docs/devel/virtio-backends.rst diff --git a/docs/devel/index-internals.rst b/docs/devel/index-internals.rst index a50889c556..e1a93df263 100644 --- a/docs/devel/index-internals.rst +++ b/docs/devel/index-internals.rst @@ -18,3 +18,4 @@ Details about QEMU's various subsystems including how to add features to them. tracing vfio-migration writing-monitor-commands + virtio-backends diff --git a/docs/devel/virtio-backends.rst b/docs/devel/virtio-backends.rst new file mode 100644 index 0000000000..9ff092e7a0 --- /dev/null +++ b/docs/devel/virtio-backends.rst @@ -0,0 +1,214 @@ +.. + Copyright (c) 2022, Linaro Limited + Written by Alex Bennée + +Writing VirtIO backends for QEMU +================================ + +This document attempts to outline the information a developer needs to +know to write device emulations in QEMU. It is specifically focused on +implementing VirtIO devices. For VirtIO the frontend is the driver +running on the guest. The backend is the everything that QEMU needs to +do to handle the emulation of the VirtIO device. This can be done +entirely in QEMU, divided between QEMU and the kernel (vhost) or +handled by a separate process which is configured by QEMU +(vhost-user). + +VirtIO Transports +----------------- + +VirtIO supports a number of different transports. While the details of +the configuration and operation of the device will generally be the +same QEMU represents them as different devices depending on the +transport they use. For example -device virtio-foo represents the foo +device using mmio and -device virtio-foo-pci is the same class of +device using the PCI transport. + +Using the QEMU Object Model (QOM) +--------------------------------- + +Generally all devices in QEMU are super classes of ``TYPE_DEVICE`` +however VirtIO devices should be based on ``TYPE_VIRTIO_DEVICE`` which +itself is derived from the base class. For example: + +.. code:: c + + static const TypeInfo virtio_blk_info = { + .name = TYPE_VIRTIO_BLK, + .parent = TYPE_VIRTIO_DEVICE, + .instance_size = sizeof(VirtIOBlock), + .instance_init = virtio_blk_instance_init, + .class_init = virtio_blk_class_init, + }; + +The author may decide to have a more expansive class hierarchy to +support multiple device types. For example the Virtio GPU device: + +.. code:: c + + static const TypeInfo virtio_gpu_base_info = { + .name = TYPE_VIRTIO_GPU_BASE, + .parent = TYPE_VIRTIO_DEVICE, + .instance_size = sizeof(VirtIOGPUBase), + .class_size = sizeof(VirtIOGPUBaseClass), + .class_init = virtio_gpu_base_class_init, + .abstract = true + }; + + static const TypeInfo vhost_user_gpu_info = { + .name = TYPE_VHOST_USER_GPU, + .parent = TYPE_VIRTIO_GPU_BASE, + .instance_size = sizeof(VhostUserGPU), + .instance_init = vhost_user_gpu_instance_init, + .instance_finalize = vhost_user_gpu_instance_finalize, + .class_init = vhost_user_gpu_class_init, + }; + + static const TypeInfo virtio_gpu_info = { + .name = TYPE_VIRTIO_GPU, + .parent = TYPE_VIRTIO_GPU_BASE, + .instance_size = sizeof(VirtIOGPU), + .class_size = sizeof(VirtIOGPUClass), + .class_init = virtio_gpu_class_init, + }; + +defines a base class for the VirtIO GPU and then specialises two +versions, one for the internal implementation and the other for the +vhost-user version. + +VirtIOPCIProxy +^^^^^^^^^^^^^^ + +[AJB: the following is supposition and welcomes more informed +opinions] + +Probably due to legacy from the pre-QOM days PCI VirtIO devices don't +follow the normal hierarchy. Instead the a standalone object is based +on the VirtIOPCIProxy class and the specific VirtIO instance is +manually instantiated: + +.. code:: c + + /* + * virtio-blk-pci: This extends VirtioPCIProxy. + */ + #define TYPE_VIRTIO_BLK_PCI "virtio-blk-pci-base" + DECLARE_INSTANCE_CHECKER(VirtIOBlkPCI, VIRTIO_BLK_PCI, + TYPE_VIRTIO_BLK_PCI) + + struct VirtIOBlkPCI { + VirtIOPCIProxy parent_obj; + VirtIOBlock vdev; + }; + + static Property virtio_blk_pci_properties[] = { + DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, + DEV_NVECTORS_UNSPECIFIED), + DEFINE_PROP_END_OF_LIST(), + }; + + static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) + { + VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + ... + + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); + } + + static void virtio_blk_pci_class_init(ObjectClass *klass, void *data) + { + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + device_class_set_props(dc, virtio_blk_pci_properties); + k->realize = virtio_blk_pci_realize; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK; + pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; + } + + static void virtio_blk_pci_instance_init(Object *obj) + { + VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_BLK); + object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), + "bootindex"); + } + + static const VirtioPCIDeviceTypeInfo virtio_blk_pci_info = { + .base_name = TYPE_VIRTIO_BLK_PCI, + .generic_name = "virtio-blk-pci", + .transitional_name = "virtio-blk-pci-transitional", + .non_transitional_name = "virtio-blk-pci-non-transitional", + .instance_size = sizeof(VirtIOBlkPCI), + .instance_init = virtio_blk_pci_instance_init, + .class_init = virtio_blk_pci_class_init, + }; + +Here you can see the instance_init has to manually instantiate the +underlying ``TYPE_VIRTIO_BLOCK`` object and link an alias for one of +it's properties to the PCI device. + + +Back End Implementations +------------------------ + +There are a number of places where the implementation of the backend +can be done: + +* in QEMU itself +* in the host kernel (a.k.a vhost) +* in a separate process (a.k.a. vhost-user) + +vhost_ops vs TYPE_VHOST_USER_BACKEND +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There are two choices to how to implement vhost code. Most of the code +which has to work with either vhost or vhost-user uses +``vhost_dev_init()`` to instantiate the appropriate backend. This +means including a ``struct vhost_dev`` in the main object structure. + +For vhost-user devices you also need to add code to track the +initialisation of the ``chardev`` device used for the control socket +between QEMU and the external vhost-user process. + +If you only need to implement a vhost-user backed the other option is +a use a QOM-ified version of vhost-user. + +.. code:: c + + static void + vhost_user_gpu_instance_init(Object *obj) + { + VhostUserGPU *g = VHOST_USER_GPU(obj); + + g->vhost = VHOST_USER_BACKEND(object_new(TYPE_VHOST_USER_BACKEND)); + object_property_add_alias(obj, "chardev", + OBJECT(g->vhost), "chardev"); + } + + static const TypeInfo vhost_user_gpu_info = { + .name = TYPE_VHOST_USER_GPU, + .parent = TYPE_VIRTIO_GPU_BASE, + .instance_size = sizeof(VhostUserGPU), + .instance_init = vhost_user_gpu_instance_init, + .instance_finalize = vhost_user_gpu_instance_finalize, + .class_init = vhost_user_gpu_class_init, + }; + +Using it this way entails adding a ``struct VhostUserBackend`` to your +core object structure and manually instantiating the backend. This +sub-structure tracks both the ``vhost_dev`` and ``CharDev`` types +needed for the connection. Instead of calling ``vhost_dev_init`` you +would call ``vhost_user_backend_dev_init`` which does what is needed +on your behalf. From 27351992bf238f669dd08655d31ad111905bf899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 21 Mar 2022 15:30:34 +0000 Subject: [PATCH 372/935] include/hw: start documenting the vhost API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While trying to get my head around the nest of interactions for vhost devices I though I could start by documenting the key API functions. This patch documents the main API hooks for creating and starting a vhost device as well as how the configuration changes are handled. Signed-off-by: Alex Bennée Cc: Michael S. Tsirkin Cc: Stefan Hajnoczi Cc: Marc-André Lureau Message-Id: <20220321153037.3622127-11-alex.bennee@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/hw/virtio/vhost.h | 132 +++++++++++++++++++++++++++++++++++--- 1 file changed, 122 insertions(+), 10 deletions(-) diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index 58a73e7b7a..b291fe4e24 100644 --- a/include/hw/virtio/vhost.h +++ b/include/hw/virtio/vhost.h @@ -61,6 +61,12 @@ typedef struct VhostDevConfigOps { } VhostDevConfigOps; struct vhost_memory; + +/** + * struct vhost_dev - common vhost_dev structure + * @vhost_ops: backend specific ops + * @config_ops: ops for config changes (see @vhost_dev_set_config_notifier) + */ struct vhost_dev { VirtIODevice *vdev; MemoryListener memory_listener; @@ -108,15 +114,129 @@ struct vhost_net { NetClientState *nc; }; +/** + * vhost_dev_init() - initialise the vhost interface + * @hdev: the common vhost_dev structure + * @opaque: opaque ptr passed to backend (vhost/vhost-user/vdpa) + * @backend_type: type of backend + * @busyloop_timeout: timeout for polling virtqueue + * @errp: error handle + * + * The initialisation of the vhost device will trigger the + * initialisation of the backend and potentially capability + * negotiation of backend interface. Configuration of the VirtIO + * itself won't happen until the interface is started. + * + * Return: 0 on success, non-zero on error while setting errp. + */ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, VhostBackendType backend_type, uint32_t busyloop_timeout, Error **errp); + +/** + * vhost_dev_cleanup() - tear down and cleanup vhost interface + * @hdev: the common vhost_dev structure + */ void vhost_dev_cleanup(struct vhost_dev *hdev); -int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev); -void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev); + +/** + * vhost_dev_enable_notifiers() - enable event notifiers + * @hdev: common vhost_dev structure + * @vdev: the VirtIODevice structure + * + * Enable notifications directly to the vhost device rather than being + * triggered by QEMU itself. Notifications should be enabled before + * the vhost device is started via @vhost_dev_start. + * + * Return: 0 on success, < 0 on error. + */ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); + +/** + * vhost_dev_disable_notifiers - disable event notifications + * @hdev: common vhost_dev structure + * @vdev: the VirtIODevice structure + * + * Disable direct notifications to vhost device. + */ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); +/** + * vhost_dev_start() - start the vhost device + * @hdev: common vhost_dev structure + * @vdev: the VirtIODevice structure + * + * Starts the vhost device. From this point VirtIO feature negotiation + * can start and the device can start processing VirtIO transactions. + * + * Return: 0 on success, < 0 on error. + */ +int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev); + +/** + * vhost_dev_stop() - stop the vhost device + * @hdev: common vhost_dev structure + * @vdev: the VirtIODevice structure + * + * Stop the vhost device. After the device is stopped the notifiers + * can be disabled (@vhost_dev_disable_notifiers) and the device can + * be torn down (@vhost_dev_cleanup). + */ +void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev); + +/** + * DOC: vhost device configuration handling + * + * The VirtIO device configuration space is used for rarely changing + * or initialisation time parameters. The configuration can be updated + * by either the guest driver or the device itself. If the device can + * change the configuration over time the vhost handler should + * register a @VhostDevConfigOps structure with + * @vhost_dev_set_config_notifier so the guest can be notified. Some + * devices register a handler anyway and will signal an error if an + * unexpected config change happens. + */ + +/** + * vhost_dev_get_config() - fetch device configuration + * @hdev: common vhost_dev_structure + * @config: pointer to device appropriate config structure + * @config_len: size of device appropriate config structure + * + * Return: 0 on success, < 0 on error while setting errp + */ +int vhost_dev_get_config(struct vhost_dev *hdev, uint8_t *config, + uint32_t config_len, Error **errp); + +/** + * vhost_dev_set_config() - set device configuration + * @hdev: common vhost_dev_structure + * @data: pointer to data to set + * @offset: offset into configuration space + * @size: length of set + * @flags: @VhostSetConfigType flags + * + * By use of @offset/@size a subset of the configuration space can be + * written to. The @flags are used to indicate if it is a normal + * transaction or related to migration. + * + * Return: 0 on success, non-zero on error + */ +int vhost_dev_set_config(struct vhost_dev *dev, const uint8_t *data, + uint32_t offset, uint32_t size, uint32_t flags); + +/** + * vhost_dev_set_config_notifier() - register VhostDevConfigOps + * @hdev: common vhost_dev_structure + * @ops: notifier ops + * + * If the device is expected to change configuration a notifier can be + * setup to handle the case. + */ +void vhost_dev_set_config_notifier(struct vhost_dev *dev, + const VhostDevConfigOps *ops); + + /* Test and clear masked event pending status. * Should be called after unmask to avoid losing events. */ @@ -136,14 +256,6 @@ int vhost_net_set_backend(struct vhost_dev *hdev, struct vhost_vring_file *file); int vhost_device_iotlb_miss(struct vhost_dev *dev, uint64_t iova, int write); -int vhost_dev_get_config(struct vhost_dev *hdev, uint8_t *config, - uint32_t config_len, Error **errp); -int vhost_dev_set_config(struct vhost_dev *dev, const uint8_t *data, - uint32_t offset, uint32_t size, uint32_t flags); -/* notifier callback in case vhost device config space changed - */ -void vhost_dev_set_config_notifier(struct vhost_dev *dev, - const VhostDevConfigOps *ops); void vhost_dev_reset_inflight(struct vhost_inflight *inflight); void vhost_dev_free_inflight(struct vhost_inflight *inflight); From 56534930b5cd3a6c7259cfeba69f08ba28c8f62a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 21 Mar 2022 15:30:36 +0000 Subject: [PATCH 373/935] hw/virtio/vhost-user: don't suppress F_CONFIG when supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously we would silently suppress VHOST_USER_PROTOCOL_F_CONFIG during the protocol negotiation if the QEMU stub hadn't implemented the vhost_dev_config_notifier. However this isn't the only way we can handle config messages, the existing vdc->get/set_config can do this as well. Lightly re-factor the code to check for both potential methods and instead of silently squashing the feature error out. It is unlikely that a vhost-user backend expecting to handle CONFIG messages will behave correctly if they never get sent. Fixes: 1c3e5a2617 ("vhost-user: back SET/GET_CONFIG requests with a protocol feature") Cc: Maxime Coquelin Cc: Michael S. Tsirkin Cc: Stefan Hajnoczi Signed-off-by: Alex Bennée Message-Id: <20220321153037.3622127-13-alex.bennee@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/scsi/vhost-user-scsi.c | 1 + hw/virtio/vhost-user.c | 44 ++++++++++++++++++++++++---------- include/hw/virtio/vhost-user.h | 1 + 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index 1b2f7eed98..9be21d07ee 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -121,6 +121,7 @@ static void vhost_user_scsi_realize(DeviceState *dev, Error **errp) vsc->dev.backend_features = 0; vqs = vsc->dev.vqs; + s->vhost_user.supports_config = true; ret = vhost_dev_init(&vsc->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0, errp); if (ret < 0) { diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 6c8f722262..b0d417651d 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -1949,14 +1949,15 @@ static int vhost_user_postcopy_notifier(NotifierWithReturn *notifier, static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque, Error **errp) { - uint64_t features, protocol_features, ram_slots; + uint64_t features, ram_slots; struct vhost_user *u; + VhostUserState *vus = (VhostUserState *) opaque; int err; assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); u = g_new0(struct vhost_user, 1); - u->user = opaque; + u->user = vus; u->dev = dev; dev->opaque = u; @@ -1967,6 +1968,10 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque, } if (virtio_has_feature(features, VHOST_USER_F_PROTOCOL_FEATURES)) { + bool supports_f_config = vus->supports_config || + (dev->config_ops && dev->config_ops->vhost_dev_config_notifier); + uint64_t protocol_features; + dev->backend_features |= 1ULL << VHOST_USER_F_PROTOCOL_FEATURES; err = vhost_user_get_u64(dev, VHOST_USER_GET_PROTOCOL_FEATURES, @@ -1976,19 +1981,34 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque, return -EPROTO; } - dev->protocol_features = - protocol_features & VHOST_USER_PROTOCOL_FEATURE_MASK; + /* + * We will use all the protocol features we support - although + * we suppress F_CONFIG if we know QEMUs internal code can not support + * it. + */ + protocol_features &= VHOST_USER_PROTOCOL_FEATURE_MASK; - if (!dev->config_ops || !dev->config_ops->vhost_dev_config_notifier) { - /* Don't acknowledge CONFIG feature if device doesn't support it */ - dev->protocol_features &= ~(1ULL << VHOST_USER_PROTOCOL_F_CONFIG); - } else if (!(protocol_features & - (1ULL << VHOST_USER_PROTOCOL_F_CONFIG))) { - error_setg(errp, "Device expects VHOST_USER_PROTOCOL_F_CONFIG " - "but backend does not support it."); - return -EINVAL; + if (supports_f_config) { + if (!virtio_has_feature(protocol_features, + VHOST_USER_PROTOCOL_F_CONFIG)) { + error_setg(errp, "vhost-user device %s expecting " + "VHOST_USER_PROTOCOL_F_CONFIG but the vhost-user backend does " + "not support it.", dev->vdev->name); + return -EPROTO; + } + } else { + if (virtio_has_feature(protocol_features, + VHOST_USER_PROTOCOL_F_CONFIG)) { + warn_reportf_err(*errp, "vhost-user backend supports " + "VHOST_USER_PROTOCOL_F_CONFIG for " + "device %s but QEMU does not.", + dev->vdev->name); + protocol_features &= ~(1ULL << VHOST_USER_PROTOCOL_F_CONFIG); + } } + /* final set of protocol features */ + dev->protocol_features = protocol_features; err = vhost_user_set_protocol_features(dev, dev->protocol_features); if (err < 0) { error_setg_errno(errp, EPROTO, "vhost_backend_init failed"); diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h index e44a41bb70..6e0e8a71a3 100644 --- a/include/hw/virtio/vhost-user.h +++ b/include/hw/virtio/vhost-user.h @@ -22,6 +22,7 @@ typedef struct VhostUserState { CharBackend *chr; VhostUserHostNotifier notifier[VIRTIO_QUEUE_MAX]; int memory_slots; + bool supports_config; } VhostUserState; bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp); From 503e355465ba0eafad49c2e174995d2e234ed288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 21 Mar 2022 15:30:37 +0000 Subject: [PATCH 374/935] virtio/vhost-user: dynamically assign VhostUserHostNotifiers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At a couple of hundred bytes per notifier allocating one for every potential queue is very wasteful as most devices only have a few queues. Instead of having this handled statically dynamically assign them and track in a GPtrArray. [AJB: it's hard to trigger the vhost notifiers code, I assume as it requires a KVM guest with appropriate backend] Signed-off-by: Alex Bennée Message-Id: <20220321153037.3622127-14-alex.bennee@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/trace-events | 1 + hw/virtio/vhost-user.c | 83 +++++++++++++++++++++++++++------- include/hw/virtio/vhost-user.h | 42 ++++++++++++++++- 3 files changed, 108 insertions(+), 18 deletions(-) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 65e3b704ec..ab8e095b73 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -23,6 +23,7 @@ vhost_user_postcopy_waker_found(uint64_t client_addr) "0x%"PRIx64 vhost_user_postcopy_waker_nomatch(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64 vhost_user_read(uint32_t req, uint32_t flags) "req:%d flags:0x%"PRIx32"" vhost_user_write(uint32_t req, uint32_t flags) "req:%d flags:0x%"PRIx32"" +vhost_user_create_notifier(int idx, void *n) "idx:%d n:%p" # vhost-vdpa.c vhost_vdpa_dma_map(void *vdpa, int fd, uint32_t msg_type, uint64_t iova, uint64_t size, uint64_t uaddr, uint8_t perm, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" uaddr: 0x%"PRIx64" perm: 0x%"PRIx8" type: %"PRIu8 diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index b0d417651d..b040c1ad2b 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -1174,14 +1174,16 @@ static void vhost_user_host_notifier_free(VhostUserHostNotifier *n) n->unmap_addr = NULL; } -static void vhost_user_host_notifier_remove(VhostUserState *user, - VirtIODevice *vdev, int queue_idx) +/* + * clean-up function for notifier, will finally free the structure + * under rcu. + */ +static void vhost_user_host_notifier_remove(VhostUserHostNotifier *n, + VirtIODevice *vdev) { - VhostUserHostNotifier *n = &user->notifier[queue_idx]; - if (n->addr) { if (vdev) { - virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false); + virtio_queue_set_host_notifier_mr(vdev, n->idx, &n->mr, false); } assert(!n->unmap_addr); n->unmap_addr = n->addr; @@ -1225,6 +1227,15 @@ static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable) return 0; } +static VhostUserHostNotifier *fetch_notifier(VhostUserState *u, + int idx) +{ + if (idx >= u->notifiers->len) { + return NULL; + } + return g_ptr_array_index(u->notifiers, idx); +} + static int vhost_user_get_vring_base(struct vhost_dev *dev, struct vhost_vring_state *ring) { @@ -1237,7 +1248,10 @@ static int vhost_user_get_vring_base(struct vhost_dev *dev, }; struct vhost_user *u = dev->opaque; - vhost_user_host_notifier_remove(u->user, dev->vdev, ring->index); + VhostUserHostNotifier *n = fetch_notifier(u->user, ring->index); + if (n) { + vhost_user_host_notifier_remove(n, dev->vdev); + } ret = vhost_user_write(dev, &msg, NULL, 0); if (ret < 0) { @@ -1502,6 +1516,29 @@ static int vhost_user_slave_handle_config_change(struct vhost_dev *dev) return dev->config_ops->vhost_dev_config_notifier(dev); } +/* + * Fetch or create the notifier for a given idx. Newly created + * notifiers are added to the pointer array that tracks them. + */ +static VhostUserHostNotifier *fetch_or_create_notifier(VhostUserState *u, + int idx) +{ + VhostUserHostNotifier *n = NULL; + if (idx >= u->notifiers->len) { + g_ptr_array_set_size(u->notifiers, idx); + } + + n = g_ptr_array_index(u->notifiers, idx); + if (!n) { + n = g_new0(VhostUserHostNotifier, 1); + n->idx = idx; + g_ptr_array_insert(u->notifiers, idx, n); + trace_vhost_user_create_notifier(idx, n); + } + + return n; +} + static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, VhostUserVringArea *area, int fd) @@ -1521,9 +1558,12 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, return -EINVAL; } - n = &user->notifier[queue_idx]; - - vhost_user_host_notifier_remove(user, vdev, queue_idx); + /* + * Fetch notifier and invalidate any old data before setting up + * new mapped address. + */ + n = fetch_or_create_notifier(user, queue_idx); + vhost_user_host_notifier_remove(n, vdev); if (area->u64 & VHOST_USER_VRING_NOFD_MASK) { return 0; @@ -2526,6 +2566,20 @@ static int vhost_user_set_inflight_fd(struct vhost_dev *dev, return vhost_user_write(dev, &msg, &inflight->fd, 1); } +static void vhost_user_state_destroy(gpointer data) +{ + VhostUserHostNotifier *n = (VhostUserHostNotifier *) data; + if (n) { + vhost_user_host_notifier_remove(n, NULL); + object_unparent(OBJECT(&n->mr)); + /* + * We can't free until vhost_user_host_notifier_remove has + * done it's thing so schedule the free with RCU. + */ + g_free_rcu(n, rcu); + } +} + bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp) { if (user->chr) { @@ -2534,23 +2588,18 @@ bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp) } user->chr = chr; user->memory_slots = 0; + user->notifiers = g_ptr_array_new_full(VIRTIO_QUEUE_MAX / 4, + &vhost_user_state_destroy); return true; } void vhost_user_cleanup(VhostUserState *user) { - int i; - VhostUserHostNotifier *n; - if (!user->chr) { return; } memory_region_transaction_begin(); - for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { - n = &user->notifier[i]; - vhost_user_host_notifier_remove(user, NULL, i); - object_unparent(OBJECT(&n->mr)); - } + user->notifiers = (GPtrArray *) g_ptr_array_free(user->notifiers, true); memory_region_transaction_commit(); user->chr = NULL; } diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h index 6e0e8a71a3..c6e693cd3f 100644 --- a/include/hw/virtio/vhost-user.h +++ b/include/hw/virtio/vhost-user.h @@ -11,21 +11,61 @@ #include "chardev/char-fe.h" #include "hw/virtio/virtio.h" +/** + * VhostUserHostNotifier - notifier information for one queue + * @rcu: rcu_head for cleanup + * @mr: memory region of notifier + * @addr: current mapped address + * @unmap_addr: address to be un-mapped + * @idx: virtioqueue index + * + * The VhostUserHostNotifier entries are re-used. When an old mapping + * is to be released it is moved to @unmap_addr and @addr is replaced. + * Once the RCU process has completed the unmap @unmap_addr is + * cleared. + */ typedef struct VhostUserHostNotifier { struct rcu_head rcu; MemoryRegion mr; void *addr; void *unmap_addr; + int idx; } VhostUserHostNotifier; +/** + * VhostUserState - shared state for all vhost-user devices + * @chr: the character backend for the socket + * @notifiers: GPtrArray of @VhostUserHostnotifier + * @memory_slots: + */ typedef struct VhostUserState { CharBackend *chr; - VhostUserHostNotifier notifier[VIRTIO_QUEUE_MAX]; + GPtrArray *notifiers; int memory_slots; bool supports_config; } VhostUserState; +/** + * vhost_user_init() - initialise shared vhost_user state + * @user: allocated area for storing shared state + * @chr: the chardev for the vhost socket + * @errp: error handle + * + * User can either directly g_new() space for the state or embed + * VhostUserState in their larger device structure and just point to + * it. + * + * Return: true on success, false on error while setting errp. + */ bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp); + +/** + * vhost_user_cleanup() - cleanup state + * @user: ptr to use state + * + * Cleans up shared state and notifiers, callee is responsible for + * freeing the @VhostUserState memory itself. + */ void vhost_user_cleanup(VhostUserState *user); #endif From 3857cd5c7ffd0bcc49bd2b66654af0909c847d02 Mon Sep 17 00:00:00 2001 From: Jonah Palmer Date: Fri, 1 Apr 2022 09:23:18 -0400 Subject: [PATCH 375/935] virtio: drop name parameter for virtio_init() This patch drops the name parameter for the virtio_init function. The pair between the numeric device ID and the string device ID (name) of a virtio device already exists, but not in a way that lets us map between them. This patch lets us do this and removes the need for the name parameter in the virtio_init function. Signed-off-by: Jonah Palmer Message-Id: <1648819405-25696-2-git-send-email-jonah.palmer@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/9pfs/virtio-9p-device.c | 2 +- hw/block/vhost-user-blk.c | 2 +- hw/block/virtio-blk.c | 2 +- hw/char/virtio-serial-bus.c | 3 +- hw/display/virtio-gpu-base.c | 2 +- hw/input/virtio-input.c | 3 +- hw/net/virtio-net.c | 2 +- hw/scsi/virtio-scsi.c | 3 +- hw/virtio/vhost-user-fs.c | 3 +- hw/virtio/vhost-user-i2c.c | 7 +--- hw/virtio/vhost-user-rng.c | 2 +- hw/virtio/vhost-user-vsock.c | 2 +- hw/virtio/vhost-vsock-common.c | 5 +-- hw/virtio/vhost-vsock.c | 2 +- hw/virtio/virtio-balloon.c | 3 +- hw/virtio/virtio-crypto.c | 2 +- hw/virtio/virtio-iommu.c | 3 +- hw/virtio/virtio-mem.c | 3 +- hw/virtio/virtio-pmem.c | 3 +- hw/virtio/virtio-rng.c | 2 +- hw/virtio/virtio.c | 55 ++++++++++++++++++++++++-- include/hw/virtio/vhost-vsock-common.h | 2 +- include/hw/virtio/virtio-gpu.h | 3 +- include/hw/virtio/virtio.h | 4 +- 24 files changed, 77 insertions(+), 43 deletions(-) diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 54ee93b71f..5f522e68e9 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -216,7 +216,7 @@ static void virtio_9p_device_realize(DeviceState *dev, Error **errp) } v->config_size = sizeof(struct virtio_9p_config) + strlen(s->fsconf.tag); - virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, v->config_size); + virtio_init(vdev, VIRTIO_ID_9P, v->config_size); v->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output); } diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index 1a42ae9187..e8cb170032 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -491,7 +491,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) return; } - virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, + virtio_init(vdev, VIRTIO_ID_BLOCK, sizeof(struct virtio_blk_config)); s->virtqs = g_new(VirtQueue *, s->num_queues); diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 6a1cc41877..cd804795c6 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -1206,7 +1206,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) virtio_blk_set_config_size(s, s->host_features); - virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, s->config_size); + virtio_init(vdev, VIRTIO_ID_BLOCK, s->config_size); s->blk = conf->conf.blk; s->rq = NULL; diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index 6048d408b8..7d4601cb5d 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -1044,8 +1044,7 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp) VIRTIO_CONSOLE_F_EMERG_WRITE)) { config_size = offsetof(struct virtio_console_config, emerg_wr); } - virtio_init(vdev, "virtio-serial", VIRTIO_ID_CONSOLE, - config_size); + virtio_init(vdev, VIRTIO_ID_CONSOLE, config_size); /* Spawn a new virtio-serial bus on which the ports will ride as devices */ qbus_init(&vser->bus, sizeof(vser->bus), TYPE_VIRTIO_SERIAL_BUS, diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c index fff0fb4a82..8ba5da4312 100644 --- a/hw/display/virtio-gpu-base.c +++ b/hw/display/virtio-gpu-base.c @@ -173,7 +173,7 @@ virtio_gpu_base_device_realize(DeviceState *qdev, } g->virtio_config.num_scanouts = cpu_to_le32(g->conf.max_outputs); - virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU, + virtio_init(VIRTIO_DEVICE(g), VIRTIO_ID_GPU, sizeof(struct virtio_gpu_config)); if (virtio_gpu_virgl_enabled(g->conf)) { diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c index 54bcb46c74..5b5398b3ca 100644 --- a/hw/input/virtio-input.c +++ b/hw/input/virtio-input.c @@ -257,8 +257,7 @@ static void virtio_input_device_realize(DeviceState *dev, Error **errp) vinput->cfg_size += 8; assert(vinput->cfg_size <= sizeof(virtio_input_config)); - virtio_init(vdev, "virtio-input", VIRTIO_ID_INPUT, - vinput->cfg_size); + virtio_init(vdev, VIRTIO_ID_INPUT, vinput->cfg_size); vinput->evt = virtio_add_queue(vdev, 64, virtio_input_handle_evt); vinput->sts = virtio_add_queue(vdev, 64, virtio_input_handle_sts); } diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index e4748a7e6c..bd0224caaf 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -3393,7 +3393,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) } virtio_net_set_config_size(n, n->host_features); - virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size); + virtio_init(vdev, VIRTIO_ID_NET, n->config_size); /* * We set a lower limit on RX queue size to what it always was. diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index db54d104be..4141dddd51 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -1013,8 +1013,7 @@ void virtio_scsi_common_realize(DeviceState *dev, VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(dev); int i; - virtio_init(vdev, "virtio-scsi", VIRTIO_ID_SCSI, - sizeof(VirtIOSCSIConfig)); + virtio_init(vdev, VIRTIO_ID_SCSI, sizeof(VirtIOSCSIConfig)); if (s->conf.num_queues == VIRTIO_SCSI_AUTO_NUM_QUEUES) { s->conf.num_queues = 1; diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c index c595957983..b875640147 100644 --- a/hw/virtio/vhost-user-fs.c +++ b/hw/virtio/vhost-user-fs.c @@ -219,8 +219,7 @@ static void vuf_device_realize(DeviceState *dev, Error **errp) return; } - virtio_init(vdev, "vhost-user-fs", VIRTIO_ID_FS, - sizeof(struct virtio_fs_config)); + virtio_init(vdev, VIRTIO_ID_FS, sizeof(struct virtio_fs_config)); /* Hiprio queue */ fs->hiprio_vq = virtio_add_queue(vdev, fs->conf.queue_size, vuf_handle_output); diff --git a/hw/virtio/vhost-user-i2c.c b/hw/virtio/vhost-user-i2c.c index 42c7f6d9e5..6020eee093 100644 --- a/hw/virtio/vhost-user-i2c.c +++ b/hw/virtio/vhost-user-i2c.c @@ -14,11 +14,6 @@ #include "qemu/error-report.h" #include "standard-headers/linux/virtio_ids.h" -/* Remove this once the header is updated in Linux kernel */ -#ifndef VIRTIO_ID_I2C_ADAPTER -#define VIRTIO_ID_I2C_ADAPTER 34 -#endif - static const int feature_bits[] = { VIRTIO_I2C_F_ZERO_LENGTH_REQUEST, VHOST_INVALID_FEATURE_BIT @@ -227,7 +222,7 @@ static void vu_i2c_device_realize(DeviceState *dev, Error **errp) return; } - virtio_init(vdev, "vhost-user-i2c", VIRTIO_ID_I2C_ADAPTER, 0); + virtio_init(vdev, VIRTIO_ID_I2C_ADAPTER, 0); i2c->vhost_dev.nvqs = 1; i2c->vq = virtio_add_queue(vdev, 4, vu_i2c_handle_output); diff --git a/hw/virtio/vhost-user-rng.c b/hw/virtio/vhost-user-rng.c index 209ee5bf9a..08bccba9dc 100644 --- a/hw/virtio/vhost-user-rng.c +++ b/hw/virtio/vhost-user-rng.c @@ -203,7 +203,7 @@ static void vu_rng_device_realize(DeviceState *dev, Error **errp) return; } - virtio_init(vdev, "vhost-user-rng", VIRTIO_ID_RNG, 0); + virtio_init(vdev, VIRTIO_ID_RNG, 0); rng->req_vq = virtio_add_queue(vdev, 4, vu_rng_handle_output); if (!rng->req_vq) { diff --git a/hw/virtio/vhost-user-vsock.c b/hw/virtio/vhost-user-vsock.c index 52bd682c34..0f8ff99f85 100644 --- a/hw/virtio/vhost-user-vsock.c +++ b/hw/virtio/vhost-user-vsock.c @@ -107,7 +107,7 @@ static void vuv_device_realize(DeviceState *dev, Error **errp) return; } - vhost_vsock_common_realize(vdev, "vhost-user-vsock"); + vhost_vsock_common_realize(vdev); vhost_dev_set_config_notifier(&vvc->vhost_dev, &vsock_ops); diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c index ed706681ac..ad5c8ff5d5 100644 --- a/hw/virtio/vhost-vsock-common.c +++ b/hw/virtio/vhost-vsock-common.c @@ -224,12 +224,11 @@ int vhost_vsock_common_post_load(void *opaque, int version_id) return 0; } -void vhost_vsock_common_realize(VirtIODevice *vdev, const char *name) +void vhost_vsock_common_realize(VirtIODevice *vdev) { VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); - virtio_init(vdev, name, VIRTIO_ID_VSOCK, - sizeof(struct virtio_vsock_config)); + virtio_init(vdev, VIRTIO_ID_VSOCK, sizeof(struct virtio_vsock_config)); /* Receive and transmit queues belong to vhost */ vvc->recv_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c index 714046210b..0338de892f 100644 --- a/hw/virtio/vhost-vsock.c +++ b/hw/virtio/vhost-vsock.c @@ -169,7 +169,7 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp) } } - vhost_vsock_common_realize(vdev, "vhost-vsock"); + vhost_vsock_common_realize(vdev); ret = vhost_dev_init(&vvc->vhost_dev, (void *)(uintptr_t)vhostfd, VHOST_BACKEND_TYPE_KERNEL, 0, errp); diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 8f1b38ef5c..73ac5eb675 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -882,8 +882,7 @@ static void virtio_balloon_device_realize(DeviceState *dev, Error **errp) VirtIOBalloon *s = VIRTIO_BALLOON(dev); int ret; - virtio_init(vdev, "virtio-balloon", VIRTIO_ID_BALLOON, - virtio_balloon_config_size(s)); + virtio_init(vdev, VIRTIO_ID_BALLOON, virtio_balloon_config_size(s)); ret = qemu_add_balloon_handler(virtio_balloon_to_target, virtio_balloon_stat, s); diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index 0e31e3cc04..df9adb2c07 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -810,7 +810,7 @@ static void virtio_crypto_device_realize(DeviceState *dev, Error **errp) return; } - virtio_init(vdev, "virtio-crypto", VIRTIO_ID_CRYPTO, vcrypto->config_size); + virtio_init(vdev, VIRTIO_ID_CRYPTO, vcrypto->config_size); vcrypto->curr_queues = 1; vcrypto->vqs = g_new0(VirtIOCryptoQueue, vcrypto->max_queues); for (i = 0; i < vcrypto->max_queues; i++) { diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index 57c09d98a9..2597e166f9 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -1033,8 +1033,7 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp) VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOIOMMU *s = VIRTIO_IOMMU(dev); - virtio_init(vdev, "virtio-iommu", VIRTIO_ID_IOMMU, - sizeof(struct virtio_iommu_config)); + virtio_init(vdev, VIRTIO_ID_IOMMU, sizeof(struct virtio_iommu_config)); memset(s->iommu_pcibus_by_bus_num, 0, sizeof(s->iommu_pcibus_by_bus_num)); diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index 5aca408726..30d03e987a 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -867,8 +867,7 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp) vmem->block_size; vmem->bitmap = bitmap_new(vmem->bitmap_size); - virtio_init(vdev, TYPE_VIRTIO_MEM, VIRTIO_ID_MEM, - sizeof(struct virtio_mem_config)); + virtio_init(vdev, VIRTIO_ID_MEM, sizeof(struct virtio_mem_config)); vmem->vq = virtio_add_queue(vdev, 128, virtio_mem_handle_request); host_memory_backend_set_mapped(vmem->memdev, true); diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c index 5dd21c2c44..a1abfe0e1b 100644 --- a/hw/virtio/virtio-pmem.c +++ b/hw/virtio/virtio-pmem.c @@ -122,8 +122,7 @@ static void virtio_pmem_realize(DeviceState *dev, Error **errp) } host_memory_backend_set_mapped(pmem->memdev, true); - virtio_init(vdev, TYPE_VIRTIO_PMEM, VIRTIO_ID_PMEM, - sizeof(struct virtio_pmem_config)); + virtio_init(vdev, VIRTIO_ID_PMEM, sizeof(struct virtio_pmem_config)); pmem->rq_vq = virtio_add_queue(vdev, 128, virtio_pmem_flush); } diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index cc8e9f775d..7e12fc03bf 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -215,7 +215,7 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp) return; } - virtio_init(vdev, "virtio-rng", VIRTIO_ID_RNG, 0); + virtio_init(vdev, VIRTIO_ID_RNG, 0); vrng->vq = virtio_add_queue(vdev, 8, handle_input); vrng->quota_remaining = vrng->conf.max_bytes; diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 67a873f54a..7f9fcfd06d 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -132,6 +132,56 @@ struct VirtQueue QLIST_ENTRY(VirtQueue) node; }; +const char *virtio_device_names[] = { + [VIRTIO_ID_NET] = "virtio-net", + [VIRTIO_ID_BLOCK] = "virtio-blk", + [VIRTIO_ID_CONSOLE] = "virtio-serial", + [VIRTIO_ID_RNG] = "virtio-rng", + [VIRTIO_ID_BALLOON] = "virtio-balloon", + [VIRTIO_ID_IOMEM] = "virtio-iomem", + [VIRTIO_ID_RPMSG] = "virtio-rpmsg", + [VIRTIO_ID_SCSI] = "virtio-scsi", + [VIRTIO_ID_9P] = "virtio-9p", + [VIRTIO_ID_MAC80211_WLAN] = "virtio-mac-wlan", + [VIRTIO_ID_RPROC_SERIAL] = "virtio-rproc-serial", + [VIRTIO_ID_CAIF] = "virtio-caif", + [VIRTIO_ID_MEMORY_BALLOON] = "virtio-mem-balloon", + [VIRTIO_ID_GPU] = "virtio-gpu", + [VIRTIO_ID_CLOCK] = "virtio-clk", + [VIRTIO_ID_INPUT] = "virtio-input", + [VIRTIO_ID_VSOCK] = "vhost-vsock", + [VIRTIO_ID_CRYPTO] = "virtio-crypto", + [VIRTIO_ID_SIGNAL_DIST] = "virtio-signal", + [VIRTIO_ID_PSTORE] = "virtio-pstore", + [VIRTIO_ID_IOMMU] = "virtio-iommu", + [VIRTIO_ID_MEM] = "virtio-mem", + [VIRTIO_ID_SOUND] = "virtio-sound", + [VIRTIO_ID_FS] = "virtio-user-fs", + [VIRTIO_ID_PMEM] = "virtio-pmem", + [VIRTIO_ID_RPMB] = "virtio-rpmb", + [VIRTIO_ID_MAC80211_HWSIM] = "virtio-mac-hwsim", + [VIRTIO_ID_VIDEO_ENCODER] = "virtio-vid-encoder", + [VIRTIO_ID_VIDEO_DECODER] = "virtio-vid-decoder", + [VIRTIO_ID_SCMI] = "virtio-scmi", + [VIRTIO_ID_NITRO_SEC_MOD] = "virtio-nitro-sec-mod", + [VIRTIO_ID_I2C_ADAPTER] = "vhost-user-i2c", + [VIRTIO_ID_WATCHDOG] = "virtio-watchdog", + [VIRTIO_ID_CAN] = "virtio-can", + [VIRTIO_ID_DMABUF] = "virtio-dmabuf", + [VIRTIO_ID_PARAM_SERV] = "virtio-param-serv", + [VIRTIO_ID_AUDIO_POLICY] = "virtio-audio-pol", + [VIRTIO_ID_BT] = "virtio-bluetooth", + [VIRTIO_ID_GPIO] = "virtio-gpio" +}; + +static const char *virtio_id_to_name(uint16_t device_id) +{ + assert(device_id < G_N_ELEMENTS(virtio_device_names)); + const char *name = virtio_device_names[device_id]; + assert(name != NULL); + return name; +} + /* Called within call_rcu(). */ static void virtio_free_region_cache(VRingMemoryRegionCaches *caches) { @@ -3207,8 +3257,7 @@ void virtio_instance_init_common(Object *proxy_obj, void *data, qdev_alias_all_properties(vdev, proxy_obj); } -void virtio_init(VirtIODevice *vdev, const char *name, - uint16_t device_id, size_t config_size) +void virtio_init(VirtIODevice *vdev, uint16_t device_id, size_t config_size) { BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); @@ -3237,7 +3286,7 @@ void virtio_init(VirtIODevice *vdev, const char *name, vdev->vq[i].host_notifier_enabled = false; } - vdev->name = name; + vdev->name = virtio_id_to_name(device_id); vdev->config_len = config_size; if (vdev->config_len) { vdev->config = g_malloc0(config_size); diff --git a/include/hw/virtio/vhost-vsock-common.h b/include/hw/virtio/vhost-vsock-common.h index 456a9c2365..93c782101d 100644 --- a/include/hw/virtio/vhost-vsock-common.h +++ b/include/hw/virtio/vhost-vsock-common.h @@ -44,7 +44,7 @@ int vhost_vsock_common_start(VirtIODevice *vdev); void vhost_vsock_common_stop(VirtIODevice *vdev); int vhost_vsock_common_pre_save(void *opaque); int vhost_vsock_common_post_load(void *opaque, int version_id); -void vhost_vsock_common_realize(VirtIODevice *vdev, const char *name); +void vhost_vsock_common_realize(VirtIODevice *vdev); void vhost_vsock_common_unrealize(VirtIODevice *vdev); uint64_t vhost_vsock_common_get_features(VirtIODevice *vdev, uint64_t features, Error **errp); diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 2179b75703..afff9e158e 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -22,6 +22,7 @@ #include "sysemu/vhost-user-backend.h" #include "standard-headers/linux/virtio_gpu.h" +#include "standard-headers/linux/virtio_ids.h" #include "qom/object.h" #define TYPE_VIRTIO_GPU_BASE "virtio-gpu-base" @@ -37,8 +38,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPUGL, VIRTIO_GPU_GL) #define TYPE_VHOST_USER_GPU "vhost-user-gpu" OBJECT_DECLARE_SIMPLE_TYPE(VhostUserGPU, VHOST_USER_GPU) -#define VIRTIO_ID_GPU 16 - struct virtio_gpu_simple_resource { uint32_t resource_id; uint32_t width; diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index b62a35fdca..b6890ffa70 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -165,8 +165,8 @@ struct VirtioDeviceClass { void virtio_instance_init_common(Object *proxy_obj, void *data, size_t vdev_size, const char *vdev_name); -void virtio_init(VirtIODevice *vdev, const char *name, - uint16_t device_id, size_t config_size); +void virtio_init(VirtIODevice *vdev, uint16_t device_id, size_t config_size); + void virtio_cleanup(VirtIODevice *vdev); void virtio_error(VirtIODevice *vdev, const char *fmt, ...) G_GNUC_PRINTF(2, 3); From c255488d67dc0d52052a12e0242bf00dcbe5223f Mon Sep 17 00:00:00 2001 From: Jonah Palmer Date: Fri, 1 Apr 2022 09:23:19 -0400 Subject: [PATCH 376/935] virtio: add vhost support for virtio devices This patch adds a get_vhost() callback function for VirtIODevices that returns the device's corresponding vhost_dev structure, if the vhost device is running. This patch also adds a vhost_started flag for VirtIODevices. Previously, a VirtIODevice wouldn't be able to tell if its corresponding vhost device was active or not. Signed-off-by: Jonah Palmer Message-Id: <1648819405-25696-3-git-send-email-jonah.palmer@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/vhost-user-blk.c | 7 +++++++ hw/display/vhost-user-gpu.c | 7 +++++++ hw/input/vhost-user-input.c | 7 +++++++ hw/net/virtio-net.c | 9 +++++++++ hw/scsi/vhost-scsi.c | 8 ++++++++ hw/virtio/vhost-user-fs.c | 7 +++++++ hw/virtio/vhost-user-rng.c | 7 +++++++ hw/virtio/vhost-vsock-common.c | 7 +++++++ hw/virtio/vhost.c | 4 +++- hw/virtio/virtio-crypto.c | 10 ++++++++++ hw/virtio/virtio.c | 1 + include/hw/virtio/virtio.h | 3 +++ 12 files changed, 76 insertions(+), 1 deletion(-) diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index e8cb170032..5dca4eab09 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -569,6 +569,12 @@ static void vhost_user_blk_instance_init(Object *obj) "/disk@0,0", DEVICE(obj)); } +static struct vhost_dev *vhost_user_blk_get_vhost(VirtIODevice *vdev) +{ + VHostUserBlk *s = VHOST_USER_BLK(vdev); + return &s->dev; +} + static const VMStateDescription vmstate_vhost_user_blk = { .name = "vhost-user-blk", .minimum_version_id = 1, @@ -603,6 +609,7 @@ static void vhost_user_blk_class_init(ObjectClass *klass, void *data) vdc->get_features = vhost_user_blk_get_features; vdc->set_status = vhost_user_blk_set_status; vdc->reset = vhost_user_blk_reset; + vdc->get_vhost = vhost_user_blk_get_vhost; } static const TypeInfo vhost_user_blk_info = { diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c index 09818231bd..96e56c4467 100644 --- a/hw/display/vhost-user-gpu.c +++ b/hw/display/vhost-user-gpu.c @@ -565,6 +565,12 @@ vhost_user_gpu_device_realize(DeviceState *qdev, Error **errp) g->vhost_gpu_fd = -1; } +static struct vhost_dev *vhost_user_gpu_get_vhost(VirtIODevice *vdev) +{ + VhostUserGPU *g = VHOST_USER_GPU(vdev); + return &g->vhost->dev; +} + static Property vhost_user_gpu_properties[] = { VIRTIO_GPU_BASE_PROPERTIES(VhostUserGPU, parent_obj.conf), DEFINE_PROP_END_OF_LIST(), @@ -586,6 +592,7 @@ vhost_user_gpu_class_init(ObjectClass *klass, void *data) vdc->guest_notifier_pending = vhost_user_gpu_guest_notifier_pending; vdc->get_config = vhost_user_gpu_get_config; vdc->set_config = vhost_user_gpu_set_config; + vdc->get_vhost = vhost_user_gpu_get_vhost; device_class_set_props(dc, vhost_user_gpu_properties); } diff --git a/hw/input/vhost-user-input.c b/hw/input/vhost-user-input.c index aeb0624fe5..1352e372ff 100644 --- a/hw/input/vhost-user-input.c +++ b/hw/input/vhost-user-input.c @@ -78,6 +78,12 @@ static void vhost_input_set_config(VirtIODevice *vdev, virtio_notify_config(vdev); } +static struct vhost_dev *vhost_input_get_vhost(VirtIODevice *vdev) +{ + VHostUserInput *vhi = VHOST_USER_INPUT(vdev); + return &vhi->vhost->dev; +} + static const VMStateDescription vmstate_vhost_input = { .name = "vhost-user-input", .unmigratable = 1, @@ -92,6 +98,7 @@ static void vhost_input_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_vhost_input; vdc->get_config = vhost_input_get_config; vdc->set_config = vhost_input_set_config; + vdc->get_vhost = vhost_input_get_vhost; vic->realize = vhost_input_realize; vic->change_active = vhost_input_change_active; } diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index bd0224caaf..a788f1c5c7 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -3620,6 +3620,14 @@ static bool dev_unplug_pending(void *opaque) return vdc->primary_unplug_pending(dev); } +static struct vhost_dev *virtio_net_get_vhost(VirtIODevice *vdev) +{ + VirtIONet *n = VIRTIO_NET(vdev); + NetClientState *nc = qemu_get_queue(n->nic); + struct vhost_net *net = get_vhost_net(nc->peer); + return &net->dev; +} + static const VMStateDescription vmstate_virtio_net = { .name = "virtio-net", .minimum_version_id = VIRTIO_NET_VM_VERSION, @@ -3722,6 +3730,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) vdc->post_load = virtio_net_post_load_virtio; vdc->vmsd = &vmstate_virtio_net_device; vdc->primary_unplug_pending = primary_unplug_pending; + vdc->get_vhost = virtio_net_get_vhost; } static const TypeInfo virtio_net_info = { diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 778f43e4c1..3059068175 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -273,6 +273,13 @@ static void vhost_scsi_unrealize(DeviceState *dev) virtio_scsi_common_unrealize(dev); } +static struct vhost_dev *vhost_scsi_get_vhost(VirtIODevice *vdev) +{ + VHostSCSI *s = VHOST_SCSI(vdev); + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); + return &vsc->dev; +} + static Property vhost_scsi_properties[] = { DEFINE_PROP_STRING("vhostfd", VirtIOSCSICommon, conf.vhostfd), DEFINE_PROP_STRING("wwpn", VirtIOSCSICommon, conf.wwpn), @@ -307,6 +314,7 @@ static void vhost_scsi_class_init(ObjectClass *klass, void *data) vdc->get_features = vhost_scsi_common_get_features; vdc->set_config = vhost_scsi_common_set_config; vdc->set_status = vhost_scsi_set_status; + vdc->get_vhost = vhost_scsi_get_vhost; fwc->get_dev_path = vhost_scsi_common_get_fw_dev_path; } diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c index b875640147..e513e4fdda 100644 --- a/hw/virtio/vhost-user-fs.c +++ b/hw/virtio/vhost-user-fs.c @@ -276,6 +276,12 @@ static void vuf_device_unrealize(DeviceState *dev) fs->vhost_dev.vqs = NULL; } +static struct vhost_dev *vuf_get_vhost(VirtIODevice *vdev) +{ + VHostUserFS *fs = VHOST_USER_FS(vdev); + return &fs->vhost_dev; +} + static const VMStateDescription vuf_vmstate = { .name = "vhost-user-fs", .unmigratable = 1, @@ -313,6 +319,7 @@ static void vuf_class_init(ObjectClass *klass, void *data) vdc->set_status = vuf_set_status; vdc->guest_notifier_mask = vuf_guest_notifier_mask; vdc->guest_notifier_pending = vuf_guest_notifier_pending; + vdc->get_vhost = vuf_get_vhost; } static const TypeInfo vuf_info = { diff --git a/hw/virtio/vhost-user-rng.c b/hw/virtio/vhost-user-rng.c index 08bccba9dc..3a7bf8e32d 100644 --- a/hw/virtio/vhost-user-rng.c +++ b/hw/virtio/vhost-user-rng.c @@ -247,6 +247,12 @@ static void vu_rng_device_unrealize(DeviceState *dev) vhost_user_cleanup(&rng->vhost_user); } +static struct vhost_dev *vu_rng_get_vhost(VirtIODevice *vdev) +{ + VHostUserRNG *rng = VHOST_USER_RNG(vdev); + return &rng->vhost_dev; +} + static const VMStateDescription vu_rng_vmstate = { .name = "vhost-user-rng", .unmigratable = 1, @@ -272,6 +278,7 @@ static void vu_rng_class_init(ObjectClass *klass, void *data) vdc->set_status = vu_rng_set_status; vdc->guest_notifier_mask = vu_rng_guest_notifier_mask; vdc->guest_notifier_pending = vu_rng_guest_notifier_pending; + vdc->get_vhost = vu_rng_get_vhost; } static const TypeInfo vu_rng_info = { diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c index ad5c8ff5d5..7394818e00 100644 --- a/hw/virtio/vhost-vsock-common.c +++ b/hw/virtio/vhost-vsock-common.c @@ -258,6 +258,12 @@ void vhost_vsock_common_unrealize(VirtIODevice *vdev) virtio_cleanup(vdev); } +static struct vhost_dev *vhost_vsock_common_get_vhost(VirtIODevice *vdev) +{ + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + return &vvc->vhost_dev; +} + static Property vhost_vsock_common_properties[] = { DEFINE_PROP_ON_OFF_AUTO("seqpacket", VHostVSockCommon, seqpacket, ON_OFF_AUTO_AUTO), @@ -273,6 +279,7 @@ static void vhost_vsock_common_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_MISC, dc->categories); vdc->guest_notifier_mask = vhost_vsock_common_guest_notifier_mask; vdc->guest_notifier_pending = vhost_vsock_common_guest_notifier_pending; + vdc->get_vhost = vhost_vsock_common_get_vhost; } static const TypeInfo vhost_vsock_common_info = { diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 2bc72c27c5..dd3263df56 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1738,6 +1738,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) /* should only be called after backend is connected */ assert(hdev->vhost_ops); + vdev->vhost_started = true; hdev->started = true; hdev->vdev = vdev; @@ -1810,7 +1811,7 @@ fail_vq: fail_mem: fail_features: - + vdev->vhost_started = false; hdev->started = false; return r; } @@ -1841,6 +1842,7 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) } vhost_log_put(hdev, true); hdev->started = false; + vdev->vhost_started = false; hdev->vdev = NULL; } diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index df9adb2c07..c3829e7498 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -961,6 +961,15 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx) return cryptodev_vhost_virtqueue_pending(vdev, queue, idx); } +static struct vhost_dev *virtio_crypto_get_vhost(VirtIODevice *vdev) +{ + VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); + CryptoDevBackend *b = vcrypto->cryptodev; + CryptoDevBackendClient *cc = b->conf.peers.ccs[0]; + CryptoDevBackendVhost *vhost_crypto = cryptodev_get_vhost(cc, b, 0); + return &vhost_crypto->dev; +} + static void virtio_crypto_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -977,6 +986,7 @@ static void virtio_crypto_class_init(ObjectClass *klass, void *data) vdc->set_status = virtio_crypto_set_status; vdc->guest_notifier_mask = virtio_crypto_guest_notifier_mask; vdc->guest_notifier_pending = virtio_crypto_guest_notifier_pending; + vdc->get_vhost = virtio_crypto_get_vhost; } static void virtio_crypto_instance_init(Object *obj) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 7f9fcfd06d..5d607aeaa0 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -3271,6 +3271,7 @@ void virtio_init(VirtIODevice *vdev, uint16_t device_id, size_t config_size) vdev->start_on_kick = false; vdev->started = false; + vdev->vhost_started = false; vdev->device_id = device_id; vdev->status = 0; qatomic_set(&vdev->isr, 0); diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index b6890ffa70..db1c0ddf6b 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -22,6 +22,7 @@ #include "standard-headers/linux/virtio_config.h" #include "standard-headers/linux/virtio_ring.h" #include "qom/object.h" +#include "hw/virtio/vhost.h" /* A guest should never accept this. It implies negotiation is broken. */ #define VIRTIO_F_BAD_FEATURE 30 @@ -102,6 +103,7 @@ struct VirtIODevice bool started; bool start_on_kick; /* when virtio 1.0 feature has not been negotiated */ bool disable_legacy_check; + bool vhost_started; VMChangeStateEntry *vmstate; char *bus_name; uint8_t device_endian; @@ -160,6 +162,7 @@ struct VirtioDeviceClass { int (*post_load)(VirtIODevice *vdev); const VMStateDescription *vmsd; bool (*primary_unplug_pending)(void *opaque); + struct vhost_dev *(*get_vhost)(VirtIODevice *vdev); }; void virtio_instance_init_common(Object *proxy_obj, void *data, From c98ce274dbd6373589ae01b652d88f93633db830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 26 Apr 2022 17:00:40 +0100 Subject: [PATCH 377/935] tests: fix encoding of IP addresses in x509 certs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to encode just the address bytes, not the whole struct sockaddr data. Add a test case to validate that we're matching on SAN IP addresses correctly. Signed-off-by: Daniel P. Berrangé Message-Id: <20220426160048.812266-2-berrange@redhat.com> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- tests/unit/crypto-tls-x509-helpers.c | 16 +++++++++++++--- tests/unit/test-crypto-tlssession.c | 11 +++++++++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/tests/unit/crypto-tls-x509-helpers.c b/tests/unit/crypto-tls-x509-helpers.c index fc609b3fd4..e9937f60d8 100644 --- a/tests/unit/crypto-tls-x509-helpers.c +++ b/tests/unit/crypto-tls-x509-helpers.c @@ -168,9 +168,19 @@ test_tls_get_ipaddr(const char *addrstr, hints.ai_flags = AI_NUMERICHOST; g_assert(getaddrinfo(addrstr, NULL, &hints, &res) == 0); - *datalen = res->ai_addrlen; - *data = g_new(char, *datalen); - memcpy(*data, res->ai_addr, *datalen); + if (res->ai_family == AF_INET) { + struct sockaddr_in *in = (struct sockaddr_in *)res->ai_addr; + *datalen = sizeof(in->sin_addr); + *data = g_new(char, *datalen); + memcpy(*data, &in->sin_addr, *datalen); + } else if (res->ai_family == AF_INET6) { + struct sockaddr_in6 *in = (struct sockaddr_in6 *)res->ai_addr; + *datalen = sizeof(in->sin6_addr); + *data = g_new(char, *datalen); + memcpy(*data, &in->sin6_addr, *datalen); + } else { + g_assert_not_reached(); + } freeaddrinfo(res); } diff --git a/tests/unit/test-crypto-tlssession.c b/tests/unit/test-crypto-tlssession.c index a266dc32da..f222959d36 100644 --- a/tests/unit/test-crypto-tlssession.c +++ b/tests/unit/test-crypto-tlssession.c @@ -512,12 +512,19 @@ int main(int argc, char **argv) false, true, "wiki.qemu.org", NULL); TEST_SESS_REG(altname4, cacertreq.filename, + servercertalt1req.filename, clientcertreq.filename, + false, false, "192.168.122.1", NULL); + TEST_SESS_REG(altname5, cacertreq.filename, + servercertalt1req.filename, clientcertreq.filename, + false, false, "fec0::dead:beaf", NULL); + + TEST_SESS_REG(altname6, cacertreq.filename, servercertalt2req.filename, clientcertreq.filename, false, true, "qemu.org", NULL); - TEST_SESS_REG(altname5, cacertreq.filename, + TEST_SESS_REG(altname7, cacertreq.filename, servercertalt2req.filename, clientcertreq.filename, false, false, "www.qemu.org", NULL); - TEST_SESS_REG(altname6, cacertreq.filename, + TEST_SESS_REG(altname8, cacertreq.filename, servercertalt2req.filename, clientcertreq.filename, false, false, "wiki.qemu.org", NULL); From 5bc6364bfb496623cc7f856bdb0358ffbe3c18d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 26 Apr 2022 17:00:41 +0100 Subject: [PATCH 378/935] tests: add more helper macros for creating TLS x509 certs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These macros are more suited to the general consumers of certs in the test suite, where we don't need to exercise every single possible permutation. Signed-off-by: Daniel P. Berrangé Message-Id: <20220426160048.812266-3-berrange@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Dr. David Alan Gilbert --- tests/unit/crypto-tls-x509-helpers.h | 53 ++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/tests/unit/crypto-tls-x509-helpers.h b/tests/unit/crypto-tls-x509-helpers.h index cf6329e653..247e7160eb 100644 --- a/tests/unit/crypto-tls-x509-helpers.h +++ b/tests/unit/crypto-tls-x509-helpers.h @@ -26,6 +26,9 @@ #include +#define QCRYPTO_TLS_TEST_CLIENT_NAME "ACME QEMU Client" +#define QCRYPTO_TLS_TEST_CLIENT_HOSTILE_NAME "ACME Hostile Client" + /* * This contains parameter about how to generate * certificates. @@ -118,6 +121,56 @@ void test_tls_cleanup(const char *keyfile); }; \ test_tls_generate_cert(&varname, NULL) +# define TLS_ROOT_REQ_SIMPLE(varname, fname) \ + QCryptoTLSTestCertReq varname = { \ + .filename = fname, \ + .cn = "qemu-CA", \ + .basicConstraintsEnable = true, \ + .basicConstraintsCritical = true, \ + .basicConstraintsIsCA = true, \ + .keyUsageEnable = true, \ + .keyUsageCritical = true, \ + .keyUsageValue = GNUTLS_KEY_KEY_CERT_SIGN, \ + }; \ + test_tls_generate_cert(&varname, NULL) + +# define TLS_CERT_REQ_SIMPLE_CLIENT(varname, cavarname, cname, fname) \ + QCryptoTLSTestCertReq varname = { \ + .filename = fname, \ + .cn = cname, \ + .basicConstraintsEnable = true, \ + .basicConstraintsCritical = true, \ + .basicConstraintsIsCA = false, \ + .keyUsageEnable = true, \ + .keyUsageCritical = true, \ + .keyUsageValue = \ + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, \ + .keyPurposeEnable = true, \ + .keyPurposeCritical = true, \ + .keyPurposeOID1 = GNUTLS_KP_TLS_WWW_CLIENT, \ + }; \ + test_tls_generate_cert(&varname, cavarname.crt) + +# define TLS_CERT_REQ_SIMPLE_SERVER(varname, cavarname, fname, \ + hostname, ipaddr) \ + QCryptoTLSTestCertReq varname = { \ + .filename = fname, \ + .cn = hostname ? hostname : ipaddr, \ + .altname1 = hostname, \ + .ipaddr1 = ipaddr, \ + .basicConstraintsEnable = true, \ + .basicConstraintsCritical = true, \ + .basicConstraintsIsCA = false, \ + .keyUsageEnable = true, \ + .keyUsageCritical = true, \ + .keyUsageValue = \ + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, \ + .keyPurposeEnable = true, \ + .keyPurposeCritical = true, \ + .keyPurposeOID1 = GNUTLS_KP_TLS_WWW_SERVER, \ + }; \ + test_tls_generate_cert(&varname, cavarname.crt) + extern const asn1_static_node pkix_asn1_tab[]; #endif From 58d25e97f38214c04d5ba55950cc6d9fff574236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 26 Apr 2022 17:00:42 +0100 Subject: [PATCH 379/935] tests: add migration tests of TLS with PSK credentials MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This validates that we correctly handle migration success and failure scenarios when using TLS with pre shared keys. Signed-off-by: Daniel P. Berrangé Message-Id: <20220426160048.812266-4-berrange@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Dr. David Alan Gilbert --- tests/qtest/meson.build | 7 +- tests/qtest/migration-test.c | 161 +++++++++++++++++++++++++++- tests/unit/crypto-tls-psk-helpers.c | 18 +++- tests/unit/crypto-tls-psk-helpers.h | 1 + 4 files changed, 179 insertions(+), 8 deletions(-) diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 3551b9c946..166450135d 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -273,13 +273,18 @@ endif tpmemu_files = ['tpm-emu.c', 'tpm-util.c', 'tpm-tests.c'] +migration_files = [files('migration-helpers.c')] +if gnutls.found() + migration_files += [files('../unit/crypto-tls-psk-helpers.c'), gnutls] +endif + qtests = { 'bios-tables-test': [io, 'boot-sector.c', 'acpi-utils.c', 'tpm-emu.c'], 'cdrom-test': files('boot-sector.c'), 'dbus-vmstate-test': files('migration-helpers.c') + dbus_vmstate1, 'erst-test': files('erst-test.c'), 'ivshmem-test': [rt, '../../contrib/ivshmem-server/ivshmem-server.c'], - 'migration-test': files('migration-helpers.c'), + 'migration-test': migration_files, 'pxe-test': files('boot-sector.c'), 'qos-test': [chardev, io, qos_test_ss.apply(config_host, strict: false).sources()], 'tpm-crb-swtpm-test': [io, tpmemu_files], diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index cba6023eb5..2eefc9c1ff 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -23,9 +23,13 @@ #include "qapi/qapi-visit-sockets.h" #include "qapi/qobject-input-visitor.h" #include "qapi/qobject-output-visitor.h" +#include "crypto/tlscredspsk.h" #include "migration-helpers.h" #include "tests/migration/migration-test.h" +#ifdef CONFIG_GNUTLS +# include "tests/unit/crypto-tls-psk-helpers.h" +#endif /* CONFIG_GNUTLS */ /* For dirty ring test; so far only x86_64 is supported */ #if defined(__linux__) && defined(HOST_X86_64) @@ -640,6 +644,100 @@ static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest) cleanup("dest_serial"); } +#ifdef CONFIG_GNUTLS +struct TestMigrateTLSPSKData { + char *workdir; + char *workdiralt; + char *pskfile; + char *pskfilealt; +}; + +static void * +test_migrate_tls_psk_start_common(QTestState *from, + QTestState *to, + bool mismatch) +{ + struct TestMigrateTLSPSKData *data = + g_new0(struct TestMigrateTLSPSKData, 1); + QDict *rsp; + + data->workdir = g_strdup_printf("%s/tlscredspsk0", tmpfs); + data->pskfile = g_strdup_printf("%s/%s", data->workdir, + QCRYPTO_TLS_CREDS_PSKFILE); + mkdir(data->workdir, 0700); + test_tls_psk_init(data->pskfile); + + if (mismatch) { + data->workdiralt = g_strdup_printf("%s/tlscredspskalt0", tmpfs); + data->pskfilealt = g_strdup_printf("%s/%s", data->workdiralt, + QCRYPTO_TLS_CREDS_PSKFILE); + mkdir(data->workdiralt, 0700); + test_tls_psk_init_alt(data->pskfilealt); + } + + rsp = wait_command(from, + "{ 'execute': 'object-add'," + " 'arguments': { 'qom-type': 'tls-creds-psk'," + " 'id': 'tlscredspsk0'," + " 'endpoint': 'client'," + " 'dir': %s," + " 'username': 'qemu'} }", + data->workdir); + qobject_unref(rsp); + + rsp = wait_command(to, + "{ 'execute': 'object-add'," + " 'arguments': { 'qom-type': 'tls-creds-psk'," + " 'id': 'tlscredspsk0'," + " 'endpoint': 'server'," + " 'dir': %s } }", + mismatch ? data->workdiralt : data->workdir); + qobject_unref(rsp); + + migrate_set_parameter_str(from, "tls-creds", "tlscredspsk0"); + migrate_set_parameter_str(to, "tls-creds", "tlscredspsk0"); + + return data; +} + +static void * +test_migrate_tls_psk_start_match(QTestState *from, + QTestState *to) +{ + return test_migrate_tls_psk_start_common(from, to, false); +} + +static void * +test_migrate_tls_psk_start_mismatch(QTestState *from, + QTestState *to) +{ + return test_migrate_tls_psk_start_common(from, to, true); +} + +static void +test_migrate_tls_psk_finish(QTestState *from, + QTestState *to, + void *opaque) +{ + struct TestMigrateTLSPSKData *data = opaque; + + test_tls_psk_cleanup(data->pskfile); + if (data->pskfilealt) { + test_tls_psk_cleanup(data->pskfilealt); + } + rmdir(data->workdir); + if (data->workdiralt) { + rmdir(data->workdiralt); + } + + g_free(data->workdiralt); + g_free(data->pskfilealt); + g_free(data->workdir); + g_free(data->pskfile); + g_free(data); +} +#endif /* CONFIG_GNUTLS */ + static int migrate_postcopy_prepare(QTestState **from_ptr, QTestState **to_ptr, MigrateStart *args) @@ -911,7 +1009,7 @@ static void test_precopy_common(MigrateCommon *args) test_migrate_end(from, to, args->result == MIG_TEST_SUCCEED); } -static void test_precopy_unix(void) +static void test_precopy_unix_plain(void) { g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); MigrateCommon args = { @@ -922,6 +1020,21 @@ static void test_precopy_unix(void) test_precopy_common(&args); } +#ifdef CONFIG_GNUTLS +static void test_precopy_unix_tls_psk(void) +{ + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + MigrateCommon args = { + .connect_uri = uri, + .listen_uri = uri, + .start_hook = test_migrate_tls_psk_start_match, + .finish_hook = test_migrate_tls_psk_finish, + }; + + test_precopy_common(&args); +} +#endif + static void test_precopy_unix_dirty_ring(void) { g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); @@ -1026,7 +1139,7 @@ static void test_xbzrle_unix(void) test_xbzrle(uri); } -static void test_precopy_tcp(void) +static void test_precopy_tcp_plain(void) { MigrateCommon args = { .listen_uri = "tcp:127.0.0.1:0", @@ -1035,6 +1148,34 @@ static void test_precopy_tcp(void) test_precopy_common(&args); } +#ifdef CONFIG_GNUTLS +static void test_precopy_tcp_tls_psk_match(void) +{ + MigrateCommon args = { + .listen_uri = "tcp:127.0.0.1:0", + .start_hook = test_migrate_tls_psk_start_match, + .finish_hook = test_migrate_tls_psk_finish, + }; + + test_precopy_common(&args); +} + +static void test_precopy_tcp_tls_psk_mismatch(void) +{ + MigrateCommon args = { + .start = { + .hide_stderr = true, + }, + .listen_uri = "tcp:127.0.0.1:0", + .start_hook = test_migrate_tls_psk_start_mismatch, + .finish_hook = test_migrate_tls_psk_finish, + .result = MIG_TEST_FAIL, + }; + + test_precopy_common(&args); +} +#endif /* CONFIG_GNUTLS */ + static void *test_migrate_fd_start_hook(QTestState *from, QTestState *to) { @@ -1497,8 +1638,20 @@ int main(int argc, char **argv) qtest_add_func("/migration/postcopy/unix", test_postcopy); qtest_add_func("/migration/postcopy/recovery", test_postcopy_recovery); qtest_add_func("/migration/bad_dest", test_baddest); - qtest_add_func("/migration/precopy/unix", test_precopy_unix); - qtest_add_func("/migration/precopy/tcp", test_precopy_tcp); + qtest_add_func("/migration/precopy/unix/plain", test_precopy_unix_plain); +#ifdef CONFIG_GNUTLS + qtest_add_func("/migration/precopy/unix/tls/psk", + test_precopy_unix_tls_psk); +#endif /* CONFIG_GNUTLS */ + + qtest_add_func("/migration/precopy/tcp/plain", test_precopy_tcp_plain); +#ifdef CONFIG_GNUTLS + qtest_add_func("/migration/precopy/tcp/tls/psk/match", + test_precopy_tcp_tls_psk_match); + qtest_add_func("/migration/precopy/tcp/tls/psk/mismatch", + test_precopy_tcp_tls_psk_mismatch); +#endif /* CONFIG_GNUTLS */ + /* qtest_add_func("/migration/ignore_shared", test_ignore_shared); */ qtest_add_func("/migration/xbzrle/unix", test_xbzrle_unix); qtest_add_func("/migration/fd_proto", test_migrate_fd_proto); diff --git a/tests/unit/crypto-tls-psk-helpers.c b/tests/unit/crypto-tls-psk-helpers.c index 4bea7c6fa2..511e08cc9c 100644 --- a/tests/unit/crypto-tls-psk-helpers.c +++ b/tests/unit/crypto-tls-psk-helpers.c @@ -24,7 +24,8 @@ #include "crypto-tls-psk-helpers.h" #include "qemu/sockets.h" -void test_tls_psk_init(const char *pskfile) +static void +test_tls_psk_init_common(const char *pskfile, const char *user, const char *key) { FILE *fp; @@ -33,11 +34,22 @@ void test_tls_psk_init(const char *pskfile) g_critical("Failed to create pskfile %s: %s", pskfile, strerror(errno)); abort(); } - /* Don't do this in real applications! Use psktool. */ - fprintf(fp, "qemu:009d5638c40fde0c\n"); + fprintf(fp, "%s:%s\n", user, key); fclose(fp); } +void test_tls_psk_init(const char *pskfile) +{ + /* Don't hard code a key like this in real applications! Use psktool. */ + test_tls_psk_init_common(pskfile, "qemu", "009d5638c40fde0c"); +} + +void test_tls_psk_init_alt(const char *pskfile) +{ + /* Don't hard code a key like this in real applications! Use psktool. */ + test_tls_psk_init_common(pskfile, "qemu", "10ffa6a2c42f0388"); +} + void test_tls_psk_cleanup(const char *pskfile) { unlink(pskfile); diff --git a/tests/unit/crypto-tls-psk-helpers.h b/tests/unit/crypto-tls-psk-helpers.h index faa645c629..67f8bdda71 100644 --- a/tests/unit/crypto-tls-psk-helpers.h +++ b/tests/unit/crypto-tls-psk-helpers.h @@ -24,6 +24,7 @@ #include void test_tls_psk_init(const char *keyfile); +void test_tls_psk_init_alt(const char *keyfile); void test_tls_psk_cleanup(const char *keyfile); #endif From d47b83b118eed26e10ff4693fb1f0a433a38d0a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 26 Apr 2022 17:00:43 +0100 Subject: [PATCH 380/935] tests: add migration tests of TLS with x509 credentials MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This validates that we correctly handle migration success and failure scenarios when using TLS with x509 certificates. There are quite a few different scenarios that matter in relation to hostname validation. Signed-off-by: Daniel P. Berrangé Message-Id: <20220426160048.812266-5-berrange@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Dr. David Alan Gilbert dgilbert: Manual merge due to ifdef change in 3 --- meson.build | 1 + tests/qtest/meson.build | 5 + tests/qtest/migration-test.c | 405 +++++++++++++++++++++++++++++++++-- 3 files changed, 397 insertions(+), 14 deletions(-) diff --git a/meson.build b/meson.build index 9b20dcd143..93aa31a9e4 100644 --- a/meson.build +++ b/meson.build @@ -1742,6 +1742,7 @@ config_host_data.set('CONFIG_KEYUTILS', keyutils.found()) config_host_data.set('CONFIG_GETTID', has_gettid) config_host_data.set('CONFIG_GNUTLS', gnutls.found()) config_host_data.set('CONFIG_GNUTLS_CRYPTO', gnutls_crypto.found()) +config_host_data.set('CONFIG_TASN1', tasn1.found()) config_host_data.set('CONFIG_GCRYPT', gcrypt.found()) config_host_data.set('CONFIG_NETTLE', nettle.found()) config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private') diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 166450135d..b425484920 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -276,6 +276,11 @@ tpmemu_files = ['tpm-emu.c', 'tpm-util.c', 'tpm-tests.c'] migration_files = [files('migration-helpers.c')] if gnutls.found() migration_files += [files('../unit/crypto-tls-psk-helpers.c'), gnutls] + + if tasn1.found() + migration_files += [files('../unit/crypto-tls-x509-helpers.c', + '../unit/pkix_asn1_tab.c'), tasn1] + endif endif qtests = { diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 2eefc9c1ff..5a3edf2da6 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -29,6 +29,9 @@ #include "tests/migration/migration-test.h" #ifdef CONFIG_GNUTLS # include "tests/unit/crypto-tls-psk-helpers.h" +# ifdef CONFIG_TASN1 +# include "tests/unit/crypto-tls-x509-helpers.h" +# endif /* CONFIG_TASN1 */ #endif /* CONFIG_GNUTLS */ /* For dirty ring test; so far only x86_64 is supported */ @@ -736,6 +739,234 @@ test_migrate_tls_psk_finish(QTestState *from, g_free(data->pskfile); g_free(data); } + +#ifdef CONFIG_TASN1 +typedef struct { + char *workdir; + char *keyfile; + char *cacert; + char *servercert; + char *serverkey; + char *clientcert; + char *clientkey; +} TestMigrateTLSX509Data; + +typedef struct { + bool verifyclient; + bool clientcert; + bool hostileclient; + bool authzclient; + const char *certhostname; + const char *certipaddr; +} TestMigrateTLSX509; + +static void * +test_migrate_tls_x509_start_common(QTestState *from, + QTestState *to, + TestMigrateTLSX509 *args) +{ + TestMigrateTLSX509Data *data = g_new0(TestMigrateTLSX509Data, 1); + QDict *rsp; + + data->workdir = g_strdup_printf("%s/tlscredsx5090", tmpfs); + data->keyfile = g_strdup_printf("%s/key.pem", data->workdir); + + data->cacert = g_strdup_printf("%s/ca-cert.pem", data->workdir); + data->serverkey = g_strdup_printf("%s/server-key.pem", data->workdir); + data->servercert = g_strdup_printf("%s/server-cert.pem", data->workdir); + if (args->clientcert) { + data->clientkey = g_strdup_printf("%s/client-key.pem", data->workdir); + data->clientcert = g_strdup_printf("%s/client-cert.pem", data->workdir); + } + + mkdir(data->workdir, 0700); + + test_tls_init(data->keyfile); + g_assert(link(data->keyfile, data->serverkey) == 0); + if (args->clientcert) { + g_assert(link(data->keyfile, data->clientkey) == 0); + } + + TLS_ROOT_REQ_SIMPLE(cacertreq, data->cacert); + if (args->clientcert) { + TLS_CERT_REQ_SIMPLE_CLIENT(servercertreq, cacertreq, + args->hostileclient ? + QCRYPTO_TLS_TEST_CLIENT_HOSTILE_NAME : + QCRYPTO_TLS_TEST_CLIENT_NAME, + data->clientcert); + } + + TLS_CERT_REQ_SIMPLE_SERVER(clientcertreq, cacertreq, + data->servercert, + args->certhostname, + args->certipaddr); + + rsp = wait_command(from, + "{ 'execute': 'object-add'," + " 'arguments': { 'qom-type': 'tls-creds-x509'," + " 'id': 'tlscredsx509client0'," + " 'endpoint': 'client'," + " 'dir': %s," + " 'sanity-check': true," + " 'verify-peer': true} }", + data->workdir); + qobject_unref(rsp); + migrate_set_parameter_str(from, "tls-creds", "tlscredsx509client0"); + if (args->certhostname) { + migrate_set_parameter_str(from, "tls-hostname", args->certhostname); + } + + rsp = wait_command(to, + "{ 'execute': 'object-add'," + " 'arguments': { 'qom-type': 'tls-creds-x509'," + " 'id': 'tlscredsx509server0'," + " 'endpoint': 'server'," + " 'dir': %s," + " 'sanity-check': true," + " 'verify-peer': %i} }", + data->workdir, args->verifyclient); + qobject_unref(rsp); + migrate_set_parameter_str(to, "tls-creds", "tlscredsx509server0"); + + if (args->authzclient) { + rsp = wait_command(to, + "{ 'execute': 'object-add'," + " 'arguments': { 'qom-type': 'authz-simple'," + " 'id': 'tlsauthz0'," + " 'identity': %s} }", + "CN=" QCRYPTO_TLS_TEST_CLIENT_NAME); + migrate_set_parameter_str(to, "tls-authz", "tlsauthz0"); + } + + return data; +} + +/* + * The normal case: match server's cert hostname against + * whatever host we were telling QEMU to connect to (if any) + */ +static void * +test_migrate_tls_x509_start_default_host(QTestState *from, + QTestState *to) +{ + TestMigrateTLSX509 args = { + .verifyclient = true, + .clientcert = true, + .certipaddr = "127.0.0.1" + }; + return test_migrate_tls_x509_start_common(from, to, &args); +} + +/* + * The unusual case: the server's cert is different from + * the address we're telling QEMU to connect to (if any), + * so we must give QEMU an explicit hostname to validate + */ +static void * +test_migrate_tls_x509_start_override_host(QTestState *from, + QTestState *to) +{ + TestMigrateTLSX509 args = { + .verifyclient = true, + .clientcert = true, + .certhostname = "qemu.org", + }; + return test_migrate_tls_x509_start_common(from, to, &args); +} + +/* + * The unusual case: the server's cert is different from + * the address we're telling QEMU to connect to, and so we + * expect the client to reject the server + */ +static void * +test_migrate_tls_x509_start_mismatch_host(QTestState *from, + QTestState *to) +{ + TestMigrateTLSX509 args = { + .verifyclient = true, + .clientcert = true, + .certipaddr = "10.0.0.1", + }; + return test_migrate_tls_x509_start_common(from, to, &args); +} + +static void * +test_migrate_tls_x509_start_friendly_client(QTestState *from, + QTestState *to) +{ + TestMigrateTLSX509 args = { + .verifyclient = true, + .clientcert = true, + .authzclient = true, + .certipaddr = "127.0.0.1", + }; + return test_migrate_tls_x509_start_common(from, to, &args); +} + +static void * +test_migrate_tls_x509_start_hostile_client(QTestState *from, + QTestState *to) +{ + TestMigrateTLSX509 args = { + .verifyclient = true, + .clientcert = true, + .hostileclient = true, + .authzclient = true, + .certipaddr = "127.0.0.1", + }; + return test_migrate_tls_x509_start_common(from, to, &args); +} + +/* + * The case with no client certificate presented, + * and no server verification + */ +static void * +test_migrate_tls_x509_start_allow_anon_client(QTestState *from, + QTestState *to) +{ + TestMigrateTLSX509 args = { + .certipaddr = "127.0.0.1", + }; + return test_migrate_tls_x509_start_common(from, to, &args); +} + +/* + * The case with no client certificate presented, + * and server verification rejecting + */ +static void * +test_migrate_tls_x509_start_reject_anon_client(QTestState *from, + QTestState *to) +{ + TestMigrateTLSX509 args = { + .verifyclient = true, + .certipaddr = "127.0.0.1", + }; + return test_migrate_tls_x509_start_common(from, to, &args); +} + +static void +test_migrate_tls_x509_finish(QTestState *from, + QTestState *to, + void *opaque) +{ + TestMigrateTLSX509Data *data = opaque; + + test_tls_cleanup(data->keyfile); + unlink(data->cacert); + unlink(data->servercert); + unlink(data->serverkey); + unlink(data->clientcert); + unlink(data->clientkey); + rmdir(data->workdir); + + g_free(data->workdir); + g_free(data->keyfile); + g_free(data); +} +#endif /* CONFIG_TASN1 */ #endif /* CONFIG_GNUTLS */ static int migrate_postcopy_prepare(QTestState **from_ptr, @@ -1020,20 +1251,6 @@ static void test_precopy_unix_plain(void) test_precopy_common(&args); } -#ifdef CONFIG_GNUTLS -static void test_precopy_unix_tls_psk(void) -{ - g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); - MigrateCommon args = { - .connect_uri = uri, - .listen_uri = uri, - .start_hook = test_migrate_tls_psk_start_match, - .finish_hook = test_migrate_tls_psk_finish, - }; - - test_precopy_common(&args); -} -#endif static void test_precopy_unix_dirty_ring(void) { @@ -1049,6 +1266,53 @@ static void test_precopy_unix_dirty_ring(void) test_precopy_common(&args); } +#ifdef CONFIG_GNUTLS +static void test_precopy_unix_tls_psk(void) +{ + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + MigrateCommon args = { + .connect_uri = uri, + .listen_uri = uri, + .start_hook = test_migrate_tls_psk_start_match, + .finish_hook = test_migrate_tls_psk_finish, + }; + + test_precopy_common(&args); +} + +#ifdef CONFIG_TASN1 +static void test_precopy_unix_tls_x509_default_host(void) +{ + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + MigrateCommon args = { + .start = { + .hide_stderr = true, + }, + .connect_uri = uri, + .listen_uri = uri, + .start_hook = test_migrate_tls_x509_start_default_host, + .finish_hook = test_migrate_tls_x509_finish, + .result = MIG_TEST_FAIL_DEST_QUIT_ERR, + }; + + test_precopy_common(&args); +} + +static void test_precopy_unix_tls_x509_override_host(void) +{ + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + MigrateCommon args = { + .connect_uri = uri, + .listen_uri = uri, + .start_hook = test_migrate_tls_x509_start_override_host, + .finish_hook = test_migrate_tls_x509_finish, + }; + + test_precopy_common(&args); +} +#endif /* CONFIG_TASN1 */ +#endif /* CONFIG_GNUTLS */ + #if 0 /* Currently upset on aarch64 TCG */ static void test_ignore_shared(void) @@ -1174,6 +1438,97 @@ static void test_precopy_tcp_tls_psk_mismatch(void) test_precopy_common(&args); } + +#ifdef CONFIG_TASN1 +static void test_precopy_tcp_tls_x509_default_host(void) +{ + MigrateCommon args = { + .listen_uri = "tcp:127.0.0.1:0", + .start_hook = test_migrate_tls_x509_start_default_host, + .finish_hook = test_migrate_tls_x509_finish, + }; + + test_precopy_common(&args); +} + +static void test_precopy_tcp_tls_x509_override_host(void) +{ + MigrateCommon args = { + .listen_uri = "tcp:127.0.0.1:0", + .start_hook = test_migrate_tls_x509_start_override_host, + .finish_hook = test_migrate_tls_x509_finish, + }; + + test_precopy_common(&args); +} + +static void test_precopy_tcp_tls_x509_mismatch_host(void) +{ + MigrateCommon args = { + .start = { + .hide_stderr = true, + }, + .listen_uri = "tcp:127.0.0.1:0", + .start_hook = test_migrate_tls_x509_start_mismatch_host, + .finish_hook = test_migrate_tls_x509_finish, + .result = MIG_TEST_FAIL_DEST_QUIT_ERR, + }; + + test_precopy_common(&args); +} + +static void test_precopy_tcp_tls_x509_friendly_client(void) +{ + MigrateCommon args = { + .listen_uri = "tcp:127.0.0.1:0", + .start_hook = test_migrate_tls_x509_start_friendly_client, + .finish_hook = test_migrate_tls_x509_finish, + }; + + test_precopy_common(&args); +} + +static void test_precopy_tcp_tls_x509_hostile_client(void) +{ + MigrateCommon args = { + .start = { + .hide_stderr = true, + }, + .listen_uri = "tcp:127.0.0.1:0", + .start_hook = test_migrate_tls_x509_start_hostile_client, + .finish_hook = test_migrate_tls_x509_finish, + .result = MIG_TEST_FAIL, + }; + + test_precopy_common(&args); +} + +static void test_precopy_tcp_tls_x509_allow_anon_client(void) +{ + MigrateCommon args = { + .listen_uri = "tcp:127.0.0.1:0", + .start_hook = test_migrate_tls_x509_start_allow_anon_client, + .finish_hook = test_migrate_tls_x509_finish, + }; + + test_precopy_common(&args); +} + +static void test_precopy_tcp_tls_x509_reject_anon_client(void) +{ + MigrateCommon args = { + .start = { + .hide_stderr = true, + }, + .listen_uri = "tcp:127.0.0.1:0", + .start_hook = test_migrate_tls_x509_start_reject_anon_client, + .finish_hook = test_migrate_tls_x509_finish, + .result = MIG_TEST_FAIL, + }; + + test_precopy_common(&args); +} +#endif /* CONFIG_TASN1 */ #endif /* CONFIG_GNUTLS */ static void *test_migrate_fd_start_hook(QTestState *from, @@ -1642,6 +1997,12 @@ int main(int argc, char **argv) #ifdef CONFIG_GNUTLS qtest_add_func("/migration/precopy/unix/tls/psk", test_precopy_unix_tls_psk); +#ifdef CONFIG_TASN1 + qtest_add_func("/migration/precopy/unix/tls/x509/default-host", + test_precopy_unix_tls_x509_default_host); + qtest_add_func("/migration/precopy/unix/tls/x509/override-host", + test_precopy_unix_tls_x509_override_host); +#endif /* CONFIG_TASN1 */ #endif /* CONFIG_GNUTLS */ qtest_add_func("/migration/precopy/tcp/plain", test_precopy_tcp_plain); @@ -1650,6 +2011,22 @@ int main(int argc, char **argv) test_precopy_tcp_tls_psk_match); qtest_add_func("/migration/precopy/tcp/tls/psk/mismatch", test_precopy_tcp_tls_psk_mismatch); +#ifdef CONFIG_TASN1 + qtest_add_func("/migration/precopy/tcp/tls/x509/default-host", + test_precopy_tcp_tls_x509_default_host); + qtest_add_func("/migration/precopy/tcp/tls/x509/override-host", + test_precopy_tcp_tls_x509_override_host); + qtest_add_func("/migration/precopy/tcp/tls/x509/mismatch-host", + test_precopy_tcp_tls_x509_mismatch_host); + qtest_add_func("/migration/precopy/tcp/tls/x509/friendly-client", + test_precopy_tcp_tls_x509_friendly_client); + qtest_add_func("/migration/precopy/tcp/tls/x509/hostile-client", + test_precopy_tcp_tls_x509_hostile_client); + qtest_add_func("/migration/precopy/tcp/tls/x509/allow-anon-client", + test_precopy_tcp_tls_x509_allow_anon_client); + qtest_add_func("/migration/precopy/tcp/tls/x509/reject-anon-client", + test_precopy_tcp_tls_x509_reject_anon_client); +#endif /* CONFIG_TASN1 */ #endif /* CONFIG_GNUTLS */ /* qtest_add_func("/migration/ignore_shared", test_ignore_shared); */ From 83bcba1ec1f706eb3ec0d6fdeee2bc32f95d9b1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 26 Apr 2022 17:00:44 +0100 Subject: [PATCH 381/935] tests: convert XBZRLE migration test to use common helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most of the XBZRLE migration test logic is common with the rest of the precopy tests, so it can use the helper with just one small tweak. Reviewed-by: Peter Xu Signed-off-by: Daniel P. Berrangé Message-Id: <20220426160048.812266-6-berrange@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- tests/qtest/migration-test.c | 67 ++++++++++++++---------------------- 1 file changed, 25 insertions(+), 42 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 5a3edf2da6..a1dc08a93e 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -1174,6 +1174,9 @@ typedef struct { /* This test should fail, dest qemu should fail with abnormal status */ MIG_TEST_FAIL_DEST_QUIT_ERR, } result; + + /* Optional: set number of migration passes to wait for */ + unsigned int iterations; } MigrateCommon; static void test_precopy_common(MigrateCommon *args) @@ -1219,7 +1222,13 @@ static void test_precopy_common(MigrateCommon *args) qtest_set_expected_status(to, 1); } } else { - wait_for_migration_pass(from); + if (args->iterations) { + while (args->iterations--) { + wait_for_migration_pass(from); + } + } else { + wait_for_migration_pass(from); + } migrate_set_parameter_int(from, "downtime-limit", CONVERGE_DOWNTIME); @@ -1350,57 +1359,31 @@ static void test_ignore_shared(void) } #endif -static void test_xbzrle(const char *uri) +static void * +test_migrate_xbzrle_start(QTestState *from, + QTestState *to) { - MigrateStart args = {}; - QTestState *from, *to; - - if (test_migrate_start(&from, &to, uri, &args)) { - return; - } - - /* - * We want to pick a speed slow enough that the test completes - * quickly, but that it doesn't complete precopy even on a slow - * machine, so also set the downtime. - */ - /* 1 ms should make it not converge*/ - migrate_set_parameter_int(from, "downtime-limit", 1); - /* 1GB/s */ - migrate_set_parameter_int(from, "max-bandwidth", 1000000000); - migrate_set_parameter_int(from, "xbzrle-cache-size", 33554432); migrate_set_capability(from, "xbzrle", true); migrate_set_capability(to, "xbzrle", true); - /* Wait for the first serial output from the source */ - wait_for_serial("src_serial"); - migrate_qmp(from, uri, "{}"); - - wait_for_migration_pass(from); - /* Make sure we have 2 passes, so the xbzrle cache gets a workout */ - wait_for_migration_pass(from); - - /* 1000ms should converge */ - migrate_set_parameter_int(from, "downtime-limit", 1000); - - if (!got_stop) { - qtest_qmp_eventwait(from, "STOP"); - } - qtest_qmp_eventwait(to, "RESUME"); - - wait_for_serial("dest_serial"); - wait_for_migration_complete(from); - - test_migrate_end(from, to, true); + return NULL; } -static void test_xbzrle_unix(void) +static void test_precopy_unix_xbzrle(void) { g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + MigrateCommon args = { + .connect_uri = uri, + .listen_uri = uri, - test_xbzrle(uri); + .start_hook = test_migrate_xbzrle_start, + + .iterations = 2, + }; + + test_precopy_common(&args); } static void test_precopy_tcp_plain(void) @@ -1994,6 +1977,7 @@ int main(int argc, char **argv) qtest_add_func("/migration/postcopy/recovery", test_postcopy_recovery); qtest_add_func("/migration/bad_dest", test_baddest); qtest_add_func("/migration/precopy/unix/plain", test_precopy_unix_plain); + qtest_add_func("/migration/precopy/unix/xbzrle", test_precopy_unix_xbzrle); #ifdef CONFIG_GNUTLS qtest_add_func("/migration/precopy/unix/tls/psk", test_precopy_unix_tls_psk); @@ -2030,7 +2014,6 @@ int main(int argc, char **argv) #endif /* CONFIG_GNUTLS */ /* qtest_add_func("/migration/ignore_shared", test_ignore_shared); */ - qtest_add_func("/migration/xbzrle/unix", test_xbzrle_unix); qtest_add_func("/migration/fd_proto", test_migrate_fd_proto); qtest_add_func("/migration/validate_uuid", test_validate_uuid); qtest_add_func("/migration/validate_uuid_error", test_validate_uuid_error); From 490facffcf21647e7088f4f0c2c5a8f5f45625e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 26 Apr 2022 17:00:45 +0100 Subject: [PATCH 382/935] tests: convert multifd migration tests to use common helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most of the multifd migration test logic is common with the rest of the precopy tests, so it can use the helper without difficulty. The only exception of the multifd cancellation test which tries to run multiple migrations in a row. Reviewed-by: Peter Xu Signed-off-by: Daniel P. Berrangé Message-Id: <20220426160048.812266-7-berrange@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- tests/qtest/migration-test.c | 83 +++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index a1dc08a93e..f551c8d030 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -1740,26 +1740,12 @@ static void test_migrate_auto_converge(void) test_migrate_end(from, to, true); } -static void test_multifd_tcp(const char *method) +static void * +test_migrate_precopy_tcp_multifd_start_common(QTestState *from, + QTestState *to, + const char *method) { - MigrateStart args = {}; - QTestState *from, *to; QDict *rsp; - g_autofree char *uri = NULL; - - if (test_migrate_start(&from, &to, "defer", &args)) { - return; - } - - /* - * We want to pick a speed slow enough that the test completes - * quickly, but that it doesn't complete precopy even on a slow - * machine, so also set the downtime. - */ - /* 1 ms should make it not converge*/ - migrate_set_parameter_int(from, "downtime-limit", 1); - /* 1GB/s */ - migrate_set_parameter_int(from, "max-bandwidth", 1000000000); migrate_set_parameter_int(from, "multifd-channels", 16); migrate_set_parameter_int(to, "multifd-channels", 16); @@ -1775,41 +1761,58 @@ static void test_multifd_tcp(const char *method) " 'arguments': { 'uri': 'tcp:127.0.0.1:0' }}"); qobject_unref(rsp); - /* Wait for the first serial output from the source */ - wait_for_serial("src_serial"); - - uri = migrate_get_socket_address(to, "socket-address"); - - migrate_qmp(from, uri, "{}"); - - wait_for_migration_pass(from); - - migrate_set_parameter_int(from, "downtime-limit", CONVERGE_DOWNTIME); - - if (!got_stop) { - qtest_qmp_eventwait(from, "STOP"); - } - qtest_qmp_eventwait(to, "RESUME"); - - wait_for_serial("dest_serial"); - wait_for_migration_complete(from); - test_migrate_end(from, to, true); + return NULL; } +static void * +test_migrate_precopy_tcp_multifd_start(QTestState *from, + QTestState *to) +{ + return test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); +} + +static void * +test_migrate_precopy_tcp_multifd_zlib_start(QTestState *from, + QTestState *to) +{ + return test_migrate_precopy_tcp_multifd_start_common(from, to, "zlib"); +} + +#ifdef CONFIG_ZSTD +static void * +test_migrate_precopy_tcp_multifd_zstd_start(QTestState *from, + QTestState *to) +{ + return test_migrate_precopy_tcp_multifd_start_common(from, to, "zstd"); +} +#endif /* CONFIG_ZSTD */ + static void test_multifd_tcp_none(void) { - test_multifd_tcp("none"); + MigrateCommon args = { + .listen_uri = "defer", + .start_hook = test_migrate_precopy_tcp_multifd_start, + }; + test_precopy_common(&args); } static void test_multifd_tcp_zlib(void) { - test_multifd_tcp("zlib"); + MigrateCommon args = { + .listen_uri = "defer", + .start_hook = test_migrate_precopy_tcp_multifd_zlib_start, + }; + test_precopy_common(&args); } #ifdef CONFIG_ZSTD static void test_multifd_tcp_zstd(void) { - test_multifd_tcp("zstd"); + MigrateCommon args = { + .listen_uri = "defer", + .start_hook = test_migrate_precopy_tcp_multifd_zstd_start, + }; + test_precopy_common(&args); } #endif From 4d6d2e872a9f5aef4b08eb285a1fd7221312d562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 26 Apr 2022 17:00:46 +0100 Subject: [PATCH 383/935] tests: add multifd migration tests of TLS with PSK credentials MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This validates that we correctly handle multifd migration success and failure scenarios when using TLS with pre shared keys. Signed-off-by: Daniel P. Berrangé Message-Id: <20220426160048.812266-8-berrange@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Dr. David Alan Gilbert --- tests/qtest/migration-test.c | 60 +++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index f551c8d030..133665b500 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -1816,6 +1816,48 @@ static void test_multifd_tcp_zstd(void) } #endif +#ifdef CONFIG_GNUTLS +static void * +test_migrate_multifd_tcp_tls_psk_start_match(QTestState *from, + QTestState *to) +{ + test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); + return test_migrate_tls_psk_start_match(from, to); +} + +static void * +test_migrate_multifd_tcp_tls_psk_start_mismatch(QTestState *from, + QTestState *to) +{ + test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); + return test_migrate_tls_psk_start_mismatch(from, to); +} + +static void test_multifd_tcp_tls_psk_match(void) +{ + MigrateCommon args = { + .listen_uri = "defer", + .start_hook = test_migrate_multifd_tcp_tls_psk_start_match, + .finish_hook = test_migrate_tls_psk_finish, + }; + test_precopy_common(&args); +} + +static void test_multifd_tcp_tls_psk_mismatch(void) +{ + MigrateCommon args = { + .start = { + .hide_stderr = true, + }, + .listen_uri = "defer", + .start_hook = test_migrate_multifd_tcp_tls_psk_start_mismatch, + .finish_hook = test_migrate_tls_psk_finish, + .result = MIG_TEST_FAIL, + }; + test_precopy_common(&args); +} +#endif /* CONFIG_GNUTLS */ + /* * This test does: * source target @@ -2026,12 +2068,22 @@ int main(int argc, char **argv) test_validate_uuid_dst_not_set); qtest_add_func("/migration/auto_converge", test_migrate_auto_converge); - qtest_add_func("/migration/multifd/tcp/none", test_multifd_tcp_none); - qtest_add_func("/migration/multifd/tcp/cancel", test_multifd_tcp_cancel); - qtest_add_func("/migration/multifd/tcp/zlib", test_multifd_tcp_zlib); + qtest_add_func("/migration/multifd/tcp/plain/none", + test_multifd_tcp_none); + qtest_add_func("/migration/multifd/tcp/plain/cancel", + test_multifd_tcp_cancel); + qtest_add_func("/migration/multifd/tcp/plain/zlib", + test_multifd_tcp_zlib); #ifdef CONFIG_ZSTD - qtest_add_func("/migration/multifd/tcp/zstd", test_multifd_tcp_zstd); + qtest_add_func("/migration/multifd/tcp/plain/zstd", + test_multifd_tcp_zstd); #endif +#ifdef CONFIG_GNUTLS + qtest_add_func("/migration/multifd/tcp/tls/psk/match", + test_multifd_tcp_tls_psk_match); + qtest_add_func("/migration/multifd/tcp/tls/psk/mismatch", + test_multifd_tcp_tls_psk_mismatch); +#endif /* CONFIG_GNUTLS */ if (kvm_dirty_ring_supported()) { qtest_add_func("/migration/dirty_ring", From ff32f1dd3281d77b86d195dd62c6ec66a881b6fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 26 Apr 2022 17:00:47 +0100 Subject: [PATCH 384/935] tests: add multifd migration tests of TLS with x509 credentials MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This validates that we correctly handle multifd migration success and failure scenarios when using TLS with x509 certificates. There are quite a few different scenarios that matter in relation to hostname validation, but we skip a couple as we can assume that the non-multifd coverage applies to some extent. Signed-off-by: Daniel P. Berrangé Message-Id: <20220426160048.812266-9-berrange@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Dr. David Alan Gilbert --- tests/qtest/migration-test.c | 127 +++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 133665b500..efc6ec1614 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -1833,6 +1833,48 @@ test_migrate_multifd_tcp_tls_psk_start_mismatch(QTestState *from, return test_migrate_tls_psk_start_mismatch(from, to); } +#ifdef CONFIG_TASN1 +static void * +test_migrate_multifd_tls_x509_start_default_host(QTestState *from, + QTestState *to) +{ + test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); + return test_migrate_tls_x509_start_default_host(from, to); +} + +static void * +test_migrate_multifd_tls_x509_start_override_host(QTestState *from, + QTestState *to) +{ + test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); + return test_migrate_tls_x509_start_override_host(from, to); +} + +static void * +test_migrate_multifd_tls_x509_start_mismatch_host(QTestState *from, + QTestState *to) +{ + test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); + return test_migrate_tls_x509_start_mismatch_host(from, to); +} + +static void * +test_migrate_multifd_tls_x509_start_allow_anon_client(QTestState *from, + QTestState *to) +{ + test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); + return test_migrate_tls_x509_start_allow_anon_client(from, to); +} + +static void * +test_migrate_multifd_tls_x509_start_reject_anon_client(QTestState *from, + QTestState *to) +{ + test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); + return test_migrate_tls_x509_start_reject_anon_client(from, to); +} +#endif /* CONFIG_TASN1 */ + static void test_multifd_tcp_tls_psk_match(void) { MigrateCommon args = { @@ -1856,6 +1898,79 @@ static void test_multifd_tcp_tls_psk_mismatch(void) }; test_precopy_common(&args); } + +#ifdef CONFIG_TASN1 +static void test_multifd_tcp_tls_x509_default_host(void) +{ + MigrateCommon args = { + .listen_uri = "defer", + .start_hook = test_migrate_multifd_tls_x509_start_default_host, + .finish_hook = test_migrate_tls_x509_finish, + }; + test_precopy_common(&args); +} + +static void test_multifd_tcp_tls_x509_override_host(void) +{ + MigrateCommon args = { + .listen_uri = "defer", + .start_hook = test_migrate_multifd_tls_x509_start_override_host, + .finish_hook = test_migrate_tls_x509_finish, + }; + test_precopy_common(&args); +} + +static void test_multifd_tcp_tls_x509_mismatch_host(void) +{ + /* + * This has different behaviour to the non-multifd case. + * + * In non-multifd case when client aborts due to mismatched + * cert host, the server has already started trying to load + * migration state, and so it exits with I/O failure. + * + * In multifd case when client aborts due to mismatched + * cert host, the server is still waiting for the other + * multifd connections to arrive so hasn't started trying + * to load migration state, and thus just aborts the migration + * without exiting. + */ + MigrateCommon args = { + .start = { + .hide_stderr = true, + }, + .listen_uri = "defer", + .start_hook = test_migrate_multifd_tls_x509_start_mismatch_host, + .finish_hook = test_migrate_tls_x509_finish, + .result = MIG_TEST_FAIL, + }; + test_precopy_common(&args); +} + +static void test_multifd_tcp_tls_x509_allow_anon_client(void) +{ + MigrateCommon args = { + .listen_uri = "defer", + .start_hook = test_migrate_multifd_tls_x509_start_allow_anon_client, + .finish_hook = test_migrate_tls_x509_finish, + }; + test_precopy_common(&args); +} + +static void test_multifd_tcp_tls_x509_reject_anon_client(void) +{ + MigrateCommon args = { + .start = { + .hide_stderr = true, + }, + .listen_uri = "defer", + .start_hook = test_migrate_multifd_tls_x509_start_reject_anon_client, + .finish_hook = test_migrate_tls_x509_finish, + .result = MIG_TEST_FAIL, + }; + test_precopy_common(&args); +} +#endif /* CONFIG_TASN1 */ #endif /* CONFIG_GNUTLS */ /* @@ -2083,6 +2198,18 @@ int main(int argc, char **argv) test_multifd_tcp_tls_psk_match); qtest_add_func("/migration/multifd/tcp/tls/psk/mismatch", test_multifd_tcp_tls_psk_mismatch); +#ifdef CONFIG_TASN1 + qtest_add_func("/migration/multifd/tcp/tls/x509/default-host", + test_multifd_tcp_tls_x509_default_host); + qtest_add_func("/migration/multifd/tcp/tls/x509/override-host", + test_multifd_tcp_tls_x509_override_host); + qtest_add_func("/migration/multifd/tcp/tls/x509/mismatch-host", + test_multifd_tcp_tls_x509_mismatch_host); + qtest_add_func("/migration/multifd/tcp/tls/x509/allow-anon-client", + test_multifd_tcp_tls_x509_allow_anon_client); + qtest_add_func("/migration/multifd/tcp/tls/x509/reject-anon-client", + test_multifd_tcp_tls_x509_reject_anon_client); +#endif /* CONFIG_TASN1 */ #endif /* CONFIG_GNUTLS */ if (kvm_dirty_ring_supported()) { From fd3540adb96d6f7ee7541be14f972a74c93faf3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 26 Apr 2022 17:00:48 +0100 Subject: [PATCH 385/935] tests: ensure migration status isn't reported as failed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Various methods in the migration test call 'query_migrate' to fetch the current status and then access a particular field. Almost all of these cases expect the migration to be in a non-failed state. In the case of 'wait_for_migration_pass' in particular, if the status is 'failed' then it will get into an infinite loop. By validating that the status is not 'failed' the test suite will assert rather than hang when getting into an unexpected state. Reviewed-by: Peter Xu Signed-off-by: Daniel P. Berrangé Message-Id: <20220426160048.812266-10-berrange@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- tests/qtest/migration-helpers.c | 13 +++++++++++++ tests/qtest/migration-helpers.h | 1 + tests/qtest/migration-test.c | 6 +++--- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helpers.c index 4ee26014b7..a6aa59e4e6 100644 --- a/tests/qtest/migration-helpers.c +++ b/tests/qtest/migration-helpers.c @@ -107,6 +107,19 @@ QDict *migrate_query(QTestState *who) return wait_command(who, "{ 'execute': 'query-migrate' }"); } +QDict *migrate_query_not_failed(QTestState *who) +{ + const char *status; + QDict *rsp = migrate_query(who); + status = qdict_get_str(rsp, "status"); + if (g_str_equal(status, "failed")) { + g_printerr("query-migrate shows failed migration: %s\n", + qdict_get_str(rsp, "error-desc")); + } + g_assert(!g_str_equal(status, "failed")); + return rsp; +} + /* * Note: caller is responsible to free the returned object via * g_free() after use diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration-helpers.h index 2731399aaa..78587c2b82 100644 --- a/tests/qtest/migration-helpers.h +++ b/tests/qtest/migration-helpers.h @@ -27,6 +27,7 @@ G_GNUC_PRINTF(3, 4) void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...); QDict *migrate_query(QTestState *who); +QDict *migrate_query_not_failed(QTestState *who); void wait_for_migration_status(QTestState *who, const char *goal, const char **ungoals); diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index efc6ec1614..d33e8060f9 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -181,7 +181,7 @@ static int64_t read_ram_property_int(QTestState *who, const char *property) QDict *rsp_return, *rsp_ram; int64_t result; - rsp_return = migrate_query(who); + rsp_return = migrate_query_not_failed(who); if (!qdict_haskey(rsp_return, "ram")) { /* Still in setup */ result = 0; @@ -198,7 +198,7 @@ static int64_t read_migrate_property_int(QTestState *who, const char *property) QDict *rsp_return; int64_t result; - rsp_return = migrate_query(who); + rsp_return = migrate_query_not_failed(who); result = qdict_get_try_int(rsp_return, property, 0); qobject_unref(rsp_return); return result; @@ -213,7 +213,7 @@ static void read_blocktime(QTestState *who) { QDict *rsp_return; - rsp_return = migrate_query(who); + rsp_return = migrate_query_not_failed(who); g_assert(qdict_haskey(rsp_return, "postcopy-blocktime")); qobject_unref(rsp_return); } From 354081d43de44ebd3497fe08f7f0121a5517d528 Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Fri, 13 May 2022 03:28:30 -0300 Subject: [PATCH 386/935] meson.build: Fix docker-test-build@alpine when including linux/errqueue.h A build error happens in alpine CI when linux/errqueue.h is included in io/channel-socket.c, due to redefining of 'struct __kernel_timespec': === ninja: job failed: [...] In file included from /usr/include/linux/errqueue.h:6, from ../io/channel-socket.c:29: /usr/include/linux/time_types.h:7:8: error: redefinition of 'struct __kernel_timespec' 7 | struct __kernel_timespec { | ^~~~~~~~~~~~~~~~~ In file included from /usr/include/liburing.h:19, from /builds/user/qemu/include/block/aio.h:18, from /builds/user/qemu/include/io/channel.h:26, from /builds/user/qemu/include/io/channel-socket.h:24, from ../io/channel-socket.c:24: /usr/include/liburing/compat.h:9:8: note: originally defined here 9 | struct __kernel_timespec { | ^~~~~~~~~~~~~~~~~ ninja: subcommand failed === As above error message suggests, 'struct __kernel_timespec' was already defined by liburing/compat.h. Fix alpine CI by adding test to disable liburing in configure step if a redefinition happens between linux/errqueue.h and liburing/compat.h. [dgilbert: This has been fixed in Alpine issue 13813 and liburing] Signed-off-by: Leonardo Bras Message-Id: <20220513062836.965425-2-leobras@redhat.com> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- meson.build | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/meson.build b/meson.build index 93aa31a9e4..53a4728250 100644 --- a/meson.build +++ b/meson.build @@ -515,12 +515,23 @@ if not get_option('linux_aio').auto() or have_block required: get_option('linux_aio'), kwargs: static_kwargs) endif + +linux_io_uring_test = ''' + #include + #include + + int main(void) { return 0; }''' + linux_io_uring = not_found if not get_option('linux_io_uring').auto() or have_block linux_io_uring = dependency('liburing', version: '>=0.3', required: get_option('linux_io_uring'), method: 'pkg-config', kwargs: static_kwargs) + if not cc.links(linux_io_uring_test) + linux_io_uring = not_found + endif endif + libnfs = not_found if not get_option('libnfs').auto() or have_block libnfs = dependency('libnfs', version: '>=1.9.3', From b88651cb4d4fa416fdbb6afaf5b26ec8c035eaad Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Fri, 13 May 2022 03:28:31 -0300 Subject: [PATCH 387/935] QIOChannel: Add flags on io_writev and introduce io_flush callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add flags to io_writev and introduce io_flush as optional callback to QIOChannelClass, allowing the implementation of zero copy writes by subclasses. How to use them: - Write data using qio_channel_writev*(...,QIO_CHANNEL_WRITE_FLAG_ZERO_COPY), - Wait write completion with qio_channel_flush(). Notes: As some zero copy write implementations work asynchronously, it's recommended to keep the write buffer untouched until the return of qio_channel_flush(), to avoid the risk of sending an updated buffer instead of the buffer state during write. As io_flush callback is optional, if a subclass does not implement it, then: - io_flush will return 0 without changing anything. Also, some functions like qio_channel_writev_full_all() were adapted to receive a flag parameter. That allows shared code between zero copy and non-zero copy writev, and also an easier implementation on new flags. Signed-off-by: Leonardo Bras Reviewed-by: Daniel P. Berrangé Reviewed-by: Peter Xu Reviewed-by: Juan Quintela Message-Id: <20220513062836.965425-3-leobras@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- chardev/char-io.c | 2 +- hw/remote/mpqemu-link.c | 2 +- include/io/channel.h | 38 +++++++++++++++++++++- io/channel-buffer.c | 1 + io/channel-command.c | 1 + io/channel-file.c | 1 + io/channel-socket.c | 2 ++ io/channel-tls.c | 1 + io/channel-websock.c | 1 + io/channel.c | 49 +++++++++++++++++++++++------ migration/rdma.c | 1 + scsi/pr-manager-helper.c | 2 +- tests/unit/test-io-channel-socket.c | 1 + 13 files changed, 88 insertions(+), 14 deletions(-) diff --git a/chardev/char-io.c b/chardev/char-io.c index 8ced184160..4451128cba 100644 --- a/chardev/char-io.c +++ b/chardev/char-io.c @@ -122,7 +122,7 @@ int io_channel_send_full(QIOChannel *ioc, ret = qio_channel_writev_full( ioc, &iov, 1, - fds, nfds, NULL); + fds, nfds, 0, NULL); if (ret == QIO_CHANNEL_ERR_BLOCK) { if (offset) { return offset; diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c index 2a4aa651ca..9bd98e8219 100644 --- a/hw/remote/mpqemu-link.c +++ b/hw/remote/mpqemu-link.c @@ -68,7 +68,7 @@ bool mpqemu_msg_send(MPQemuMsg *msg, QIOChannel *ioc, Error **errp) } if (!qio_channel_writev_full_all(ioc, send, G_N_ELEMENTS(send), - fds, nfds, errp)) { + fds, nfds, 0, errp)) { ret = true; } else { trace_mpqemu_send_io_error(msg->cmd, msg->size, nfds); diff --git a/include/io/channel.h b/include/io/channel.h index 88988979f8..c680ee7480 100644 --- a/include/io/channel.h +++ b/include/io/channel.h @@ -32,12 +32,15 @@ OBJECT_DECLARE_TYPE(QIOChannel, QIOChannelClass, #define QIO_CHANNEL_ERR_BLOCK -2 +#define QIO_CHANNEL_WRITE_FLAG_ZERO_COPY 0x1 + typedef enum QIOChannelFeature QIOChannelFeature; enum QIOChannelFeature { QIO_CHANNEL_FEATURE_FD_PASS, QIO_CHANNEL_FEATURE_SHUTDOWN, QIO_CHANNEL_FEATURE_LISTEN, + QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY, }; @@ -104,6 +107,7 @@ struct QIOChannelClass { size_t niov, int *fds, size_t nfds, + int flags, Error **errp); ssize_t (*io_readv)(QIOChannel *ioc, const struct iovec *iov, @@ -136,6 +140,8 @@ struct QIOChannelClass { IOHandler *io_read, IOHandler *io_write, void *opaque); + int (*io_flush)(QIOChannel *ioc, + Error **errp); }; /* General I/O handling functions */ @@ -228,6 +234,7 @@ ssize_t qio_channel_readv_full(QIOChannel *ioc, * @niov: the length of the @iov array * @fds: an array of file handles to send * @nfds: number of file handles in @fds + * @flags: write flags (QIO_CHANNEL_WRITE_FLAG_*) * @errp: pointer to a NULL-initialized error object * * Write data to the IO channel, reading it from the @@ -260,6 +267,7 @@ ssize_t qio_channel_writev_full(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp); /** @@ -837,6 +845,7 @@ int qio_channel_readv_full_all(QIOChannel *ioc, * @niov: the length of the @iov array * @fds: an array of file handles to send * @nfds: number of file handles in @fds + * @flags: write flags (QIO_CHANNEL_WRITE_FLAG_*) * @errp: pointer to a NULL-initialized error object * * @@ -846,6 +855,14 @@ int qio_channel_readv_full_all(QIOChannel *ioc, * to be written, yielding from the current coroutine * if required. * + * If QIO_CHANNEL_WRITE_FLAG_ZERO_COPY is passed in flags, + * instead of waiting for all requested data to be written, + * this function will wait until it's all queued for writing. + * In this case, if the buffer gets changed between queueing and + * sending, the updated buffer will be sent. If this is not a + * desired behavior, it's suggested to call qio_channel_flush() + * before reusing the buffer. + * * Returns: 0 if all bytes were written, or -1 on error */ @@ -853,6 +870,25 @@ int qio_channel_writev_full_all(QIOChannel *ioc, const struct iovec *iov, size_t niov, int *fds, size_t nfds, - Error **errp); + int flags, Error **errp); + +/** + * qio_channel_flush: + * @ioc: the channel object + * @errp: pointer to a NULL-initialized error object + * + * Will block until every packet queued with + * qio_channel_writev_full() + QIO_CHANNEL_WRITE_FLAG_ZERO_COPY + * is sent, or return in case of any error. + * + * If not implemented, acts as a no-op, and returns 0. + * + * Returns -1 if any error is found, + * 1 if every send failed to use zero copy. + * 0 otherwise. + */ + +int qio_channel_flush(QIOChannel *ioc, + Error **errp); #endif /* QIO_CHANNEL_H */ diff --git a/io/channel-buffer.c b/io/channel-buffer.c index baa4e2b089..bf52011be2 100644 --- a/io/channel-buffer.c +++ b/io/channel-buffer.c @@ -81,6 +81,7 @@ static ssize_t qio_channel_buffer_writev(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp) { QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc); diff --git a/io/channel-command.c b/io/channel-command.c index 4a1f969aaa..9f2f4a1793 100644 --- a/io/channel-command.c +++ b/io/channel-command.c @@ -276,6 +276,7 @@ static ssize_t qio_channel_command_writev(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp) { QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc); diff --git a/io/channel-file.c b/io/channel-file.c index d146ace7db..b67687c2aa 100644 --- a/io/channel-file.c +++ b/io/channel-file.c @@ -114,6 +114,7 @@ static ssize_t qio_channel_file_writev(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp) { QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc); diff --git a/io/channel-socket.c b/io/channel-socket.c index e531d7bd2a..05c425abb8 100644 --- a/io/channel-socket.c +++ b/io/channel-socket.c @@ -524,6 +524,7 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp) { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); @@ -619,6 +620,7 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp) { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); diff --git a/io/channel-tls.c b/io/channel-tls.c index 2ae1b92fc0..4ce890a538 100644 --- a/io/channel-tls.c +++ b/io/channel-tls.c @@ -301,6 +301,7 @@ static ssize_t qio_channel_tls_writev(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp) { QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc); diff --git a/io/channel-websock.c b/io/channel-websock.c index 55145a6a8c..9619906ac3 100644 --- a/io/channel-websock.c +++ b/io/channel-websock.c @@ -1127,6 +1127,7 @@ static ssize_t qio_channel_websock_writev(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp) { QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc); diff --git a/io/channel.c b/io/channel.c index e8b019dc36..0640941ac5 100644 --- a/io/channel.c +++ b/io/channel.c @@ -72,18 +72,32 @@ ssize_t qio_channel_writev_full(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp) { QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc); - if ((fds || nfds) && - !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_FD_PASS)) { + if (fds || nfds) { + if (!qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_FD_PASS)) { + error_setg_errno(errp, EINVAL, + "Channel does not support file descriptor passing"); + return -1; + } + if (flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) { + error_setg_errno(errp, EINVAL, + "Zero Copy does not support file descriptor passing"); + return -1; + } + } + + if ((flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) && + !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) { error_setg_errno(errp, EINVAL, - "Channel does not support file descriptor passing"); + "Requested Zero Copy feature is not available"); return -1; } - return klass->io_writev(ioc, iov, niov, fds, nfds, errp); + return klass->io_writev(ioc, iov, niov, fds, nfds, flags, errp); } @@ -217,14 +231,14 @@ int qio_channel_writev_all(QIOChannel *ioc, size_t niov, Error **errp) { - return qio_channel_writev_full_all(ioc, iov, niov, NULL, 0, errp); + return qio_channel_writev_full_all(ioc, iov, niov, NULL, 0, 0, errp); } int qio_channel_writev_full_all(QIOChannel *ioc, const struct iovec *iov, size_t niov, int *fds, size_t nfds, - Error **errp) + int flags, Error **errp) { int ret = -1; struct iovec *local_iov = g_new(struct iovec, niov); @@ -237,8 +251,10 @@ int qio_channel_writev_full_all(QIOChannel *ioc, while (nlocal_iov > 0) { ssize_t len; - len = qio_channel_writev_full(ioc, local_iov, nlocal_iov, fds, nfds, - errp); + + len = qio_channel_writev_full(ioc, local_iov, nlocal_iov, fds, + nfds, flags, errp); + if (len == QIO_CHANNEL_ERR_BLOCK) { if (qemu_in_coroutine()) { qio_channel_yield(ioc, G_IO_OUT); @@ -277,7 +293,7 @@ ssize_t qio_channel_writev(QIOChannel *ioc, size_t niov, Error **errp) { - return qio_channel_writev_full(ioc, iov, niov, NULL, 0, errp); + return qio_channel_writev_full(ioc, iov, niov, NULL, 0, 0, errp); } @@ -297,7 +313,7 @@ ssize_t qio_channel_write(QIOChannel *ioc, Error **errp) { struct iovec iov = { .iov_base = (char *)buf, .iov_len = buflen }; - return qio_channel_writev_full(ioc, &iov, 1, NULL, 0, errp); + return qio_channel_writev_full(ioc, &iov, 1, NULL, 0, 0, errp); } @@ -473,6 +489,19 @@ off_t qio_channel_io_seek(QIOChannel *ioc, return klass->io_seek(ioc, offset, whence, errp); } +int qio_channel_flush(QIOChannel *ioc, + Error **errp) +{ + QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc); + + if (!klass->io_flush || + !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) { + return 0; + } + + return klass->io_flush(ioc, errp); +} + static void qio_channel_restart_read(void *opaque) { diff --git a/migration/rdma.c b/migration/rdma.c index ef1e65ec36..672d1958a9 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2840,6 +2840,7 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, size_t niov, int *fds, size_t nfds, + int flags, Error **errp) { QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc); diff --git a/scsi/pr-manager-helper.c b/scsi/pr-manager-helper.c index 451c7631b7..3be52a98d5 100644 --- a/scsi/pr-manager-helper.c +++ b/scsi/pr-manager-helper.c @@ -77,7 +77,7 @@ static int pr_manager_helper_write(PRManagerHelper *pr_mgr, iov.iov_base = (void *)buf; iov.iov_len = sz; n_written = qio_channel_writev_full(QIO_CHANNEL(pr_mgr->ioc), &iov, 1, - nfds ? &fd : NULL, nfds, errp); + nfds ? &fd : NULL, nfds, 0, errp); if (n_written <= 0) { assert(n_written != QIO_CHANNEL_ERR_BLOCK); diff --git a/tests/unit/test-io-channel-socket.c b/tests/unit/test-io-channel-socket.c index c49eec1f03..6713886d02 100644 --- a/tests/unit/test-io-channel-socket.c +++ b/tests/unit/test-io-channel-socket.c @@ -444,6 +444,7 @@ static void test_io_channel_unix_fd_pass(void) G_N_ELEMENTS(iosend), fdsend, G_N_ELEMENTS(fdsend), + 0, &error_abort); qio_channel_readv_full(dst, From 2bc58ffc2926a4efdd03edfb5909861fefc68c3d Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Fri, 13 May 2022 03:28:32 -0300 Subject: [PATCH 388/935] QIOChannelSocket: Implement io_writev zero copy flag & io_flush for CONFIG_LINUX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For CONFIG_LINUX, implement the new zero copy flag and the optional callback io_flush on QIOChannelSocket, but enables it only when MSG_ZEROCOPY feature is available in the host kernel, which is checked on qio_channel_socket_connect_sync() qio_channel_socket_flush() was implemented by counting how many times sendmsg(...,MSG_ZEROCOPY) was successfully called, and then reading the socket's error queue, in order to find how many of them finished sending. Flush will loop until those counters are the same, or until some error occurs. Notes on using writev() with QIO_CHANNEL_WRITE_FLAG_ZERO_COPY: 1: Buffer - As MSG_ZEROCOPY tells the kernel to use the same user buffer to avoid copying, some caution is necessary to avoid overwriting any buffer before it's sent. If something like this happen, a newer version of the buffer may be sent instead. - If this is a problem, it's recommended to call qio_channel_flush() before freeing or re-using the buffer. 2: Locked memory - When using MSG_ZERCOCOPY, the buffer memory will be locked after queued, and unlocked after it's sent. - Depending on the size of each buffer, and how often it's sent, it may require a larger amount of locked memory than usually available to non-root user. - If the required amount of locked memory is not available, writev_zero_copy will return an error, which can abort an operation like migration, - Because of this, when an user code wants to add zero copy as a feature, it requires a mechanism to disable it, so it can still be accessible to less privileged users. Signed-off-by: Leonardo Bras Reviewed-by: Peter Xu Reviewed-by: Daniel P. Berrangé Reviewed-by: Juan Quintela Message-Id: <20220513062836.965425-4-leobras@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- include/io/channel-socket.h | 2 + io/channel-socket.c | 116 ++++++++++++++++++++++++++++++++++-- 2 files changed, 114 insertions(+), 4 deletions(-) diff --git a/include/io/channel-socket.h b/include/io/channel-socket.h index e747e63514..513c428fe4 100644 --- a/include/io/channel-socket.h +++ b/include/io/channel-socket.h @@ -47,6 +47,8 @@ struct QIOChannelSocket { socklen_t localAddrLen; struct sockaddr_storage remoteAddr; socklen_t remoteAddrLen; + ssize_t zero_copy_queued; + ssize_t zero_copy_sent; }; diff --git a/io/channel-socket.c b/io/channel-socket.c index 05c425abb8..dc9c165de1 100644 --- a/io/channel-socket.c +++ b/io/channel-socket.c @@ -25,6 +25,14 @@ #include "io/channel-watch.h" #include "trace.h" #include "qapi/clone-visitor.h" +#ifdef CONFIG_LINUX +#include +#include + +#if (defined(MSG_ZEROCOPY) && defined(SO_ZEROCOPY)) +#define QEMU_MSG_ZEROCOPY +#endif +#endif #define SOCKET_MAX_FDS 16 @@ -54,6 +62,8 @@ qio_channel_socket_new(void) sioc = QIO_CHANNEL_SOCKET(object_new(TYPE_QIO_CHANNEL_SOCKET)); sioc->fd = -1; + sioc->zero_copy_queued = 0; + sioc->zero_copy_sent = 0; ioc = QIO_CHANNEL(sioc); qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN); @@ -153,6 +163,16 @@ int qio_channel_socket_connect_sync(QIOChannelSocket *ioc, return -1; } +#ifdef QEMU_MSG_ZEROCOPY + int ret, v = 1; + ret = setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, &v, sizeof(v)); + if (ret == 0) { + /* Zero copy available on host */ + qio_channel_set_feature(QIO_CHANNEL(ioc), + QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY); + } +#endif + return 0; } @@ -533,6 +553,7 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc, char control[CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)]; size_t fdsize = sizeof(int) * nfds; struct cmsghdr *cmsg; + int sflags = 0; memset(control, 0, CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)); @@ -557,15 +578,31 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc, memcpy(CMSG_DATA(cmsg), fds, fdsize); } +#ifdef QEMU_MSG_ZEROCOPY + if (flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) { + sflags = MSG_ZEROCOPY; + } +#endif + retry: - ret = sendmsg(sioc->fd, &msg, 0); + ret = sendmsg(sioc->fd, &msg, sflags); if (ret <= 0) { - if (errno == EAGAIN) { + switch (errno) { + case EAGAIN: return QIO_CHANNEL_ERR_BLOCK; - } - if (errno == EINTR) { + case EINTR: goto retry; +#ifdef QEMU_MSG_ZEROCOPY + case ENOBUFS: + if (sflags & MSG_ZEROCOPY) { + error_setg_errno(errp, errno, + "Process can't lock enough memory for using MSG_ZEROCOPY"); + return -1; + } + break; +#endif } + error_setg_errno(errp, errno, "Unable to write to socket"); return -1; @@ -659,6 +696,74 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc, } #endif /* WIN32 */ + +#ifdef QEMU_MSG_ZEROCOPY +static int qio_channel_socket_flush(QIOChannel *ioc, + Error **errp) +{ + QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); + struct msghdr msg = {}; + struct sock_extended_err *serr; + struct cmsghdr *cm; + char control[CMSG_SPACE(sizeof(*serr))]; + int received; + int ret = 1; + + msg.msg_control = control; + msg.msg_controllen = sizeof(control); + memset(control, 0, sizeof(control)); + + while (sioc->zero_copy_sent < sioc->zero_copy_queued) { + received = recvmsg(sioc->fd, &msg, MSG_ERRQUEUE); + if (received < 0) { + switch (errno) { + case EAGAIN: + /* Nothing on errqueue, wait until something is available */ + qio_channel_wait(ioc, G_IO_ERR); + continue; + case EINTR: + continue; + default: + error_setg_errno(errp, errno, + "Unable to read errqueue"); + return -1; + } + } + + cm = CMSG_FIRSTHDR(&msg); + if (cm->cmsg_level != SOL_IP && + cm->cmsg_type != IP_RECVERR) { + error_setg_errno(errp, EPROTOTYPE, + "Wrong cmsg in errqueue"); + return -1; + } + + serr = (void *) CMSG_DATA(cm); + if (serr->ee_errno != SO_EE_ORIGIN_NONE) { + error_setg_errno(errp, serr->ee_errno, + "Error on socket"); + return -1; + } + if (serr->ee_origin != SO_EE_ORIGIN_ZEROCOPY) { + error_setg_errno(errp, serr->ee_origin, + "Error not from zero copy"); + return -1; + } + + /* No errors, count successfully finished sendmsg()*/ + sioc->zero_copy_sent += serr->ee_data - serr->ee_info + 1; + + /* If any sendmsg() succeeded using zero copy, return 0 at the end */ + if (serr->ee_code != SO_EE_CODE_ZEROCOPY_COPIED) { + ret = 0; + } + } + + return ret; +} + +#endif /* QEMU_MSG_ZEROCOPY */ + static int qio_channel_socket_set_blocking(QIOChannel *ioc, bool enabled, @@ -789,6 +894,9 @@ static void qio_channel_socket_class_init(ObjectClass *klass, ioc_klass->io_set_delay = qio_channel_socket_set_delay; ioc_klass->io_create_watch = qio_channel_socket_create_watch; ioc_klass->io_set_aio_fd_handler = qio_channel_socket_set_aio_fd_handler; +#ifdef QEMU_MSG_ZEROCOPY + ioc_klass->io_flush = qio_channel_socket_flush; +#endif } static const TypeInfo qio_channel_socket_info = { From abb6295b3ace5d17c3a65936913fc346616dbf14 Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Fri, 13 May 2022 03:28:33 -0300 Subject: [PATCH 389/935] migration: Add zero-copy-send parameter for QMP/HMP for Linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add property that allows zero-copy migration of memory pages on the sending side, and also includes a helper function migrate_use_zero_copy_send() to check if it's enabled. No code is introduced to actually do the migration, but it allow future implementations to enable/disable this feature. On non-Linux builds this parameter is compiled-out. Signed-off-by: Leonardo Bras Reviewed-by: Peter Xu Reviewed-by: Daniel P. Berrangé Reviewed-by: Juan Quintela Acked-by: Markus Armbruster Message-Id: <20220513062836.965425-5-leobras@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- migration/migration.c | 32 ++++++++++++++++++++++++++++++++ migration/migration.h | 5 +++++ migration/socket.c | 11 +++++++++-- monitor/hmp-cmds.c | 6 ++++++ qapi/migration.json | 24 ++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 2 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 5a31b23bd6..3e91f4b5e2 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -910,6 +910,10 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) params->multifd_zlib_level = s->parameters.multifd_zlib_level; params->has_multifd_zstd_level = true; params->multifd_zstd_level = s->parameters.multifd_zstd_level; +#ifdef CONFIG_LINUX + params->has_zero_copy_send = true; + params->zero_copy_send = s->parameters.zero_copy_send; +#endif params->has_xbzrle_cache_size = true; params->xbzrle_cache_size = s->parameters.xbzrle_cache_size; params->has_max_postcopy_bandwidth = true; @@ -1567,6 +1571,11 @@ static void migrate_params_test_apply(MigrateSetParameters *params, if (params->has_multifd_compression) { dest->multifd_compression = params->multifd_compression; } +#ifdef CONFIG_LINUX + if (params->has_zero_copy_send) { + dest->zero_copy_send = params->zero_copy_send; + } +#endif if (params->has_xbzrle_cache_size) { dest->xbzrle_cache_size = params->xbzrle_cache_size; } @@ -1679,6 +1688,11 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) if (params->has_multifd_compression) { s->parameters.multifd_compression = params->multifd_compression; } +#ifdef CONFIG_LINUX + if (params->has_zero_copy_send) { + s->parameters.zero_copy_send = params->zero_copy_send; + } +#endif if (params->has_xbzrle_cache_size) { s->parameters.xbzrle_cache_size = params->xbzrle_cache_size; xbzrle_cache_resize(params->xbzrle_cache_size, errp); @@ -2563,6 +2577,17 @@ int migrate_multifd_zstd_level(void) return s->parameters.multifd_zstd_level; } +#ifdef CONFIG_LINUX +bool migrate_use_zero_copy_send(void) +{ + MigrationState *s; + + s = migrate_get_current(); + + return s->parameters.zero_copy_send; +} +#endif + int migrate_use_xbzrle(void) { MigrationState *s; @@ -4206,6 +4231,10 @@ static Property migration_properties[] = { DEFINE_PROP_UINT8("multifd-zstd-level", MigrationState, parameters.multifd_zstd_level, DEFAULT_MIGRATE_MULTIFD_ZSTD_LEVEL), +#ifdef CONFIG_LINUX + DEFINE_PROP_BOOL("zero_copy_send", MigrationState, + parameters.zero_copy_send, false), +#endif DEFINE_PROP_SIZE("xbzrle-cache-size", MigrationState, parameters.xbzrle_cache_size, DEFAULT_MIGRATE_XBZRLE_CACHE_SIZE), @@ -4303,6 +4332,9 @@ static void migration_instance_init(Object *obj) params->has_multifd_compression = true; params->has_multifd_zlib_level = true; params->has_multifd_zstd_level = true; +#ifdef CONFIG_LINUX + params->has_zero_copy_send = true; +#endif params->has_xbzrle_cache_size = true; params->has_max_postcopy_bandwidth = true; params->has_max_cpu_throttle = true; diff --git a/migration/migration.h b/migration/migration.h index a863032b71..e8f2941a55 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -375,6 +375,11 @@ MultiFDCompression migrate_multifd_compression(void); int migrate_multifd_zlib_level(void); int migrate_multifd_zstd_level(void); +#ifdef CONFIG_LINUX +bool migrate_use_zero_copy_send(void); +#else +#define migrate_use_zero_copy_send() (false) +#endif int migrate_use_xbzrle(void); uint64_t migrate_xbzrle_cache_size(void); bool migrate_colo_enabled(void); diff --git a/migration/socket.c b/migration/socket.c index 05705a32d8..3754d8f72c 100644 --- a/migration/socket.c +++ b/migration/socket.c @@ -74,9 +74,16 @@ static void socket_outgoing_migration(QIOTask *task, if (qio_task_propagate_error(task, &err)) { trace_migration_socket_outgoing_error(error_get_pretty(err)); - } else { - trace_migration_socket_outgoing_connected(data->hostname); + goto out; } + + trace_migration_socket_outgoing_connected(data->hostname); + + if (migrate_use_zero_copy_send()) { + error_setg(&err, "Zero copy send not available in migration"); + } + +out: migration_channel_connect(data->s, sioc, data->hostname, err); object_unref(OBJECT(sioc)); } diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 93061a11af..622c783c32 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -1309,6 +1309,12 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) p->has_multifd_zstd_level = true; visit_type_uint8(v, param, &p->multifd_zstd_level, &err); break; +#ifdef CONFIG_LINUX + case MIGRATION_PARAMETER_ZERO_COPY_SEND: + p->has_zero_copy_send = true; + visit_type_bool(v, param, &p->zero_copy_send, &err); + break; +#endif case MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE: p->has_xbzrle_cache_size = true; if (!visit_type_size(v, param, &cache_size, &err)) { diff --git a/qapi/migration.json b/qapi/migration.json index 409eb086a2..2222f44250 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -741,6 +741,13 @@ # will consume more CPU. # Defaults to 1. (Since 5.0) # +# @zero-copy-send: Controls behavior on sending memory pages on migration. +# When true, enables a zero-copy mechanism for sending +# memory pages, if host supports it. +# Requires that QEMU be permitted to use locked memory +# for guest RAM pages. +# Defaults to false. (Since 7.1) +# # @block-bitmap-mapping: Maps block nodes and bitmaps on them to # aliases for the purpose of dirty bitmap migration. Such # aliases may for example be the corresponding names on the @@ -780,6 +787,7 @@ 'xbzrle-cache-size', 'max-postcopy-bandwidth', 'max-cpu-throttle', 'multifd-compression', 'multifd-zlib-level' ,'multifd-zstd-level', + { 'name': 'zero-copy-send', 'if' : 'CONFIG_LINUX'}, 'block-bitmap-mapping' ] } ## @@ -906,6 +914,13 @@ # will consume more CPU. # Defaults to 1. (Since 5.0) # +# @zero-copy-send: Controls behavior on sending memory pages on migration. +# When true, enables a zero-copy mechanism for sending +# memory pages, if host supports it. +# Requires that QEMU be permitted to use locked memory +# for guest RAM pages. +# Defaults to false. (Since 7.1) +# # @block-bitmap-mapping: Maps block nodes and bitmaps on them to # aliases for the purpose of dirty bitmap migration. Such # aliases may for example be the corresponding names on the @@ -960,6 +975,7 @@ '*multifd-compression': 'MultiFDCompression', '*multifd-zlib-level': 'uint8', '*multifd-zstd-level': 'uint8', + '*zero-copy-send': { 'type': 'bool', 'if': 'CONFIG_LINUX' }, '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ] } } ## @@ -1106,6 +1122,13 @@ # will consume more CPU. # Defaults to 1. (Since 5.0) # +# @zero-copy-send: Controls behavior on sending memory pages on migration. +# When true, enables a zero-copy mechanism for sending +# memory pages, if host supports it. +# Requires that QEMU be permitted to use locked memory +# for guest RAM pages. +# Defaults to false. (Since 7.1) +# # @block-bitmap-mapping: Maps block nodes and bitmaps on them to # aliases for the purpose of dirty bitmap migration. Such # aliases may for example be the corresponding names on the @@ -1158,6 +1181,7 @@ '*multifd-compression': 'MultiFDCompression', '*multifd-zlib-level': 'uint8', '*multifd-zstd-level': 'uint8', + '*zero-copy-send': { 'type': 'bool', 'if': 'CONFIG_LINUX' }, '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ] } } ## From d2fafb6a6814a8998607d0baf691265032996a0f Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Fri, 13 May 2022 03:28:34 -0300 Subject: [PATCH 390/935] migration: Add migrate_use_tls() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A lot of places check parameters.tls_creds in order to evaluate if TLS is in use, and sometimes call migrate_get_current() just for that test. Add new helper function migrate_use_tls() in order to simplify testing for TLS usage. Signed-off-by: Leonardo Bras Reviewed-by: Juan Quintela Reviewed-by: Peter Xu Reviewed-by: Daniel P. Berrangé Message-Id: <20220513062836.965425-6-leobras@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- migration/channel.c | 3 +-- migration/migration.c | 9 +++++++++ migration/migration.h | 1 + migration/multifd.c | 5 +---- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/migration/channel.c b/migration/channel.c index c6a8dcf1d7..a162d00fea 100644 --- a/migration/channel.c +++ b/migration/channel.c @@ -38,8 +38,7 @@ void migration_channel_process_incoming(QIOChannel *ioc) trace_migration_set_incoming_channel( ioc, object_get_typename(OBJECT(ioc))); - if (s->parameters.tls_creds && - *s->parameters.tls_creds && + if (migrate_use_tls() && !object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_TLS)) { migration_tls_channel_process_incoming(s, ioc, &local_err); diff --git a/migration/migration.c b/migration/migration.c index 3e91f4b5e2..4b6df2eb5e 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -2588,6 +2588,15 @@ bool migrate_use_zero_copy_send(void) } #endif +int migrate_use_tls(void) +{ + MigrationState *s; + + s = migrate_get_current(); + + return s->parameters.tls_creds && *s->parameters.tls_creds; +} + int migrate_use_xbzrle(void) { MigrationState *s; diff --git a/migration/migration.h b/migration/migration.h index e8f2941a55..485d58b95f 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -380,6 +380,7 @@ bool migrate_use_zero_copy_send(void); #else #define migrate_use_zero_copy_send() (false) #endif +int migrate_use_tls(void); int migrate_use_xbzrle(void); uint64_t migrate_xbzrle_cache_size(void); bool migrate_colo_enabled(void); diff --git a/migration/multifd.c b/migration/multifd.c index 9ea4f581e2..2a8c8570c3 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -782,15 +782,12 @@ static bool multifd_channel_connect(MultiFDSendParams *p, QIOChannel *ioc, Error *error) { - MigrationState *s = migrate_get_current(); - trace_multifd_set_outgoing_channel( ioc, object_get_typename(OBJECT(ioc)), migrate_get_current()->hostname, error); if (!error) { - if (s->parameters.tls_creds && - *s->parameters.tls_creds && + if (migrate_use_tls() && !object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_TLS)) { multifd_tls_channel_connect(p, ioc, &error); From 33d70973a3a6e8c6b62bcbc64d9e488961981007 Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Fri, 13 May 2022 03:28:35 -0300 Subject: [PATCH 391/935] multifd: multifd_send_sync_main now returns negative on error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even though multifd_send_sync_main() currently emits error_reports, it's callers don't really check it before continuing. Change multifd_send_sync_main() to return -1 on error and 0 on success. Also change all it's callers to make use of this change and possibly fail earlier. (This change is important to next patch on multifd zero copy implementation, to make it sure an error in zero-copy flush does not go unnoticed. Signed-off-by: Leonardo Bras Reviewed-by: Daniel P. Berrangé Reviewed-by: Peter Xu Message-Id: <20220513062836.965425-7-leobras@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- migration/multifd.c | 10 ++++++---- migration/multifd.h | 2 +- migration/ram.c | 29 ++++++++++++++++++++++------- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/migration/multifd.c b/migration/multifd.c index 2a8c8570c3..15fb668e64 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -566,17 +566,17 @@ void multifd_save_cleanup(void) multifd_send_state = NULL; } -void multifd_send_sync_main(QEMUFile *f) +int multifd_send_sync_main(QEMUFile *f) { int i; if (!migrate_use_multifd()) { - return; + return 0; } if (multifd_send_state->pages->num) { if (multifd_send_pages(f) < 0) { error_report("%s: multifd_send_pages fail", __func__); - return; + return -1; } } for (i = 0; i < migrate_multifd_channels(); i++) { @@ -589,7 +589,7 @@ void multifd_send_sync_main(QEMUFile *f) if (p->quit) { error_report("%s: channel %d has already quit", __func__, i); qemu_mutex_unlock(&p->mutex); - return; + return -1; } p->packet_num = multifd_send_state->packet_num++; @@ -608,6 +608,8 @@ void multifd_send_sync_main(QEMUFile *f) qemu_sem_wait(&p->sem_sync); } trace_multifd_send_sync_main(multifd_send_state->packet_num); + + return 0; } static void *multifd_send_thread(void *opaque) diff --git a/migration/multifd.h b/migration/multifd.h index 7d0effcb03..bcf5992945 100644 --- a/migration/multifd.h +++ b/migration/multifd.h @@ -20,7 +20,7 @@ int multifd_load_cleanup(Error **errp); bool multifd_recv_all_channels_created(void); bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp); void multifd_recv_sync_main(void); -void multifd_send_sync_main(QEMUFile *f); +int multifd_send_sync_main(QEMUFile *f); int multifd_queue_page(QEMUFile *f, RAMBlock *block, ram_addr_t offset); /* Multifd Compression flags */ diff --git a/migration/ram.c b/migration/ram.c index a2489a2699..5f5e37f64d 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -2909,6 +2909,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque) { RAMState **rsp = opaque; RAMBlock *block; + int ret; if (compress_threads_save_setup()) { return -1; @@ -2943,7 +2944,11 @@ static int ram_save_setup(QEMUFile *f, void *opaque) ram_control_before_iterate(f, RAM_CONTROL_SETUP); ram_control_after_iterate(f, RAM_CONTROL_SETUP); - multifd_send_sync_main(f); + ret = multifd_send_sync_main(f); + if (ret < 0) { + return ret; + } + qemu_put_be64(f, RAM_SAVE_FLAG_EOS); qemu_fflush(f); @@ -3052,7 +3057,11 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) out: if (ret >= 0 && migration_is_setup_or_active(migrate_get_current()->state)) { - multifd_send_sync_main(rs->f); + ret = multifd_send_sync_main(rs->f); + if (ret < 0) { + return ret; + } + qemu_put_be64(f, RAM_SAVE_FLAG_EOS); qemu_fflush(f); ram_transferred_add(8); @@ -3112,13 +3121,19 @@ static int ram_save_complete(QEMUFile *f, void *opaque) ram_control_after_iterate(f, RAM_CONTROL_FINISH); } - if (ret >= 0) { - multifd_send_sync_main(rs->f); - qemu_put_be64(f, RAM_SAVE_FLAG_EOS); - qemu_fflush(f); + if (ret < 0) { + return ret; } - return ret; + ret = multifd_send_sync_main(rs->f); + if (ret < 0) { + return ret; + } + + qemu_put_be64(f, RAM_SAVE_FLAG_EOS); + qemu_fflush(f); + + return 0; } static void ram_save_pending(QEMUFile *f, void *opaque, uint64_t max_size, From b7dbdd8e76cd03453c234dbb9578d20969859d74 Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Fri, 13 May 2022 03:28:36 -0300 Subject: [PATCH 392/935] multifd: Send header packet without flags if zero-copy-send is enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since d48c3a0445 ("multifd: Use a single writev on the send side"), sending the header packet and the memory pages happens in the same writev, which can potentially make the migration faster. Using channel-socket as example, this works well with the default copying mechanism of sendmsg(), but with zero-copy-send=true, it will cause the migration to often break. This happens because the header packet buffer gets reused quite often, and there is a high chance that by the time the MSG_ZEROCOPY mechanism get to send the buffer, it has already changed, sending the wrong data and causing the migration to abort. It means that, as it is, the buffer for the header packet is not suitable for sending with MSG_ZEROCOPY. In order to enable zero copy for multifd, send the header packet on an individual write(), without any flags, and the remanining pages with a writev(), as it was happening before. This only changes how a migration with zero-copy-send=true works, not changing any current behavior for migrations with zero-copy-send=false. Signed-off-by: Leonardo Bras Reviewed-by: Peter Xu Reviewed-by: Daniel P. Berrangé Message-Id: <20220513062836.965425-8-leobras@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- migration/multifd.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/migration/multifd.c b/migration/multifd.c index 15fb668e64..2541cd2322 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -617,6 +617,7 @@ static void *multifd_send_thread(void *opaque) MultiFDSendParams *p = opaque; Error *local_err = NULL; int ret = 0; + bool use_zero_copy_send = migrate_use_zero_copy_send(); trace_multifd_send_thread_start(p->id); rcu_register_thread(); @@ -639,9 +640,14 @@ static void *multifd_send_thread(void *opaque) if (p->pending_job) { uint64_t packet_num = p->packet_num; uint32_t flags = p->flags; - p->iovs_num = 1; p->normal_num = 0; + if (use_zero_copy_send) { + p->iovs_num = 0; + } else { + p->iovs_num = 1; + } + for (int i = 0; i < p->pages->num; i++) { p->normal[p->normal_num] = p->pages->offset[i]; p->normal_num++; @@ -665,8 +671,18 @@ static void *multifd_send_thread(void *opaque) trace_multifd_send(p->id, packet_num, p->normal_num, flags, p->next_packet_size); - p->iov[0].iov_len = p->packet_len; - p->iov[0].iov_base = p->packet; + if (use_zero_copy_send) { + /* Send header first, without zerocopy */ + ret = qio_channel_write_all(p->c, (void *)p->packet, + p->packet_len, &local_err); + if (ret != 0) { + break; + } + } else { + /* Send header using the same writev call */ + p->iov[0].iov_len = p->packet_len; + p->iov[0].iov_base = p->packet; + } ret = qio_channel_writev_all(p->c, p->iov, p->iovs_num, &local_err); From 5b1d9bab2da4fca3a3caee97c430e5709cb32b7b Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Fri, 13 May 2022 03:28:37 -0300 Subject: [PATCH 393/935] multifd: Implement zero copy write in multifd migration (multifd-zero-copy) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement zero copy send on nocomp_send_write(), by making use of QIOChannel writev + flags & flush interface. Change multifd_send_sync_main() so flush_zero_copy() can be called after each iteration in order to make sure all dirty pages are sent before a new iteration is started. It will also flush at the beginning and at the end of migration. Also make it return -1 if flush_zero_copy() fails, in order to cancel the migration process, and avoid resuming the guest in the target host without receiving all current RAM. This will work fine on RAM migration because the RAM pages are not usually freed, and there is no problem on changing the pages content between writev_zero_copy() and the actual sending of the buffer, because this change will dirty the page and cause it to be re-sent on a next iteration anyway. A lot of locked memory may be needed in order to use multifd migration with zero-copy enabled, so disabling the feature should be necessary for low-privileged users trying to perform multifd migrations. Signed-off-by: Leonardo Bras Reviewed-by: Peter Xu Reviewed-by: Daniel P. Berrangé Message-Id: <20220513062836.965425-9-leobras@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- migration/migration.c | 11 ++++++++++- migration/multifd.c | 37 +++++++++++++++++++++++++++++++++++-- migration/multifd.h | 2 ++ migration/socket.c | 5 +++-- 4 files changed, 50 insertions(+), 5 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 4b6df2eb5e..31739b2af9 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1497,7 +1497,16 @@ static bool migrate_params_check(MigrationParameters *params, Error **errp) error_prepend(errp, "Invalid mapping given for block-bitmap-mapping: "); return false; } - +#ifdef CONFIG_LINUX + if (params->zero_copy_send && + (!migrate_use_multifd() || + params->multifd_compression != MULTIFD_COMPRESSION_NONE || + (params->tls_creds && *params->tls_creds))) { + error_setg(errp, + "Zero copy only available for non-compressed non-TLS multifd migration"); + return false; + } +#endif return true; } diff --git a/migration/multifd.c b/migration/multifd.c index 2541cd2322..9282ab6aa4 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -569,6 +569,7 @@ void multifd_save_cleanup(void) int multifd_send_sync_main(QEMUFile *f) { int i; + bool flush_zero_copy; if (!migrate_use_multifd()) { return 0; @@ -579,6 +580,20 @@ int multifd_send_sync_main(QEMUFile *f) return -1; } } + + /* + * When using zero-copy, it's necessary to flush the pages before any of + * the pages can be sent again, so we'll make sure the new version of the + * pages will always arrive _later_ than the old pages. + * + * Currently we achieve this by flushing the zero-page requested writes + * per ram iteration, but in the future we could potentially optimize it + * to be less frequent, e.g. only after we finished one whole scanning of + * all the dirty bitmaps. + */ + + flush_zero_copy = migrate_use_zero_copy_send(); + for (i = 0; i < migrate_multifd_channels(); i++) { MultiFDSendParams *p = &multifd_send_state->params[i]; @@ -600,6 +615,17 @@ int multifd_send_sync_main(QEMUFile *f) ram_counters.transferred += p->packet_len; qemu_mutex_unlock(&p->mutex); qemu_sem_post(&p->sem); + + if (flush_zero_copy && p->c) { + int ret; + Error *err = NULL; + + ret = qio_channel_flush(p->c, &err); + if (ret < 0) { + error_report_err(err); + return -1; + } + } } for (i = 0; i < migrate_multifd_channels(); i++) { MultiFDSendParams *p = &multifd_send_state->params[i]; @@ -684,8 +710,8 @@ static void *multifd_send_thread(void *opaque) p->iov[0].iov_base = p->packet; } - ret = qio_channel_writev_all(p->c, p->iov, p->iovs_num, - &local_err); + ret = qio_channel_writev_full_all(p->c, p->iov, p->iovs_num, NULL, + 0, p->write_flags, &local_err); if (ret != 0) { break; } @@ -913,6 +939,13 @@ int multifd_save_setup(Error **errp) /* We need one extra place for the packet header */ p->iov = g_new0(struct iovec, page_count + 1); p->normal = g_new0(ram_addr_t, page_count); + + if (migrate_use_zero_copy_send()) { + p->write_flags = QIO_CHANNEL_WRITE_FLAG_ZERO_COPY; + } else { + p->write_flags = 0; + } + socket_send_channel_create(multifd_new_send_channel_async, p); } diff --git a/migration/multifd.h b/migration/multifd.h index bcf5992945..4d8d89e5e5 100644 --- a/migration/multifd.h +++ b/migration/multifd.h @@ -92,6 +92,8 @@ typedef struct { uint32_t packet_len; /* pointer to the packet */ MultiFDPacket_t *packet; + /* multifd flags for sending ram */ + int write_flags; /* multifd flags for each packet */ uint32_t flags; /* size of the next packet that contains pages */ diff --git a/migration/socket.c b/migration/socket.c index 3754d8f72c..4fd5e85f50 100644 --- a/migration/socket.c +++ b/migration/socket.c @@ -79,8 +79,9 @@ static void socket_outgoing_migration(QIOTask *task, trace_migration_socket_outgoing_connected(data->hostname); - if (migrate_use_zero_copy_send()) { - error_setg(&err, "Zero copy send not available in migration"); + if (migrate_use_zero_copy_send() && + !qio_channel_has_feature(sioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) { + error_setg(&err, "Zero copy send feature not detected in host kernel"); } out: From 041eb5bcf7394898786c50f448ea358e5067144d Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 16 May 2022 15:51:02 +0200 Subject: [PATCH 394/935] seabios-hppa: Update SeaBIOS-hppa to VERSION 5 New features and fixes in SeaBIOS for hppa/parisc: * STI firmware now contains additional fonts built-in, which can be selected with qemu command-line options: -fw_cfg opt/font,string=1 - a HP 8x16 font -fw_cfg opt/font,string=2 - a HP 6x13 font -fw_cfg opt/font,string=3 - a HP 10x20 font -fw_cfg opt/font,string=4 - a Linux 16x32 font * Fixed PS/2 keyboard emulation when running in graphical mode. This allows to type boot commands in the firmware boot menu if qemu was started with "-boot menu=on" (and no linux kernel was given on the qemu command line). * Fix firmware rendenzvous code to clear all pending external intrrupts before entering the waiting loop. Signed-off-by: Helge Deller --- pc-bios/hppa-firmware.img | Bin 701964 -> 719040 bytes roms/seabios-hppa | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/hppa-firmware.img b/pc-bios/hppa-firmware.img index 0ec2d96b8f48a46dc9c0fabd50d14d5a2212a071..392bce072bad607b1baaff0136f35844fa5d439e 100644 GIT binary patch literal 719040 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
=5$`QLx#I;PNP`S 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 z%0A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

Y_ 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 >ax=P_GL9~FkT~;8u?GVzsd>|< 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

sHIR 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 Date: Wed, 11 May 2022 11:34:15 +0200 Subject: [PATCH 395/935] artist: Introduce constant for max cursor size Add the constant NGLE_MAX_SPRITE_SIZE which defines the currently maximum supported cursor size. Signed-off-by: Helge Deller Acked-by: Mark Cave-Ayland --- hw/display/artist.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/display/artist.c b/hw/display/artist.c index 39fc0c4ca5..6333ee41db 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -98,6 +98,9 @@ struct ARTISTState { int draw_line_pattern; }; +/* hardware allows up to 64x64, but we emulate 32x32 only. */ +#define NGLE_MAX_SPRITE_SIZE 32 + typedef enum { ARTIST_BUFFER_AP = 1, ARTIST_BUFFER_OVERLAY = 2, @@ -1325,11 +1328,10 @@ static void artist_realizefn(DeviceState *dev, Error **errp) framebuffer_update_memory_section(&s->fbsection, &buf->mr, 0, buf->width, buf->height); /* - * no idea whether the cursor is fixed size or not, so assume 32x32 which - * seems sufficient for HP-UX X11. + * Artist cursor max size */ - s->cursor_height = 32; - s->cursor_width = 32; + s->cursor_height = NGLE_MAX_SPRITE_SIZE; + s->cursor_width = NGLE_MAX_SPRITE_SIZE; /* * These two registers are not initialized by seabios's STI implementation. From e9683fbc3738ebbf9b4058413ffc53e086da95fc Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Wed, 11 May 2022 11:41:19 +0200 Subject: [PATCH 396/935] artist: Use human-readable variable names instead of reg_xxx Convert the variable names of some registers to human-readable and understandable names. Signed-off-by: Helge Deller Acked-by: Mark Cave-Ayland --- hw/display/artist.c | 72 ++++++++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/hw/display/artist.c b/hw/display/artist.c index 6333ee41db..c8b261a52e 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -81,9 +81,10 @@ struct ARTISTState { uint32_t plane_mask; uint32_t reg_100080; - uint32_t reg_300200; - uint32_t reg_300208; - uint32_t reg_300218; + uint32_t horiz_backporch; + uint32_t active_lines_low; + uint32_t misc_video; + uint32_t misc_ctrl; uint32_t dst_bm_access; uint32_t src_bm_access; @@ -138,8 +139,14 @@ typedef enum { BG_COLOR = 0x118014, PLANE_MASK = 0x118018, IMAGE_BITMAP_OP = 0x11801c, - CURSOR_POS = 0x300100, - CURSOR_CTRL = 0x300104, + CURSOR_POS = 0x300100, /* reg17 */ + CURSOR_CTRL = 0x300104, /* reg18 */ + MISC_VIDEO = 0x300218, /* reg21 */ + MISC_CTRL = 0x300308, /* reg27 */ + HORIZ_BACKPORCH = 0x300200, /* reg19 */ + ACTIVE_LINES_LOW = 0x300208,/* reg20 */ + FIFO1 = 0x300008, /* reg34 */ + FIFO2 = 0x380008, } artist_reg_t; typedef enum { @@ -177,12 +184,18 @@ static const char *artist_reg_name(uint64_t addr) REG_NAME(SRC_BM_ACCESS); REG_NAME(CURSOR_POS); REG_NAME(CURSOR_CTRL); + REG_NAME(HORIZ_BACKPORCH); + REG_NAME(ACTIVE_LINES_LOW); + REG_NAME(MISC_VIDEO); + REG_NAME(MISC_CTRL); REG_NAME(LINE_XY); REG_NAME(PATTERN_LINE_START); REG_NAME(LINE_SIZE); REG_NAME(LINE_END); REG_NAME(FONT_WRITE_INCR_Y); REG_NAME(FONT_WRITE_START); + REG_NAME(FIFO1); + REG_NAME(FIFO2); } return ""; } @@ -1028,16 +1041,20 @@ static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val, combine_write_reg(addr, val, size, &s->transfer_data); break; - case 0x300200: - combine_write_reg(addr, val, size, &s->reg_300200); + case HORIZ_BACKPORCH: + combine_write_reg(addr, val, size, &s->horiz_backporch); break; - case 0x300208: - combine_write_reg(addr, val, size, &s->reg_300208); + case ACTIVE_LINES_LOW: + combine_write_reg(addr, val, size, &s->active_lines_low); break; - case 0x300218: - combine_write_reg(addr, val, size, &s->reg_300218); + case MISC_VIDEO: + combine_write_reg(addr, val, size, &s->misc_video); + break; + + case MISC_CTRL: + combine_write_reg(addr, val, size, &s->misc_ctrl); break; case CURSOR_POS: @@ -1122,12 +1139,11 @@ static uint64_t artist_reg_read(void *opaque, hwaddr addr, unsigned size) case 0x100000: case 0x300000: case 0x300004: - case 0x300308: case 0x380000: break; - case 0x300008: - case 0x380008: + case FIFO1: + case FIFO2: /* * FIFO ready flag. we're not emulating the FIFOs * so we're always ready @@ -1135,16 +1151,25 @@ static uint64_t artist_reg_read(void *opaque, hwaddr addr, unsigned size) val = 0x10; break; - case 0x300200: - val = s->reg_300200; + case HORIZ_BACKPORCH: + val = s->horiz_backporch; break; - case 0x300208: - val = s->reg_300208; + case ACTIVE_LINES_LOW: + val = s->active_lines_low; + /* activeLinesLo for cursor is in reg20.b.b0 */ + val |= ((s->height - 1) & 0xff); break; - case 0x300218: - val = s->reg_300218; + case MISC_VIDEO: + /* emulate V-blank */ + val = s->misc_video ^ 0x00040000; + /* activeLinesHi for cursor is in reg21.b.b2 */ + val |= ((s->height - 1) & 0xff00); + break; + + case MISC_CTRL: + val = s->misc_ctrl; break; case 0x30023c: @@ -1379,9 +1404,10 @@ static const VMStateDescription vmstate_artist = { VMSTATE_UINT32(cursor_width, ARTISTState), VMSTATE_UINT32(plane_mask, ARTISTState), VMSTATE_UINT32(reg_100080, ARTISTState), - VMSTATE_UINT32(reg_300200, ARTISTState), - VMSTATE_UINT32(reg_300208, ARTISTState), - VMSTATE_UINT32(reg_300218, ARTISTState), + VMSTATE_UINT32(horiz_backporch, ARTISTState), + VMSTATE_UINT32(active_lines_low, ARTISTState), + VMSTATE_UINT32(misc_video, ARTISTState), + VMSTATE_UINT32(misc_ctrl, ARTISTState), VMSTATE_UINT32(dst_bm_access, ARTISTState), VMSTATE_UINT32(src_bm_access, ARTISTState), VMSTATE_UINT32(control_plane, ARTISTState), From 482afe020b558d36d3b863970ad1672981b22d48 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Wed, 11 May 2022 11:49:02 +0200 Subject: [PATCH 397/935] artist: Fix vertical X11 cursor position in HP-UX Drop the hard-coded value of 1146 lines which seems to work with HP-UX 11, but not with HP-UX 10. Instead encode the screen height in byte 0 of active_lines_low and byte 3 of misc_video as it's expected by the Xorg X11 graphics driver. This potentially allows for higher vertical screen resolutions than 1280x1024 with X11. Signed-off-by: Helge Deller Acked-by: Mark Cave-Ayland --- hw/display/artist.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/hw/display/artist.c b/hw/display/artist.c index c8b261a52e..780cb15026 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -337,10 +337,11 @@ static void artist_get_cursor_pos(ARTISTState *s, int *x, int *y) } *x = (lx - offset) / 2; - *y = 1146 - artist_get_y(s->cursor_pos); - /* subtract cursor offset from cursor control register */ *x -= (s->cursor_cntrl & 0xf0) >> 4; + + /* height minus nOffscreenScanlines is stored in cursor control register */ + *y = s->height - artist_get_y(s->cursor_pos); *y -= (s->cursor_cntrl & 0x0f); if (*x > s->width) { @@ -1158,14 +1159,17 @@ static uint64_t artist_reg_read(void *opaque, hwaddr addr, unsigned size) case ACTIVE_LINES_LOW: val = s->active_lines_low; /* activeLinesLo for cursor is in reg20.b.b0 */ - val |= ((s->height - 1) & 0xff); + val &= ~(0xff << 24); + val |= (s->height & 0xff) << 24; break; case MISC_VIDEO: /* emulate V-blank */ - val = s->misc_video ^ 0x00040000; + s->misc_video ^= 0x00040000; /* activeLinesHi for cursor is in reg21.b.b2 */ - val |= ((s->height - 1) & 0xff00); + val = s->misc_video; + val &= ~0xff00UL; + val |= (s->height & 0xff00); break; case MISC_CTRL: From a377b574eb2cbcbff3fc579529e0f1b2fbda8af8 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Wed, 11 May 2022 12:28:30 +0200 Subject: [PATCH 398/935] artist: Allow to turn cursor on or off Bit 0x80 in the cursor_cntrl register specifies if the cursor should be visible. Prevent rendering the cursor if it's invisible. Signed-off-by: Helge Deller Acked-by: Mark Cave-Ayland --- hw/display/artist.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/hw/display/artist.c b/hw/display/artist.c index 780cb15026..b8930b7c5a 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -353,10 +353,20 @@ static void artist_get_cursor_pos(ARTISTState *s, int *x, int *y) } } +static inline bool cursor_visible(ARTISTState *s) +{ + /* cursor is visible if bit 0x80 is set in cursor_cntrl */ + return s->cursor_cntrl & 0x80; +} + static void artist_invalidate_cursor(ARTISTState *s) { int x, y; + if (!cursor_visible(s)) { + return; + } + artist_get_cursor_pos(s, &x, &y); artist_invalidate_lines(&s->vram_buffer[ARTIST_BUFFER_AP], y, s->cursor_height); @@ -1218,6 +1228,10 @@ static void artist_draw_cursor(ARTISTState *s) struct vram_buffer *cursor0, *cursor1 , *buf; int cx, cy, cursor_pos_x, cursor_pos_y; + if (!cursor_visible(s)) { + return; + } + cursor0 = &s->vram_buffer[ARTIST_BUFFER_CURSOR1]; cursor1 = &s->vram_buffer[ARTIST_BUFFER_CURSOR2]; buf = &s->vram_buffer[ARTIST_BUFFER_AP]; From caca6e618d5577e45be2bcdc1e626a8b747fb56b Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Wed, 11 May 2022 12:59:47 +0200 Subject: [PATCH 399/935] artist: Emulate screen blanking The misc_video and misc_ctrl registers control the visibility of the screen. Start with the screen turned on, and hide or show the screen based on the control registers. Signed-off-by: Helge Deller Acked-by: Mark Cave-Ayland --- hw/display/artist.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/hw/display/artist.c b/hw/display/artist.c index b8930b7c5a..49dad2b824 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -201,6 +201,8 @@ static const char *artist_reg_name(uint64_t addr) } #undef REG_NAME +static void artist_invalidate(void *opaque); + /* artist has a fixed line length of 2048 bytes. */ #define ADDR_TO_Y(addr) extract32(addr, 11, 11) #define ADDR_TO_X(addr) extract32(addr, 0, 11) @@ -903,6 +905,7 @@ static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val, { ARTISTState *s = opaque; int width, height; + uint64_t oldval; trace_artist_reg_write(size, addr, artist_reg_name(addr & ~3ULL), val); @@ -1061,7 +1064,18 @@ static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val, break; case MISC_VIDEO: + oldval = s->misc_video; combine_write_reg(addr, val, size, &s->misc_video); + /* Invalidate and hide screen if graphics signal is turned off. */ + if (((oldval & 0x0A000000) == 0x0A000000) && + ((val & 0x0A000000) != 0x0A000000)) { + artist_invalidate(s); + } + /* Invalidate and redraw screen if graphics signal is turned back on. */ + if (((oldval & 0x0A000000) != 0x0A000000) && + ((val & 0x0A000000) == 0x0A000000)) { + artist_invalidate(s); + } break; case MISC_CTRL: @@ -1263,6 +1277,12 @@ static void artist_draw_cursor(ARTISTState *s) } } +static bool artist_screen_enabled(ARTISTState *s) +{ + /* We could check for (s->misc_ctrl & 0x00800000) too... */ + return ((s->misc_video & 0x0A000000) == 0x0A000000); +} + static void artist_draw_line(void *opaque, uint8_t *d, const uint8_t *src, int width, int pitch) { @@ -1270,6 +1290,12 @@ static void artist_draw_line(void *opaque, uint8_t *d, const uint8_t *src, uint32_t *cmap, *data = (uint32_t *)d; int x; + if (!artist_screen_enabled(s)) { + /* clear screen */ + memset(data, 0, s->width * sizeof(uint32_t)); + return; + } + cmap = (uint32_t *)(s->vram_buffer[ARTIST_BUFFER_CMAP].data + 0x400); for (x = 0; x < s->width; x++) { @@ -1384,6 +1410,10 @@ static void artist_realizefn(DeviceState *dev, Error **errp) s->image_bitmap_op = 0x23000300; s->plane_mask = 0xff; + /* enable screen */ + s->misc_video |= 0x0A000000; + s->misc_ctrl |= 0x00800000; + s->con = graphic_console_init(dev, 0, &artist_ops, s); qemu_console_resize(s->con, s->width, s->height); } From 9ef2c6b4ab9a430ee230ee305b6994d7eae86fe7 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 12 May 2022 13:40:39 +0200 Subject: [PATCH 400/935] artist: Fix X cursor position calculation in X11 The X cursor postion can be calculated based on the backporch and interleave values. In the emulation we ignore the HP-UX settings for backporch and use instead twice the size of the emulated cursor. With those changes the X-position of the graphics cursor is now finally working correctly on HP-UX 10 and HP-UX 11. Based on coding in Xorg X11R6.6 Signed-off-by: Helge Deller --- hw/display/artist.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/hw/display/artist.c b/hw/display/artist.c index 49dad2b824..eadaef0d46 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -1,7 +1,8 @@ /* * QEMU HP Artist Emulation * - * Copyright (c) 2019 Sven Schnelle + * Copyright (c) 2019-2022 Sven Schnelle + * Copyright (c) 2022 Helge Deller * * This work is licensed under the terms of the GNU GPL, version 2 or later. */ @@ -313,19 +314,15 @@ static void artist_rop8(ARTISTState *s, struct vram_buffer *buf, static void artist_get_cursor_pos(ARTISTState *s, int *x, int *y) { /* - * Don't know whether these magic offset values are configurable via - * some register. They seem to be the same for all resolutions. - * The cursor values provided in the registers are: - * X-value: -295 (for HP-UX 11) and 338 (for HP-UX 10.20) up to 2265 - * Y-value: 1146 down to 0 * The emulated Artist graphic is like a CRX graphic, and as such * it's usually fixed at 1280x1024 pixels. - * Because of the maximum Y-value of 1146 you can not choose a higher - * vertical resolution on HP-UX (unless you disable the mouse). + * Other resolutions may work, but no guarantee. */ - static int offset = 338; - int lx; + unsigned int hbp_times_vi, horizBackPorch; + int16_t xHi, xLo; + const int videoInterleave = 4; + const int pipelineDelay = 4; /* ignore if uninitialized */ if (s->cursor_pos == 0) { @@ -333,16 +330,23 @@ static void artist_get_cursor_pos(ARTISTState *s, int *x, int *y) return; } - lx = artist_get_x(s->cursor_pos); - if (lx < offset) { - offset = lx; - } - *x = (lx - offset) / 2; + /* + * Calculate X position based on backporch and interleave values. + * Based on code from Xorg X11R6.6 + */ + horizBackPorch = ((s->horiz_backporch & 0xff0000) >> 16) + + ((s->horiz_backporch & 0xff00) >> 8) + 2; + hbp_times_vi = horizBackPorch * videoInterleave; + xHi = s->cursor_pos >> 19; + *x = ((xHi + pipelineDelay) * videoInterleave) - hbp_times_vi; + + xLo = (s->cursor_pos >> 16) & 0x07; + *x += ((xLo - hbp_times_vi) & (videoInterleave - 1)) + 8 - 1; /* subtract cursor offset from cursor control register */ *x -= (s->cursor_cntrl & 0xf0) >> 4; - /* height minus nOffscreenScanlines is stored in cursor control register */ + /* Calculate Y position */ *y = s->height - artist_get_y(s->cursor_pos); *y -= (s->cursor_cntrl & 0x0f); @@ -1056,6 +1060,8 @@ static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val, break; case HORIZ_BACKPORCH: + /* overwrite HP-UX settings to fix X cursor position. */ + val = (NGLE_MAX_SPRITE_SIZE << 16) + (NGLE_MAX_SPRITE_SIZE << 8); combine_write_reg(addr, val, size, &s->horiz_backporch); break; From 37cbfcebdd0e7ffbfb8332a8794a91a4a8f1819d Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 13 May 2022 06:56:23 -0400 Subject: [PATCH 401/935] vhost-user: more master/slave things we switched to front-end/back-end, but newer patches reintroduced old language. Fix this up. Signed-off-by: Michael S. Tsirkin --- docs/interop/vhost-user.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst index 73e710fe32..3c12607517 100644 --- a/docs/interop/vhost-user.rst +++ b/docs/interop/vhost-user.rst @@ -340,7 +340,7 @@ drivers cannot negotiate it. This reserved feature bit was reused by the vhost-user protocol to add vhost-user protocol feature negotiation in a backwards compatible -fashion. Old vhost-user master and slave implementations continue to +fashion. Old vhost-user front-end and back-end implementations continue to work even though they are not aware of vhost-user protocol feature negotiation. From 76b1b64370007234279ea4cc8b09c98cbd2523de Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 7 Apr 2022 15:36:55 +0200 Subject: [PATCH 402/935] docs/vhost-user: Clarifications for VHOST_USER_ADD/REM_MEM_REG The specification for VHOST_USER_ADD/REM_MEM_REG messages is unclear in several points, which has led to clients having incompatible implementations. This changes the specification to be more explicit about them: * VHOST_USER_ADD_MEM_REG is not specified as receiving a file descriptor, though it obviously does need to do so. All implementations agree on this one, fix the specification. * VHOST_USER_REM_MEM_REG is not specified as receiving a file descriptor either, and it also has no reason to do so. rust-vmm does not send file descriptors for removing a memory region (in agreement with the specification), libvhost-user and QEMU do (which is a bug), though libvhost-user doesn't actually make any use of it. Change the specification so that for compatibility QEMU's behaviour becomes legal, even if discouraged, but rust-vmm's behaviour becomes the explicitly recommended mode of operation. * VHOST_USER_ADD_MEM_REG doesn't have a documented return value, which is the desired behaviour in the non-postcopy case. It also implemented like this in QEMU and rust-vmm, though libvhost-user is buggy and sometimes sends an unexpected reply. This will be fixed in a separate patch. However, in postcopy mode it does reply like VHOST_USER_SET_MEM_TABLE. This behaviour is shared between libvhost-user and QEMU; rust-vmm doesn't implement postcopy mode yet. Mention it explicitly in the spec. * The specification doesn't mention how VHOST_USER_REM_MEM_REG identifies the memory region to be removed. Change it to describe the existing behaviour of libvhost-user (guest address, user address and size must match). Signed-off-by: Kevin Wolf Message-Id: <20220407133657.155281-2-kwolf@redhat.com> Reviewed-by: Raphael Norwitz Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Stefan Hajnoczi --- docs/interop/vhost-user.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst index 3c12607517..a99ba4433c 100644 --- a/docs/interop/vhost-user.rst +++ b/docs/interop/vhost-user.rst @@ -1376,6 +1376,14 @@ Front-end message types For further details on postcopy, see ``VHOST_USER_SET_MEM_TABLE``. They apply to ``VHOST_USER_ADD_MEM_REG`` accordingly. + Exactly one file descriptor from which the memory is mapped is + passed in the ancillary data. + + In postcopy mode (see ``VHOST_USER_POSTCOPY_LISTEN``), the back-end + replies with the bases of the memory mapped region to the front-end. + For further details on postcopy, see ``VHOST_USER_SET_MEM_TABLE``. + They apply to ``VHOST_USER_ADD_MEM_REG`` accordingly. + ``VHOST_USER_REM_MEM_REG`` :id: 38 :equivalent ioctl: N/A @@ -1400,6 +1408,14 @@ Front-end message types accept messages with one file descriptor. If a file descriptor is passed, the back-end MUST close it without using it otherwise. + The memory region to be removed is identified by its guest address, + user address and size. The mmap offset is ignored. + + No file descriptors SHOULD be passed in the ancillary data. For + compatibility with existing incorrect implementations, the back-end MAY + accept messages with one file descriptor. If a file descriptor is + passed, the back-end MUST close it without using it otherwise. + ``VHOST_USER_SET_STATUS`` :id: 39 :equivalent ioctl: VHOST_VDPA_SET_STATUS From 8e58f6ec24f64b7d88f2b01d39049011f5097fae Mon Sep 17 00:00:00 2001 From: Francisco Iglesias Date: Tue, 12 Apr 2022 00:18:35 +0200 Subject: [PATCH 403/935] include/hw/pci/pcie_host: Correct PCIE_MMCFG_BUS_MASK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to [1] address bits 27 - 20 are mapped to the bus number (the TLPs bus number field is 8 bits). Below is the formula taken from Table 7-1 in [1]. " Memory Address | PCI Express Configuration Space A[(20+n-1):20] | Bus Number, 1 ≤ n ≤ 8 " [1] PCI Express® Base Specification Revision 5.0 Version 1.0 Signed-off-by: Francisco Iglesias Message-Id: <20220411221836.17699-2-frasse.iglesias@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/hw/pci/pcie_host.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/hw/pci/pcie_host.h b/include/hw/pci/pcie_host.h index 076457b270..b3c8ce973c 100644 --- a/include/hw/pci/pcie_host.h +++ b/include/hw/pci/pcie_host.h @@ -60,7 +60,7 @@ void pcie_host_mmcfg_update(PCIExpressHost *e, /* * PCI express ECAM (Enhanced Configuration Address Mapping) format. * AKA mmcfg address - * bit 20 - 28: bus number + * bit 20 - 27: bus number * bit 15 - 19: device number * bit 12 - 14: function number * bit 0 - 11: offset in configuration space of a given device @@ -68,7 +68,7 @@ void pcie_host_mmcfg_update(PCIExpressHost *e, #define PCIE_MMCFG_SIZE_MAX (1ULL << 29) #define PCIE_MMCFG_SIZE_MIN (1ULL << 20) #define PCIE_MMCFG_BUS_BIT 20 -#define PCIE_MMCFG_BUS_MASK 0x1ff +#define PCIE_MMCFG_BUS_MASK 0xff #define PCIE_MMCFG_DEVFN_BIT 12 #define PCIE_MMCFG_DEVFN_MASK 0xff #define PCIE_MMCFG_CONFOFFSET_MASK 0xfff From 1f1a7b226923c655530d6bbe7d85d87e3df2d6f1 Mon Sep 17 00:00:00 2001 From: Francisco Iglesias Date: Tue, 12 Apr 2022 00:18:36 +0200 Subject: [PATCH 404/935] include/hw/pci/pcie_host: Correct PCIE_MMCFG_SIZE_MAX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to 7.2.2 in [1] bit 27 is the last bit that can be part of the bus number, this makes the ECAM max size equal to '1 << 28'. This patch restores back this value into the PCIE_MMCFG_SIZE_MAX define (which was changed in commit 58d5b22bbd5 ("ppc4xx: Add device models found in PPC440 core SoCs")). [1] PCI Express® Base Specification Revision 5.0 Version 1.0 Signed-off-by: Francisco Iglesias Message-Id: <20220411221836.17699-3-frasse.iglesias@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/hw/pci/pcie_host.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/pci/pcie_host.h b/include/hw/pci/pcie_host.h index b3c8ce973c..82d92177da 100644 --- a/include/hw/pci/pcie_host.h +++ b/include/hw/pci/pcie_host.h @@ -65,7 +65,7 @@ void pcie_host_mmcfg_update(PCIExpressHost *e, * bit 12 - 14: function number * bit 0 - 11: offset in configuration space of a given device */ -#define PCIE_MMCFG_SIZE_MAX (1ULL << 29) +#define PCIE_MMCFG_SIZE_MAX (1ULL << 28) #define PCIE_MMCFG_SIZE_MIN (1ULL << 20) #define PCIE_MMCFG_BUS_BIT 20 #define PCIE_MMCFG_BUS_MASK 0xff From 9dee7e510969787be49771e4653a123a26d1069f Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 10 Mar 2022 20:28:10 +0800 Subject: [PATCH 405/935] hw/i386: Make pit a property of common x86 base machine type Both pc and microvm have pit property individually. Let's just make it the property of common x86 base machine type. Signed-off-by: Xiaoyao Li Reviewed-by: Sergio Lopez Message-Id: <20220310122811.807794-2-xiaoyao.li@intel.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/microvm.c | 27 +-------------------------- hw/i386/pc.c | 24 +++--------------------- hw/i386/x86.c | 25 +++++++++++++++++++++++++ include/hw/i386/microvm.h | 2 -- include/hw/i386/pc.h | 2 -- include/hw/i386/x86.h | 2 ++ 6 files changed, 31 insertions(+), 51 deletions(-) diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index 4b3b1dd262..89b555a2f5 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -257,7 +257,7 @@ static void microvm_devices_init(MicrovmMachineState *mms) g_free(i8259); } - if (mms->pit == ON_OFF_AUTO_ON || mms->pit == ON_OFF_AUTO_AUTO) { + if (x86ms->pit == ON_OFF_AUTO_ON || x86ms->pit == ON_OFF_AUTO_AUTO) { if (kvm_pit_in_kernel()) { kvm_pit_init(isa_bus, 0x40); } else { @@ -508,23 +508,6 @@ static void microvm_machine_set_pic(Object *obj, Visitor *v, const char *name, visit_type_OnOffAuto(v, name, &mms->pic, errp); } -static void microvm_machine_get_pit(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - MicrovmMachineState *mms = MICROVM_MACHINE(obj); - OnOffAuto pit = mms->pit; - - visit_type_OnOffAuto(v, name, &pit, errp); -} - -static void microvm_machine_set_pit(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - MicrovmMachineState *mms = MICROVM_MACHINE(obj); - - visit_type_OnOffAuto(v, name, &mms->pit, errp); -} - static void microvm_machine_get_rtc(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -650,7 +633,6 @@ static void microvm_machine_initfn(Object *obj) /* Configuration */ mms->pic = ON_OFF_AUTO_AUTO; - mms->pit = ON_OFF_AUTO_AUTO; mms->rtc = ON_OFF_AUTO_AUTO; mms->pcie = ON_OFF_AUTO_AUTO; mms->ioapic2 = ON_OFF_AUTO_AUTO; @@ -709,13 +691,6 @@ static void microvm_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, MICROVM_MACHINE_PIC, "Enable i8259 PIC"); - object_class_property_add(oc, MICROVM_MACHINE_PIT, "OnOffAuto", - microvm_machine_get_pit, - microvm_machine_set_pit, - NULL, NULL); - object_class_property_set_description(oc, MICROVM_MACHINE_PIT, - "Enable i8254 PIT"); - object_class_property_add(oc, MICROVM_MACHINE_RTC, "OnOffAuto", microvm_machine_get_rtc, microvm_machine_set_rtc, diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 15f37d8dc6..7c39c91335 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1123,6 +1123,7 @@ void pc_basic_device_init(struct PCMachineState *pcms, ISADevice *pit = NULL; MemoryRegion *ioport80_io = g_new(MemoryRegion, 1); MemoryRegion *ioportF0_io = g_new(MemoryRegion, 1); + X86MachineState *x86ms = X86_MACHINE(pcms); memory_region_init_io(ioport80_io, NULL, &ioport80_io_ops, NULL, "ioport80", 1); memory_region_add_subregion(isa_bus->address_space_io, 0x80, ioport80_io); @@ -1167,7 +1168,8 @@ void pc_basic_device_init(struct PCMachineState *pcms, qemu_register_boot_set(pc_boot_set, *rtc_state); - if (!xen_enabled() && pcms->pit_enabled) { + if (!xen_enabled() && + (x86ms->pit == ON_OFF_AUTO_AUTO || x86ms->pit == ON_OFF_AUTO_ON)) { if (kvm_pit_in_kernel()) { pit = kvm_pit_init(isa_bus, 0x40); } else { @@ -1537,20 +1539,6 @@ static void pc_machine_set_sata(Object *obj, bool value, Error **errp) pcms->sata_enabled = value; } -static bool pc_machine_get_pit(Object *obj, Error **errp) -{ - PCMachineState *pcms = PC_MACHINE(obj); - - return pcms->pit_enabled; -} - -static void pc_machine_set_pit(Object *obj, bool value, Error **errp) -{ - PCMachineState *pcms = PC_MACHINE(obj); - - pcms->pit_enabled = value; -} - static bool pc_machine_get_hpet(Object *obj, Error **errp) { PCMachineState *pcms = PC_MACHINE(obj); @@ -1707,7 +1695,6 @@ static void pc_machine_initfn(Object *obj) pcms->acpi_build_enabled = PC_MACHINE_GET_CLASS(pcms)->has_acpi_build; pcms->smbus_enabled = true; pcms->sata_enabled = true; - pcms->pit_enabled = true; pcms->i8042_enabled = true; pcms->max_fw_size = 8 * MiB; #ifdef CONFIG_HPET @@ -1836,11 +1823,6 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, PC_MACHINE_SATA, "Enable/disable Serial ATA bus"); - object_class_property_add_bool(oc, PC_MACHINE_PIT, - pc_machine_get_pit, pc_machine_set_pit); - object_class_property_set_description(oc, PC_MACHINE_PIT, - "Enable/disable Intel 8254 programmable interval timer emulation"); - object_class_property_add_bool(oc, "hpet", pc_machine_get_hpet, pc_machine_set_hpet); object_class_property_set_description(oc, "hpet", diff --git a/hw/i386/x86.c b/hw/i386/x86.c index f79e720cc2..784d54efa9 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -1244,6 +1244,23 @@ static void x86_machine_set_acpi(Object *obj, Visitor *v, const char *name, visit_type_OnOffAuto(v, name, &x86ms->acpi, errp); } +static void x86_machine_get_pit(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + X86MachineState *x86ms = X86_MACHINE(obj); + OnOffAuto pit = x86ms->pit; + + visit_type_OnOffAuto(v, name, &pit, errp); +} + +static void x86_machine_set_pit(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + X86MachineState *x86ms = X86_MACHINE(obj);; + + visit_type_OnOffAuto(v, name, &x86ms->pit, errp); +} + static char *x86_machine_get_oem_id(Object *obj, Error **errp) { X86MachineState *x86ms = X86_MACHINE(obj); @@ -1333,6 +1350,7 @@ static void x86_machine_initfn(Object *obj) x86ms->smm = ON_OFF_AUTO_AUTO; x86ms->acpi = ON_OFF_AUTO_AUTO; + x86ms->pit = ON_OFF_AUTO_AUTO; x86ms->pci_irq_mask = ACPI_BUILD_PCI_IRQS; x86ms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6); x86ms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8); @@ -1364,6 +1382,13 @@ static void x86_machine_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, X86_MACHINE_ACPI, "Enable ACPI"); + object_class_property_add(oc, X86_MACHINE_PIT, "OnOffAuto", + x86_machine_get_pit, + x86_machine_set_pit, + NULL, NULL); + object_class_property_set_description(oc, X86_MACHINE_PIT, + "Enable i8254 PIT"); + object_class_property_add_str(oc, X86_MACHINE_OEM_ID, x86_machine_get_oem_id, x86_machine_set_oem_id); diff --git a/include/hw/i386/microvm.h b/include/hw/i386/microvm.h index efcbd926fd..83f9ac0b2a 100644 --- a/include/hw/i386/microvm.h +++ b/include/hw/i386/microvm.h @@ -67,7 +67,6 @@ #define PCIE_ECAM_SIZE 0x10000000 /* Machine type options */ -#define MICROVM_MACHINE_PIT "pit" #define MICROVM_MACHINE_PIC "pic" #define MICROVM_MACHINE_RTC "rtc" #define MICROVM_MACHINE_PCIE "pcie" @@ -87,7 +86,6 @@ struct MicrovmMachineState { /* Machine type options */ OnOffAuto pic; - OnOffAuto pit; OnOffAuto rtc; OnOffAuto pcie; OnOffAuto ioapic2; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index aff8add155..ffcac5121e 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -46,7 +46,6 @@ typedef struct PCMachineState { bool acpi_build_enabled; bool smbus_enabled; bool sata_enabled; - bool pit_enabled; bool hpet_enabled; bool i8042_enabled; bool default_bus_bypass_iommu; @@ -64,7 +63,6 @@ typedef struct PCMachineState { #define PC_MACHINE_VMPORT "vmport" #define PC_MACHINE_SMBUS "smbus" #define PC_MACHINE_SATA "sata" -#define PC_MACHINE_PIT "pit" #define PC_MACHINE_I8042 "i8042" #define PC_MACHINE_MAX_FW_SIZE "max-fw-size" #define PC_MACHINE_SMBIOS_EP "smbios-entry-point-type" diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h index 4841a49f86..b81fce54a0 100644 --- a/include/hw/i386/x86.h +++ b/include/hw/i386/x86.h @@ -65,6 +65,7 @@ struct X86MachineState { OnOffAuto smm; OnOffAuto acpi; + OnOffAuto pit; char *oem_id; char *oem_table_id; @@ -84,6 +85,7 @@ struct X86MachineState { #define X86_MACHINE_SMM "smm" #define X86_MACHINE_ACPI "acpi" +#define X86_MACHINE_PIT "pit" #define X86_MACHINE_OEM_ID "x-oem-id" #define X86_MACHINE_OEM_TABLE_ID "x-oem-table-id" #define X86_MACHINE_BUS_LOCK_RATELIMIT "bus-lock-ratelimit" From c300bbe8d2a84003775c2ebb2b2885b80b1d9c32 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 10 Mar 2022 20:28:11 +0800 Subject: [PATCH 406/935] hw/i386: Make pic a property of common x86 base machine type Legacy PIC (8259) cannot be supported for TDX guests since TDX module doesn't allow directly interrupt injection. Using posted interrupts for the PIC is not a viable option as the guest BIOS/kernel will not do EOI for PIC IRQs, i.e. will leave the vIRR bit set. Make PIC the property of common x86 machine type. Hence all x86 machines, including microvm, can disable it. Signed-off-by: Xiaoyao Li Reviewed-by: Sergio Lopez Message-Id: <20220310122811.807794-3-xiaoyao.li@intel.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/microvm.c | 27 +-------------------------- hw/i386/pc_piix.c | 4 +++- hw/i386/pc_q35.c | 4 +++- hw/i386/x86.c | 25 +++++++++++++++++++++++++ include/hw/i386/microvm.h | 2 -- include/hw/i386/x86.h | 2 ++ 6 files changed, 34 insertions(+), 30 deletions(-) diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index 89b555a2f5..754f1d0593 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -247,7 +247,7 @@ static void microvm_devices_init(MicrovmMachineState *mms) x86ms->pci_irq_mask = 0; } - if (mms->pic == ON_OFF_AUTO_ON || mms->pic == ON_OFF_AUTO_AUTO) { + if (x86ms->pic == ON_OFF_AUTO_ON || x86ms->pic == ON_OFF_AUTO_AUTO) { qemu_irq *i8259; i8259 = i8259_init(isa_bus, x86_allocate_cpu_irq()); @@ -491,23 +491,6 @@ static void microvm_machine_reset(MachineState *machine) } } -static void microvm_machine_get_pic(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - MicrovmMachineState *mms = MICROVM_MACHINE(obj); - OnOffAuto pic = mms->pic; - - visit_type_OnOffAuto(v, name, &pic, errp); -} - -static void microvm_machine_set_pic(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - MicrovmMachineState *mms = MICROVM_MACHINE(obj); - - visit_type_OnOffAuto(v, name, &mms->pic, errp); -} - static void microvm_machine_get_rtc(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -632,7 +615,6 @@ static void microvm_machine_initfn(Object *obj) MicrovmMachineState *mms = MICROVM_MACHINE(obj); /* Configuration */ - mms->pic = ON_OFF_AUTO_AUTO; mms->rtc = ON_OFF_AUTO_AUTO; mms->pcie = ON_OFF_AUTO_AUTO; mms->ioapic2 = ON_OFF_AUTO_AUTO; @@ -684,13 +666,6 @@ static void microvm_class_init(ObjectClass *oc, void *data) x86mc->fwcfg_dma_enabled = true; - object_class_property_add(oc, MICROVM_MACHINE_PIC, "OnOffAuto", - microvm_machine_get_pic, - microvm_machine_set_pic, - NULL, NULL); - object_class_property_set_description(oc, MICROVM_MACHINE_PIC, - "Enable i8259 PIC"); - object_class_property_add(oc, MICROVM_MACHINE_RTC, "OnOffAuto", microvm_machine_get_rtc, microvm_machine_set_rtc, diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index f843dd906f..578e537b35 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -218,7 +218,9 @@ static void pc_init1(MachineState *machine, } isa_bus_irqs(isa_bus, x86ms->gsi); - pc_i8259_create(isa_bus, gsi_state->i8259_irq); + if (x86ms->pic == ON_OFF_AUTO_ON || x86ms->pic == ON_OFF_AUTO_AUTO) { + pc_i8259_create(isa_bus, gsi_state->i8259_irq); + } if (pcmc->pci_enabled) { ioapic_init_gsi(gsi_state, "i440fx"); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 302288342a..42eb8b9707 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -265,7 +265,9 @@ static void pc_q35_init(MachineState *machine) pci_bus_set_route_irq_fn(host_bus, ich9_route_intx_pin_to_irq); isa_bus = ich9_lpc->isa_bus; - pc_i8259_create(isa_bus, gsi_state->i8259_irq); + if (x86ms->pic == ON_OFF_AUTO_ON || x86ms->pic == ON_OFF_AUTO_AUTO) { + pc_i8259_create(isa_bus, gsi_state->i8259_irq); + } if (pcmc->pci_enabled) { ioapic_init_gsi(gsi_state, "q35"); diff --git a/hw/i386/x86.c b/hw/i386/x86.c index 784d54efa9..78b05ab7a2 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -1261,6 +1261,23 @@ static void x86_machine_set_pit(Object *obj, Visitor *v, const char *name, visit_type_OnOffAuto(v, name, &x86ms->pit, errp); } +static void x86_machine_get_pic(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + X86MachineState *x86ms = X86_MACHINE(obj); + OnOffAuto pic = x86ms->pic; + + visit_type_OnOffAuto(v, name, &pic, errp); +} + +static void x86_machine_set_pic(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + X86MachineState *x86ms = X86_MACHINE(obj); + + visit_type_OnOffAuto(v, name, &x86ms->pic, errp); +} + static char *x86_machine_get_oem_id(Object *obj, Error **errp) { X86MachineState *x86ms = X86_MACHINE(obj); @@ -1351,6 +1368,7 @@ static void x86_machine_initfn(Object *obj) x86ms->smm = ON_OFF_AUTO_AUTO; x86ms->acpi = ON_OFF_AUTO_AUTO; x86ms->pit = ON_OFF_AUTO_AUTO; + x86ms->pic = ON_OFF_AUTO_AUTO; x86ms->pci_irq_mask = ACPI_BUILD_PCI_IRQS; x86ms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6); x86ms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8); @@ -1389,6 +1407,13 @@ static void x86_machine_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, X86_MACHINE_PIT, "Enable i8254 PIT"); + object_class_property_add(oc, X86_MACHINE_PIC, "OnOffAuto", + x86_machine_get_pic, + x86_machine_set_pic, + NULL, NULL); + object_class_property_set_description(oc, X86_MACHINE_PIC, + "Enable i8259 PIC"); + object_class_property_add_str(oc, X86_MACHINE_OEM_ID, x86_machine_get_oem_id, x86_machine_set_oem_id); diff --git a/include/hw/i386/microvm.h b/include/hw/i386/microvm.h index 83f9ac0b2a..fad97a891d 100644 --- a/include/hw/i386/microvm.h +++ b/include/hw/i386/microvm.h @@ -67,7 +67,6 @@ #define PCIE_ECAM_SIZE 0x10000000 /* Machine type options */ -#define MICROVM_MACHINE_PIC "pic" #define MICROVM_MACHINE_RTC "rtc" #define MICROVM_MACHINE_PCIE "pcie" #define MICROVM_MACHINE_IOAPIC2 "ioapic2" @@ -85,7 +84,6 @@ struct MicrovmMachineState { X86MachineState parent; /* Machine type options */ - OnOffAuto pic; OnOffAuto rtc; OnOffAuto pcie; OnOffAuto ioapic2; diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h index b81fce54a0..9089bdd99c 100644 --- a/include/hw/i386/x86.h +++ b/include/hw/i386/x86.h @@ -66,6 +66,7 @@ struct X86MachineState { OnOffAuto smm; OnOffAuto acpi; OnOffAuto pit; + OnOffAuto pic; char *oem_id; char *oem_table_id; @@ -86,6 +87,7 @@ struct X86MachineState { #define X86_MACHINE_SMM "smm" #define X86_MACHINE_ACPI "acpi" #define X86_MACHINE_PIT "pit" +#define X86_MACHINE_PIC "pic" #define X86_MACHINE_OEM_ID "x-oem-id" #define X86_MACHINE_OEM_TABLE_ID "x-oem-table-id" #define X86_MACHINE_BUS_LOCK_RATELIMIT "bus-lock-ratelimit" From 18aa91cddd8caa14aae094f9b59c0381959cb320 Mon Sep 17 00:00:00 2001 From: Wei Huang Date: Fri, 22 Apr 2022 00:51:46 -0500 Subject: [PATCH 407/935] hw/i386/amd_iommu: Fix IOMMU event log encoding errors Coverity issues several UNINIT warnings against amd_iommu.c [1]. This patch fixes them by clearing evt before encoding. On top of it, this patch changes the event log size to 16 bytes per IOMMU specification, and fixes the event log entry format in amdvi_encode_event(). [1] CID 1487116/1487200/1487190/1487232/1487115/1487258 Reported-by: Peter Maydell Signed-off-by: Wei Huang Message-Id: <20220422055146.3312226-1-wei.huang2@amd.com> Reviewed-by: Peter Maydell Acked-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/amd_iommu.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index ea8eaeb330..725f69095b 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -201,15 +201,18 @@ static void amdvi_setevent_bits(uint64_t *buffer, uint64_t value, int start, /* * AMDVi event structure * 0:15 -> DeviceID - * 55:63 -> event type + miscellaneous info - * 63:127 -> related address + * 48:63 -> event type + miscellaneous info + * 64:127 -> related address */ static void amdvi_encode_event(uint64_t *evt, uint16_t devid, uint64_t addr, uint16_t info) { + evt[0] = 0; + evt[1] = 0; + amdvi_setevent_bits(evt, devid, 0, 16); - amdvi_setevent_bits(evt, info, 55, 8); - amdvi_setevent_bits(evt, addr, 63, 64); + amdvi_setevent_bits(evt, info, 48, 16); + amdvi_setevent_bits(evt, addr, 64, 64); } /* log an error encountered during a page walk * @@ -218,7 +221,7 @@ static void amdvi_encode_event(uint64_t *evt, uint16_t devid, uint64_t addr, static void amdvi_page_fault(AMDVIState *s, uint16_t devid, hwaddr addr, uint16_t info) { - uint64_t evt[4]; + uint64_t evt[2]; info |= AMDVI_EVENT_IOPF_I | AMDVI_EVENT_IOPF; amdvi_encode_event(evt, devid, addr, info); @@ -234,7 +237,7 @@ static void amdvi_page_fault(AMDVIState *s, uint16_t devid, static void amdvi_log_devtab_error(AMDVIState *s, uint16_t devid, hwaddr devtab, uint16_t info) { - uint64_t evt[4]; + uint64_t evt[2]; info |= AMDVI_EVENT_DEV_TAB_HW_ERROR; @@ -248,7 +251,8 @@ static void amdvi_log_devtab_error(AMDVIState *s, uint16_t devid, */ static void amdvi_log_command_error(AMDVIState *s, hwaddr addr) { - uint64_t evt[4], info = AMDVI_EVENT_COMMAND_HW_ERROR; + uint64_t evt[2]; + uint16_t info = AMDVI_EVENT_COMMAND_HW_ERROR; amdvi_encode_event(evt, 0, addr, info); amdvi_log_event(s, evt); @@ -261,7 +265,7 @@ static void amdvi_log_command_error(AMDVIState *s, hwaddr addr) static void amdvi_log_illegalcom_error(AMDVIState *s, uint16_t info, hwaddr addr) { - uint64_t evt[4]; + uint64_t evt[2]; info |= AMDVI_EVENT_ILLEGAL_COMMAND_ERROR; amdvi_encode_event(evt, 0, addr, info); @@ -276,7 +280,7 @@ static void amdvi_log_illegalcom_error(AMDVIState *s, uint16_t info, static void amdvi_log_illegaldevtab_error(AMDVIState *s, uint16_t devid, hwaddr addr, uint16_t info) { - uint64_t evt[4]; + uint64_t evt[2]; info |= AMDVI_EVENT_ILLEGAL_DEVTAB_ENTRY; amdvi_encode_event(evt, devid, addr, info); @@ -288,7 +292,7 @@ static void amdvi_log_illegaldevtab_error(AMDVIState *s, uint16_t devid, static void amdvi_log_pagetab_error(AMDVIState *s, uint16_t devid, hwaddr addr, uint16_t info) { - uint64_t evt[4]; + uint64_t evt[2]; info |= AMDVI_EVENT_PAGE_TAB_HW_ERROR; amdvi_encode_event(evt, devid, addr, info); From aa8581945a13712ff3eed0ad3ba7a9664fc1604b Mon Sep 17 00:00:00 2001 From: Si-Wei Liu Date: Fri, 6 May 2022 19:28:12 -0700 Subject: [PATCH 408/935] virtio-net: setup vhost_dev and notifiers for cvq only when feature is negotiated When the control virtqueue feature is absent or not negotiated, vhost_net_start() still tries to set up vhost_dev and install vhost notifiers for the control virtqueue, which results in erroneous ioctl calls with incorrect queue index sending down to driver. Do that only when needed. Fixes: 22288fe ("virtio-net: vhost control virtqueue support") Signed-off-by: Si-Wei Liu Acked-by: Jason Wang Message-Id: <1651890498-24478-2-git-send-email-si-wei.liu@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index a788f1c5c7..7545a16ed7 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -245,7 +245,8 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) VirtIODevice *vdev = VIRTIO_DEVICE(n); NetClientState *nc = qemu_get_queue(n->nic); int queue_pairs = n->multiqueue ? n->max_queue_pairs : 1; - int cvq = n->max_ncs - n->max_queue_pairs; + int cvq = virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ) ? + n->max_ncs - n->max_queue_pairs : 0; if (!get_vhost_net(nc->peer)) { return; From 68b0a6395f36a8f48f56f46d05f30be2067598b0 Mon Sep 17 00:00:00 2001 From: Si-Wei Liu Date: Fri, 6 May 2022 19:28:13 -0700 Subject: [PATCH 409/935] virtio-net: align ctrl_vq index for non-mq guest for vhost_vdpa With MQ enabled vdpa device and non-MQ supporting guest e.g. booting vdpa with mq=on over OVMF of single vqp, below assert failure is seen: ../hw/virtio/vhost-vdpa.c:560: vhost_vdpa_get_vq_index: Assertion `idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs' failed. 0 0x00007f8ce3ff3387 in raise () at /lib64/libc.so.6 1 0x00007f8ce3ff4a78 in abort () at /lib64/libc.so.6 2 0x00007f8ce3fec1a6 in __assert_fail_base () at /lib64/libc.so.6 3 0x00007f8ce3fec252 in () at /lib64/libc.so.6 4 0x0000558f52d79421 in vhost_vdpa_get_vq_index (dev=, idx=) at ../hw/virtio/vhost-vdpa.c:563 5 0x0000558f52d79421 in vhost_vdpa_get_vq_index (dev=, idx=) at ../hw/virtio/vhost-vdpa.c:558 6 0x0000558f52d7329a in vhost_virtqueue_mask (hdev=0x558f55c01800, vdev=0x558f568f91f0, n=2, mask=) at ../hw/virtio/vhost.c:1557 7 0x0000558f52c6b89a in virtio_pci_set_guest_notifier (d=d@entry=0x558f568f0f60, n=n@entry=2, assign=assign@entry=true, with_irqfd=with_irqfd@entry=false) at ../hw/virtio/virtio-pci.c:974 8 0x0000558f52c6c0d8 in virtio_pci_set_guest_notifiers (d=0x558f568f0f60, nvqs=3, assign=true) at ../hw/virtio/virtio-pci.c:1019 9 0x0000558f52bf091d in vhost_net_start (dev=dev@entry=0x558f568f91f0, ncs=0x558f56937cd0, data_queue_pairs=data_queue_pairs@entry=1, cvq=cvq@entry=1) at ../hw/net/vhost_net.c:361 10 0x0000558f52d4e5e7 in virtio_net_set_status (status=, n=0x558f568f91f0) at ../hw/net/virtio-net.c:289 11 0x0000558f52d4e5e7 in virtio_net_set_status (vdev=0x558f568f91f0, status=15 '\017') at ../hw/net/virtio-net.c:370 12 0x0000558f52d6c4b2 in virtio_set_status (vdev=vdev@entry=0x558f568f91f0, val=val@entry=15 '\017') at ../hw/virtio/virtio.c:1945 13 0x0000558f52c69eff in virtio_pci_common_write (opaque=0x558f568f0f60, addr=, val=, size=) at ../hw/virtio/virtio-pci.c:1292 14 0x0000558f52d15d6e in memory_region_write_accessor (mr=0x558f568f19d0, addr=20, value=, size=1, shift=, mask=, attrs=...) at ../softmmu/memory.c:492 15 0x0000558f52d127de in access_with_adjusted_size (addr=addr@entry=20, value=value@entry=0x7f8cdbffe748, size=size@entry=1, access_size_min=, access_size_max=, access_fn=0x558f52d15cf0 , mr=0x558f568f19d0, attrs=...) at ../softmmu/memory.c:554 16 0x0000558f52d157ef in memory_region_dispatch_write (mr=mr@entry=0x558f568f19d0, addr=20, data=, op=, attrs=attrs@entry=...) at ../softmmu/memory.c:1504 17 0x0000558f52d078e7 in flatview_write_continue (fv=fv@entry=0x7f8accbc3b90, addr=addr@entry=103079215124, attrs=..., ptr=ptr@entry=0x7f8ce6300028, len=len@entry=1, addr1=, l=, mr=0x558f568f19d0) at /home/opc/qemu-upstream/include/qemu/host-utils.h:165 18 0x0000558f52d07b06 in flatview_write (fv=0x7f8accbc3b90, addr=103079215124, attrs=..., buf=0x7f8ce6300028, len=1) at ../softmmu/physmem.c:2822 19 0x0000558f52d0b36b in address_space_write (as=, addr=, attrs=..., buf=buf@entry=0x7f8ce6300028, len=) at ../softmmu/physmem.c:2914 20 0x0000558f52d0b3da in address_space_rw (as=, addr=, attrs=..., attrs@entry=..., buf=buf@entry=0x7f8ce6300028, len=, is_write=) at ../softmmu/physmem.c:2924 21 0x0000558f52dced09 in kvm_cpu_exec (cpu=cpu@entry=0x558f55c2da60) at ../accel/kvm/kvm-all.c:2903 22 0x0000558f52dcfabd in kvm_vcpu_thread_fn (arg=arg@entry=0x558f55c2da60) at ../accel/kvm/kvm-accel-ops.c:49 23 0x0000558f52f9f04a in qemu_thread_start (args=) at ../util/qemu-thread-posix.c:556 24 0x00007f8ce4392ea5 in start_thread () at /lib64/libpthread.so.0 25 0x00007f8ce40bb9fd in clone () at /lib64/libc.so.6 The cause for the assert failure is due to that the vhost_dev index for the ctrl vq was not aligned with actual one in use by the guest. Upon multiqueue feature negotiation in virtio_net_set_multiqueue(), if guest doesn't support multiqueue, the guest vq layout would shrink to a single queue pair, consisting of 3 vqs in total (rx, tx and ctrl). This results in ctrl_vq taking a different vhost_dev group index than the default. We can map vq to the correct vhost_dev group by checking if MQ is supported by guest and successfully negotiated. Since the MQ feature is only present along with CTRL_VQ, we ensure the index 2 is only meant for the control vq while MQ is not supported by guest. Fixes: 22288fe ("virtio-net: vhost control virtqueue support") Suggested-by: Jason Wang Signed-off-by: Si-Wei Liu Acked-by: Jason Wang Message-Id: <1651890498-24478-3-git-send-email-si-wei.liu@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 7545a16ed7..1ea524ff09 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -14,6 +14,7 @@ #include "qemu/osdep.h" #include "qemu/atomic.h" #include "qemu/iov.h" +#include "qemu/log.h" #include "qemu/main-loop.h" #include "qemu/module.h" #include "hw/virtio/virtio.h" @@ -3172,8 +3173,22 @@ static NetClientInfo net_virtio_info = { static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) { VirtIONet *n = VIRTIO_NET(vdev); - NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); + NetClientState *nc; assert(n->vhost_started); + if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_MQ) && idx == 2) { + /* Must guard against invalid features and bogus queue index + * from being set by malicious guest, or penetrated through + * buggy migration stream. + */ + if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: bogus vq index ignored\n", __func__); + return false; + } + nc = qemu_get_subqueue(n->nic, n->max_queue_pairs); + } else { + nc = qemu_get_subqueue(n->nic, vq2q(idx)); + } return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx); } @@ -3181,8 +3196,22 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) { VirtIONet *n = VIRTIO_NET(vdev); - NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); + NetClientState *nc; assert(n->vhost_started); + if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_MQ) && idx == 2) { + /* Must guard against invalid features and bogus queue index + * from being set by malicious guest, or penetrated through + * buggy migration stream. + */ + if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: bogus vq index ignored\n", __func__); + return; + } + nc = qemu_get_subqueue(n->nic, n->max_queue_pairs); + } else { + nc = qemu_get_subqueue(n->nic, vq2q(idx)); + } vhost_net_virtqueue_mask(get_vhost_net(nc->peer), vdev, idx, mask); } From 9bd055073e375c8a0d7ebce925e05d914d69fc7f Mon Sep 17 00:00:00 2001 From: Si-Wei Liu Date: Fri, 6 May 2022 19:28:14 -0700 Subject: [PATCH 410/935] vhost-vdpa: fix improper cleanup in net_init_vhost_vdpa ... such that no memory leaks on dangling net clients in case of error. Signed-off-by: Si-Wei Liu Acked-by: Jason Wang Message-Id: <1651890498-24478-4-git-send-email-si-wei.liu@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 1e9fe47c03..df1e69ee72 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -306,7 +306,9 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, err: if (i) { - qemu_del_net_client(ncs[0]); + for (i--; i >= 0; i--) { + qemu_del_net_client(ncs[i]); + } } qemu_close(vdpa_device_fd); From 6f3910b5eee00b8cc959e94659c0d524c482a418 Mon Sep 17 00:00:00 2001 From: Si-Wei Liu Date: Fri, 6 May 2022 19:28:15 -0700 Subject: [PATCH 411/935] vhost-net: fix improper cleanup in vhost_net_start vhost_net_start() missed a corresponding stop_one() upon error from vhost_set_vring_enable(). While at it, make the error handling for err_start more robust. No real issue was found due to this though. Signed-off-by: Si-Wei Liu Acked-by: Jason Wang Message-Id: <1651890498-24478-5-git-send-email-si-wei.liu@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/vhost_net.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index df0f050548..ccac5b7a64 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -381,6 +381,7 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, r = vhost_set_vring_enable(peer, peer->vring_enable); if (r < 0) { + vhost_net_stop_one(get_vhost_net(peer), dev); goto err_start; } } @@ -390,7 +391,8 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, err_start: while (--i >= 0) { - peer = qemu_get_peer(ncs , i); + peer = qemu_get_peer(ncs, i < data_queue_pairs ? + i : n->max_queue_pairs); vhost_net_stop_one(get_vhost_net(peer), dev); } e = k->set_guest_notifiers(qbus->parent, total_notifiers, false); From 6aee7e4233f6467f69531fcd352adff028f3f5ea Mon Sep 17 00:00:00 2001 From: Si-Wei Liu Date: Fri, 6 May 2022 19:28:16 -0700 Subject: [PATCH 412/935] vhost-vdpa: backend feature should set only once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The vhost_vdpa_one_time_request() branch in vhost_vdpa_set_backend_cap() incorrectly sends down ioctls on vhost_dev with non-zero index. This may end up with multiple VHOST_SET_BACKEND_FEATURES ioctl calls sent down on the vhost-vdpa fd that is shared between all these vhost_dev's. To fix it, send down ioctl only once via the first vhost_dev with index 0. Toggle the polarity of the vhost_vdpa_one_time_request() test should do the trick. Fixes: 4d191cfdc7de ("vhost-vdpa: classify one time request") Signed-off-by: Si-Wei Liu Reviewed-by: Stefano Garzarella Acked-by: Jason Wang Acked-by: Eugenio Pérez Message-Id: <1651890498-24478-6-git-send-email-si-wei.liu@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-vdpa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index ed106bff47..870ab74b04 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -667,7 +667,7 @@ static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) features &= f; - if (vhost_vdpa_one_time_request(dev)) { + if (!vhost_vdpa_one_time_request(dev)) { r = vhost_vdpa_call(dev, VHOST_SET_BACKEND_FEATURES, &features); if (r) { return -EFAULT; From d71b0609fc04217e28d17009f04d74b08be6f466 Mon Sep 17 00:00:00 2001 From: Si-Wei Liu Date: Fri, 6 May 2022 19:28:17 -0700 Subject: [PATCH 413/935] vhost-vdpa: change name and polarity for vhost_vdpa_one_time_request() The name vhost_vdpa_one_time_request() was confusing. No matter whatever it returns, its typical occurrence had always been at requests that only need to be applied once. And the name didn't suggest what it actually checks for. Change it to vhost_vdpa_first_dev() with polarity flipped for better readibility of code. That way it is able to reflect what the check is really about. This call is applicable to request which performs operation only once, before queues are set up, and usually at the beginning of the caller function. Document the requirement for it in place. Signed-off-by: Si-Wei Liu Message-Id: <1651890498-24478-7-git-send-email-si-wei.liu@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Stefano Garzarella Acked-by: Jason Wang --- hw/virtio/vhost-vdpa.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 870ab74b04..66f054a12c 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -368,11 +368,18 @@ static void vhost_vdpa_get_iova_range(struct vhost_vdpa *v) v->iova_range.last); } -static bool vhost_vdpa_one_time_request(struct vhost_dev *dev) +/* + * The use of this function is for requests that only need to be + * applied once. Typically such request occurs at the beginning + * of operation, and before setting up queues. It should not be + * used for request that performs operation until all queues are + * set, which would need to check dev->vq_index_end instead. + */ +static bool vhost_vdpa_first_dev(struct vhost_dev *dev) { struct vhost_vdpa *v = dev->opaque; - return v->index != 0; + return v->index == 0; } static int vhost_vdpa_get_dev_features(struct vhost_dev *dev, @@ -453,7 +460,7 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) vhost_vdpa_get_iova_range(v); - if (vhost_vdpa_one_time_request(dev)) { + if (!vhost_vdpa_first_dev(dev)) { return 0; } @@ -596,7 +603,7 @@ static int vhost_vdpa_memslots_limit(struct vhost_dev *dev) static int vhost_vdpa_set_mem_table(struct vhost_dev *dev, struct vhost_memory *mem) { - if (vhost_vdpa_one_time_request(dev)) { + if (!vhost_vdpa_first_dev(dev)) { return 0; } @@ -625,7 +632,7 @@ static int vhost_vdpa_set_features(struct vhost_dev *dev, struct vhost_vdpa *v = dev->opaque; int ret; - if (vhost_vdpa_one_time_request(dev)) { + if (!vhost_vdpa_first_dev(dev)) { return 0; } @@ -667,7 +674,7 @@ static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) features &= f; - if (!vhost_vdpa_one_time_request(dev)) { + if (vhost_vdpa_first_dev(dev)) { r = vhost_vdpa_call(dev, VHOST_SET_BACKEND_FEATURES, &features); if (r) { return -EFAULT; @@ -1120,7 +1127,7 @@ static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base, struct vhost_log *log) { struct vhost_vdpa *v = dev->opaque; - if (v->shadow_vqs_enabled || vhost_vdpa_one_time_request(dev)) { + if (v->shadow_vqs_enabled || !vhost_vdpa_first_dev(dev)) { return 0; } @@ -1242,7 +1249,7 @@ static int vhost_vdpa_get_features(struct vhost_dev *dev, static int vhost_vdpa_set_owner(struct vhost_dev *dev) { - if (vhost_vdpa_one_time_request(dev)) { + if (!vhost_vdpa_first_dev(dev)) { return 0; } From 2a7888cc3aa31faee839fa5dddad354ff8941f4c Mon Sep 17 00:00:00 2001 From: Si-Wei Liu Date: Fri, 6 May 2022 19:28:18 -0700 Subject: [PATCH 414/935] virtio-net: don't handle mq request in userspace handler for vhost-vdpa virtio_queue_host_notifier_read() tends to read pending event left behind on ioeventfd in the vhost_net_stop() path, and attempts to handle outstanding kicks from userspace vq handler. However, in the ctrl_vq handler, virtio_net_handle_mq() has a recursive call into virtio_net_set_status(), which may lead to segmentation fault as shown in below stack trace: 0 0x000055f800df1780 in qdev_get_parent_bus (dev=0x0) at ../hw/core/qdev.c:376 1 0x000055f800c68ad8 in virtio_bus_device_iommu_enabled (vdev=vdev@entry=0x0) at ../hw/virtio/virtio-bus.c:331 2 0x000055f800d70d7f in vhost_memory_unmap (dev=) at ../hw/virtio/vhost.c:318 3 0x000055f800d70d7f in vhost_memory_unmap (dev=, buffer=0x7fc19bec5240, len=2052, is_write=1, access_len=2052) at ../hw/virtio/vhost.c:336 4 0x000055f800d71867 in vhost_virtqueue_stop (dev=dev@entry=0x55f8037ccc30, vdev=vdev@entry=0x55f8044ec590, vq=0x55f8037cceb0, idx=0) at ../hw/virtio/vhost.c:1241 5 0x000055f800d7406c in vhost_dev_stop (hdev=hdev@entry=0x55f8037ccc30, vdev=vdev@entry=0x55f8044ec590) at ../hw/virtio/vhost.c:1839 6 0x000055f800bf00a7 in vhost_net_stop_one (net=0x55f8037ccc30, dev=0x55f8044ec590) at ../hw/net/vhost_net.c:315 7 0x000055f800bf0678 in vhost_net_stop (dev=dev@entry=0x55f8044ec590, ncs=0x55f80452bae0, data_queue_pairs=data_queue_pairs@entry=7, cvq=cvq@entry=1) at ../hw/net/vhost_net.c:423 8 0x000055f800d4e628 in virtio_net_set_status (status=, n=0x55f8044ec590) at ../hw/net/virtio-net.c:296 9 0x000055f800d4e628 in virtio_net_set_status (vdev=vdev@entry=0x55f8044ec590, status=15 '\017') at ../hw/net/virtio-net.c:370 10 0x000055f800d534d8 in virtio_net_handle_ctrl (iov_cnt=, iov=, cmd=0 '\000', n=0x55f8044ec590) at ../hw/net/virtio-net.c:1408 11 0x000055f800d534d8 in virtio_net_handle_ctrl (vdev=0x55f8044ec590, vq=0x7fc1a7e888d0) at ../hw/net/virtio-net.c:1452 12 0x000055f800d69f37 in virtio_queue_host_notifier_read (vq=0x7fc1a7e888d0) at ../hw/virtio/virtio.c:2331 13 0x000055f800d69f37 in virtio_queue_host_notifier_read (n=n@entry=0x7fc1a7e8894c) at ../hw/virtio/virtio.c:3575 14 0x000055f800c688e6 in virtio_bus_cleanup_host_notifier (bus=, n=n@entry=14) at ../hw/virtio/virtio-bus.c:312 15 0x000055f800d73106 in vhost_dev_disable_notifiers (hdev=hdev@entry=0x55f8035b51b0, vdev=vdev@entry=0x55f8044ec590) at ../../../include/hw/virtio/virtio-bus.h:35 16 0x000055f800bf00b2 in vhost_net_stop_one (net=0x55f8035b51b0, dev=0x55f8044ec590) at ../hw/net/vhost_net.c:316 17 0x000055f800bf0678 in vhost_net_stop (dev=dev@entry=0x55f8044ec590, ncs=0x55f80452bae0, data_queue_pairs=data_queue_pairs@entry=7, cvq=cvq@entry=1) at ../hw/net/vhost_net.c:423 18 0x000055f800d4e628 in virtio_net_set_status (status=, n=0x55f8044ec590) at ../hw/net/virtio-net.c:296 19 0x000055f800d4e628 in virtio_net_set_status (vdev=0x55f8044ec590, status=15 '\017') at ../hw/net/virtio-net.c:370 20 0x000055f800d6c4b2 in virtio_set_status (vdev=0x55f8044ec590, val=) at ../hw/virtio/virtio.c:1945 21 0x000055f800d11d9d in vm_state_notify (running=running@entry=false, state=state@entry=RUN_STATE_SHUTDOWN) at ../softmmu/runstate.c:333 22 0x000055f800d04e7a in do_vm_stop (state=state@entry=RUN_STATE_SHUTDOWN, send_stop=send_stop@entry=false) at ../softmmu/cpus.c:262 23 0x000055f800d04e99 in vm_shutdown () at ../softmmu/cpus.c:280 24 0x000055f800d126af in qemu_cleanup () at ../softmmu/runstate.c:812 25 0x000055f800ad5b13 in main (argc=, argv=, envp=) at ../softmmu/main.c:51 For now, temporarily disable handling MQ request from the ctrl_vq userspace hanlder to avoid the recursive virtio_net_set_status() call. Some rework is needed to allow changing the number of queues without going through a full virtio_net_set_status cycle, particularly for vhost-vdpa backend. This patch will need to be reverted as soon as future patches of having the change of #queues handled in userspace is merged. Fixes: 402378407db ("vhost-vdpa: multiqueue support") Signed-off-by: Si-Wei Liu Acked-by: Jason Wang Message-Id: <1651890498-24478-8-git-send-email-si-wei.liu@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 1ea524ff09..7ad948ee7c 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1381,6 +1381,7 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, { VirtIODevice *vdev = VIRTIO_DEVICE(n); uint16_t queue_pairs; + NetClientState *nc = qemu_get_queue(n->nic); virtio_net_disable_rss(n); if (cmd == VIRTIO_NET_CTRL_MQ_HASH_CONFIG) { @@ -1412,6 +1413,18 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, return VIRTIO_NET_ERR; } + /* Avoid changing the number of queue_pairs for vdpa device in + * userspace handler. A future fix is needed to handle the mq + * change in userspace handler with vhost-vdpa. Let's disable + * the mq handling from userspace for now and only allow get + * done through the kernel. Ripples may be seen when falling + * back to userspace, but without doing it qemu process would + * crash on a recursive entry to virtio_net_set_status(). + */ + if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { + return VIRTIO_NET_ERR; + } + n->curr_queue_pairs = queue_pairs; /* stop the backend before changing the number of queue_pairs to avoid handling a * disabled queue */ From 6852c21db229c4bf4c1db772444bdfbbd027e5b8 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 16 May 2022 16:57:01 +0100 Subject: [PATCH 415/935] vhost-user-scsi: avoid unlink(NULL) with fd passing Commit 747421e949fc1eb3ba66b5fcccdb7ba051918241 ("Implements Backend Program conventions for vhost-user-scsi") introduced fd-passing support as part of implementing the vhost-user backend program conventions. When fd passing is used the UNIX domain socket path is NULL and we must not call unlink(2). The unlink(2) call is necessary when the listen socket, lsock, was created successfully since that means the UNIX domain socket is visible in the file system. Fixes: Coverity CID 1488353 Fixes: 747421e949fc1eb3ba66b5fcccdb7ba051918241 ("Implements Backend Program conventions for vhost-user-scsi") Signed-off-by: Stefan Hajnoczi Message-Id: <20220516155701.1789638-1-stefanha@redhat.com> Reviewed-by: Raphael Norwitz Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- contrib/vhost-user-scsi/vhost-user-scsi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contrib/vhost-user-scsi/vhost-user-scsi.c b/contrib/vhost-user-scsi/vhost-user-scsi.c index b2c0f98253..9ef61cf5a7 100644 --- a/contrib/vhost-user-scsi/vhost-user-scsi.c +++ b/contrib/vhost-user-scsi/vhost-user-scsi.c @@ -433,13 +433,16 @@ out: if (vdev_scsi) { g_main_loop_unref(vdev_scsi->loop); g_free(vdev_scsi); - unlink(opt_socket_path); } if (csock >= 0) { close(csock); } if (lsock >= 0) { close(lsock); + + if (opt_socket_path) { + unlink(opt_socket_path); + } } g_free(opt_socket_path); g_free(iscsi_uri); From e2c1d78da3223e8b39c14cce3da9e62655c1ddbb Mon Sep 17 00:00:00 2001 From: Vladislav Yaroshchuk Date: Thu, 17 Mar 2022 20:28:33 +0300 Subject: [PATCH 416/935] net/vmnet: add vmnet dependency and customizable option vmnet.framework dependency is added with 'vmnet' option to enable or disable it. Default value is 'auto'. used vmnet features are available since macOS 11.0, but new backend can be built and work properly with subset of them on 10.15 too. Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki Signed-off-by: Vladislav Yaroshchuk Signed-off-by: Jason Wang --- meson.build | 16 +++++++++++++++- meson_options.txt | 2 ++ scripts/meson-buildoptions.sh | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 53a4728250..52f6befc0f 100644 --- a/meson.build +++ b/meson.build @@ -580,6 +580,18 @@ if cocoa.found() and get_option('gtk').enabled() error('Cocoa and GTK+ cannot be enabled at the same time') endif +vmnet = dependency('appleframeworks', modules: 'vmnet', required: get_option('vmnet')) +if vmnet.found() and not cc.has_header_symbol('vmnet/vmnet.h', + 'VMNET_BRIDGED_MODE', + dependencies: vmnet) + vmnet = not_found + if get_option('vmnet').enabled() + error('vmnet.framework API is outdated') + else + warning('vmnet.framework API is outdated, disabling') + endif +endif + seccomp = not_found if not get_option('seccomp').auto() or have_system or have_tools seccomp = dependency('libseccomp', version: '>=2.3.0', @@ -1741,6 +1753,7 @@ config_host_data.set('CONFIG_VHOST_KERNEL', have_vhost_kernel) config_host_data.set('CONFIG_VHOST_USER', have_vhost_user) config_host_data.set('CONFIG_VHOST_CRYPTO', have_vhost_user_crypto) config_host_data.set('CONFIG_VHOST_VDPA', have_vhost_vdpa) +config_host_data.set('CONFIG_VMNET', vmnet.found()) config_host_data.set('CONFIG_VHOST_USER_BLK_SERVER', have_vhost_user_blk_server) config_host_data.set('CONFIG_PNG', png.found()) config_host_data.set('CONFIG_VNC', vnc.found()) @@ -3897,7 +3910,8 @@ summary(summary_info, bool_yn: true, section: 'Crypto') # Libraries summary_info = {} if targetos == 'darwin' - summary_info += {'Cocoa support': cocoa} + summary_info += {'Cocoa support': cocoa} + summary_info += {'vmnet.framework support': vmnet} endif summary_info += {'SDL support': sdl} summary_info += {'SDL image support': sdl_image} diff --git a/meson_options.txt b/meson_options.txt index 29c6b90cec..7325cdad45 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -197,6 +197,8 @@ option('netmap', type : 'feature', value : 'auto', description: 'netmap network backend support') option('vde', type : 'feature', value : 'auto', description: 'vde network backend support') +option('vmnet', type : 'feature', value : 'auto', + description: 'vmnet.framework network backend support') option('virglrenderer', type : 'feature', value : 'auto', description: 'virgl rendering support') option('png', type : 'feature', value : 'auto', diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 5d2172bfb4..9b0d151dad 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -158,6 +158,7 @@ meson_options_help() { printf "%s\n" ' vhost-kernel vhost kernel backend support' printf "%s\n" ' vhost-net vhost-net kernel acceleration support' printf "%s\n" ' vhost-user vhost-user backend support' + printf "%s\n" ' vmnet vmnet.framework network backend support' printf "%s\n" ' vhost-user-blk-server' printf "%s\n" ' build vhost-user-blk server' printf "%s\n" ' vhost-vdpa vhost-vdpa kernel backend support' From 81ad2964e93848fc0998145043c395dea67f00da Mon Sep 17 00:00:00 2001 From: Vladislav Yaroshchuk Date: Thu, 17 Mar 2022 20:28:34 +0300 Subject: [PATCH 417/935] net/vmnet: add vmnet backends to qapi/net Create separate netdevs for each vmnet operating mode: - vmnet-host - vmnet-shared - vmnet-bridged Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki Acked-by: Markus Armbruster Signed-off-by: Vladislav Yaroshchuk Signed-off-by: Jason Wang --- net/clients.h | 11 ++++ net/meson.build | 7 +++ net/net.c | 10 ++++ net/vmnet-bridged.m | 25 +++++++++ net/vmnet-common.m | 19 +++++++ net/vmnet-host.c | 24 ++++++++ net/vmnet-shared.c | 25 +++++++++ net/vmnet_int.h | 25 +++++++++ qapi/net.json | 133 +++++++++++++++++++++++++++++++++++++++++++- 9 files changed, 277 insertions(+), 2 deletions(-) create mode 100644 net/vmnet-bridged.m create mode 100644 net/vmnet-common.m create mode 100644 net/vmnet-host.c create mode 100644 net/vmnet-shared.c create mode 100644 net/vmnet_int.h diff --git a/net/clients.h b/net/clients.h index 92f9b59aed..c9157789f2 100644 --- a/net/clients.h +++ b/net/clients.h @@ -63,4 +63,15 @@ int net_init_vhost_user(const Netdev *netdev, const char *name, int net_init_vhost_vdpa(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); +#ifdef CONFIG_VMNET +int net_init_vmnet_host(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp); + +int net_init_vmnet_shared(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp); + +int net_init_vmnet_bridged(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp); +#endif /* CONFIG_VMNET */ + #endif /* QEMU_NET_CLIENTS_H */ diff --git a/net/meson.build b/net/meson.build index c965e83b26..754e2d1d40 100644 --- a/net/meson.build +++ b/net/meson.build @@ -44,4 +44,11 @@ if have_vhost_net_vdpa softmmu_ss.add(files('vhost-vdpa.c')) endif +vmnet_files = files( + 'vmnet-common.m', + 'vmnet-bridged.m', + 'vmnet-host.c', + 'vmnet-shared.c' +) +softmmu_ss.add(when: vmnet, if_true: vmnet_files) subdir('can') diff --git a/net/net.c b/net/net.c index a094cf1d29..2db160e063 100644 --- a/net/net.c +++ b/net/net.c @@ -1020,6 +1020,11 @@ static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])( #ifdef CONFIG_L2TPV3 [NET_CLIENT_DRIVER_L2TPV3] = net_init_l2tpv3, #endif +#ifdef CONFIG_VMNET + [NET_CLIENT_DRIVER_VMNET_HOST] = net_init_vmnet_host, + [NET_CLIENT_DRIVER_VMNET_SHARED] = net_init_vmnet_shared, + [NET_CLIENT_DRIVER_VMNET_BRIDGED] = net_init_vmnet_bridged, +#endif /* CONFIG_VMNET */ }; @@ -1105,6 +1110,11 @@ void show_netdevs(void) #endif #ifdef CONFIG_VHOST_VDPA "vhost-vdpa", +#endif +#ifdef CONFIG_VMNET + "vmnet-host", + "vmnet-shared", + "vmnet-bridged", #endif }; diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m new file mode 100644 index 0000000000..91c1a2f2c7 --- /dev/null +++ b/net/vmnet-bridged.m @@ -0,0 +1,25 @@ +/* + * vmnet-bridged.m + * + * Copyright(c) 2022 Vladislav Yaroshchuk + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/qapi-types-net.h" +#include "vmnet_int.h" +#include "clients.h" +#include "qemu/error-report.h" +#include "qapi/error.h" + +#include + +int net_init_vmnet_bridged(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp) +{ + error_setg(errp, "vmnet-bridged is not implemented yet"); + return -1; +} diff --git a/net/vmnet-common.m b/net/vmnet-common.m new file mode 100644 index 0000000000..3bf42fc643 --- /dev/null +++ b/net/vmnet-common.m @@ -0,0 +1,19 @@ +/* + * vmnet-common.m - network client wrapper for Apple vmnet.framework + * + * Copyright(c) 2022 Vladislav Yaroshchuk + * Copyright(c) 2021 Phillip Tennen + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/qapi-types-net.h" +#include "vmnet_int.h" +#include "clients.h" +#include "qemu/error-report.h" +#include "qapi/error.h" + +#include diff --git a/net/vmnet-host.c b/net/vmnet-host.c new file mode 100644 index 0000000000..a461d507c5 --- /dev/null +++ b/net/vmnet-host.c @@ -0,0 +1,24 @@ +/* + * vmnet-host.c + * + * Copyright(c) 2022 Vladislav Yaroshchuk + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/qapi-types-net.h" +#include "vmnet_int.h" +#include "clients.h" +#include "qemu/error-report.h" +#include "qapi/error.h" + +#include + +int net_init_vmnet_host(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp) { + error_setg(errp, "vmnet-host is not implemented yet"); + return -1; +} diff --git a/net/vmnet-shared.c b/net/vmnet-shared.c new file mode 100644 index 0000000000..6dfb133a18 --- /dev/null +++ b/net/vmnet-shared.c @@ -0,0 +1,25 @@ +/* + * vmnet-shared.c + * + * Copyright(c) 2022 Vladislav Yaroshchuk + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/qapi-types-net.h" +#include "vmnet_int.h" +#include "clients.h" +#include "qemu/error-report.h" +#include "qapi/error.h" + +#include + +int net_init_vmnet_shared(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp) +{ + error_setg(errp, "vmnet-shared is not implemented yet"); + return -1; +} diff --git a/net/vmnet_int.h b/net/vmnet_int.h new file mode 100644 index 0000000000..c383038a1d --- /dev/null +++ b/net/vmnet_int.h @@ -0,0 +1,25 @@ +/* + * vmnet_int.h + * + * Copyright(c) 2022 Vladislav Yaroshchuk + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ +#ifndef VMNET_INT_H +#define VMNET_INT_H + +#include "qemu/osdep.h" +#include "vmnet_int.h" +#include "clients.h" + +#include + +typedef struct VmnetState { + NetClientState nc; + +} VmnetState; + + +#endif /* VMNET_INT_H */ diff --git a/qapi/net.json b/qapi/net.json index b92f3f5fb4..d6f7cfd4d6 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -452,6 +452,120 @@ '*vhostdev': 'str', '*queues': 'int' } } +## +# @NetdevVmnetHostOptions: +# +# vmnet (host mode) network backend. +# +# Allows the vmnet interface to communicate with other vmnet +# interfaces that are in host mode and also with the host. +# +# @start-address: The starting IPv4 address to use for the interface. +# Must be in the private IP range (RFC 1918). Must be +# specified along with @end-address and @subnet-mask. +# This address is used as the gateway address. The +# subsequent address up to and including end-address are +# placed in the DHCP pool. +# +# @end-address: The DHCP IPv4 range end address to use for the +# interface. Must be in the private IP range (RFC 1918). +# Must be specified along with @start-address and +# @subnet-mask. +# +# @subnet-mask: The IPv4 subnet mask to use on the interface. Must +# be specified along with @start-address and @subnet-mask. +# +# @isolated: Enable isolation for this interface. Interface isolation +# ensures that vmnet interface is not able to communicate +# with any other vmnet interfaces. Only communication with +# host is allowed. Requires at least macOS Big Sur 11.0. +# +# @net-uuid: The identifier (UUID) to uniquely identify the isolated +# network vmnet interface should be added to. If +# set, no DHCP service is provided for this interface and +# network communication is allowed only with other interfaces +# added to this network identified by the UUID. Requires +# at least macOS Big Sur 11.0. +# +# Since: 7.1 +## +{ 'struct': 'NetdevVmnetHostOptions', + 'data': { + '*start-address': 'str', + '*end-address': 'str', + '*subnet-mask': 'str', + '*isolated': 'bool', + '*net-uuid': 'str' }, + 'if': 'CONFIG_VMNET' } + +## +# @NetdevVmnetSharedOptions: +# +# vmnet (shared mode) network backend. +# +# Allows traffic originating from the vmnet interface to reach the +# Internet through a network address translator (NAT). +# The vmnet interface can communicate with the host and with +# other shared mode interfaces on the same subnet. If no DHCP +# settings, subnet mask and IPv6 prefix specified, the interface can +# communicate with any of other interfaces in shared mode. +# +# @start-address: The starting IPv4 address to use for the interface. +# Must be in the private IP range (RFC 1918). Must be +# specified along with @end-address and @subnet-mask. +# This address is used as the gateway address. The +# subsequent address up to and including end-address are +# placed in the DHCP pool. +# +# @end-address: The DHCP IPv4 range end address to use for the +# interface. Must be in the private IP range (RFC 1918). +# Must be specified along with @start-address and @subnet-mask. +# +# @subnet-mask: The IPv4 subnet mask to use on the interface. Must +# be specified along with @start-address and @subnet-mask. +# +# @isolated: Enable isolation for this interface. Interface isolation +# ensures that vmnet interface is not able to communicate +# with any other vmnet interfaces. Only communication with +# host is allowed. Requires at least macOS Big Sur 11.0. +# +# @nat66-prefix: The IPv6 prefix to use into guest network. Must be a +# unique local address i.e. start with fd00::/8 and have +# length of 64. +# +# Since: 7.1 +## +{ 'struct': 'NetdevVmnetSharedOptions', + 'data': { + '*start-address': 'str', + '*end-address': 'str', + '*subnet-mask': 'str', + '*isolated': 'bool', + '*nat66-prefix': 'str' }, + 'if': 'CONFIG_VMNET' } + +## +# @NetdevVmnetBridgedOptions: +# +# vmnet (bridged mode) network backend. +# +# Bridges the vmnet interface with a physical network interface. +# +# @ifname: The name of the physical interface to be bridged. +# +# @isolated: Enable isolation for this interface. Interface isolation +# ensures that vmnet interface is not able to communicate +# with any other vmnet interfaces. Only communication with +# host is allowed. Requires at least macOS Big Sur 11.0. +# +# Since: 7.1 +## +{ 'struct': 'NetdevVmnetBridgedOptions', + 'data': { + 'ifname': 'str', + '*isolated': 'bool' }, + 'if': 'CONFIG_VMNET' } + ## # @NetClientDriver: # @@ -460,10 +574,16 @@ # Since: 2.7 # # @vhost-vdpa since 5.1 +# @vmnet-host since 7.1 +# @vmnet-shared since 7.1 +# @vmnet-bridged since 7.1 ## { 'enum': 'NetClientDriver', 'data': [ 'none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'vde', - 'bridge', 'hubport', 'netmap', 'vhost-user', 'vhost-vdpa' ] } + 'bridge', 'hubport', 'netmap', 'vhost-user', 'vhost-vdpa', + { 'name': 'vmnet-host', 'if': 'CONFIG_VMNET' }, + { 'name': 'vmnet-shared', 'if': 'CONFIG_VMNET' }, + { 'name': 'vmnet-bridged', 'if': 'CONFIG_VMNET' }] } ## # @Netdev: @@ -477,6 +597,9 @@ # Since: 1.2 # # 'l2tpv3' - since 2.1 +# 'vmnet-host' - since 7.1 +# 'vmnet-shared' - since 7.1 +# 'vmnet-bridged' - since 7.1 ## { 'union': 'Netdev', 'base': { 'id': 'str', 'type': 'NetClientDriver' }, @@ -492,7 +615,13 @@ 'hubport': 'NetdevHubPortOptions', 'netmap': 'NetdevNetmapOptions', 'vhost-user': 'NetdevVhostUserOptions', - 'vhost-vdpa': 'NetdevVhostVDPAOptions' } } + 'vhost-vdpa': 'NetdevVhostVDPAOptions', + 'vmnet-host': { 'type': 'NetdevVmnetHostOptions', + 'if': 'CONFIG_VMNET' }, + 'vmnet-shared': { 'type': 'NetdevVmnetSharedOptions', + 'if': 'CONFIG_VMNET' }, + 'vmnet-bridged': { 'type': 'NetdevVmnetBridgedOptions', + 'if': 'CONFIG_VMNET' } } } ## # @RxState: From 73f99db534e36cdf7dd045b3fde2af29132c0a35 Mon Sep 17 00:00:00 2001 From: Vladislav Yaroshchuk Date: Thu, 17 Mar 2022 20:28:35 +0300 Subject: [PATCH 418/935] net/vmnet: implement shared mode (vmnet-shared) Interaction with vmnet.framework in different modes differs only on configuration stage, so we can create common `send`, `receive`, etc. procedures and reuse them. Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki Signed-off-by: Phillip Tennen Signed-off-by: Vladislav Yaroshchuk Signed-off-by: Jason Wang --- net/vmnet-common.m | 359 +++++++++++++++++++++++++++++++++++++++++++++ net/vmnet-shared.c | 97 +++++++++++- net/vmnet_int.h | 40 ++++- 3 files changed, 491 insertions(+), 5 deletions(-) diff --git a/net/vmnet-common.m b/net/vmnet-common.m index 3bf42fc643..2cb60b9ddd 100644 --- a/net/vmnet-common.m +++ b/net/vmnet-common.m @@ -10,6 +10,8 @@ */ #include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "qemu/log.h" #include "qapi/qapi-types-net.h" #include "vmnet_int.h" #include "clients.h" @@ -17,3 +19,360 @@ #include "qapi/error.h" #include +#include + + +static void vmnet_send_completed(NetClientState *nc, ssize_t len); + + +const char *vmnet_status_map_str(vmnet_return_t status) +{ + switch (status) { + case VMNET_SUCCESS: + return "success"; + case VMNET_FAILURE: + return "general failure (possibly not enough privileges)"; + case VMNET_MEM_FAILURE: + return "memory allocation failure"; + case VMNET_INVALID_ARGUMENT: + return "invalid argument specified"; + case VMNET_SETUP_INCOMPLETE: + return "interface setup is not complete"; + case VMNET_INVALID_ACCESS: + return "invalid access, permission denied"; + case VMNET_PACKET_TOO_BIG: + return "packet size is larger than MTU"; + case VMNET_BUFFER_EXHAUSTED: + return "buffers exhausted in kernel"; + case VMNET_TOO_MANY_PACKETS: + return "packet count exceeds limit"; +#if defined(MAC_OS_VERSION_11_0) && \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0 + case VMNET_SHARING_SERVICE_BUSY: + return "conflict, sharing service is in use"; +#endif + default: + return "unknown vmnet error"; + } +} + + +/** + * Write packets from QEMU to vmnet interface. + * + * vmnet.framework supports iov, but writing more than + * one iov into vmnet interface fails with + * 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into + * one and passing it to vmnet works fine. That's the + * reason why receive_iov() left unimplemented. But it still + * works with good performance having .receive() only. + */ +ssize_t vmnet_receive_common(NetClientState *nc, + const uint8_t *buf, + size_t size) +{ + VmnetState *s = DO_UPCAST(VmnetState, nc, nc); + struct vmpktdesc packet; + struct iovec iov; + int pkt_cnt; + vmnet_return_t if_status; + + if (size > s->max_packet_size) { + warn_report("vmnet: packet is too big, %zu > %" PRIu64, + packet.vm_pkt_size, + s->max_packet_size); + return -1; + } + + iov.iov_base = (char *) buf; + iov.iov_len = size; + + packet.vm_pkt_iovcnt = 1; + packet.vm_flags = 0; + packet.vm_pkt_size = size; + packet.vm_pkt_iov = &iov; + pkt_cnt = 1; + + if_status = vmnet_write(s->vmnet_if, &packet, &pkt_cnt); + if (if_status != VMNET_SUCCESS) { + error_report("vmnet: write error: %s\n", + vmnet_status_map_str(if_status)); + return -1; + } + + if (pkt_cnt) { + return size; + } + return 0; +} + + +/** + * Read packets from vmnet interface and write them + * to temporary buffers in VmnetState. + * + * Returns read packets number (may be 0) on success, + * -1 on error + */ +static int vmnet_read_packets(VmnetState *s) +{ + assert(s->packets_send_current_pos == s->packets_send_end_pos); + + struct vmpktdesc *packets = s->packets_buf; + vmnet_return_t status; + int i; + + /* Read as many packets as present */ + s->packets_send_current_pos = 0; + s->packets_send_end_pos = VMNET_PACKETS_LIMIT; + for (i = 0; i < s->packets_send_end_pos; ++i) { + packets[i].vm_pkt_size = s->max_packet_size; + packets[i].vm_pkt_iovcnt = 1; + packets[i].vm_flags = 0; + } + + status = vmnet_read(s->vmnet_if, packets, &s->packets_send_end_pos); + if (status != VMNET_SUCCESS) { + error_printf("vmnet: read failed: %s\n", + vmnet_status_map_str(status)); + s->packets_send_current_pos = 0; + s->packets_send_end_pos = 0; + return -1; + } + return s->packets_send_end_pos; +} + + +/** + * Write packets from temporary buffers in VmnetState + * to QEMU. + */ +static void vmnet_write_packets_to_qemu(VmnetState *s) +{ + while (s->packets_send_current_pos < s->packets_send_end_pos) { + ssize_t size = qemu_send_packet_async(&s->nc, + s->iov_buf[s->packets_send_current_pos].iov_base, + s->packets_buf[s->packets_send_current_pos].vm_pkt_size, + vmnet_send_completed); + + if (size == 0) { + /* QEMU is not ready to consume more packets - + * stop and wait for completion callback call */ + return; + } + ++s->packets_send_current_pos; + } +} + + +/** + * Bottom half callback that transfers packets from vmnet interface + * to QEMU. + * + * The process of transferring packets is three-staged: + * 1. Handle vmnet event; + * 2. Read packets from vmnet interface into temporary buffer; + * 3. Write packets from temporary buffer to QEMU. + * + * QEMU may suspend this process on the last stage, returning 0 from + * qemu_send_packet_async function. If this happens, we should + * respectfully wait until it is ready to consume more packets, + * write left ones in temporary buffer and only after this + * continue reading more packets from vmnet interface. + * + * Packets to be transferred are stored into packets_buf, + * in the window [packets_send_current_pos..packets_send_end_pos) + * including current_pos, excluding end_pos. + * + * Thus, if QEMU is not ready, buffer is not read and + * packets_send_current_pos < packets_send_end_pos. + */ +static void vmnet_send_bh(void *opaque) +{ + NetClientState *nc = (NetClientState *) opaque; + VmnetState *s = DO_UPCAST(VmnetState, nc, nc); + + /* + * Do nothing if QEMU is not ready - wait + * for completion callback invocation + */ + if (s->packets_send_current_pos < s->packets_send_end_pos) { + return; + } + + /* Read packets from vmnet interface */ + if (vmnet_read_packets(s) > 0) { + /* Send them to QEMU */ + vmnet_write_packets_to_qemu(s); + } +} + + +/** + * Completion callback to be invoked by QEMU when it becomes + * ready to consume more packets. + */ +static void vmnet_send_completed(NetClientState *nc, ssize_t len) +{ + VmnetState *s = DO_UPCAST(VmnetState, nc, nc); + + /* Callback is invoked eq queued packet is sent */ + ++s->packets_send_current_pos; + + /* Complete sending packets left in VmnetState buffers */ + vmnet_write_packets_to_qemu(s); + + /* And read new ones from vmnet if VmnetState buffer is ready */ + if (s->packets_send_current_pos < s->packets_send_end_pos) { + qemu_bh_schedule(s->send_bh); + } +} + + +static void vmnet_bufs_init(VmnetState *s) +{ + struct vmpktdesc *packets = s->packets_buf; + struct iovec *iov = s->iov_buf; + int i; + + for (i = 0; i < VMNET_PACKETS_LIMIT; ++i) { + iov[i].iov_len = s->max_packet_size; + iov[i].iov_base = g_malloc0(iov[i].iov_len); + packets[i].vm_pkt_iov = iov + i; + } +} + + +int vmnet_if_create(NetClientState *nc, + xpc_object_t if_desc, + Error **errp) +{ + VmnetState *s = DO_UPCAST(VmnetState, nc, nc); + dispatch_semaphore_t if_created_sem = dispatch_semaphore_create(0); + __block vmnet_return_t if_status; + + s->if_queue = dispatch_queue_create( + "org.qemu.vmnet.if_queue", + DISPATCH_QUEUE_SERIAL + ); + + xpc_dictionary_set_bool( + if_desc, + vmnet_allocate_mac_address_key, + false + ); + +#ifdef DEBUG + qemu_log("vmnet.start.interface_desc:\n"); + xpc_dictionary_apply(if_desc, + ^bool(const char *k, xpc_object_t v) { + char *desc = xpc_copy_description(v); + qemu_log(" %s=%s\n", k, desc); + free(desc); + return true; + }); +#endif /* DEBUG */ + + s->vmnet_if = vmnet_start_interface( + if_desc, + s->if_queue, + ^(vmnet_return_t status, xpc_object_t interface_param) { + if_status = status; + if (status != VMNET_SUCCESS || !interface_param) { + dispatch_semaphore_signal(if_created_sem); + return; + } + +#ifdef DEBUG + qemu_log("vmnet.start.interface_param:\n"); + xpc_dictionary_apply(interface_param, + ^bool(const char *k, xpc_object_t v) { + char *desc = xpc_copy_description(v); + qemu_log(" %s=%s\n", k, desc); + free(desc); + return true; + }); +#endif /* DEBUG */ + + s->mtu = xpc_dictionary_get_uint64( + interface_param, + vmnet_mtu_key); + s->max_packet_size = xpc_dictionary_get_uint64( + interface_param, + vmnet_max_packet_size_key); + + dispatch_semaphore_signal(if_created_sem); + }); + + if (s->vmnet_if == NULL) { + dispatch_release(s->if_queue); + dispatch_release(if_created_sem); + error_setg(errp, + "unable to create interface with requested params"); + return -1; + } + + dispatch_semaphore_wait(if_created_sem, DISPATCH_TIME_FOREVER); + dispatch_release(if_created_sem); + + if (if_status != VMNET_SUCCESS) { + dispatch_release(s->if_queue); + error_setg(errp, + "cannot create vmnet interface: %s", + vmnet_status_map_str(if_status)); + return -1; + } + + s->send_bh = aio_bh_new(qemu_get_aio_context(), vmnet_send_bh, nc); + vmnet_bufs_init(s); + + s->packets_send_current_pos = 0; + s->packets_send_end_pos = 0; + + vmnet_interface_set_event_callback( + s->vmnet_if, + VMNET_INTERFACE_PACKETS_AVAILABLE, + s->if_queue, + ^(interface_event_t event_id, xpc_object_t event) { + assert(event_id == VMNET_INTERFACE_PACKETS_AVAILABLE); + /* + * This function is being called from a non qemu thread, so + * we only schedule a BH, and do the rest of the io completion + * handling from vmnet_send_bh() which runs in a qemu context. + */ + qemu_bh_schedule(s->send_bh); + }); + + return 0; +} + + +void vmnet_cleanup_common(NetClientState *nc) +{ + VmnetState *s = DO_UPCAST(VmnetState, nc, nc); + dispatch_semaphore_t if_stopped_sem; + + if (s->vmnet_if == NULL) { + return; + } + + if_stopped_sem = dispatch_semaphore_create(0); + vmnet_stop_interface( + s->vmnet_if, + s->if_queue, + ^(vmnet_return_t status) { + assert(status == VMNET_SUCCESS); + dispatch_semaphore_signal(if_stopped_sem); + }); + dispatch_semaphore_wait(if_stopped_sem, DISPATCH_TIME_FOREVER); + + qemu_purge_queued_packets(nc); + + qemu_bh_delete(s->send_bh); + dispatch_release(if_stopped_sem); + dispatch_release(s->if_queue); + + for (int i = 0; i < VMNET_PACKETS_LIMIT; ++i) { + g_free(s->iov_buf[i].iov_base); + } +} diff --git a/net/vmnet-shared.c b/net/vmnet-shared.c index 6dfb133a18..18cadc72bd 100644 --- a/net/vmnet-shared.c +++ b/net/vmnet-shared.c @@ -10,16 +10,105 @@ #include "qemu/osdep.h" #include "qapi/qapi-types-net.h" +#include "qapi/error.h" #include "vmnet_int.h" #include "clients.h" -#include "qemu/error-report.h" -#include "qapi/error.h" #include + +static bool validate_options(const Netdev *netdev, Error **errp) +{ + const NetdevVmnetSharedOptions *options = &(netdev->u.vmnet_shared); + +#if !defined(MAC_OS_VERSION_11_0) || \ + MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_11_0 + if (options->has_isolated) { + error_setg(errp, + "vmnet-shared.isolated feature is " + "unavailable: outdated vmnet.framework API"); + return false; + } +#endif + + if ((options->has_start_address || + options->has_end_address || + options->has_subnet_mask) && + !(options->has_start_address && + options->has_end_address && + options->has_subnet_mask)) { + error_setg(errp, + "'start-address', 'end-address', 'subnet-mask' " + "should be provided together" + ); + return false; + } + + return true; +} + +static xpc_object_t build_if_desc(const Netdev *netdev) +{ + const NetdevVmnetSharedOptions *options = &(netdev->u.vmnet_shared); + xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0); + + xpc_dictionary_set_uint64( + if_desc, + vmnet_operation_mode_key, + VMNET_SHARED_MODE + ); + + if (options->has_nat66_prefix) { + xpc_dictionary_set_string(if_desc, + vmnet_nat66_prefix_key, + options->nat66_prefix); + } + + if (options->has_start_address) { + xpc_dictionary_set_string(if_desc, + vmnet_start_address_key, + options->start_address); + xpc_dictionary_set_string(if_desc, + vmnet_end_address_key, + options->end_address); + xpc_dictionary_set_string(if_desc, + vmnet_subnet_mask_key, + options->subnet_mask); + } + +#if defined(MAC_OS_VERSION_11_0) && \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0 + xpc_dictionary_set_bool( + if_desc, + vmnet_enable_isolation_key, + options->isolated + ); +#endif + + return if_desc; +} + +static NetClientInfo net_vmnet_shared_info = { + .type = NET_CLIENT_DRIVER_VMNET_SHARED, + .size = sizeof(VmnetState), + .receive = vmnet_receive_common, + .cleanup = vmnet_cleanup_common, +}; + int net_init_vmnet_shared(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp) { - error_setg(errp, "vmnet-shared is not implemented yet"); - return -1; + NetClientState *nc = qemu_new_net_client(&net_vmnet_shared_info, + peer, "vmnet-shared", name); + xpc_object_t if_desc; + int result = -1; + + if (!validate_options(netdev, errp)) { + return result; + } + + if_desc = build_if_desc(netdev); + result = vmnet_if_create(nc, if_desc, errp); + xpc_release(if_desc); + return result; } diff --git a/net/vmnet_int.h b/net/vmnet_int.h index c383038a1d..adf6e8c20d 100644 --- a/net/vmnet_int.h +++ b/net/vmnet_int.h @@ -15,11 +15,49 @@ #include "clients.h" #include +#include + +/** + * From vmnet.framework documentation + * + * Each read/write call allows up to 200 packets to be + * read or written for a maximum of 256KB. + * + * Each packet written should be a complete + * ethernet frame. + * + * https://developer.apple.com/documentation/vmnet + */ +#define VMNET_PACKETS_LIMIT 200 typedef struct VmnetState { - NetClientState nc; + NetClientState nc; + interface_ref vmnet_if; + uint64_t mtu; + uint64_t max_packet_size; + + dispatch_queue_t if_queue; + + QEMUBH *send_bh; + + struct vmpktdesc packets_buf[VMNET_PACKETS_LIMIT]; + int packets_send_current_pos; + int packets_send_end_pos; + + struct iovec iov_buf[VMNET_PACKETS_LIMIT]; } VmnetState; +const char *vmnet_status_map_str(vmnet_return_t status); + +int vmnet_if_create(NetClientState *nc, + xpc_object_t if_desc, + Error **errp); + +ssize_t vmnet_receive_common(NetClientState *nc, + const uint8_t *buf, + size_t size); + +void vmnet_cleanup_common(NetClientState *nc); #endif /* VMNET_INT_H */ From 5cfa6437309fbf6c52a941898ca6b94dcddb5584 Mon Sep 17 00:00:00 2001 From: Vladislav Yaroshchuk Date: Thu, 17 Mar 2022 20:28:36 +0300 Subject: [PATCH 419/935] net/vmnet: implement host mode (vmnet-host) Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki Signed-off-by: Vladislav Yaroshchuk Signed-off-by: Jason Wang --- net/vmnet-host.c | 118 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 111 insertions(+), 7 deletions(-) diff --git a/net/vmnet-host.c b/net/vmnet-host.c index a461d507c5..05f8d78864 100644 --- a/net/vmnet-host.c +++ b/net/vmnet-host.c @@ -9,16 +9,120 @@ */ #include "qemu/osdep.h" +#include "qemu/uuid.h" #include "qapi/qapi-types-net.h" -#include "vmnet_int.h" -#include "clients.h" -#include "qemu/error-report.h" #include "qapi/error.h" +#include "clients.h" +#include "vmnet_int.h" #include -int net_init_vmnet_host(const Netdev *netdev, const char *name, - NetClientState *peer, Error **errp) { - error_setg(errp, "vmnet-host is not implemented yet"); - return -1; + +static bool validate_options(const Netdev *netdev, Error **errp) +{ + const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host); + +#if defined(MAC_OS_VERSION_11_0) && \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0 + + QemuUUID net_uuid; + if (options->has_net_uuid && + qemu_uuid_parse(options->net_uuid, &net_uuid) < 0) { + error_setg(errp, "Invalid UUID provided in 'net-uuid'"); + return false; + } +#else + if (options->has_isolated) { + error_setg(errp, + "vmnet-host.isolated feature is " + "unavailable: outdated vmnet.framework API"); + return false; + } + + if (options->has_net_uuid) { + error_setg(errp, + "vmnet-host.net-uuid feature is " + "unavailable: outdated vmnet.framework API"); + return false; + } +#endif + + if ((options->has_start_address || + options->has_end_address || + options->has_subnet_mask) && + !(options->has_start_address && + options->has_end_address && + options->has_subnet_mask)) { + error_setg(errp, + "'start-address', 'end-address', 'subnet-mask' " + "should be provided together"); + return false; + } + + return true; +} + +static xpc_object_t build_if_desc(const Netdev *netdev) +{ + const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host); + xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0); + + xpc_dictionary_set_uint64(if_desc, + vmnet_operation_mode_key, + VMNET_HOST_MODE); + +#if defined(MAC_OS_VERSION_11_0) && \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0 + + xpc_dictionary_set_bool(if_desc, + vmnet_enable_isolation_key, + options->isolated); + + QemuUUID net_uuid; + if (options->has_net_uuid) { + qemu_uuid_parse(options->net_uuid, &net_uuid); + xpc_dictionary_set_uuid(if_desc, + vmnet_network_identifier_key, + net_uuid.data); + } +#endif + + if (options->has_start_address) { + xpc_dictionary_set_string(if_desc, + vmnet_start_address_key, + options->start_address); + xpc_dictionary_set_string(if_desc, + vmnet_end_address_key, + options->end_address); + xpc_dictionary_set_string(if_desc, + vmnet_subnet_mask_key, + options->subnet_mask); + } + + return if_desc; +} + +static NetClientInfo net_vmnet_host_info = { + .type = NET_CLIENT_DRIVER_VMNET_HOST, + .size = sizeof(VmnetState), + .receive = vmnet_receive_common, + .cleanup = vmnet_cleanup_common, +}; + +int net_init_vmnet_host(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp) +{ + NetClientState *nc = qemu_new_net_client(&net_vmnet_host_info, + peer, "vmnet-host", name); + xpc_object_t if_desc; + int result = -1; + + if (!validate_options(netdev, errp)) { + return result; + } + + if_desc = build_if_desc(netdev); + result = vmnet_if_create(nc, if_desc, errp); + xpc_release(if_desc); + return result; } From 2c313ae2a0676d79eaa260a2cba64d93feb0683f Mon Sep 17 00:00:00 2001 From: Vladislav Yaroshchuk Date: Thu, 17 Mar 2022 20:28:37 +0300 Subject: [PATCH 420/935] net/vmnet: implement bridged mode (vmnet-bridged) Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki Signed-off-by: Vladislav Yaroshchuk Signed-off-by: Jason Wang --- net/vmnet-bridged.m | 137 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 132 insertions(+), 5 deletions(-) diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m index 91c1a2f2c7..46d2282863 100644 --- a/net/vmnet-bridged.m +++ b/net/vmnet-bridged.m @@ -10,16 +10,143 @@ #include "qemu/osdep.h" #include "qapi/qapi-types-net.h" -#include "vmnet_int.h" -#include "clients.h" -#include "qemu/error-report.h" #include "qapi/error.h" +#include "clients.h" +#include "vmnet_int.h" #include + +static bool validate_ifname(const char *ifname) +{ + xpc_object_t shared_if_list = vmnet_copy_shared_interface_list(); + bool match = false; + if (!xpc_array_get_count(shared_if_list)) { + goto done; + } + + match = !xpc_array_apply( + shared_if_list, + ^bool(size_t index, xpc_object_t value) { + return strcmp(xpc_string_get_string_ptr(value), ifname) != 0; + }); + +done: + xpc_release(shared_if_list); + return match; +} + + +static char* get_valid_ifnames() +{ + xpc_object_t shared_if_list = vmnet_copy_shared_interface_list(); + __block char *if_list = NULL; + __block char *if_list_prev = NULL; + + if (!xpc_array_get_count(shared_if_list)) { + goto done; + } + + xpc_array_apply( + shared_if_list, + ^bool(size_t index, xpc_object_t value) { + /* build list of strings like "en0 en1 en2 " */ + if_list = g_strconcat(xpc_string_get_string_ptr(value), + " ", + if_list_prev, + NULL); + g_free(if_list_prev); + if_list_prev = if_list; + return true; + }); + +done: + xpc_release(shared_if_list); + return if_list; +} + + +static bool validate_options(const Netdev *netdev, Error **errp) +{ + const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged); + char* if_list; + + if (!validate_ifname(options->ifname)) { + if_list = get_valid_ifnames(); + if (if_list) { + error_setg(errp, + "unsupported ifname '%s', expected one of [ %s]", + options->ifname, + if_list); + g_free(if_list); + } else { + error_setg(errp, + "unsupported ifname '%s', no supported " + "interfaces available", + options->ifname); + } + return false; + } + +#if !defined(MAC_OS_VERSION_11_0) || \ + MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_11_0 + if (options->has_isolated) { + error_setg(errp, + "vmnet-bridged.isolated feature is " + "unavailable: outdated vmnet.framework API"); + return false; + } +#endif + return true; +} + + +static xpc_object_t build_if_desc(const Netdev *netdev) +{ + const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged); + xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0); + + xpc_dictionary_set_uint64(if_desc, + vmnet_operation_mode_key, + VMNET_BRIDGED_MODE + ); + + xpc_dictionary_set_string(if_desc, + vmnet_shared_interface_name_key, + options->ifname); + +#if defined(MAC_OS_VERSION_11_0) && \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0 + xpc_dictionary_set_bool(if_desc, + vmnet_enable_isolation_key, + options->isolated); +#endif + return if_desc; +} + + +static NetClientInfo net_vmnet_bridged_info = { + .type = NET_CLIENT_DRIVER_VMNET_BRIDGED, + .size = sizeof(VmnetState), + .receive = vmnet_receive_common, + .cleanup = vmnet_cleanup_common, +}; + + int net_init_vmnet_bridged(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp) { - error_setg(errp, "vmnet-bridged is not implemented yet"); - return -1; + NetClientState *nc = qemu_new_net_client(&net_vmnet_bridged_info, + peer, "vmnet-bridged", name); + xpc_object_t if_desc; + int result = -1; + + if (!validate_options(netdev, errp)) { + return result; + } + + if_desc = build_if_desc(netdev); + result = vmnet_if_create(nc, if_desc, errp); + xpc_release(if_desc); + return result; } From b0290db12d7b6567916ee3cba7bf2f08183121e8 Mon Sep 17 00:00:00 2001 From: Vladislav Yaroshchuk Date: Thu, 17 Mar 2022 20:28:38 +0300 Subject: [PATCH 421/935] net/vmnet: update qemu-options.hx Update qemu-options.hx to support vmnet networking backend. Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki Signed-off-by: Vladislav Yaroshchuk Signed-off-by: Jason Wang --- qemu-options.hx | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/qemu-options.hx b/qemu-options.hx index b484640067..a664baaa18 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2795,6 +2795,25 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, #ifdef __linux__ "-netdev vhost-vdpa,id=str,vhostdev=/path/to/dev\n" " configure a vhost-vdpa network,Establish a vhost-vdpa netdev\n" +#endif +#ifdef CONFIG_VMNET + "-netdev vmnet-host,id=str[,isolated=on|off][,net-uuid=uuid]\n" + " [,start-address=addr,end-address=addr,subnet-mask=mask]\n" + " configure a vmnet network backend in host mode with ID 'str',\n" + " isolate this interface from others with 'isolated',\n" + " configure the address range and choose a subnet mask,\n" + " specify network UUID 'uuid' to disable DHCP and interact with\n" + " vmnet-host interfaces within this isolated network\n" + "-netdev vmnet-shared,id=str[,isolated=on|off][,nat66-prefix=addr]\n" + " [,start-address=addr,end-address=addr,subnet-mask=mask]\n" + " configure a vmnet network backend in shared mode with ID 'str',\n" + " configure the address range and choose a subnet mask,\n" + " set IPv6 ULA prefix (of length 64) to use for internal network,\n" + " isolate this interface from others with 'isolated'\n" + "-netdev vmnet-bridged,id=str,ifname=name[,isolated=on|off]\n" + " configure a vmnet network backend in bridged mode with ID 'str',\n" + " use 'ifname=name' to select a physical network interface to be bridged,\n" + " isolate this interface from others with 'isolated'\n" #endif "-netdev hubport,id=str,hubid=n[,netdev=nd]\n" " configure a hub port on the hub with ID 'n'\n", QEMU_ARCH_ALL) @@ -2814,6 +2833,9 @@ DEF("nic", HAS_ARG, QEMU_OPTION_nic, #endif #ifdef CONFIG_POSIX "vhost-user|" +#endif +#ifdef CONFIG_VMNET + "vmnet-host|vmnet-shared|vmnet-bridged|" #endif "socket][,option][,...][mac=macaddr]\n" " initialize an on-board / default host NIC (using MAC address\n" @@ -2836,6 +2858,9 @@ DEF("net", HAS_ARG, QEMU_OPTION_net, #endif #ifdef CONFIG_NETMAP "netmap|" +#endif +#ifdef CONFIG_VMNET + "vmnet-host|vmnet-shared|vmnet-bridged|" #endif "socket][,option][,option][,...]\n" " old way to initialize a host network interface\n" From fd8c8c056d17e78efdcfe680b4830cd646d5d5a0 Mon Sep 17 00:00:00 2001 From: Vladislav Yaroshchuk Date: Thu, 17 Mar 2022 20:28:39 +0300 Subject: [PATCH 422/935] net/vmnet: update hmp-commands.hx Update HMP for supporting vmnet. Reviewed-by: Akihiko Odaki Tested-by: Akihiko Odaki Signed-off-by: Vladislav Yaroshchuk Signed-off-by: Jason Wang --- hmp-commands.hx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 03e6a73d1f..564f1de364 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1269,7 +1269,11 @@ ERST { .name = "netdev_add", .args_type = "netdev:O", - .params = "[user|tap|socket|vde|bridge|hubport|netmap|vhost-user],id=str[,prop=value][,...]", + .params = "[user|tap|socket|vde|bridge|hubport|netmap|vhost-user" +#ifdef CONFIG_VMNET + "|vmnet-host|vmnet-shared|vmnet-bridged" +#endif + "],id=str[,prop=value][,...]", .help = "add host network device", .cmd = hmp_netdev_add, .command_completion = netdev_add_completion, From 052c2579b89b0d87debe8b05594b5180f0fde87d Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 10 Mar 2022 17:55:50 +0100 Subject: [PATCH 423/935] tulip: Assign default MAC address if not specified MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MAC of the tulip card is stored in the EEPROM and at startup tulip_fill_eeprom() is called to initialize the EEPROM with the MAC address given on the command line, e.g.: -device tulip,mac=00:11:22:33:44:55 In case the mac address was not given on the command line, tulip_fill_eeprom() initializes the MAC in EEPROM with 00:00:00:00:00:00 which breaks e.g. a HP-UX guest. Fix this problem by moving qemu_macaddr_default_if_unset() a few lines up, so that a default mac address is assigned before tulip_fill_eeprom() initializes the EEPROM. Signed-off-by: Helge Deller Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Jason Wang --- hw/net/tulip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/net/tulip.c b/hw/net/tulip.c index d5b6cc5ee6..097e905bec 100644 --- a/hw/net/tulip.c +++ b/hw/net/tulip.c @@ -967,6 +967,8 @@ static void pci_tulip_realize(PCIDevice *pci_dev, Error **errp) pci_conf = s->dev.config; pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */ + qemu_macaddr_default_if_unset(&s->c.macaddr); + s->eeprom = eeprom93xx_new(&pci_dev->qdev, 64); tulip_fill_eeprom(s); @@ -981,8 +983,6 @@ static void pci_tulip_realize(PCIDevice *pci_dev, Error **errp) s->irq = pci_allocate_irq(&s->dev); - qemu_macaddr_default_if_unset(&s->c.macaddr); - s->nic = qemu_new_nic(&net_tulip_info, &s->c, object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s); From e4e68c31db5472111fbff528d7348a7e6b2ae07d Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 16 May 2022 10:23:10 +0200 Subject: [PATCH 424/935] gitlab-ci: Switch the container of the 'check-patch' & 'check-dco' jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'check-patch' and 'check-dco' jobs only need Python and git for checking the patches, so it's not really necessary to use a container here that has all the other build dependencies installed. By using a lightweight Alpine container, we can improve the runtime here quite a bit, cutting it down from ca. 1:30 minutes to ca. 45 seconds. Suggested-by: Daniel P. Berrangé Message-Id: <20220516082310.33876-1-thuth@redhat.com> Reviewed-by: Daniel P. Berrangé Reviewed-by: John Snow Signed-off-by: Thomas Huth --- .gitlab-ci.d/static_checks.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.d/static_checks.yml b/.gitlab-ci.d/static_checks.yml index 5e955540d3..94858e3272 100644 --- a/.gitlab-ci.d/static_checks.yml +++ b/.gitlab-ci.d/static_checks.yml @@ -1,12 +1,13 @@ check-patch: stage: build - image: $CI_REGISTRY_IMAGE/qemu/centos8:latest - needs: - job: amd64-centos8-container + image: python:3.10-alpine + needs: [] script: - .gitlab-ci.d/check-patch.py variables: GIT_DEPTH: 1000 + before_script: + - apk -U add git perl rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project"' when: never @@ -15,12 +16,13 @@ check-patch: check-dco: stage: build - image: $CI_REGISTRY_IMAGE/qemu/centos8:latest - needs: - job: amd64-centos8-container + image: python:3.10-alpine + needs: [] script: .gitlab-ci.d/check-dco.py variables: GIT_DEPTH: 1000 + before_script: + - apk -U add git rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' when: never From f3f0cbaf97c78b1fc1f3855f576e46ea6ad4f34c Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 16 May 2022 13:59:12 +0200 Subject: [PATCH 425/935] Remove Ubuntu 18.04 container support from the repository MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to our "Supported build platforms" policy, we now do not support Ubuntu 18.04 anymore. Remove the related container files and entries from our CI. Message-Id: <20220516115912.120951-1-thuth@redhat.com> Reviewed-by: Daniel P. Berrangé Signed-off-by: Thomas Huth --- .gitlab-ci.d/containers.yml | 5 - .../custom-runners/ubuntu-20.04-aarch32.yml | 2 +- .../custom-runners/ubuntu-20.04-aarch64.yml | 2 +- scripts/ci/setup/build-environment.yml | 14 +- tests/docker/dockerfiles/ubuntu1804.docker | 144 ------------------ tests/lcitool/refresh | 7 - 6 files changed, 4 insertions(+), 170 deletions(-) delete mode 100644 tests/docker/dockerfiles/ubuntu1804.docker diff --git a/.gitlab-ci.d/containers.yml b/.gitlab-ci.d/containers.yml index b9b675fdcb..e9df90bbdd 100644 --- a/.gitlab-ci.d/containers.yml +++ b/.gitlab-ci.d/containers.yml @@ -19,11 +19,6 @@ amd64-debian-container: variables: NAME: debian-amd64 -amd64-ubuntu1804-container: - extends: .container_job_template - variables: - NAME: ubuntu1804 - amd64-ubuntu2004-container: extends: .container_job_template variables: diff --git a/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch32.yml b/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch32.yml index 9c589bc4cf..47856ac53c 100644 --- a/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch32.yml +++ b/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch32.yml @@ -1,6 +1,6 @@ # All ubuntu-20.04 jobs should run successfully in an environment # setup by the scripts/ci/setup/qemu/build-environment.yml task -# "Install basic packages to build QEMU on Ubuntu 18.04/20.04" +# "Install basic packages to build QEMU on Ubuntu 20.04" ubuntu-20.04-aarch32-all: needs: [] diff --git a/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml b/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml index 920e388bd0..951e490db1 100644 --- a/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml +++ b/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml @@ -1,6 +1,6 @@ # All ubuntu-20.04 jobs should run successfully in an environment # setup by the scripts/ci/setup/qemu/build-environment.yml task -# "Install basic packages to build QEMU on Ubuntu 18.04/20.04" +# "Install basic packages to build QEMU on Ubuntu 20.04" ubuntu-20.04-aarch64-all-linux-static: needs: [] diff --git a/scripts/ci/setup/build-environment.yml b/scripts/ci/setup/build-environment.yml index 9182e0c253..232525b91d 100644 --- a/scripts/ci/setup/build-environment.yml +++ b/scripts/ci/setup/build-environment.yml @@ -33,10 +33,9 @@ when: - ansible_facts['distribution'] == 'Ubuntu' - - name: Install basic packages to build QEMU on Ubuntu 18.04/20.04 + - name: Install basic packages to build QEMU on Ubuntu 20.04 package: name: - # Originally from tests/docker/dockerfiles/ubuntu1804.docker - ccache - gcc - gettext @@ -90,7 +89,7 @@ when: - ansible_facts['distribution'] == 'Ubuntu' - - name: Install packages to build QEMU on Ubuntu 18.04/20.04 on non-s390x + - name: Install packages to build QEMU on Ubuntu 20.04 on non-s390x package: name: - libspice-server-dev @@ -100,15 +99,6 @@ - ansible_facts['distribution'] == 'Ubuntu' - ansible_facts['architecture'] != 's390x' - - name: Install basic packages to build QEMU on Ubuntu 18.04 - package: - name: - # Originally from tests/docker/dockerfiles/ubuntu1804.docker - - clang - when: - - ansible_facts['distribution'] == 'Ubuntu' - - ansible_facts['distribution_version'] == '18.04' - - name: Install basic packages to build QEMU on Ubuntu 20.04 package: name: diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker deleted file mode 100644 index b3f2156580..0000000000 --- a/tests/docker/dockerfiles/ubuntu1804.docker +++ /dev/null @@ -1,144 +0,0 @@ -# THIS FILE WAS AUTO-GENERATED -# -# $ lcitool dockerfile --layers all ubuntu-1804 qemu -# -# https://gitlab.com/libvirt/libvirt-ci - -FROM docker.io/library/ubuntu:18.04 - -RUN export DEBIAN_FRONTEND=noninteractive && \ - apt-get update && \ - apt-get install -y eatmydata && \ - eatmydata apt-get dist-upgrade -y && \ - eatmydata apt-get install --no-install-recommends -y \ - bash \ - bc \ - bsdmainutils \ - bzip2 \ - ca-certificates \ - ccache \ - clang \ - dbus \ - debianutils \ - diffutils \ - exuberant-ctags \ - findutils \ - g++ \ - gcc \ - gcovr \ - genisoimage \ - gettext \ - git \ - glusterfs-common \ - hostname \ - libaio-dev \ - libasan5 \ - libasound2-dev \ - libattr1-dev \ - libbrlapi-dev \ - libbz2-dev \ - libc6-dev \ - libcacard-dev \ - libcap-ng-dev \ - libcapstone-dev \ - libcurl4-gnutls-dev \ - libdaxctl-dev \ - libdrm-dev \ - libepoxy-dev \ - libfdt-dev \ - libffi-dev \ - libgbm-dev \ - libgcrypt20-dev \ - libglib2.0-dev \ - libgnutls28-dev \ - libgtk-3-dev \ - libibumad-dev \ - libibverbs-dev \ - libiscsi-dev \ - libjemalloc-dev \ - libjpeg-turbo8-dev \ - liblttng-ust-dev \ - liblzo2-dev \ - libncursesw5-dev \ - libnfs-dev \ - libnuma-dev \ - libpam0g-dev \ - libpcre2-dev \ - libpixman-1-dev \ - libpmem-dev \ - libpng-dev \ - libpulse-dev \ - librbd-dev \ - librdmacm-dev \ - libsasl2-dev \ - libsdl2-dev \ - libsdl2-image-dev \ - libseccomp-dev \ - libselinux1-dev \ - libsnappy-dev \ - libspice-protocol-dev \ - libspice-server-dev \ - libssh-dev \ - libsystemd-dev \ - libtasn1-6-dev \ - libubsan1 \ - libudev-dev \ - libusb-1.0-0-dev \ - libusbredirhost-dev \ - libvdeplug-dev \ - libvirglrenderer-dev \ - libvte-2.91-dev \ - libxen-dev \ - libzstd-dev \ - llvm \ - locales \ - make \ - multipath-tools \ - netcat-openbsd \ - nettle-dev \ - ninja-build \ - openssh-client \ - perl-base \ - pkgconf \ - python3 \ - python3-numpy \ - python3-opencv \ - python3-pillow \ - python3-pip \ - python3-setuptools \ - python3-sphinx \ - python3-sphinx-rtd-theme \ - python3-venv \ - python3-wheel \ - python3-yaml \ - rpm2cpio \ - sed \ - sparse \ - systemtap-sdt-dev \ - tar \ - tesseract-ocr \ - tesseract-ocr-eng \ - texinfo \ - xfslibs-dev \ - zlib1g-dev && \ - eatmydata apt-get autoremove -y && \ - eatmydata apt-get autoclean -y && \ - sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ - dpkg-reconfigure locales && \ - dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ - mkdir -p /usr/libexec/ccache-wrappers && \ - ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/c++ && \ - ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ - ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang && \ - ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \ - ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc - -RUN pip3 install meson==0.56.0 - -ENV LANG "en_US.UTF-8" -ENV MAKE "/usr/bin/make" -ENV NINJA "/usr/bin/ninja" -ENV PYTHON "/usr/bin/python3" -ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" -# https://bugs.launchpad.net/qemu/+bug/1838763 -ENV QEMU_CONFIGURE_OPTS --disable-libssh diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh index 2d198ad281..fb49bbc441 100755 --- a/tests/lcitool/refresh +++ b/tests/lcitool/refresh @@ -65,11 +65,6 @@ def generate_cirrus(target, trailer=None): cmd = lcitool_cmd + ["variables", target, "qemu"] generate(filename, cmd, trailer) -ubuntu1804_skipssh = [ - "# https://bugs.launchpad.net/qemu/+bug/1838763\n", - "ENV QEMU_CONFIGURE_OPTS --disable-libssh\n" -] - ubuntu2004_tsanhack = [ "# Apply patch https://reviews.llvm.org/D75820\n", "# This is required for TSan in clang-10 to compile with QEMU.\n", @@ -85,8 +80,6 @@ def debian_cross_build(prefix, targets): try: generate_dockerfile("centos8", "centos-stream-8") generate_dockerfile("fedora", "fedora-35") - generate_dockerfile("ubuntu1804", "ubuntu-1804", - trailer="".join(ubuntu1804_skipssh)) generate_dockerfile("ubuntu2004", "ubuntu-2004", trailer="".join(ubuntu2004_tsanhack)) generate_dockerfile("opensuse-leap", "opensuse-leap-152") From 83f79d4efc8dac7e511bc4375d0f9d90ff9db731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 13 May 2022 16:49:05 +0100 Subject: [PATCH 426/935] tests/qtest: fix registration of ABRT handler for QEMU cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qtest_init registers a hook to cleanup the running QEMU process should g_assert() fire before qtest_quit is called. When the first hook is registered, it is supposed to triggere registration of the SIGABRT handler. Unfortunately the logic in hook_list_is_empty is inverted, so the SIGABRT handler never gets registered, unless 2 or more QEMU processes are run concurrently. This caused qtest to leak QEMU processes anytime g_assert triggers. Signed-off-by: Daniel P. Berrangé Message-Id: <20220513154906.206715-2-berrange@redhat.com> Reviewed-by: Thomas Huth Signed-off-by: Thomas Huth --- tests/qtest/libqtest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 228357f1ea..4a4697c0d1 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -197,11 +197,11 @@ static bool hook_list_is_empty(GHookList *hook_list) GHook *hook = g_hook_first_valid(hook_list, TRUE); if (!hook) { - return false; + return true; } g_hook_unref(hook_list, hook); - return true; + return false; } void qtest_add_abrt_handler(GHookFunc fn, const void *data) From 6cbde91a27587ca27a3c1979fe7f5f0d28eb6db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 13 May 2022 16:49:06 +0100 Subject: [PATCH 427/935] tests/qtest: use prctl(PR_SET_PDEATHSIG) as fallback to kill QEMU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Although we register a ABRT handler to kill off QEMU when g_assert() triggers, we want an extra safety net. The QEMU process might be non-functional and thus not have responded to SIGTERM. The test script might also have crashed with SEGV, in which case the cleanup handlers won't ever run. Using the Linux specific prctl(PR_SET_PDEATHSIG) syscall, we can ensure that QEMU gets sent SIGKILL as soon as the controlling qtest exits, if nothing else has correctly told it to quit. Note, technically the death signal is sent when the *thread* that called fork() exits. IOW, if you are calling qtest_init() in one thread, letting that thread exit, and then expecting to run qtest_quit() in a different thread, things are not going to work out. Fortunately that is not a scenario that exists in qtests, as pairs of qtest_init and qtest_quit are always called from the same thread. Signed-off-by: Daniel P. Berrangé Message-Id: <20220513154906.206715-3-berrange@redhat.com> Reviewed-by: Thomas Huth Signed-off-by: Thomas Huth --- tests/qtest/libqtest.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 4a4697c0d1..2e49618454 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -19,6 +19,9 @@ #include #include #include +#ifdef __linux__ +#include +#endif /* __linux__ */ #include "libqtest.h" #include "libqmp.h" @@ -301,6 +304,20 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args) s->expected_status = 0; s->qemu_pid = fork(); if (s->qemu_pid == 0) { +#ifdef __linux__ + /* + * Although we register a ABRT handler to kill off QEMU + * when g_assert() triggers, we want an extra safety + * net. The QEMU process might be non-functional and + * thus not have responded to SIGTERM. The test script + * might also have crashed with SEGV, in which case the + * cleanup handlers won't ever run. + * + * This PR_SET_PDEATHSIG setup will ensure any remaining + * QEMU will get terminated with SIGKILL in these cases. + */ + prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); +#endif /* __linux__ */ if (!g_setenv("QEMU_AUDIO_DRV", "none", true)) { exit(1); } From 0ce9b08c10d043307d125709032a897d05c80bdd Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 13 May 2022 08:39:58 +0200 Subject: [PATCH 428/935] docs/about: Update the support statement for Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Our support statement for Windows currently talks about "Vista / Server 2008" - which is related to the API of Windows, and this is not easy to understand for the non-technical users. Additionally, glib sets the _WIN32_WINNT macro to 0x0601 already, which indicates the Windows 7 API, so QEMU effectively depends on the Windows 7 API, too. Thus let's bump the _WIN32_WINNT setting in QEMU to the same level as glib uses and adjust our support statement in the documentation to something similar that we're using for Linux and the *BSD systems (i.e. only the two most recent versions), which should hopefully be easier to understand for the users now. And since we're nowadays also compile-testing QEMU with MSYS2 on Windows itself, I think we could mention this build environment here, too. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/880 Reviewed-by: Daniel P. Berrangé Reviewed-by: Stefan Weil Message-Id: <20220513063958.1181443-1-thuth@redhat.com> Signed-off-by: Thomas Huth --- configure | 2 ++ docs/about/build-platforms.rst | 12 ++++++++---- include/qemu/osdep.h | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/configure b/configure index 0cc8c876f7..103a7b02e8 100755 --- a/configure +++ b/configure @@ -1486,6 +1486,8 @@ fi ########################################## # glib support probe +# When bumping glib_req_ver, please check also whether we should increase +# the _WIN32_WINNT setting in osdep.h according to the value from glib glib_req_ver=2.56 glib_modules=gthread-2.0 if test "$modules" = yes; then diff --git a/docs/about/build-platforms.rst b/docs/about/build-platforms.rst index e9163ba556..1958edb430 100644 --- a/docs/about/build-platforms.rst +++ b/docs/about/build-platforms.rst @@ -86,11 +86,15 @@ similar versions. Windows ------- -The project supports building with current versions of the MinGW toolchain, -hosted on Linux (Debian/Fedora). +The project aims to support the two most recent versions of Windows that are +still supported by the vendor. The minimum Windows API that is currently +targeted is "Windows 7", so theoretically the QEMU binaries can still be run +on older versions of Windows, too. However, such old versions of Windows are +not tested anymore, so it is recommended to use one of the latest versions of +Windows instead. -The version of the Windows API that's currently targeted is Vista / Server -2008. +The project supports building QEMU with current versions of the MinGW +toolchain, either hosted on Linux (Debian/Fedora) or via MSYS2 on Windows. .. _Homebrew: https://brew.sh/ .. _MacPorts: https://www.macports.org/ diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 1c1e7eca98..a72e99db85 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -75,7 +75,7 @@ QEMU_EXTERN_C int daemon(int, int); #ifdef _WIN32 /* as defined in sdkddkver.h */ #ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 /* Vista */ +#define _WIN32_WINNT 0x0601 /* Windows 7 API (should be in sync with glib) */ #endif /* reduces the number of implicitly included headers */ #ifndef WIN32_LEAN_AND_MEAN From 28e7e95e6bc374262a3f03cf7b6fb7a1b3c3ebbe Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 16 May 2022 16:58:21 +0200 Subject: [PATCH 429/935] tests/vm: Add capstone to the NetBSD and OpenBSD VMs The Capstone library that is shipped with NetBSD and OpenBSD works fine when compiling QEMU, so let's enable this in our build-test VMs to get a little bit more build-test coverage. Message-Id: <20220516145823.148450-2-thuth@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Thomas Huth --- tests/vm/netbsd | 3 ++- tests/vm/openbsd | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/vm/netbsd b/tests/vm/netbsd index 4cc58df130..45aa9a7fda 100755 --- a/tests/vm/netbsd +++ b/tests/vm/netbsd @@ -46,7 +46,8 @@ class NetBSDVM(basevm.BaseVM): "jpeg", "png", - # libs: ui + # libs: ui + "capstone", "SDL2", "gtk3+", "libxkbcommon", diff --git a/tests/vm/openbsd b/tests/vm/openbsd index dc34b2718b..13c8254214 100755 --- a/tests/vm/openbsd +++ b/tests/vm/openbsd @@ -48,7 +48,8 @@ class OpenBSDVM(basevm.BaseVM): "jpeg", "png", - # libs: ui + # libs: ui + "capstone", "sdl2", "gtk+3", "libxkbcommon", From 43ecd16678b74b281c3cc7de0dd62a36279b6025 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 16 May 2022 16:58:22 +0200 Subject: [PATCH 430/935] capstone: Allow version 3.0.5 again According to https://lore.kernel.org/qemu-devel/20200921174118.39352-1-richard.henderson@linaro.org/ there was an issue with Capstone 3.0.4 from Ubuntu 18, which was the reason for bumping our minimum Capstone requirement to version 4.0. And indeed, compiling with that version 3.0.4 from Ubuntu 18.04 still fails (after allowing it with a hack in meson.build). But now that we've dropped support for Ubuntu 18.04, that issue is not relevant anymore. Compiling with Capstone version 3.0.5 (e.g. used in Ubuntu 20.04) seems to work fine, so let's allow that version again. Message-Id: <20220516145823.148450-3-thuth@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Thomas Huth --- .gitlab-ci.d/buildtest.yml | 1 + meson.build | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index 0aea7ab84c..a4d43d743b 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -42,6 +42,7 @@ build-system-ubuntu: variables: IMAGE: ubuntu2004 CONFIGURE_ARGS: --enable-docs --enable-fdt=system --enable-slirp=system + --enable-capstone=system TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu microblazeel-softmmu mips64el-softmmu MAKE_CHECK_ARGS: check-build diff --git a/meson.build b/meson.build index 53a4728250..526ff29a86 100644 --- a/meson.build +++ b/meson.build @@ -2525,7 +2525,7 @@ capstone = not_found capstone_opt = get_option('capstone') if capstone_opt in ['enabled', 'auto', 'system'] have_internal = fs.exists(meson.current_source_dir() / 'capstone/Makefile') - capstone = dependency('capstone', version: '>=4.0', + capstone = dependency('capstone', version: '>=3.0.5', kwargs: static_kwargs, method: 'pkg-config', required: capstone_opt == 'system' or capstone_opt == 'enabled' and not have_internal) From 83602083b4ada6ceb86bfb327e83556ebab120fc Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 16 May 2022 16:58:23 +0200 Subject: [PATCH 431/935] capstone: Remove the capstone submodule Now that we allow compiling with Capstone v3.0.5 again, all our supported build hosts should provide at least this version of the disassembler library, so we do not need to ship this as a submodule anymore. Message-Id: <20220516145823.148450-4-thuth@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Thomas Huth --- .gitlab-ci.d/buildtest.yml | 4 +- .gitlab-ci.d/windows.yml | 5 +- .gitmodules | 3 - capstone | 1 - configure | 21 ------- meson.build | 113 ++-------------------------------- meson_options.txt | 3 +- scripts/meson-buildoptions.sh | 5 +- 8 files changed, 11 insertions(+), 144 deletions(-) delete mode 160000 capstone diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index a4d43d743b..e9620c3074 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -42,7 +42,7 @@ build-system-ubuntu: variables: IMAGE: ubuntu2004 CONFIGURE_ARGS: --enable-docs --enable-fdt=system --enable-slirp=system - --enable-capstone=system + --enable-capstone TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu microblazeel-softmmu mips64el-softmmu MAKE_CHECK_ARGS: check-build @@ -119,7 +119,7 @@ build-system-fedora: variables: IMAGE: fedora CONFIGURE_ARGS: --disable-gcrypt --enable-nettle --enable-docs - --enable-fdt=system --enable-slirp=system --enable-capstone=system + --enable-fdt=system --enable-slirp=system --enable-capstone TARGETS: tricore-softmmu microblaze-softmmu mips-softmmu xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu MAKE_CHECK_ARGS: check-build diff --git a/.gitlab-ci.d/windows.yml b/.gitlab-ci.d/windows.yml index 47f6073773..cf7724b8e5 100644 --- a/.gitlab-ci.d/windows.yml +++ b/.gitlab-ci.d/windows.yml @@ -57,7 +57,7 @@ msys2-64bit: - $env:CHERE_INVOKING = 'yes' # Preserve the current working directory - $env:MSYSTEM = 'MINGW64' # Start a 64 bit Mingw environment - .\msys64\usr\bin\bash -lc './configure --target-list=x86_64-softmmu - --enable-capstone=system --without-default-devices' + --enable-capstone --without-default-devices' - .\msys64\usr\bin\bash -lc "sed -i '/^ROMS=/d' build/config-host.mak" - .\msys64\usr\bin\bash -lc 'make -j2' - .\msys64\usr\bin\bash -lc 'make check' @@ -90,7 +90,6 @@ msys2-32bit: - $env:MSYSTEM = 'MINGW32' # Start a 32-bit MinG environment - mkdir output - cd output - - ..\msys64\usr\bin\bash -lc "../configure --target-list=ppc64-softmmu - --enable-capstone=system" + - ..\msys64\usr\bin\bash -lc "../configure --target-list=ppc64-softmmu" - ..\msys64\usr\bin\bash -lc 'make -j2' - ..\msys64\usr\bin\bash -lc 'make check' diff --git a/.gitmodules b/.gitmodules index f4b6a9b401..b8bff47df8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -31,9 +31,6 @@ [submodule "ui/keycodemapdb"] path = ui/keycodemapdb url = https://gitlab.com/qemu-project/keycodemapdb.git -[submodule "capstone"] - path = capstone - url = https://gitlab.com/qemu-project/capstone.git [submodule "roms/seabios-hppa"] path = roms/seabios-hppa url = https://gitlab.com/qemu-project/seabios-hppa.git diff --git a/capstone b/capstone deleted file mode 160000 index f8b1b83301..0000000000 --- a/capstone +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f8b1b833015a4ae47110ed068e0deb7106ced66d diff --git a/configure b/configure index 103a7b02e8..180ee688dc 100755 --- a/configure +++ b/configure @@ -307,10 +307,8 @@ skip_meson=no # 1. Track which submodules are needed if test "$default_feature" = no ; then - capstone="disabled" slirp="disabled" else - capstone="auto" slirp="auto" fi fdt="auto" @@ -869,14 +867,6 @@ for opt do --enable-uuid|--disable-uuid) echo "$0: $opt is obsolete, UUID support is always built" >&2 ;; - --disable-capstone) capstone="disabled" - ;; - --enable-capstone) capstone="enabled" - ;; - --enable-capstone=git) capstone="internal" - ;; - --enable-capstone=*) capstone="$optarg" - ;; --with-git=*) git="$optarg" ;; --with-git-submodules=*) @@ -1566,16 +1556,6 @@ case "$fdt" in ;; esac -########################################## -# capstone - -case "$capstone" in - auto | enabled | internal) - # Simpler to always update submodule, even if not needed. - git_submodules="${git_submodules} capstone" - ;; -esac - ########################################## # check and set a backend for coroutine @@ -2220,7 +2200,6 @@ if test "$skip_meson" = no; then test "$werror" = yes && meson_option_add -Dwerror=true # QEMU options - test "$capstone" != auto && meson_option_add "-Dcapstone=$capstone" test "$cfi" != false && meson_option_add "-Dcfi=$cfi" test "$fdt" != auto && meson_option_add "-Dfdt=$fdt" test -n "${LIB_FUZZING_ENGINE+xxx}" && meson_option_add "-Dfuzzing_engine=$LIB_FUZZING_ENGINE" diff --git a/meson.build b/meson.build index 526ff29a86..c4fb8fa5d0 100644 --- a/meson.build +++ b/meson.build @@ -2522,13 +2522,10 @@ genh += custom_target('config-poison.h', ############## capstone = not_found -capstone_opt = get_option('capstone') -if capstone_opt in ['enabled', 'auto', 'system'] - have_internal = fs.exists(meson.current_source_dir() / 'capstone/Makefile') +if not get_option('capstone').auto() or have_system or have_user capstone = dependency('capstone', version: '>=3.0.5', kwargs: static_kwargs, method: 'pkg-config', - required: capstone_opt == 'system' or - capstone_opt == 'enabled' and not have_internal) + required: get_option('capstone')) # Some versions of capstone have broken pkg-config file # that reports a wrong -I path, causing the #include to @@ -2537,110 +2534,10 @@ if capstone_opt in ['enabled', 'auto', 'system'] if capstone.found() and not cc.compiles('#include ', dependencies: [capstone]) capstone = not_found - if capstone_opt == 'system' - error('system capstone requested, it does not appear to work') + if get_option('capstone').enabled() + error('capstone requested, but it does not appear to work') endif endif - - if capstone.found() - capstone_opt = 'system' - elif have_internal - capstone_opt = 'internal' - else - capstone_opt = 'disabled' - endif -endif -if capstone_opt == 'internal' - capstone_data = configuration_data() - capstone_data.set('CAPSTONE_USE_SYS_DYN_MEM', '1') - - capstone_files = files( - 'capstone/cs.c', - 'capstone/MCInst.c', - 'capstone/MCInstrDesc.c', - 'capstone/MCRegisterInfo.c', - 'capstone/SStream.c', - 'capstone/utils.c' - ) - - if 'CONFIG_ARM_DIS' in config_all_disas - capstone_data.set('CAPSTONE_HAS_ARM', '1') - capstone_files += files( - 'capstone/arch/ARM/ARMDisassembler.c', - 'capstone/arch/ARM/ARMInstPrinter.c', - 'capstone/arch/ARM/ARMMapping.c', - 'capstone/arch/ARM/ARMModule.c' - ) - endif - - # FIXME: This config entry currently depends on a c++ compiler. - # Which is needed for building libvixl, but not for capstone. - if 'CONFIG_ARM_A64_DIS' in config_all_disas - capstone_data.set('CAPSTONE_HAS_ARM64', '1') - capstone_files += files( - 'capstone/arch/AArch64/AArch64BaseInfo.c', - 'capstone/arch/AArch64/AArch64Disassembler.c', - 'capstone/arch/AArch64/AArch64InstPrinter.c', - 'capstone/arch/AArch64/AArch64Mapping.c', - 'capstone/arch/AArch64/AArch64Module.c' - ) - endif - - if 'CONFIG_PPC_DIS' in config_all_disas - capstone_data.set('CAPSTONE_HAS_POWERPC', '1') - capstone_files += files( - 'capstone/arch/PowerPC/PPCDisassembler.c', - 'capstone/arch/PowerPC/PPCInstPrinter.c', - 'capstone/arch/PowerPC/PPCMapping.c', - 'capstone/arch/PowerPC/PPCModule.c' - ) - endif - - if 'CONFIG_S390_DIS' in config_all_disas - capstone_data.set('CAPSTONE_HAS_SYSZ', '1') - capstone_files += files( - 'capstone/arch/SystemZ/SystemZDisassembler.c', - 'capstone/arch/SystemZ/SystemZInstPrinter.c', - 'capstone/arch/SystemZ/SystemZMapping.c', - 'capstone/arch/SystemZ/SystemZModule.c', - 'capstone/arch/SystemZ/SystemZMCTargetDesc.c' - ) - endif - - if 'CONFIG_I386_DIS' in config_all_disas - capstone_data.set('CAPSTONE_HAS_X86', 1) - capstone_files += files( - 'capstone/arch/X86/X86Disassembler.c', - 'capstone/arch/X86/X86DisassemblerDecoder.c', - 'capstone/arch/X86/X86ATTInstPrinter.c', - 'capstone/arch/X86/X86IntelInstPrinter.c', - 'capstone/arch/X86/X86InstPrinterCommon.c', - 'capstone/arch/X86/X86Mapping.c', - 'capstone/arch/X86/X86Module.c' - ) - endif - - configure_file(output: 'capstone-defs.h', configuration: capstone_data) - - capstone_cargs = [ - # FIXME: There does not seem to be a way to completely replace the c_args - # that come from add_project_arguments() -- we can only add to them. - # So: disable all warnings with a big hammer. - '-Wno-error', '-w', - - # Include all configuration defines via a header file, which will wind up - # as a dependency on the object file, and thus changes here will result - # in a rebuild. - '-include', 'capstone-defs.h' - ] - - libcapstone = static_library('capstone', - build_by_default: false, - sources: capstone_files, - c_args: capstone_cargs, - include_directories: 'capstone/include') - capstone = declare_dependency(link_with: libcapstone, - include_directories: 'capstone/include/capstone') endif slirp = not_found @@ -3970,7 +3867,7 @@ summary_info += {'bzip2 support': libbzip2} summary_info += {'lzfse support': liblzfse} summary_info += {'zstd support': zstd} summary_info += {'NUMA host support': numa} -summary_info += {'capstone': capstone_opt == 'internal' ? capstone_opt : capstone} +summary_info += {'capstone': capstone} summary_info += {'libpmem support': libpmem} summary_info += {'libdaxctl support': libdaxctl} summary_info += {'libudev': libudev} diff --git a/meson_options.txt b/meson_options.txt index 29c6b90cec..fcdc43f7db 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -252,8 +252,7 @@ option('virtfs', type: 'feature', value: 'auto', option('virtiofsd', type: 'feature', value: 'auto', description: 'build virtiofs daemon (virtiofsd)') -option('capstone', type: 'combo', value: 'auto', - choices: ['disabled', 'enabled', 'auto', 'system', 'internal'], +option('capstone', type: 'feature', value: 'auto', description: 'Whether and how to find the capstone library') option('slirp', type: 'combo', value: 'auto', choices: ['disabled', 'enabled', 'auto', 'system', 'internal'], diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 5d2172bfb4..7fc56d3f4a 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -16,9 +16,6 @@ meson_options_help() { printf "%s\n" ' --enable-block-drv-whitelist-in-tools' printf "%s\n" ' use block whitelist also in tools instead of only' printf "%s\n" ' QEMU' - printf "%s\n" ' --enable-capstone[=CHOICE]' - printf "%s\n" ' Whether and how to find the capstone library' - printf "%s\n" ' (choices: auto/disabled/enabled/internal/system)' printf "%s\n" ' --enable-cfi Control-Flow Integrity (CFI)' printf "%s\n" ' --enable-cfi-debug Verbose errors in case of CFI violation' printf "%s\n" ' --enable-debug-mutex mutex debugging support' @@ -77,6 +74,7 @@ meson_options_help() { printf "%s\n" ' brlapi brlapi character device driver' printf "%s\n" ' bzip2 bzip2 support for DMG images' printf "%s\n" ' cap-ng cap_ng support' + printf "%s\n" ' capstone Whether and how to find the capstone library' printf "%s\n" ' cloop cloop image format support' printf "%s\n" ' cocoa Cocoa user interface (macOS only)' printf "%s\n" ' coreaudio CoreAudio sound support' @@ -209,7 +207,6 @@ _meson_option_parse() { --disable-cap-ng) printf "%s" -Dcap_ng=disabled ;; --enable-capstone) printf "%s" -Dcapstone=enabled ;; --disable-capstone) printf "%s" -Dcapstone=disabled ;; - --enable-capstone=*) quote_sh "-Dcapstone=$2" ;; --enable-cfi) printf "%s" -Dcfi=true ;; --disable-cfi) printf "%s" -Dcfi=false ;; --enable-cfi-debug) printf "%s" -Dcfi_debug=true ;; From 9f225e607f215003de1e4157255bb0199adff9aa Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 5 May 2022 19:39:47 +0100 Subject: [PATCH 432/935] target/arm: Postpone interpretation of stage 2 descriptor attribute bits In the original Arm v8 two-stage translation, both stage 1 and stage 2 specify memory attributes (memory type, cacheability, shareability); these are then combined to produce the overall memory attributes for the whole stage 1+2 access. In QEMU we implement this by having get_phys_addr() fill in an ARMCacheAttrs struct, and we convert both the stage 1 and stage 2 attribute bit formats to the same encoding (an 8-bit attribute value matching the MAIR_EL1 fields, plus a 2-bit shareability value). The new FEAT_S2FWB feature allows the guest to enable a different interpretation of the attribute bits in the stage 2 descriptors. These bits can now be used to control details of how the stage 1 and 2 attributes should be combined (for instance they can say "always use the stage 1 attributes" or "ignore the stage 1 attributes and always be Device memory"). This means we need to pass the raw bit information for stage 2 down to the function which combines the stage 1 and stage 2 information. Add a field to ARMCacheAttrs that indicates whether the attrs field should be interpreted as MAIR format, or as the raw stage 2 attribute bits from the descriptor, and store the appropriate values when filling in cacheattrs. We only need to interpret the attrs field in a few places: * in do_ats_write(), where we know to expect a MAIR value (there is no ATS instruction to do a stage-2-only walk) * in S1_ptw_translate(), where we want to know whether the combined S1 + S2 attributes indicate Device memory that should provoke a fault * in combine_cacheattrs(), which does the S1 + S2 combining Update those places accordingly. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220505183950.2781801-2-peter.maydell@linaro.org --- target/arm/helper.c | 42 ++++++++++++++++++++++++++++++++++++------ target/arm/internals.h | 7 ++++++- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 432bd81919..93c58ad29a 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -3187,6 +3187,12 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, ret = get_phys_addr(env, value, access_type, mmu_idx, &phys_addr, &attrs, &prot, &page_size, &fi, &cacheattrs); + /* + * ATS operations only do S1 or S1+S2 translations, so we never + * have to deal with the ARMCacheAttrs format for S2 only. + */ + assert(!cacheattrs.is_s2_format); + if (ret) { /* * Some kinds of translation fault must cause exceptions rather @@ -10717,6 +10723,19 @@ static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, return true; } +static bool ptw_attrs_are_device(CPUARMState *env, ARMCacheAttrs cacheattrs) +{ + /* + * For an S1 page table walk, the stage 1 attributes are always + * some form of "this is Normal memory". The combined S1+S2 + * attributes are therefore only Device if stage 2 specifies Device. + * With HCR_EL2.FWB == 0 this is when descriptor bits [5:4] are 0b00, + * ie when cacheattrs.attrs bits [3:2] are 0b00. + */ + assert(cacheattrs.is_s2_format); + return (cacheattrs.attrs & 0xc) == 0; +} + /* Translate a S1 pagetable walk through S2 if needed. */ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, hwaddr addr, bool *is_secure, @@ -10745,7 +10764,7 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, return ~0; } if ((arm_hcr_el2_eff(env) & HCR_PTW) && - (cacheattrs.attrs & 0xf0) == 0) { + ptw_attrs_are_device(env, cacheattrs)) { /* * PTW set and S1 walk touched S2 Device memory: * generate Permission fault. @@ -11817,12 +11836,14 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, } if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) { - cacheattrs->attrs = convert_stage2_attrs(env, extract32(attrs, 0, 4)); + cacheattrs->is_s2_format = true; + cacheattrs->attrs = extract32(attrs, 0, 4); } else { /* Index into MAIR registers for cache attributes */ uint8_t attrindx = extract32(attrs, 0, 3); uint64_t mair = env->cp15.mair_el[regime_el(env, mmu_idx)]; assert(attrindx <= 7); + cacheattrs->is_s2_format = false; cacheattrs->attrs = extract64(mair, attrindx * 8, 8); } @@ -12560,14 +12581,22 @@ static uint8_t combine_cacheattr_nibble(uint8_t s1, uint8_t s2) /* Combine S1 and S2 cacheability/shareability attributes, per D4.5.4 * and CombineS1S2Desc() * + * @env: CPUARMState * @s1: Attributes from stage 1 walk * @s2: Attributes from stage 2 walk */ -static ARMCacheAttrs combine_cacheattrs(ARMCacheAttrs s1, ARMCacheAttrs s2) +static ARMCacheAttrs combine_cacheattrs(CPUARMState *env, + ARMCacheAttrs s1, ARMCacheAttrs s2) { uint8_t s1lo, s2lo, s1hi, s2hi; ARMCacheAttrs ret; bool tagged = false; + uint8_t s2_mair_attrs; + + assert(s2.is_s2_format && !s1.is_s2_format); + ret.is_s2_format = false; + + s2_mair_attrs = convert_stage2_attrs(env, s2.attrs); if (s1.attrs == 0xf0) { tagged = true; @@ -12575,9 +12604,9 @@ static ARMCacheAttrs combine_cacheattrs(ARMCacheAttrs s1, ARMCacheAttrs s2) } s1lo = extract32(s1.attrs, 0, 4); - s2lo = extract32(s2.attrs, 0, 4); + s2lo = extract32(s2_mair_attrs, 0, 4); s1hi = extract32(s1.attrs, 4, 4); - s2hi = extract32(s2.attrs, 4, 4); + s2hi = extract32(s2_mair_attrs, 4, 4); /* Combine shareability attributes (table D4-43) */ if (s1.shareability == 2 || s2.shareability == 2) { @@ -12731,7 +12760,7 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, } cacheattrs->shareability = 0; } - *cacheattrs = combine_cacheattrs(*cacheattrs, cacheattrs2); + *cacheattrs = combine_cacheattrs(env, *cacheattrs, cacheattrs2); /* Check if IPA translates to secure or non-secure PA space. */ if (arm_is_secure_below_el3(env)) { @@ -12849,6 +12878,7 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, /* Fill in cacheattr a-la AArch64.TranslateAddressS1Off. */ hcr = arm_hcr_el2_eff(env); cacheattrs->shareability = 0; + cacheattrs->is_s2_format = false; if (hcr & HCR_DC) { if (hcr & HCR_DCT) { memattr = 0xf0; /* Tagged, Normal, WB, RWA */ diff --git a/target/arm/internals.h b/target/arm/internals.h index 6ca0e95746..9b354eea7e 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1149,8 +1149,13 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, /* Cacheability and shareability attributes for a memory access */ typedef struct ARMCacheAttrs { - unsigned int attrs:8; /* as in the MAIR register encoding */ + /* + * If is_s2_format is true, attrs is the S2 descriptor bits [5:2] + * Otherwise, attrs is the same as the MAIR_EL1 8-bit format + */ + unsigned int attrs:8; unsigned int shareability:2; /* as in the SH field of the VMSAv8-64 PTEs */ + bool is_s2_format:1; } ARMCacheAttrs; bool get_phys_addr(CPUARMState *env, target_ulong address, From 4a0b47c8150d3ac0a90f470191d64a3b199e6269 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 5 May 2022 19:39:48 +0100 Subject: [PATCH 433/935] target/arm: Factor out FWB=0 specific part of combine_cacheattrs() Factor out the part of combine_cacheattrs() that is specific to handling HCR_EL2.FWB == 0. This is the part where we combine the memory type and cacheability attributes. The "force Outer Shareable for Device or Normal Inner-NC Outer-NC" logic remains in combine_cacheattrs() because it holds regardless (this is the equivalent of the pseudocode EffectiveShareability() function). Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220505183950.2781801-3-peter.maydell@linaro.org --- target/arm/helper.c | 88 +++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 38 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 93c58ad29a..a2a9635841 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -12578,6 +12578,46 @@ static uint8_t combine_cacheattr_nibble(uint8_t s1, uint8_t s2) } } +/* + * Combine the memory type and cacheability attributes of + * s1 and s2 for the HCR_EL2.FWB == 0 case, returning the + * combined attributes in MAIR_EL1 format. + */ +static uint8_t combined_attrs_nofwb(CPUARMState *env, + ARMCacheAttrs s1, ARMCacheAttrs s2) +{ + uint8_t s1lo, s2lo, s1hi, s2hi, s2_mair_attrs, ret_attrs; + + s2_mair_attrs = convert_stage2_attrs(env, s2.attrs); + + s1lo = extract32(s1.attrs, 0, 4); + s2lo = extract32(s2_mair_attrs, 0, 4); + s1hi = extract32(s1.attrs, 4, 4); + s2hi = extract32(s2_mair_attrs, 4, 4); + + /* Combine memory type and cacheability attributes */ + if (s1hi == 0 || s2hi == 0) { + /* Device has precedence over normal */ + if (s1lo == 0 || s2lo == 0) { + /* nGnRnE has precedence over anything */ + ret_attrs = 0; + } else if (s1lo == 4 || s2lo == 4) { + /* non-Reordering has precedence over Reordering */ + ret_attrs = 4; /* nGnRE */ + } else if (s1lo == 8 || s2lo == 8) { + /* non-Gathering has precedence over Gathering */ + ret_attrs = 8; /* nGRE */ + } else { + ret_attrs = 0xc; /* GRE */ + } + } else { /* Normal memory */ + /* Outer/inner cacheability combine independently */ + ret_attrs = combine_cacheattr_nibble(s1hi, s2hi) << 4 + | combine_cacheattr_nibble(s1lo, s2lo); + } + return ret_attrs; +} + /* Combine S1 and S2 cacheability/shareability attributes, per D4.5.4 * and CombineS1S2Desc() * @@ -12588,26 +12628,17 @@ static uint8_t combine_cacheattr_nibble(uint8_t s1, uint8_t s2) static ARMCacheAttrs combine_cacheattrs(CPUARMState *env, ARMCacheAttrs s1, ARMCacheAttrs s2) { - uint8_t s1lo, s2lo, s1hi, s2hi; ARMCacheAttrs ret; bool tagged = false; - uint8_t s2_mair_attrs; assert(s2.is_s2_format && !s1.is_s2_format); ret.is_s2_format = false; - s2_mair_attrs = convert_stage2_attrs(env, s2.attrs); - if (s1.attrs == 0xf0) { tagged = true; s1.attrs = 0xff; } - s1lo = extract32(s1.attrs, 0, 4); - s2lo = extract32(s2_mair_attrs, 0, 4); - s1hi = extract32(s1.attrs, 4, 4); - s2hi = extract32(s2_mair_attrs, 4, 4); - /* Combine shareability attributes (table D4-43) */ if (s1.shareability == 2 || s2.shareability == 2) { /* if either are outer-shareable, the result is outer-shareable */ @@ -12621,37 +12652,18 @@ static ARMCacheAttrs combine_cacheattrs(CPUARMState *env, } /* Combine memory type and cacheability attributes */ - if (s1hi == 0 || s2hi == 0) { - /* Device has precedence over normal */ - if (s1lo == 0 || s2lo == 0) { - /* nGnRnE has precedence over anything */ - ret.attrs = 0; - } else if (s1lo == 4 || s2lo == 4) { - /* non-Reordering has precedence over Reordering */ - ret.attrs = 4; /* nGnRE */ - } else if (s1lo == 8 || s2lo == 8) { - /* non-Gathering has precedence over Gathering */ - ret.attrs = 8; /* nGRE */ - } else { - ret.attrs = 0xc; /* GRE */ - } + ret.attrs = combined_attrs_nofwb(env, s1, s2); - /* Any location for which the resultant memory type is any - * type of Device memory is always treated as Outer Shareable. - */ + /* + * Any location for which the resultant memory type is any + * type of Device memory is always treated as Outer Shareable. + * Any location for which the resultant memory type is Normal + * Inner Non-cacheable, Outer Non-cacheable is always treated + * as Outer Shareable. + * TODO: FEAT_XS adds another value (0x40) also meaning iNCoNC + */ + if ((ret.attrs & 0xf0) == 0 || ret.attrs == 0x44) { ret.shareability = 2; - } else { /* Normal memory */ - /* Outer/inner cacheability combine independently */ - ret.attrs = combine_cacheattr_nibble(s1hi, s2hi) << 4 - | combine_cacheattr_nibble(s1lo, s2lo); - - if (ret.attrs == 0x44) { - /* Any location for which the resultant memory type is Normal - * Inner Non-cacheable, Outer Non-cacheable is always treated - * as Outer Shareable. - */ - ret.shareability = 2; - } } /* TODO: CombineS1S2Desc does not consider transient, only WB, RWA. */ From 8c7e17ef389699fd392e8613e144816b90af3a3a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 5 May 2022 19:39:49 +0100 Subject: [PATCH 434/935] target/arm: Implement FEAT_S2FWB Implement the handling of FEAT_S2FWB; the meat of this is in the new combined_attrs_fwb() function which combines S1 and S2 attributes when HCR_EL2.FWB is set. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220505183950.2781801-4-peter.maydell@linaro.org --- target/arm/cpu.h | 5 +++ target/arm/helper.c | 84 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 86 insertions(+), 3 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 18ca61e8e2..98efc638bb 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3941,6 +3941,11 @@ static inline bool isar_feature_aa64_st(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, ST) != 0; } +static inline bool isar_feature_aa64_fwb(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, FWB) != 0; +} + static inline bool isar_feature_aa64_bti(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0; diff --git a/target/arm/helper.c b/target/arm/helper.c index a2a9635841..073d6509c8 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5161,6 +5161,9 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) if (cpu_isar_feature(aa64_scxtnum, cpu)) { valid_mask |= HCR_ENSCXT; } + if (cpu_isar_feature(aa64_fwb, cpu)) { + valid_mask |= HCR_FWB; + } } /* Clear RES0 bits. */ @@ -5172,8 +5175,10 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) * HCR_PTW forbids certain page-table setups * HCR_DC disables stage1 and enables stage2 translation * HCR_DCT enables tagging on (disabled) stage1 translation + * HCR_FWB changes the interpretation of stage2 descriptor bits */ - if ((env->cp15.hcr_el2 ^ value) & (HCR_VM | HCR_PTW | HCR_DC | HCR_DCT)) { + if ((env->cp15.hcr_el2 ^ value) & + (HCR_VM | HCR_PTW | HCR_DC | HCR_DCT | HCR_FWB)) { tlb_flush(CPU(cpu)); } env->cp15.hcr_el2 = value; @@ -10731,9 +10736,15 @@ static bool ptw_attrs_are_device(CPUARMState *env, ARMCacheAttrs cacheattrs) * attributes are therefore only Device if stage 2 specifies Device. * With HCR_EL2.FWB == 0 this is when descriptor bits [5:4] are 0b00, * ie when cacheattrs.attrs bits [3:2] are 0b00. + * With HCR_EL2.FWB == 1 this is when descriptor bit [4] is 0, ie + * when cacheattrs.attrs bit [2] is 0. */ assert(cacheattrs.is_s2_format); - return (cacheattrs.attrs & 0xc) == 0; + if (arm_hcr_el2_eff(env) & HCR_FWB) { + return (cacheattrs.attrs & 0x4) == 0; + } else { + return (cacheattrs.attrs & 0xc) == 0; + } } /* Translate a S1 pagetable walk through S2 if needed. */ @@ -12618,6 +12629,69 @@ static uint8_t combined_attrs_nofwb(CPUARMState *env, return ret_attrs; } +static uint8_t force_cacheattr_nibble_wb(uint8_t attr) +{ + /* + * Given the 4 bits specifying the outer or inner cacheability + * in MAIR format, return a value specifying Normal Write-Back, + * with the allocation and transient hints taken from the input + * if the input specified some kind of cacheable attribute. + */ + if (attr == 0 || attr == 4) { + /* + * 0 == an UNPREDICTABLE encoding + * 4 == Non-cacheable + * Either way, force Write-Back RW allocate non-transient + */ + return 0xf; + } + /* Change WriteThrough to WriteBack, keep allocation and transient hints */ + return attr | 4; +} + +/* + * Combine the memory type and cacheability attributes of + * s1 and s2 for the HCR_EL2.FWB == 1 case, returning the + * combined attributes in MAIR_EL1 format. + */ +static uint8_t combined_attrs_fwb(CPUARMState *env, + ARMCacheAttrs s1, ARMCacheAttrs s2) +{ + switch (s2.attrs) { + case 7: + /* Use stage 1 attributes */ + return s1.attrs; + case 6: + /* + * Force Normal Write-Back. Note that if S1 is Normal cacheable + * then we take the allocation hints from it; otherwise it is + * RW allocate, non-transient. + */ + if ((s1.attrs & 0xf0) == 0) { + /* S1 is Device */ + return 0xff; + } + /* Need to check the Inner and Outer nibbles separately */ + return force_cacheattr_nibble_wb(s1.attrs & 0xf) | + force_cacheattr_nibble_wb(s1.attrs >> 4) << 4; + case 5: + /* If S1 attrs are Device, use them; otherwise Normal Non-cacheable */ + if ((s1.attrs & 0xf0) == 0) { + return s1.attrs; + } + return 0x44; + case 0 ... 3: + /* Force Device, of subtype specified by S2 */ + return s2.attrs << 2; + default: + /* + * RESERVED values (including RES0 descriptor bit [5] being nonzero); + * arbitrarily force Device. + */ + return 0; + } +} + /* Combine S1 and S2 cacheability/shareability attributes, per D4.5.4 * and CombineS1S2Desc() * @@ -12652,7 +12726,11 @@ static ARMCacheAttrs combine_cacheattrs(CPUARMState *env, } /* Combine memory type and cacheability attributes */ - ret.attrs = combined_attrs_nofwb(env, s1, s2); + if (arm_hcr_el2_eff(env) & HCR_FWB) { + ret.attrs = combined_attrs_fwb(env, s1, s2); + } else { + ret.attrs = combined_attrs_nofwb(env, s1, s2); + } /* * Any location for which the resultant memory type is any From e04bf5a793ee5e7afdda8a1d1af08888fd67a989 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 5 May 2022 19:39:50 +0100 Subject: [PATCH 435/935] target/arm: Enable FEAT_S2FWB for -cpu max Enable the FEAT_S2FWB for -cpu max. Since FEAT_S2FWB requires that CLIDR_EL1.{LoUU,LoUIS} are zero, we explicitly squash these (the inherited CLIDR_EL1 value from the Cortex-A57 has them as 1). Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220505183950.2781801-5-peter.maydell@linaro.org --- docs/system/arm/emulation.rst | 1 + target/arm/cpu64.c | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index 8ed466bf68..8f25502ced 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -52,6 +52,7 @@ the following architecture extensions: - FEAT_RAS (Reliability, availability, and serviceability) - FEAT_RDM (Advanced SIMD rounding double multiply accumulate instructions) - FEAT_RNG (Random number generator) +- FEAT_S2FWB (Stage 2 forced Write-Back) - FEAT_SB (Speculation Barrier) - FEAT_SEL2 (Secure EL2) - FEAT_SHA1 (SHA1 instructions) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 04427e073f..e83c013e1f 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -812,6 +812,7 @@ static void aarch64_max_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); uint64_t t; + uint32_t u; if (kvm_enabled() || hvf_enabled()) { /* With KVM or HVF, '-cpu max' is identical to '-cpu host' */ @@ -842,6 +843,15 @@ static void aarch64_max_initfn(Object *obj) t = FIELD_DP64(t, MIDR_EL1, REVISION, 0); cpu->midr = t; + /* + * We're going to set FEAT_S2FWB, which mandates that CLIDR_EL1.{LoUU,LoUIS} + * are zero. + */ + u = cpu->clidr; + u = FIELD_DP32(u, CLIDR_EL1, LOUIS, 0); + u = FIELD_DP32(u, CLIDR_EL1, LOUU, 0); + cpu->clidr = u; + t = cpu->isar.id_aa64isar0; t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2); /* FEAT_PMULL */ t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); /* FEAT_SHA1 */ @@ -918,6 +928,7 @@ static void aarch64_max_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64MMFR2, IESB, 1); /* FEAT_IESB */ t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1); /* FEAT_LVA */ t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* FEAT_TTST */ + t = FIELD_DP64(t, ID_AA64MMFR2, FWB, 1); /* FEAT_S2FWB */ t = FIELD_DP64(t, ID_AA64MMFR2, TTL, 1); /* FEAT_TTL */ t = FIELD_DP64(t, ID_AA64MMFR2, BBM, 2); /* FEAT_BBM at level 2 */ cpu->isar.id_aa64mmfr2 = t; From 75662f36e3d11b986456210670719a7837111cd7 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 9 May 2022 16:54:57 +0100 Subject: [PATCH 436/935] target/arm: Implement FEAT_IDST The Armv8.4 feature FEAT_IDST specifies that exceptions generated by read accesses to the feature ID space should report a syndrome code of 0x18 (EC_SYSTEMREGISTERTRAP) rather than 0x00 (EC_UNCATEGORIZED). The feature ID space is defined to be: op0 == 3, op1 == {0,1,3}, CRn == 0, CRm == {0-7}, op2 == {0-7} In our implementation we might return the EC_UNCATEGORIZED syndrome value for a system register access in four cases: * no reginfo struct in the hashtable * cp_access_ok() fails (ie ri->access doesn't permit the access) * ri->accessfn returns CP_ACCESS_TRAP_UNCATEGORIZED at runtime * ri->type includes ARM_CP_RAISES_EXC, and the readfn raises an UNDEF exception at runtime We have very few regdefs that set ARM_CP_RAISES_EXC, and none of them are in the feature ID space. (In the unlikely event that any are added in future they would need to take care of setting the correct syndrome themselves.) This patch deals with the other three cases, and enables FEAT_IDST for AArch64 -cpu max. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220509155457.3560724-1-peter.maydell@linaro.org --- docs/system/arm/emulation.rst | 1 + target/arm/cpregs.h | 24 ++++++++++++++++++++++++ target/arm/cpu.h | 5 +++++ target/arm/cpu64.c | 1 + target/arm/op_helper.c | 9 +++++++++ target/arm/translate-a64.c | 28 ++++++++++++++++++++++++++-- 6 files changed, 66 insertions(+), 2 deletions(-) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index 8f25502ced..3e95bba0d2 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -31,6 +31,7 @@ the following architecture extensions: - FEAT_FlagM2 (Enhancements to flag manipulation instructions) - FEAT_HPDS (Hierarchical permission disables) - FEAT_I8MM (AArch64 Int8 matrix multiplication instructions) +- FEAT_IDST (ID space trap handling) - FEAT_IESB (Implicit error synchronization event) - FEAT_JSCVT (JavaScript conversion instructions) - FEAT_LOR (Limited ordering regions) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index db03d6a7e1..d9b678c2f1 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -461,4 +461,28 @@ static inline bool cp_access_ok(int current_el, /* Raw read of a coprocessor register (as needed for migration, etc) */ uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri); +/* + * Return true if the cp register encoding is in the "feature ID space" as + * defined by FEAT_IDST (and thus should be reported with ER_ELx.EC + * as EC_SYSTEMREGISTERTRAP rather than EC_UNCATEGORIZED). + */ +static inline bool arm_cpreg_encoding_in_idspace(uint8_t opc0, uint8_t opc1, + uint8_t opc2, + uint8_t crn, uint8_t crm) +{ + return opc0 == 3 && (opc1 == 0 || opc1 == 1 || opc1 == 3) && + crn == 0 && crm < 8; +} + +/* + * As arm_cpreg_encoding_in_idspace(), but take the encoding from an + * ARMCPRegInfo. + */ +static inline bool arm_cpreg_in_idspace(const ARMCPRegInfo *ri) +{ + return ri->state == ARM_CP_STATE_AA64 && + arm_cpreg_encoding_in_idspace(ri->opc0, ri->opc1, ri->opc2, + ri->crn, ri->crm); +} + #endif /* TARGET_ARM_CPREGS_H */ diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 98efc638bb..a99b430e54 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3946,6 +3946,11 @@ static inline bool isar_feature_aa64_fwb(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, FWB) != 0; } +static inline bool isar_feature_aa64_ids(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, IDS) != 0; +} + static inline bool isar_feature_aa64_bti(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0; diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index e83c013e1f..804a54922c 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -928,6 +928,7 @@ static void aarch64_max_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64MMFR2, IESB, 1); /* FEAT_IESB */ t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1); /* FEAT_LVA */ t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* FEAT_TTST */ + t = FIELD_DP64(t, ID_AA64MMFR2, IDS, 1); /* FEAT_IDST */ t = FIELD_DP64(t, ID_AA64MMFR2, FWB, 1); /* FEAT_S2FWB */ t = FIELD_DP64(t, ID_AA64MMFR2, TTL, 1); /* FEAT_TTL */ t = FIELD_DP64(t, ID_AA64MMFR2, BBM, 2); /* FEAT_BBM at level 2 */ diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index 390b6578a8..c4bd668870 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -631,6 +631,7 @@ uint32_t HELPER(mrs_banked)(CPUARMState *env, uint32_t tgtmode, uint32_t regno) void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome, uint32_t isread) { + ARMCPU *cpu = env_archcpu(env); const ARMCPRegInfo *ri = rip; CPAccessResult res = CP_ACCESS_OK; int target_el; @@ -674,6 +675,14 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome, case CP_ACCESS_TRAP: break; case CP_ACCESS_TRAP_UNCATEGORIZED: + if (cpu_isar_feature(aa64_ids, cpu) && isread && + arm_cpreg_in_idspace(ri)) { + /* + * FEAT_IDST says this should be reported as EC_SYSTEMREGISTERTRAP, + * not EC_UNCATEGORIZED + */ + break; + } syndrome = syn_uncategorized(); break; default: diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 6a27234a5c..176a3c83ba 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1795,6 +1795,30 @@ static void gen_set_nzcv(TCGv_i64 tcg_rt) tcg_temp_free_i32(nzcv); } +static void gen_sysreg_undef(DisasContext *s, bool isread, + uint8_t op0, uint8_t op1, uint8_t op2, + uint8_t crn, uint8_t crm, uint8_t rt) +{ + /* + * Generate code to emit an UNDEF with correct syndrome + * information for a failed system register access. + * This is EC_UNCATEGORIZED (ie a standard UNDEF) in most cases, + * but if FEAT_IDST is implemented then read accesses to registers + * in the feature ID space are reported with the EC_SYSTEMREGISTERTRAP + * syndrome. + */ + uint32_t syndrome; + + if (isread && dc_isar_feature(aa64_ids, s) && + arm_cpreg_encoding_in_idspace(op0, op1, op2, crn, crm)) { + syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread); + } else { + syndrome = syn_uncategorized(); + } + gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syndrome, + default_exception_el(s)); +} + /* MRS - move from system register * MSR (register) - move to system register * SYS @@ -1820,13 +1844,13 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch64 " "system register op0:%d op1:%d crn:%d crm:%d op2:%d\n", isread ? "read" : "write", op0, op1, crn, crm, op2); - unallocated_encoding(s); + gen_sysreg_undef(s, isread, op0, op1, op2, crn, crm, rt); return; } /* Check access permissions */ if (!cp_access_ok(s->current_el, ri, isread)) { - unallocated_encoding(s); + gen_sysreg_undef(s, isread, op0, op1, op2, crn, crm, rt); return; } From 3d52472f81f0e0684fcab238ab816faeee6b8bcd Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 9 May 2022 17:04:43 +0100 Subject: [PATCH 437/935] target/arm: Drop unsupported_encoding() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The unsupported_encoding() macro logs a LOG_UNIMP message and then generates code to raise the usual exception for an unallocated encoding. Back when we were still implementing the A64 decoder this was helpful for flagging up when guest code was using something we hadn't yet implemented. Now we completely cover the A64 instruction set it is barely used. The only remaining uses are for five instructions whose semantics are "UNDEF, unless being run under external halting debug": * HLT (when not being used for semihosting) * DCPSR1, DCPS2, DCPS3 * DRPS QEMU doesn't implement external halting debug, so for us the UNDEF is the architecturally correct behaviour (because it's not possible to execute these instructions with halting debug enabled). The LOG_UNIMP doesn't serve a useful purpose; replace these uses of unsupported_encoding() with unallocated_encoding(), and delete the macro. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20220509160443.3561604-1-peter.maydell@linaro.org --- target/arm/translate-a64.c | 8 ++++---- target/arm/translate-a64.h | 9 --------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 176a3c83ba..f502545307 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -2127,13 +2127,13 @@ static void disas_exc(DisasContext *s, uint32_t insn) * with our 32-bit semihosting). */ if (s->current_el == 0) { - unsupported_encoding(s, insn); + unallocated_encoding(s); break; } #endif gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST); } else { - unsupported_encoding(s, insn); + unallocated_encoding(s); } break; case 5: @@ -2142,7 +2142,7 @@ static void disas_exc(DisasContext *s, uint32_t insn) break; } /* DCPS1, DCPS2, DCPS3 */ - unsupported_encoding(s, insn); + unallocated_encoding(s); break; default: unallocated_encoding(s); @@ -2307,7 +2307,7 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn) if (op3 != 0 || op4 != 0 || rn != 0x1f) { goto do_unallocated; } else { - unsupported_encoding(s, insn); + unallocated_encoding(s); } return; diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h index 38884158aa..f2e8ee0ee1 100644 --- a/target/arm/translate-a64.h +++ b/target/arm/translate-a64.h @@ -18,15 +18,6 @@ #ifndef TARGET_ARM_TRANSLATE_A64_H #define TARGET_ARM_TRANSLATE_A64_H -#define unsupported_encoding(s, insn) \ - do { \ - qemu_log_mask(LOG_UNIMP, \ - "%s:%d: unsupported instruction encoding 0x%08x " \ - "at pc=%016" PRIx64 "\n", \ - __FILE__, __LINE__, insn, s->pc_curr); \ - unallocated_encoding(s); \ - } while (0) - TCGv_i64 new_tmp_a64(DisasContext *s); TCGv_i64 new_tmp_a64_local(DisasContext *s); TCGv_i64 new_tmp_a64_zero(DisasContext *s); From 272f75e89088c968c861fef516a4ebc70846dcd5 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 12 May 2022 16:14:52 +0100 Subject: [PATCH 438/935] hw/intc/arm_gicv3_cpuif: Handle CPUs that don't specify GICv3 parameters We allow a GICv3 to be connected to any CPU, but we don't do anything to handle the case where the CPU type doesn't in hardware have a GICv3 CPU interface and so the various GIC configuration fields (gic_num_lrs, vprebits, vpribits) are not specified. The current behaviour is that we will add the EL1 CPU interface registers, but will not put in the EL2 CPU interface registers, even if the CPU has EL2, which will leave the GIC in a broken state and probably result in the guest crashing as it tries to set it up. This only affects the virt board when using the cortex-a15 or cortex-a7 CPU types (both 32-bit) with -machine gic-version=3 (or 'max') and -machine virtualization=on. Instead of failing to set up the EL2 registers, if the CPU doesn't define the GIC configuration set it to a reasonable default, matching the standard configuration for most Arm CPUs. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220512151457.3899052-2-peter.maydell@linaro.org --- hw/intc/arm_gicv3_cpuif.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index 9efba798f8..df2f858356 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -2755,6 +2755,15 @@ void gicv3_init_cpuif(GICv3State *s) ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i)); GICv3CPUState *cs = &s->cpu[i]; + /* + * If the CPU doesn't define a GICv3 configuration, probably because + * in real hardware it doesn't have one, then we use default values + * matching the one used by most Arm CPUs. This applies to: + * cpu->gic_num_lrs + * cpu->gic_vpribits + * cpu->gic_vprebits + */ + /* Note that we can't just use the GICv3CPUState as an opaque pointer * in define_arm_cp_regs_with_opaque(), because when we're called back * it might be with code translated by CPU 0 but run by CPU 1, in @@ -2763,13 +2772,12 @@ void gicv3_init_cpuif(GICv3State *s) * get back to the GICv3CPUState from the CPUARMState. */ define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); - if (arm_feature(&cpu->env, ARM_FEATURE_EL2) - && cpu->gic_num_lrs) { + if (arm_feature(&cpu->env, ARM_FEATURE_EL2)) { int j; - cs->num_list_regs = cpu->gic_num_lrs; - cs->vpribits = cpu->gic_vpribits; - cs->vprebits = cpu->gic_vprebits; + cs->num_list_regs = cpu->gic_num_lrs ?: 4; + cs->vpribits = cpu->gic_vpribits ?: 5; + cs->vprebits = cpu->gic_vprebits ?: 5; /* Check against architectural constraints: getting these * wrong would be a bug in the CPU code defining these, From 9c6f933e71ccfde036d7e19c1ddc2b1a82cc45c0 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 12 May 2022 16:14:53 +0100 Subject: [PATCH 439/935] hw/intc/arm_gicv3: report correct PRIbits field in ICV_CTLR_EL1 As noted in the comment, the PRIbits field in ICV_CTLR_EL1 is supposed to match the ICH_VTR_EL2 PRIbits setting; that is, it is the virtual priority bit setting, not the physical priority bit setting. (For QEMU currently we always implement 8 bits of physical priority, so the PRIbits field was previously 7, since it is defined to be "priority bits - 1".) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220512151457.3899052-3-peter.maydell@linaro.org Message-id: 20220506162129.2896966-2-peter.maydell@linaro.org --- hw/intc/arm_gicv3_cpuif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index df2f858356..ebf269b73a 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -657,7 +657,7 @@ static uint64_t icv_ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) * should match the ones reported in ich_vtr_read(). */ value = ICC_CTLR_EL1_A3V | (1 << ICC_CTLR_EL1_IDBITS_SHIFT) | - (7 << ICC_CTLR_EL1_PRIBITS_SHIFT); + ((cs->vpribits - 1) << ICC_CTLR_EL1_PRIBITS_SHIFT); if (cs->ich_vmcr_el2 & ICH_VMCR_EL2_VEOIM) { value |= ICC_CTLR_EL1_EOIMODE; From 9774c0f7ba6ae2980a291cb53a13661ddaa2f5de Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 12 May 2022 16:14:54 +0100 Subject: [PATCH 440/935] hw/intc/arm_gicv3_kvm.c: Stop using GIC_MIN_BPR constant The GIC_MIN_BPR constant defines the minimum BPR value that the TCG emulated GICv3 supports. We're currently using this also as the value we reset the KVM GICv3 ICC_BPR registers to, but this is only right by accident. We want to make the emulated GICv3 use a configurable number of priority bits, which means that GIC_MIN_BPR will no longer be a constant. Replace the uses in the KVM reset code with literal 0, plus a constant explaining why this is reasonable. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220512151457.3899052-4-peter.maydell@linaro.org Message-id: 20220506162129.2896966-3-peter.maydell@linaro.org --- hw/intc/arm_gicv3_kvm.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 2922c516e5..3ca643ecba 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -673,9 +673,19 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) s = c->gic; c->icc_pmr_el1 = 0; - c->icc_bpr[GICV3_G0] = GIC_MIN_BPR; - c->icc_bpr[GICV3_G1] = GIC_MIN_BPR; - c->icc_bpr[GICV3_G1NS] = GIC_MIN_BPR; + /* + * Architecturally the reset value of the ICC_BPR registers + * is UNKNOWN. We set them all to 0 here; when the kernel + * uses these values to program the ICH_VMCR_EL2 fields that + * determine the guest-visible ICC_BPR register values, the + * hardware's "writing a value less than the minimum sets + * the field to the minimum value" behaviour will result in + * them effectively resetting to the correct minimum value + * for the host GIC. + */ + c->icc_bpr[GICV3_G0] = 0; + c->icc_bpr[GICV3_G1] = 0; + c->icc_bpr[GICV3_G1NS] = 0; c->icc_sre_el1 = 0x7; memset(c->icc_apr, 0, sizeof(c->icc_apr)); From 84597ff39484ec171567c7c80061100eb4a6c331 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 12 May 2022 16:14:55 +0100 Subject: [PATCH 441/935] hw/intc/arm_gicv3: Support configurable number of physical priority bits The GICv3 code has always supported a configurable number of virtual priority and preemption bits, but our implementation currently hardcodes the number of physical priority bits at 8. This is not what most hardware implementations provide; for instance the Cortex-A53 provides only 5 bits of physical priority. Make the number of physical priority/preemption bits driven by fields in the GICv3CPUState, the way that we already do for virtual priority/preemption bits. We set cs->pribits to 8, so there is no behavioural change in this commit. A following commit will add the machinery for CPUs to set this to the correct value for their implementation. Note that changing the number of priority bits would be a migration compatibility break, because the semantics of the icc_apr[][] array changes. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220512151457.3899052-5-peter.maydell@linaro.org Message-id: 20220506162129.2896966-4-peter.maydell@linaro.org --- hw/intc/arm_gicv3_cpuif.c | 182 ++++++++++++++++++++--------- include/hw/intc/arm_gicv3_common.h | 7 +- 2 files changed, 130 insertions(+), 59 deletions(-) diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index ebf269b73a..69a15f7a44 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -787,6 +787,36 @@ static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri) return intid; } +static uint32_t icc_fullprio_mask(GICv3CPUState *cs) +{ + /* + * Return a mask word which clears the unimplemented priority bits + * from a priority value for a physical interrupt. (Not to be confused + * with the group priority, whose mask depends on the value of BPR + * for the interrupt group.) + */ + return ~0U << (8 - cs->pribits); +} + +static inline int icc_min_bpr(GICv3CPUState *cs) +{ + /* The minimum BPR for the physical interface. */ + return 7 - cs->prebits; +} + +static inline int icc_min_bpr_ns(GICv3CPUState *cs) +{ + return icc_min_bpr(cs) + 1; +} + +static inline int icc_num_aprs(GICv3CPUState *cs) +{ + /* Return the number of APR registers (1, 2, or 4) */ + int aprmax = 1 << MAX(cs->prebits - 5, 0); + assert(aprmax <= ARRAY_SIZE(cs->icc_apr[0])); + return aprmax; +} + static int icc_highest_active_prio(GICv3CPUState *cs) { /* Calculate the current running priority based on the set bits @@ -794,14 +824,14 @@ static int icc_highest_active_prio(GICv3CPUState *cs) */ int i; - for (i = 0; i < ARRAY_SIZE(cs->icc_apr[0]); i++) { + for (i = 0; i < icc_num_aprs(cs); i++) { uint32_t apr = cs->icc_apr[GICV3_G0][i] | cs->icc_apr[GICV3_G1][i] | cs->icc_apr[GICV3_G1NS][i]; if (!apr) { continue; } - return (i * 32 + ctz32(apr)) << (GIC_MIN_BPR + 1); + return (i * 32 + ctz32(apr)) << (icc_min_bpr(cs) + 1); } /* No current active interrupts: return idle priority */ return 0xff; @@ -980,7 +1010,7 @@ static void icc_pmr_write(CPUARMState *env, const ARMCPRegInfo *ri, trace_gicv3_icc_pmr_write(gicv3_redist_affid(cs), value); - value &= 0xff; + value &= icc_fullprio_mask(cs); if (arm_feature(env, ARM_FEATURE_EL3) && !arm_is_secure(env) && (env->cp15.scr_el3 & SCR_FIQ)) { @@ -1004,7 +1034,7 @@ static void icc_activate_irq(GICv3CPUState *cs, int irq) */ uint32_t mask = icc_gprio_mask(cs, cs->hppi.grp); int prio = cs->hppi.prio & mask; - int aprbit = prio >> 1; + int aprbit = prio >> (8 - cs->prebits); int regno = aprbit / 32; int regbit = aprbit % 32; @@ -1162,7 +1192,7 @@ static void icc_drop_prio(GICv3CPUState *cs, int grp) */ int i; - for (i = 0; i < ARRAY_SIZE(cs->icc_apr[grp]); i++) { + for (i = 0; i < icc_num_aprs(cs); i++) { uint64_t *papr = &cs->icc_apr[grp][i]; if (!*papr) { @@ -1590,7 +1620,7 @@ static void icc_bpr_write(CPUARMState *env, const ARMCPRegInfo *ri, return; } - minval = (grp == GICV3_G1NS) ? GIC_MIN_BPR_NS : GIC_MIN_BPR; + minval = (grp == GICV3_G1NS) ? icc_min_bpr_ns(cs) : icc_min_bpr(cs); if (value < minval) { value = minval; } @@ -2171,19 +2201,19 @@ static void icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) cs->icc_ctlr_el1[GICV3_S] = ICC_CTLR_EL1_A3V | (1 << ICC_CTLR_EL1_IDBITS_SHIFT) | - (7 << ICC_CTLR_EL1_PRIBITS_SHIFT); + ((cs->pribits - 1) << ICC_CTLR_EL1_PRIBITS_SHIFT); cs->icc_ctlr_el1[GICV3_NS] = ICC_CTLR_EL1_A3V | (1 << ICC_CTLR_EL1_IDBITS_SHIFT) | - (7 << ICC_CTLR_EL1_PRIBITS_SHIFT); + ((cs->pribits - 1) << ICC_CTLR_EL1_PRIBITS_SHIFT); cs->icc_pmr_el1 = 0; - cs->icc_bpr[GICV3_G0] = GIC_MIN_BPR; - cs->icc_bpr[GICV3_G1] = GIC_MIN_BPR; - cs->icc_bpr[GICV3_G1NS] = GIC_MIN_BPR_NS; + cs->icc_bpr[GICV3_G0] = icc_min_bpr(cs); + cs->icc_bpr[GICV3_G1] = icc_min_bpr(cs); + cs->icc_bpr[GICV3_G1NS] = icc_min_bpr_ns(cs); memset(cs->icc_apr, 0, sizeof(cs->icc_apr)); memset(cs->icc_igrpen, 0, sizeof(cs->icc_igrpen)); cs->icc_ctlr_el3 = ICC_CTLR_EL3_NDS | ICC_CTLR_EL3_A3V | (1 << ICC_CTLR_EL3_IDBITS_SHIFT) | - (7 << ICC_CTLR_EL3_PRIBITS_SHIFT); + ((cs->pribits - 1) << ICC_CTLR_EL3_PRIBITS_SHIFT); memset(cs->ich_apr, 0, sizeof(cs->ich_apr)); cs->ich_hcr_el2 = 0; @@ -2238,27 +2268,6 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { .readfn = icc_ap_read, .writefn = icc_ap_write, }, - { .name = "ICC_AP0R1_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 5, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_fiq_access, - .readfn = icc_ap_read, - .writefn = icc_ap_write, - }, - { .name = "ICC_AP0R2_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 6, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_fiq_access, - .readfn = icc_ap_read, - .writefn = icc_ap_write, - }, - { .name = "ICC_AP0R3_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 7, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_fiq_access, - .readfn = icc_ap_read, - .writefn = icc_ap_write, - }, /* All the ICC_AP1R*_EL1 registers are banked */ { .name = "ICC_AP1R0_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 0, @@ -2267,27 +2276,6 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { .readfn = icc_ap_read, .writefn = icc_ap_write, }, - { .name = "ICC_AP1R1_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 1, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_irq_access, - .readfn = icc_ap_read, - .writefn = icc_ap_write, - }, - { .name = "ICC_AP1R2_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 2, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_irq_access, - .readfn = icc_ap_read, - .writefn = icc_ap_write, - }, - { .name = "ICC_AP1R3_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 3, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_irq_access, - .readfn = icc_ap_read, - .writefn = icc_ap_write, - }, { .name = "ICC_DIR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 1, .type = ARM_CP_IO | ARM_CP_NO_RAW, @@ -2430,6 +2418,54 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { }, }; +static const ARMCPRegInfo gicv3_cpuif_icc_apxr1_reginfo[] = { + { .name = "ICC_AP0R1_EL1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 5, + .type = ARM_CP_IO | ARM_CP_NO_RAW, + .access = PL1_RW, .accessfn = gicv3_fiq_access, + .readfn = icc_ap_read, + .writefn = icc_ap_write, + }, + { .name = "ICC_AP1R1_EL1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 1, + .type = ARM_CP_IO | ARM_CP_NO_RAW, + .access = PL1_RW, .accessfn = gicv3_irq_access, + .readfn = icc_ap_read, + .writefn = icc_ap_write, + }, +}; + +static const ARMCPRegInfo gicv3_cpuif_icc_apxr23_reginfo[] = { + { .name = "ICC_AP0R2_EL1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 6, + .type = ARM_CP_IO | ARM_CP_NO_RAW, + .access = PL1_RW, .accessfn = gicv3_fiq_access, + .readfn = icc_ap_read, + .writefn = icc_ap_write, + }, + { .name = "ICC_AP0R3_EL1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 7, + .type = ARM_CP_IO | ARM_CP_NO_RAW, + .access = PL1_RW, .accessfn = gicv3_fiq_access, + .readfn = icc_ap_read, + .writefn = icc_ap_write, + }, + { .name = "ICC_AP1R2_EL1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 2, + .type = ARM_CP_IO | ARM_CP_NO_RAW, + .access = PL1_RW, .accessfn = gicv3_irq_access, + .readfn = icc_ap_read, + .writefn = icc_ap_write, + }, + { .name = "ICC_AP1R3_EL1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 3, + .type = ARM_CP_IO | ARM_CP_NO_RAW, + .access = PL1_RW, .accessfn = gicv3_irq_access, + .readfn = icc_ap_read, + .writefn = icc_ap_write, + }, +}; + static uint64_t ich_ap_read(CPUARMState *env, const ARMCPRegInfo *ri) { GICv3CPUState *cs = icc_cs_from_env(env); @@ -2772,6 +2808,44 @@ void gicv3_init_cpuif(GICv3State *s) * get back to the GICv3CPUState from the CPUARMState. */ define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); + + /* + * For the moment, retain the existing behaviour of 8 priority bits; + * in a following commit we will take this from the CPU state, + * as we do for the virtual priority bits. + */ + cs->pribits = 8; + /* + * The GICv3 has separate ID register fields for virtual priority + * and preemption bit values, but only a single ID register field + * for the physical priority bits. The preemption bit count is + * always the same as the priority bit count, except that 8 bits + * of priority means 7 preemption bits. We precalculate the + * preemption bits because it simplifies the code and makes the + * parallels between the virtual and physical bits of the GIC + * a bit clearer. + */ + cs->prebits = cs->pribits; + if (cs->prebits == 8) { + cs->prebits--; + } + /* + * Check that CPU code defining pribits didn't violate + * architectural constraints our implementation relies on. + */ + g_assert(cs->pribits >= 4 && cs->pribits <= 8); + + /* + * gicv3_cpuif_reginfo[] defines ICC_AP*R0_EL1; add definitions + * for ICC_AP*R{1,2,3}_EL1 if the prebits value requires them. + */ + if (cs->prebits >= 6) { + define_arm_cp_regs(cpu, gicv3_cpuif_icc_apxr1_reginfo); + } + if (cs->prebits == 7) { + define_arm_cp_regs(cpu, gicv3_cpuif_icc_apxr23_reginfo); + } + if (arm_feature(&cpu->env, ARM_FEATURE_EL2)) { int j; diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h index 4e41610055..46677ec345 100644 --- a/include/hw/intc/arm_gicv3_common.h +++ b/include/hw/intc/arm_gicv3_common.h @@ -51,11 +51,6 @@ /* Maximum number of list registers (architectural limit) */ #define GICV3_LR_MAX 16 -/* Minimum BPR for Secure, or when security not enabled */ -#define GIC_MIN_BPR 0 -/* Minimum BPR for Nonsecure when security is enabled */ -#define GIC_MIN_BPR_NS (GIC_MIN_BPR + 1) - /* For some distributor fields we want to model the array of 32-bit * register values which hold various bitmaps corresponding to enabled, * pending, etc bits. These macros and functions facilitate that; the @@ -206,6 +201,8 @@ struct GICv3CPUState { int num_list_regs; int vpribits; /* number of virtual priority bits */ int vprebits; /* number of virtual preemption bits */ + int pribits; /* number of physical priority bits */ + int prebits; /* number of physical preemption bits */ /* Current highest priority pending interrupt for this CPU. * This is cached information that can be recalculated from the From 39f29e599355f9512482b67624e7a6c9000c5ddd Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 12 May 2022 16:14:56 +0100 Subject: [PATCH 442/935] hw/intc/arm_gicv3: Use correct number of priority bits for the CPU Make the GICv3 set its number of bits of physical priority from the implementation-specific value provided in the CPU state struct, in the same way we already do for virtual priority bits. Because this would be a migration compatibility break, we provide a property force-8-bit-prio which is enabled for 7.0 and earlier versioned board models to retain the legacy "always use 8 bits" behaviour. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220512151457.3899052-6-peter.maydell@linaro.org Message-id: 20220506162129.2896966-5-peter.maydell@linaro.org --- hw/core/machine.c | 4 +++- hw/intc/arm_gicv3_common.c | 5 +++++ hw/intc/arm_gicv3_cpuif.c | 15 +++++++++++---- include/hw/intc/arm_gicv3_common.h | 1 + target/arm/cpu.h | 1 + target/arm/cpu64.c | 6 ++++++ 6 files changed, 27 insertions(+), 5 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index b03d9192ba..bb0dc8f6a9 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -41,7 +41,9 @@ #include "hw/virtio/virtio-pci.h" #include "qom/object_interfaces.h" -GlobalProperty hw_compat_7_0[] = {}; +GlobalProperty hw_compat_7_0[] = { + { "arm-gicv3-common", "force-8-bit-prio", "on" }, +}; const size_t hw_compat_7_0_len = G_N_ELEMENTS(hw_compat_7_0); GlobalProperty hw_compat_6_2[] = { diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c index 5634c6fc78..351843db4a 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c @@ -563,6 +563,11 @@ static Property arm_gicv3_common_properties[] = { DEFINE_PROP_UINT32("revision", GICv3State, revision, 3), DEFINE_PROP_BOOL("has-lpi", GICv3State, lpi_enable, 0), DEFINE_PROP_BOOL("has-security-extensions", GICv3State, security_extn, 0), + /* + * Compatibility property: force 8 bits of physical priority, even + * if the CPU being emulated should have fewer. + */ + DEFINE_PROP_BOOL("force-8-bit-prio", GICv3State, force_8bit_prio, 0), DEFINE_PROP_ARRAY("redist-region-count", GICv3State, nb_redist_regions, redist_region_count, qdev_prop_uint32, uint32_t), DEFINE_PROP_LINK("sysmem", GICv3State, dma, TYPE_MEMORY_REGION, diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index 69a15f7a44..66e06b787c 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -2798,6 +2798,7 @@ void gicv3_init_cpuif(GICv3State *s) * cpu->gic_num_lrs * cpu->gic_vpribits * cpu->gic_vprebits + * cpu->gic_pribits */ /* Note that we can't just use the GICv3CPUState as an opaque pointer @@ -2810,11 +2811,17 @@ void gicv3_init_cpuif(GICv3State *s) define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); /* - * For the moment, retain the existing behaviour of 8 priority bits; - * in a following commit we will take this from the CPU state, - * as we do for the virtual priority bits. + * The CPU implementation specifies the number of supported + * bits of physical priority. For backwards compatibility + * of migration, we have a compat property that forces use + * of 8 priority bits regardless of what the CPU really has. */ - cs->pribits = 8; + if (s->force_8bit_prio) { + cs->pribits = 8; + } else { + cs->pribits = cpu->gic_pribits ?: 5; + } + /* * The GICv3 has separate ID register fields for virtual priority * and preemption bit values, but only a single ID register field diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h index 46677ec345..ab5182a28a 100644 --- a/include/hw/intc/arm_gicv3_common.h +++ b/include/hw/intc/arm_gicv3_common.h @@ -248,6 +248,7 @@ struct GICv3State { uint32_t revision; bool lpi_enable; bool security_extn; + bool force_8bit_prio; bool irq_reset_nonsecure; bool gicd_no_migration_shift_bug; diff --git a/target/arm/cpu.h b/target/arm/cpu.h index a99b430e54..a42464eb57 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1002,6 +1002,7 @@ struct ArchCPU { int gic_num_lrs; /* number of list registers */ int gic_vpribits; /* number of virtual priority bits */ int gic_vprebits; /* number of virtual preemption bits */ + int gic_pribits; /* number of physical priority bits */ /* Whether the cfgend input is high (i.e. this CPU should reset into * big-endian mode). This setting isn't used directly: instead it modifies diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 804a54922c..7628f4fa39 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -87,6 +87,7 @@ static void aarch64_a57_initfn(Object *obj) cpu->gic_num_lrs = 4; cpu->gic_vpribits = 5; cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; define_cortex_a72_a57_a53_cp_reginfo(cpu); } @@ -140,6 +141,7 @@ static void aarch64_a53_initfn(Object *obj) cpu->gic_num_lrs = 4; cpu->gic_vpribits = 5; cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; define_cortex_a72_a57_a53_cp_reginfo(cpu); } @@ -191,6 +193,7 @@ static void aarch64_a72_initfn(Object *obj) cpu->gic_num_lrs = 4; cpu->gic_vpribits = 5; cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; define_cortex_a72_a57_a53_cp_reginfo(cpu); } @@ -252,6 +255,7 @@ static void aarch64_a76_initfn(Object *obj) cpu->gic_num_lrs = 4; cpu->gic_vpribits = 5; cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; /* From B5.1 AdvSIMD AArch64 register summary */ cpu->isar.mvfr0 = 0x10110222; @@ -317,6 +321,7 @@ static void aarch64_neoverse_n1_initfn(Object *obj) cpu->gic_num_lrs = 4; cpu->gic_vpribits = 5; cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; /* From B5.1 AdvSIMD AArch64 register summary */ cpu->isar.mvfr0 = 0x10110222; @@ -1008,6 +1013,7 @@ static void aarch64_a64fx_initfn(Object *obj) cpu->gic_num_lrs = 4; cpu->gic_vpribits = 5; cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; /* Suppport of A64FX's vector length are 128,256 and 512bit only */ aarch64_add_sve_properties(obj); From 5d55f827677a521feaab6dc651168e6136954e88 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 12 May 2022 16:14:57 +0100 Subject: [PATCH 443/935] hw/intc/arm_gicv3: Provide ich_num_aprs() We previously open-coded the expression for the number of virtual APR registers and the assertion that it was not going to cause us to overflow the cs->ich_apr[] array. Factor this out into a new ich_num_aprs() function, for consistency with the icc_num_aprs() function we just added for the physical APR handling. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220512151457.3899052-7-peter.maydell@linaro.org Message-id: 20220506162129.2896966-6-peter.maydell@linaro.org --- hw/intc/arm_gicv3_cpuif.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index 66e06b787c..8867e2e496 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -49,6 +49,14 @@ static inline int icv_min_vbpr(GICv3CPUState *cs) return 7 - cs->vprebits; } +static inline int ich_num_aprs(GICv3CPUState *cs) +{ + /* Return the number of virtual APR registers (1, 2, or 4) */ + int aprmax = 1 << (cs->vprebits - 5); + assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0])); + return aprmax; +} + /* Simple accessor functions for LR fields */ static uint32_t ich_lr_vintid(uint64_t lr) { @@ -145,9 +153,7 @@ static int ich_highest_active_virt_prio(GICv3CPUState *cs) * in the ICH Active Priority Registers. */ int i; - int aprmax = 1 << (cs->vprebits - 5); - - assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0])); + int aprmax = ich_num_aprs(cs); for (i = 0; i < aprmax; i++) { uint32_t apr = cs->ich_apr[GICV3_G0][i] | @@ -1333,9 +1339,7 @@ static int icv_drop_prio(GICv3CPUState *cs) * 32 bits are actually relevant. */ int i; - int aprmax = 1 << (cs->vprebits - 5); - - assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0])); + int aprmax = ich_num_aprs(cs); for (i = 0; i < aprmax; i++) { uint64_t *papr0 = &cs->ich_apr[GICV3_G0][i]; From e1be11a5a440bfa552e0a8bb109d72294054e3f0 Mon Sep 17 00:00:00 2001 From: Chris Howard Date: Thu, 12 May 2022 11:42:02 +0200 Subject: [PATCH 444/935] Fix aarch64 debug register names. Give all the debug registers their correct names including the index, rather than having multiple registers all with the same name string, which is confusing when viewed over the gdbstub interface. Signed-off-by: CHRIS HOWARD Reviewed-by: Richard Henderson Message-id: 4127D8CA-D54A-47C7-A039-0DB7361E30C0@web.de [PMM: expanded commit message] Signed-off-by: Peter Maydell --- target/arm/helper.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 073d6509c8..91f78c91ce 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6554,14 +6554,16 @@ static void define_debug_regs(ARMCPU *cpu) } for (i = 0; i < brps; i++) { + char *dbgbvr_el1_name = g_strdup_printf("DBGBVR%d_EL1", i); + char *dbgbcr_el1_name = g_strdup_printf("DBGBCR%d_EL1", i); ARMCPRegInfo dbgregs[] = { - { .name = "DBGBVR", .state = ARM_CP_STATE_BOTH, + { .name = dbgbvr_el1_name, .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 4, .access = PL1_RW, .accessfn = access_tda, .fieldoffset = offsetof(CPUARMState, cp15.dbgbvr[i]), .writefn = dbgbvr_write, .raw_writefn = raw_write }, - { .name = "DBGBCR", .state = ARM_CP_STATE_BOTH, + { .name = dbgbcr_el1_name, .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 5, .access = PL1_RW, .accessfn = access_tda, .fieldoffset = offsetof(CPUARMState, cp15.dbgbcr[i]), @@ -6569,17 +6571,21 @@ static void define_debug_regs(ARMCPU *cpu) }, }; define_arm_cp_regs(cpu, dbgregs); + g_free(dbgbvr_el1_name); + g_free(dbgbcr_el1_name); } for (i = 0; i < wrps; i++) { + char *dbgwvr_el1_name = g_strdup_printf("DBGWVR%d_EL1", i); + char *dbgwcr_el1_name = g_strdup_printf("DBGWCR%d_EL1", i); ARMCPRegInfo dbgregs[] = { - { .name = "DBGWVR", .state = ARM_CP_STATE_BOTH, + { .name = dbgwvr_el1_name, .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 6, .access = PL1_RW, .accessfn = access_tda, .fieldoffset = offsetof(CPUARMState, cp15.dbgwvr[i]), .writefn = dbgwvr_write, .raw_writefn = raw_write }, - { .name = "DBGWCR", .state = ARM_CP_STATE_BOTH, + { .name = dbgwcr_el1_name, .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 7, .access = PL1_RW, .accessfn = access_tda, .fieldoffset = offsetof(CPUARMState, cp15.dbgwcr[i]), @@ -6587,6 +6593,8 @@ static void define_debug_regs(ARMCPU *cpu) }, }; define_arm_cp_regs(cpu, dbgregs); + g_free(dbgwvr_el1_name); + g_free(dbgwcr_el1_name); } } From 6e76d35f2375c3ef58aaaccbe5cee54b20a1f74a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 9 May 2022 22:20:35 +0200 Subject: [PATCH 445/935] hw/adc/zynq-xadc: Use qemu_irq typedef MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Except hw/core/irq.c which implements the forward-declared opaque qemu_irq structure, hw/adc/zynq-xadc.{c,h} are the only files not using the typedef. Fix this single exception. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Bernhard Beschow Message-id: 20220509202035.50335-1-philippe.mathieu.daude@gmail.com Signed-off-by: Peter Maydell --- hw/adc/zynq-xadc.c | 4 ++-- include/hw/adc/zynq-xadc.h | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/adc/zynq-xadc.c b/hw/adc/zynq-xadc.c index cfc7bab065..032e19cbd0 100644 --- a/hw/adc/zynq-xadc.c +++ b/hw/adc/zynq-xadc.c @@ -86,7 +86,7 @@ static void zynq_xadc_update_ints(ZynqXADCState *s) s->regs[INT_STS] |= INT_DFIFO_GTH; } - qemu_set_irq(s->qemu_irq, !!(s->regs[INT_STS] & ~s->regs[INT_MASK])); + qemu_set_irq(s->irq, !!(s->regs[INT_STS] & ~s->regs[INT_MASK])); } static void zynq_xadc_reset(DeviceState *d) @@ -262,7 +262,7 @@ static void zynq_xadc_init(Object *obj) memory_region_init_io(&s->iomem, obj, &xadc_ops, s, "zynq-xadc", ZYNQ_XADC_MMIO_SIZE); sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->qemu_irq); + sysbus_init_irq(sbd, &s->irq); } static const VMStateDescription vmstate_zynq_xadc = { diff --git a/include/hw/adc/zynq-xadc.h b/include/hw/adc/zynq-xadc.h index 2017b7a803..c10cc4c379 100644 --- a/include/hw/adc/zynq-xadc.h +++ b/include/hw/adc/zynq-xadc.h @@ -39,8 +39,7 @@ struct ZynqXADCState { uint16_t xadc_dfifo[ZYNQ_XADC_FIFO_DEPTH]; uint16_t xadc_dfifo_entries; - struct IRQState *qemu_irq; - + qemu_irq irq; }; #endif /* ZYNQ_XADC_H */ From 1a13efcc56f0a50149da25ecca1f81f346496f86 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 13 May 2022 14:18:01 +0100 Subject: [PATCH 446/935] target/arm/helper.c: Delete stray obsolete comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit 88ce6c6ee85d we switched from directly fishing the number of breakpoints and watchpoints out of the ID register fields to abstracting out functions to do this job, but we forgot to delete the now-obsolete comment in define_debug_regs() about the relation between the ID field value and the actual number of breakpoints and watchpoints. Delete the obsolete comment. Reported-by: CHRIS HOWARD Signed-off-by: Peter Maydell Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Message-id: 20220513131801.4082712-1-peter.maydell@linaro.org --- target/arm/helper.c | 1 - 1 file changed, 1 deletion(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 91f78c91ce..d4db21dc92 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6540,7 +6540,6 @@ static void define_debug_regs(ARMCPU *cpu) define_one_arm_cp_reg(cpu, &dbgdidr); } - /* Note that all these register fields hold "number of Xs minus 1". */ brps = arm_num_brps(cpu); wrps = arm_num_wrps(cpu); ctx_cmps = arm_num_ctx_cmps(cpu); From 24526bb92f69a323a9339dd94e823ad1d680f483 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 13 May 2022 13:28:52 +0100 Subject: [PATCH 447/935] target/arm: Make number of counters in PMCR follow the CPU Currently we give all the v7-and-up CPUs a PMU with 4 counters. This means that we don't provide the 6 counters that are required by the Arm BSA (Base System Architecture) specification if the CPU supports the Virtualization extensions. Instead of having a single PMCR_NUM_COUNTERS, make each CPU type specify the PMCR reset value (obtained from the appropriate TRM), and use the 'N' field of that value to define the number of counters provided. This means that we now supply 6 counters instead of 4 for: Cortex-A9, Cortex-A15, Cortex-A53, Cortex-A57, Cortex-A72, Cortex-A76, Neoverse-N1, '-cpu max' This CPU goes from 4 to 8 counters: A64FX These CPUs remain with 4 counters: Cortex-A7, Cortex-A8 This CPU goes down from 4 to 3 counters: Cortex-R5 Note that because we now use the PMCR reset value of the specific implementation, we no longer set the LC bit out of reset. This has an UNKNOWN value out of reset for all cores with any AArch32 support, so guest software should be setting it anyway if it wants it. This change was originally landed in commit f7fb73b8cdd3f7 (during the 6.0 release cycle) but was then reverted by commit 21c2dd77a6aa517 before that release because it did not work with KVM. This version fixes that by creating the scratch vCPU in kvm_arm_get_host_cpu_features() with the KVM_ARM_VCPU_PMU_V3 feature if KVM supports it, and then only asking KVM for the PMCR_EL0 value if the vCPU has a PMU. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson [PMM: Added the correct value for a64fx] Message-id: 20220513122852.4063586-1-peter.maydell@linaro.org --- target/arm/cpu.h | 1 + target/arm/cpu64.c | 11 +++++++++++ target/arm/cpu_tcg.c | 6 ++++++ target/arm/helper.c | 25 ++++++++++++++----------- target/arm/internals.h | 4 +++- target/arm/kvm64.c | 12 ++++++++++++ 6 files changed, 47 insertions(+), 12 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index a42464eb57..3dc79f121b 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -965,6 +965,7 @@ struct ArchCPU { uint64_t id_aa64dfr0; uint64_t id_aa64dfr1; uint64_t id_aa64zfr0; + uint64_t reset_pmcr_el0; } isar; uint64_t midr; uint32_t revidr; diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 7628f4fa39..a752b64856 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -79,6 +79,7 @@ static void aarch64_a57_initfn(Object *obj) cpu->isar.id_aa64isar0 = 0x00011120; cpu->isar.id_aa64mmfr0 = 0x00001124; cpu->isar.dbgdidr = 0x3516d000; + cpu->isar.reset_pmcr_el0 = 0x41013000; cpu->clidr = 0x0a200023; cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ @@ -133,6 +134,7 @@ static void aarch64_a53_initfn(Object *obj) cpu->isar.id_aa64isar0 = 0x00011120; cpu->isar.id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */ cpu->isar.dbgdidr = 0x3516d000; + cpu->isar.reset_pmcr_el0 = 0x41033000; cpu->clidr = 0x0a200023; cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */ cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */ @@ -185,6 +187,7 @@ static void aarch64_a72_initfn(Object *obj) cpu->isar.id_aa64isar0 = 0x00011120; cpu->isar.id_aa64mmfr0 = 0x00001124; cpu->isar.dbgdidr = 0x3516d000; + cpu->isar.reset_pmcr_el0 = 0x41023000; cpu->clidr = 0x0a200023; cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ @@ -261,6 +264,9 @@ static void aarch64_a76_initfn(Object *obj) cpu->isar.mvfr0 = 0x10110222; cpu->isar.mvfr1 = 0x13211111; cpu->isar.mvfr2 = 0x00000043; + + /* From D5.1 AArch64 PMU register summary */ + cpu->isar.reset_pmcr_el0 = 0x410b3000; } static void aarch64_neoverse_n1_initfn(Object *obj) @@ -327,6 +333,9 @@ static void aarch64_neoverse_n1_initfn(Object *obj) cpu->isar.mvfr0 = 0x10110222; cpu->isar.mvfr1 = 0x13211111; cpu->isar.mvfr2 = 0x00000043; + + /* From D5.1 AArch64 PMU register summary */ + cpu->isar.reset_pmcr_el0 = 0x410c3000; } void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) @@ -1022,6 +1031,8 @@ static void aarch64_a64fx_initfn(Object *obj) set_bit(1, cpu->sve_vq_supported); /* 256bit */ set_bit(3, cpu->sve_vq_supported); /* 512bit */ + cpu->isar.reset_pmcr_el0 = 0x46014040; + /* TODO: Add A64FX specific HPC extension registers */ } diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index ea4eccddc3..b751a19c8a 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -425,6 +425,7 @@ static void cortex_a8_initfn(Object *obj) cpu->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */ cpu->ccsidr[2] = 0xf0000000; /* No L2 icache. */ cpu->reset_auxcr = 2; + cpu->isar.reset_pmcr_el0 = 0x41002000; define_arm_cp_regs(cpu, cortexa8_cp_reginfo); } @@ -496,6 +497,7 @@ static void cortex_a9_initfn(Object *obj) cpu->clidr = (1 << 27) | (1 << 24) | 3; cpu->ccsidr[0] = 0xe00fe019; /* 16k L1 dcache. */ cpu->ccsidr[1] = 0x200fe019; /* 16k L1 icache. */ + cpu->isar.reset_pmcr_el0 = 0x41093000; define_arm_cp_regs(cpu, cortexa9_cp_reginfo); } @@ -565,6 +567,7 @@ static void cortex_a7_initfn(Object *obj) cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */ + cpu->isar.reset_pmcr_el0 = 0x41072000; define_arm_cp_regs(cpu, cortexa15_cp_reginfo); /* Same as A15 */ } @@ -607,6 +610,7 @@ static void cortex_a15_initfn(Object *obj) cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */ + cpu->isar.reset_pmcr_el0 = 0x410F3000; define_arm_cp_regs(cpu, cortexa15_cp_reginfo); } @@ -835,6 +839,7 @@ static void cortex_r5_initfn(Object *obj) cpu->isar.id_isar6 = 0x0; cpu->mp_is_up = true; cpu->pmsav7_dregion = 16; + cpu->isar.reset_pmcr_el0 = 0x41151800; define_arm_cp_regs(cpu, cortexr5_cp_reginfo); } @@ -1093,6 +1098,7 @@ static void arm_max_initfn(Object *obj) cpu->isar.id_isar5 = 0x00011121; cpu->isar.id_isar6 = 0; cpu->isar.dbgdidr = 0x3516d000; + cpu->isar.reset_pmcr_el0 = 0x41013000; cpu->clidr = 0x0a200023; cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ diff --git a/target/arm/helper.c b/target/arm/helper.c index d4db21dc92..aa7a8e0572 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -39,7 +39,6 @@ #include "cpregs.h" #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */ -#define PMCR_NUM_COUNTERS 4 /* QEMU IMPDEF choice */ #ifndef CONFIG_USER_ONLY @@ -5544,13 +5543,6 @@ static const ARMCPRegInfo el2_cp_reginfo[] = { .resetvalue = 0, .writefn = gt_hyp_ctl_write, .raw_writefn = raw_write }, #endif - /* The only field of MDCR_EL2 that has a defined architectural reset value - * is MDCR_EL2.HPMN which should reset to the value of PMCR_EL0.N. - */ - { .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1, - .access = PL2_RW, .resetvalue = PMCR_NUM_COUNTERS, - .fieldoffset = offsetof(CPUARMState, cp15.mdcr_el2), }, { .name = "HPFAR", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 4, .access = PL2_RW, .accessfn = access_el3_aa32ns, @@ -6604,7 +6596,7 @@ static void define_pmu_regs(ARMCPU *cpu) * field as main ID register, and we implement four counters in * addition to the cycle count register. */ - unsigned int i, pmcrn = PMCR_NUM_COUNTERS; + unsigned int i, pmcrn = pmu_num_counters(&cpu->env); ARMCPRegInfo pmcr = { .name = "PMCR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 0, .access = PL0_RW, @@ -6619,10 +6611,10 @@ static void define_pmu_regs(ARMCPU *cpu) .access = PL0_RW, .accessfn = pmreg_access, .type = ARM_CP_IO, .fieldoffset = offsetof(CPUARMState, cp15.c9_pmcr), - .resetvalue = (cpu->midr & 0xff000000) | (pmcrn << PMCRN_SHIFT) | - PMCRLC, + .resetvalue = cpu->isar.reset_pmcr_el0, .writefn = pmcr_write, .raw_writefn = raw_write, }; + define_one_arm_cp_reg(cpu, &pmcr); define_one_arm_cp_reg(cpu, &pmcr64); for (i = 0; i < pmcrn; i++) { @@ -7979,6 +7971,17 @@ void register_cp_regs_for_features(ARMCPU *cpu) .type = ARM_CP_EL3_NO_EL2_C_NZ, .fieldoffset = offsetof(CPUARMState, cp15.vmpidr_el2) }, }; + /* + * The only field of MDCR_EL2 that has a defined architectural reset + * value is MDCR_EL2.HPMN which should reset to the value of PMCR_EL0.N. + */ + ARMCPRegInfo mdcr_el2 = { + .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1, + .access = PL2_RW, .resetvalue = pmu_num_counters(env), + .fieldoffset = offsetof(CPUARMState, cp15.mdcr_el2), + }; + define_one_arm_cp_reg(cpu, &mdcr_el2); define_arm_cp_regs(cpu, vpidr_regs); define_arm_cp_regs(cpu, el2_cp_reginfo); if (arm_feature(env, ARM_FEATURE_V8)) { diff --git a/target/arm/internals.h b/target/arm/internals.h index 9b354eea7e..b654bee468 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1304,7 +1304,9 @@ enum MVEECIState { static inline uint32_t pmu_num_counters(CPUARMState *env) { - return (env->cp15.c9_pmcr & PMCRN_MASK) >> PMCRN_SHIFT; + ARMCPU *cpu = env_archcpu(env); + + return (cpu->isar.reset_pmcr_el0 & PMCRN_MASK) >> PMCRN_SHIFT; } /* Bits allowed to be set/cleared for PMCNTEN* and PMINTEN* */ diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index b8cfaf5782..363032da90 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -505,6 +505,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) */ int fdarray[3]; bool sve_supported; + bool pmu_supported = false; uint64_t features = 0; uint64_t t; int err; @@ -537,6 +538,11 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) 1 << KVM_ARM_VCPU_PTRAUTH_GENERIC); } + if (kvm_arm_pmu_supported()) { + init.features[0] |= 1 << KVM_ARM_VCPU_PMU_V3; + pmu_supported = true; + } + if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) { return false; } @@ -659,6 +665,12 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) dbgdidr |= (1 << 15); /* RES1 bit */ ahcf->isar.dbgdidr = dbgdidr; } + + if (pmu_supported) { + /* PMCR_EL0 is only accessible if the vCPU has feature PMU_V3 */ + err |= read_sys_reg64(fdarray[2], &ahcf->isar.reset_pmcr_el0, + ARM64_SYS_REG(3, 3, 9, 12, 0)); + } } sve_supported = ioctl(fdarray[0], KVM_CHECK_EXTENSION, KVM_CAP_ARM_SVE) > 0; From e8ca920f3d1cedf7f2ebb41d13cd4d5946d3d882 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 13 May 2022 14:13:15 +0100 Subject: [PATCH 448/935] hw/arm/virt: Fix incorrect non-secure flash dtb node name In the virt board with secure=on we put two nodes in the dtb for flash devices: one for the secure-only flash, and one for the non-secure flash. We get the reg properties for these correct, but in the DT node name, which by convention includes the base address of devices, we used the wrong address. Fix it. Spotted by dtc, which will complain Warning (unique_unit_address): /flash@0: duplicate unit-address (also used in node /secflash@0) if you dump the dtb from QEMU with -machine dumpdtb=file.dtb and then decompile it with dtc. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220513131316.4081539-2-peter.maydell@linaro.org --- hw/arm/virt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 1a45f44435..587e885a98 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1195,7 +1195,7 @@ static void virt_flash_fdt(VirtMachineState *vms, qemu_fdt_setprop_string(ms->fdt, nodename, "secure-status", "okay"); g_free(nodename); - nodename = g_strdup_printf("/flash@%" PRIx64, flashbase); + nodename = g_strdup_printf("/flash@%" PRIx64, flashbase + flashsize); qemu_fdt_add_subnode(ms->fdt, nodename); qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "cfi-flash"); qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", From afdcbddcc92ef75ed1905e6ae7aa00db06e86dfc Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 13 May 2022 14:13:16 +0100 Subject: [PATCH 449/935] hw/arm/virt: Drop #size-cells and #address-cells from gpio-keys dtb node The virt board generates a gpio-keys node in the dtb, but it incorrectly gives this node #size-cells and #address-cells properties. If you dump the dtb with 'machine dumpdtb=file.dtb' and run it through dtc, dtc will warn about this: Warning (avoid_unnecessary_addr_size): /gpio-keys: unnecessary #address-cells/#size-cells without "ranges" or child "reg" property Remove the bogus properties. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220513131316.4081539-3-peter.maydell@linaro.org --- hw/arm/virt.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 587e885a98..097238faa7 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -925,8 +925,6 @@ static void create_gpio_keys(char *fdt, DeviceState *pl061_dev, qemu_fdt_add_subnode(fdt, "/gpio-keys"); qemu_fdt_setprop_string(fdt, "/gpio-keys", "compatible", "gpio-keys"); - qemu_fdt_setprop_cell(fdt, "/gpio-keys", "#size-cells", 0); - qemu_fdt_setprop_cell(fdt, "/gpio-keys", "#address-cells", 1); qemu_fdt_add_subnode(fdt, "/gpio-keys/poweroff"); qemu_fdt_setprop_string(fdt, "/gpio-keys/poweroff", From 9598c1bb39b2d4f0d3a55072cc70251c452132cd Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 16 May 2022 11:30:58 +0100 Subject: [PATCH 450/935] ptimer: Rename PTIMER_POLICY_DEFAULT to PTIMER_POLICY_LEGACY The traditional ptimer behaviour includes a collection of weird edge case behaviours. In 2016 we improved the ptimer implementation to fix these and generally make the behaviour more flexible, with ptimers opting in to the new behaviour by passing an appropriate set of policy flags to ptimer_init(). For backwards-compatibility, we defined PTIMER_POLICY_DEFAULT (which sets no flags) to give the old weird behaviour. This turns out to be a poor choice of name, because people writing new devices which use ptimers are misled into thinking that the default is probably a sensible choice of flags, when in fact it is almost always not what you want. Rename PTIMER_POLICY_DEFAULT to PTIMER_POLICY_LEGACY and beef up the comment to more clearly say that new devices should not be using it. The code-change part of this commit was produced by sed -i -e 's/PTIMER_POLICY_DEFAULT/PTIMER_POLICY_LEGACY/g' $(git grep -l PTIMER_POLICY_DEFAULT) with the exception of a test name string change in tests/unit/ptimer-test.c which was added manually. Signed-off-by: Peter Maydell Reviewed-by: Francisco Iglesias Reviewed-by: Richard Henderson Message-id: 20220516103058.162280-1-peter.maydell@linaro.org --- hw/arm/musicpal.c | 2 +- hw/dma/xilinx_axidma.c | 2 +- hw/dma/xlnx_csu_dma.c | 2 +- hw/m68k/mcf5206.c | 2 +- hw/m68k/mcf5208.c | 2 +- hw/net/can/xlnx-zynqmp-can.c | 2 +- hw/net/fsl_etsec/etsec.c | 2 +- hw/net/lan9118.c | 2 +- hw/rtc/exynos4210_rtc.c | 4 ++-- hw/timer/allwinner-a10-pit.c | 2 +- hw/timer/altera_timer.c | 2 +- hw/timer/arm_timer.c | 2 +- hw/timer/digic-timer.c | 2 +- hw/timer/etraxfs_timer.c | 6 +++--- hw/timer/exynos4210_mct.c | 6 +++--- hw/timer/exynos4210_pwm.c | 2 +- hw/timer/grlib_gptimer.c | 2 +- hw/timer/imx_epit.c | 4 ++-- hw/timer/imx_gpt.c | 2 +- hw/timer/mss-timer.c | 2 +- hw/timer/sh_timer.c | 2 +- hw/timer/slavio_timer.c | 2 +- hw/timer/xilinx_timer.c | 2 +- include/hw/ptimer.h | 16 ++++++++++++---- tests/unit/ptimer-test.c | 6 +++--- 25 files changed, 44 insertions(+), 36 deletions(-) diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index 7c840fb428..b65c020115 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -464,7 +464,7 @@ static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s, sysbus_init_irq(dev, &s->irq); s->freq = freq; - s->ptimer = ptimer_init(mv88w8618_timer_tick, s, PTIMER_POLICY_DEFAULT); + s->ptimer = ptimer_init(mv88w8618_timer_tick, s, PTIMER_POLICY_LEGACY); } static uint64_t mv88w8618_pit_read(void *opaque, hwaddr offset, diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index bc383f53cc..cbb8f0f169 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -552,7 +552,7 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp) st->dma = s; st->nr = i; - st->ptimer = ptimer_init(timer_hit, st, PTIMER_POLICY_DEFAULT); + st->ptimer = ptimer_init(timer_hit, st, PTIMER_POLICY_LEGACY); ptimer_transaction_begin(st->ptimer); ptimer_set_freq(st->ptimer, s->freqhz); ptimer_transaction_commit(st->ptimer); diff --git a/hw/dma/xlnx_csu_dma.c b/hw/dma/xlnx_csu_dma.c index 60ada3286b..1ce52ea5a2 100644 --- a/hw/dma/xlnx_csu_dma.c +++ b/hw/dma/xlnx_csu_dma.c @@ -666,7 +666,7 @@ static void xlnx_csu_dma_realize(DeviceState *dev, Error **errp) sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); s->src_timer = ptimer_init(xlnx_csu_dma_src_timeout_hit, - s, PTIMER_POLICY_DEFAULT); + s, PTIMER_POLICY_LEGACY); s->attr = MEMTXATTRS_UNSPECIFIED; diff --git a/hw/m68k/mcf5206.c b/hw/m68k/mcf5206.c index 6d93d761a5..2ab1b4f059 100644 --- a/hw/m68k/mcf5206.c +++ b/hw/m68k/mcf5206.c @@ -152,7 +152,7 @@ static m5206_timer_state *m5206_timer_init(qemu_irq irq) m5206_timer_state *s; s = g_new0(m5206_timer_state, 1); - s->timer = ptimer_init(m5206_timer_trigger, s, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init(m5206_timer_trigger, s, PTIMER_POLICY_LEGACY); s->irq = irq; m5206_timer_reset(s); return s; diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c index 655207e393..be1033f84f 100644 --- a/hw/m68k/mcf5208.c +++ b/hw/m68k/mcf5208.c @@ -197,7 +197,7 @@ static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic) /* Timers. */ for (i = 0; i < 2; i++) { s = g_new0(m5208_timer_state, 1); - s->timer = ptimer_init(m5208_timer_trigger, s, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init(m5208_timer_trigger, s, PTIMER_POLICY_LEGACY); memory_region_init_io(&s->iomem, NULL, &m5208_timer_ops, s, "m5208-timer", 0x00004000); memory_region_add_subregion(address_space, 0xfc080000 + 0x4000 * i, diff --git a/hw/net/can/xlnx-zynqmp-can.c b/hw/net/can/xlnx-zynqmp-can.c index 22bb8910fa..82ac48cee2 100644 --- a/hw/net/can/xlnx-zynqmp-can.c +++ b/hw/net/can/xlnx-zynqmp-can.c @@ -1079,7 +1079,7 @@ static void xlnx_zynqmp_can_realize(DeviceState *dev, Error **errp) /* Allocate a new timer. */ s->can_timer = ptimer_init(xlnx_zynqmp_can_ptimer_cb, s, - PTIMER_POLICY_DEFAULT); + PTIMER_POLICY_LEGACY); ptimer_transaction_begin(s->can_timer); diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c index 6d50c39543..4e6cc708de 100644 --- a/hw/net/fsl_etsec/etsec.c +++ b/hw/net/fsl_etsec/etsec.c @@ -393,7 +393,7 @@ static void etsec_realize(DeviceState *dev, Error **errp) object_get_typename(OBJECT(dev)), dev->id, etsec); qemu_format_nic_info_str(qemu_get_queue(etsec->nic), etsec->conf.macaddr.a); - etsec->ptimer = ptimer_init(etsec_timer_hit, etsec, PTIMER_POLICY_DEFAULT); + etsec->ptimer = ptimer_init(etsec_timer_hit, etsec, PTIMER_POLICY_LEGACY); ptimer_transaction_begin(etsec->ptimer); ptimer_set_freq(etsec->ptimer, 100); ptimer_transaction_commit(etsec->ptimer); diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c index 6aff424cbe..456ae38107 100644 --- a/hw/net/lan9118.c +++ b/hw/net/lan9118.c @@ -1363,7 +1363,7 @@ static void lan9118_realize(DeviceState *dev, Error **errp) s->pmt_ctrl = 1; s->txp = &s->tx_packet; - s->timer = ptimer_init(lan9118_tick, s, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init(lan9118_tick, s, PTIMER_POLICY_LEGACY); ptimer_transaction_begin(s->timer); ptimer_set_freq(s->timer, 10000); ptimer_set_limit(s->timer, 0xffff, 1); diff --git a/hw/rtc/exynos4210_rtc.c b/hw/rtc/exynos4210_rtc.c index ae67641de6..d1620c7a2a 100644 --- a/hw/rtc/exynos4210_rtc.c +++ b/hw/rtc/exynos4210_rtc.c @@ -564,14 +564,14 @@ static void exynos4210_rtc_init(Object *obj) Exynos4210RTCState *s = EXYNOS4210_RTC(obj); SysBusDevice *dev = SYS_BUS_DEVICE(obj); - s->ptimer = ptimer_init(exynos4210_rtc_tick, s, PTIMER_POLICY_DEFAULT); + s->ptimer = ptimer_init(exynos4210_rtc_tick, s, PTIMER_POLICY_LEGACY); ptimer_transaction_begin(s->ptimer); ptimer_set_freq(s->ptimer, RTC_BASE_FREQ); exynos4210_rtc_update_freq(s, 0); ptimer_transaction_commit(s->ptimer); s->ptimer_1Hz = ptimer_init(exynos4210_rtc_1Hz_tick, - s, PTIMER_POLICY_DEFAULT); + s, PTIMER_POLICY_LEGACY); ptimer_transaction_begin(s->ptimer_1Hz); ptimer_set_freq(s->ptimer_1Hz, RTC_BASE_FREQ); ptimer_transaction_commit(s->ptimer_1Hz); diff --git a/hw/timer/allwinner-a10-pit.c b/hw/timer/allwinner-a10-pit.c index c3fc2a4daa..971f78462a 100644 --- a/hw/timer/allwinner-a10-pit.c +++ b/hw/timer/allwinner-a10-pit.c @@ -275,7 +275,7 @@ static void a10_pit_init(Object *obj) tc->container = s; tc->index = i; - s->timer[i] = ptimer_init(a10_pit_timer_cb, tc, PTIMER_POLICY_DEFAULT); + s->timer[i] = ptimer_init(a10_pit_timer_cb, tc, PTIMER_POLICY_LEGACY); } } diff --git a/hw/timer/altera_timer.c b/hw/timer/altera_timer.c index c6e02d2b5a..0f1f54206a 100644 --- a/hw/timer/altera_timer.c +++ b/hw/timer/altera_timer.c @@ -185,7 +185,7 @@ static void altera_timer_realize(DeviceState *dev, Error **errp) return; } - t->ptimer = ptimer_init(timer_hit, t, PTIMER_POLICY_DEFAULT); + t->ptimer = ptimer_init(timer_hit, t, PTIMER_POLICY_LEGACY); ptimer_transaction_begin(t->ptimer); ptimer_set_freq(t->ptimer, t->freq_hz); ptimer_transaction_commit(t->ptimer); diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c index 84cf2726bb..69c8863472 100644 --- a/hw/timer/arm_timer.c +++ b/hw/timer/arm_timer.c @@ -180,7 +180,7 @@ static arm_timer_state *arm_timer_init(uint32_t freq) s->freq = freq; s->control = TIMER_CTRL_IE; - s->timer = ptimer_init(arm_timer_tick, s, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init(arm_timer_tick, s, PTIMER_POLICY_LEGACY); vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_arm_timer, s); return s; } diff --git a/hw/timer/digic-timer.c b/hw/timer/digic-timer.c index e3aae4a45a..d5186f4454 100644 --- a/hw/timer/digic-timer.c +++ b/hw/timer/digic-timer.c @@ -139,7 +139,7 @@ static void digic_timer_init(Object *obj) { DigicTimerState *s = DIGIC_TIMER(obj); - s->ptimer = ptimer_init(digic_timer_tick, NULL, PTIMER_POLICY_DEFAULT); + s->ptimer = ptimer_init(digic_timer_tick, NULL, PTIMER_POLICY_LEGACY); /* * FIXME: there is no documentation on Digic timer diff --git a/hw/timer/etraxfs_timer.c b/hw/timer/etraxfs_timer.c index 139e5b86a4..ecc2831baf 100644 --- a/hw/timer/etraxfs_timer.c +++ b/hw/timer/etraxfs_timer.c @@ -370,9 +370,9 @@ static void etraxfs_timer_realize(DeviceState *dev, Error **errp) ETRAXTimerState *t = ETRAX_TIMER(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - t->ptimer_t0 = ptimer_init(timer0_hit, t, PTIMER_POLICY_DEFAULT); - t->ptimer_t1 = ptimer_init(timer1_hit, t, PTIMER_POLICY_DEFAULT); - t->ptimer_wd = ptimer_init(watchdog_hit, t, PTIMER_POLICY_DEFAULT); + t->ptimer_t0 = ptimer_init(timer0_hit, t, PTIMER_POLICY_LEGACY); + t->ptimer_t1 = ptimer_init(timer1_hit, t, PTIMER_POLICY_LEGACY); + t->ptimer_wd = ptimer_init(watchdog_hit, t, PTIMER_POLICY_LEGACY); sysbus_init_irq(sbd, &t->irq); sysbus_init_irq(sbd, &t->nmi); diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index d0e5343996..e175a9f5b9 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -1503,17 +1503,17 @@ static void exynos4210_mct_init(Object *obj) /* Global timer */ s->g_timer.ptimer_frc = ptimer_init(exynos4210_gfrc_event, s, - PTIMER_POLICY_DEFAULT); + PTIMER_POLICY_LEGACY); memset(&s->g_timer.reg, 0, sizeof(struct gregs)); /* Local timers */ for (i = 0; i < 2; i++) { s->l_timer[i].tick_timer.ptimer_tick = ptimer_init(exynos4210_ltick_event, &s->l_timer[i], - PTIMER_POLICY_DEFAULT); + PTIMER_POLICY_LEGACY); s->l_timer[i].ptimer_frc = ptimer_init(exynos4210_lfrc_event, &s->l_timer[i], - PTIMER_POLICY_DEFAULT); + PTIMER_POLICY_LEGACY); s->l_timer[i].id = i; } diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c index 220088120e..02924a9e5b 100644 --- a/hw/timer/exynos4210_pwm.c +++ b/hw/timer/exynos4210_pwm.c @@ -400,7 +400,7 @@ static void exynos4210_pwm_init(Object *obj) sysbus_init_irq(dev, &s->timer[i].irq); s->timer[i].ptimer = ptimer_init(exynos4210_pwm_tick, &s->timer[i], - PTIMER_POLICY_DEFAULT); + PTIMER_POLICY_LEGACY); s->timer[i].id = i; s->timer[i].parent = s; } diff --git a/hw/timer/grlib_gptimer.c b/hw/timer/grlib_gptimer.c index d511890109..5c4923c1e0 100644 --- a/hw/timer/grlib_gptimer.c +++ b/hw/timer/grlib_gptimer.c @@ -383,7 +383,7 @@ static void grlib_gptimer_realize(DeviceState *dev, Error **errp) timer->unit = unit; timer->ptimer = ptimer_init(grlib_gptimer_hit, timer, - PTIMER_POLICY_DEFAULT); + PTIMER_POLICY_LEGACY); timer->id = i; /* One IRQ line for each timer */ diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c index ebd58254d1..2bf8c754b2 100644 --- a/hw/timer/imx_epit.c +++ b/hw/timer/imx_epit.c @@ -347,9 +347,9 @@ static void imx_epit_realize(DeviceState *dev, Error **errp) 0x00001000); sysbus_init_mmio(sbd, &s->iomem); - s->timer_reload = ptimer_init(imx_epit_reload, s, PTIMER_POLICY_DEFAULT); + s->timer_reload = ptimer_init(imx_epit_reload, s, PTIMER_POLICY_LEGACY); - s->timer_cmp = ptimer_init(imx_epit_cmp, s, PTIMER_POLICY_DEFAULT); + s->timer_cmp = ptimer_init(imx_epit_cmp, s, PTIMER_POLICY_LEGACY); } static void imx_epit_class_init(ObjectClass *klass, void *data) diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c index 5c0d9a269c..80b8302639 100644 --- a/hw/timer/imx_gpt.c +++ b/hw/timer/imx_gpt.c @@ -505,7 +505,7 @@ static void imx_gpt_realize(DeviceState *dev, Error **errp) 0x00001000); sysbus_init_mmio(sbd, &s->iomem); - s->timer = ptimer_init(imx_gpt_timeout, s, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init(imx_gpt_timeout, s, PTIMER_POLICY_LEGACY); } static void imx_gpt_class_init(ObjectClass *klass, void *data) diff --git a/hw/timer/mss-timer.c b/hw/timer/mss-timer.c index fe0ca905f3..ee7438f168 100644 --- a/hw/timer/mss-timer.c +++ b/hw/timer/mss-timer.c @@ -232,7 +232,7 @@ static void mss_timer_init(Object *obj) for (i = 0; i < NUM_TIMERS; i++) { struct Msf2Timer *st = &t->timers[i]; - st->ptimer = ptimer_init(timer_hit, st, PTIMER_POLICY_DEFAULT); + st->ptimer = ptimer_init(timer_hit, st, PTIMER_POLICY_LEGACY); ptimer_transaction_begin(st->ptimer); ptimer_set_freq(st->ptimer, t->freq_hz); ptimer_transaction_commit(st->ptimer); diff --git a/hw/timer/sh_timer.c b/hw/timer/sh_timer.c index c72c327bfa..7788939766 100644 --- a/hw/timer/sh_timer.c +++ b/hw/timer/sh_timer.c @@ -239,7 +239,7 @@ static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq) s->enabled = 0; s->irq = irq; - s->timer = ptimer_init(sh_timer_tick, s, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init(sh_timer_tick, s, PTIMER_POLICY_LEGACY); sh_timer_write(s, OFFSET_TCOR >> 2, s->tcor); sh_timer_write(s, OFFSET_TCNT >> 2, s->tcnt); diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c index 90fdce4c44..8c4f6eb06b 100644 --- a/hw/timer/slavio_timer.c +++ b/hw/timer/slavio_timer.c @@ -405,7 +405,7 @@ static void slavio_timer_init(Object *obj) tc->timer_index = i; s->cputimer[i].timer = ptimer_init(slavio_timer_irq, tc, - PTIMER_POLICY_DEFAULT); + PTIMER_POLICY_LEGACY); ptimer_transaction_begin(s->cputimer[i].timer); ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD); ptimer_transaction_commit(s->cputimer[i].timer); diff --git a/hw/timer/xilinx_timer.c b/hw/timer/xilinx_timer.c index 1eb927eb84..c7f17cd646 100644 --- a/hw/timer/xilinx_timer.c +++ b/hw/timer/xilinx_timer.c @@ -223,7 +223,7 @@ static void xilinx_timer_realize(DeviceState *dev, Error **errp) xt->parent = t; xt->nr = i; - xt->ptimer = ptimer_init(timer_hit, xt, PTIMER_POLICY_DEFAULT); + xt->ptimer = ptimer_init(timer_hit, xt, PTIMER_POLICY_LEGACY); ptimer_transaction_begin(xt->ptimer); ptimer_set_freq(xt->ptimer, t->freq_hz); ptimer_transaction_commit(xt->ptimer); diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h index c443218475..4dc02b0de4 100644 --- a/include/hw/ptimer.h +++ b/include/hw/ptimer.h @@ -33,9 +33,17 @@ * to stderr when the guest attempts to enable the timer. */ -/* The default ptimer policy retains backward compatibility with the legacy - * timers. Custom policies are adjusting the default one. Consider providing - * a correct policy for your timer. +/* + * The 'legacy' ptimer policy retains backward compatibility with the + * traditional ptimer behaviour from before policy flags were introduced. + * It has several weird behaviours which don't match typical hardware + * timer behaviour. For a new device using ptimers, you should not + * use PTIMER_POLICY_LEGACY, but instead check the actual behaviour + * that you need and specify the right set of policy flags to get that. + * + * If you are overhauling an existing device that uses PTIMER_POLICY_LEGACY + * and are in a position to check or test the real hardware behaviour, + * consider updating it to specify the right policy flags. * * The rough edges of the default policy: * - Starting to run with a period = 0 emits error message and stops the @@ -54,7 +62,7 @@ * since the last period, effectively restarting the timer with a * counter = counter value at the moment of change (.i.e. one less). */ -#define PTIMER_POLICY_DEFAULT 0 +#define PTIMER_POLICY_LEGACY 0 /* Periodic timer counter stays with "0" for a one period before wrapping * around. */ diff --git a/tests/unit/ptimer-test.c b/tests/unit/ptimer-test.c index 9176b96c1c..a80ef5aff4 100644 --- a/tests/unit/ptimer-test.c +++ b/tests/unit/ptimer-test.c @@ -768,8 +768,8 @@ static void add_ptimer_tests(uint8_t policy) char policy_name[256] = ""; char *tmp; - if (policy == PTIMER_POLICY_DEFAULT) { - g_sprintf(policy_name, "default"); + if (policy == PTIMER_POLICY_LEGACY) { + g_sprintf(policy_name, "legacy"); } if (policy & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD) { @@ -862,7 +862,7 @@ static void add_ptimer_tests(uint8_t policy) static void add_all_ptimer_policies_comb_tests(void) { int last_policy = PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT; - int policy = PTIMER_POLICY_DEFAULT; + int policy = PTIMER_POLICY_LEGACY; for (; policy < (last_policy << 1); policy++) { if ((policy & PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT) && From 07b034ea828eb089de1a88e0043a8f3065f2d205 Mon Sep 17 00:00:00 2001 From: Florian Lugou Date: Tue, 17 May 2022 16:52:42 +0200 Subject: [PATCH 451/935] target/arm: Fix PAuth keys access checks for disabled SEL2 As per the description of the HCR_EL2.APK field in the ARMv8 ARM, Pointer Authentication keys accesses should only be trapped to Secure EL2 if it is enabled. Signed-off-by: Florian Lugou Reviewed-by: Richard Henderson Message-id: 20220517145242.1215271-1-florian.lugou@provenrun.com Signed-off-by: Peter Maydell --- target/arm/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index aa7a8e0572..fdd51e5e75 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6768,7 +6768,7 @@ static CPAccessResult access_pauth(CPUARMState *env, const ARMCPRegInfo *ri, int el = arm_current_el(env); if (el < 2 && - arm_feature(env, ARM_FEATURE_EL2) && + arm_is_el2_enabled(env) && !(arm_hcr_el2_eff(env) & HCR_APK)) { return CP_ACCESS_TRAP_EL2; } From 5814d587fe861fe9cab651638959f6db843df54e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 16 May 2022 22:48:44 -0700 Subject: [PATCH 452/935] target/arm: Enable FEAT_HCX for -cpu max This feature adds a new register, HCRX_EL2, which controls many of the newer AArch64 features. So far the register is effectively RES0, because none of the new features are done. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220517054850.177016-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 20 ++++++++++++++++++ target/arm/cpu64.c | 1 + target/arm/helper.c | 50 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 3dc79f121b..fac526a490 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -362,6 +362,7 @@ typedef struct CPUArchState { uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */ uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */ uint64_t hcr_el2; /* Hypervisor configuration register */ + uint64_t hcrx_el2; /* Extended Hypervisor configuration register */ uint64_t scr_el3; /* Secure configuration register. */ union { /* Fault status registers. */ struct { @@ -1545,6 +1546,19 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) #define HCR_TWEDEN (1ULL << 59) #define HCR_TWEDEL MAKE_64BIT_MASK(60, 4) +#define HCRX_ENAS0 (1ULL << 0) +#define HCRX_ENALS (1ULL << 1) +#define HCRX_ENASR (1ULL << 2) +#define HCRX_FNXS (1ULL << 3) +#define HCRX_FGTNXS (1ULL << 4) +#define HCRX_SMPME (1ULL << 5) +#define HCRX_TALLINT (1ULL << 6) +#define HCRX_VINMI (1ULL << 7) +#define HCRX_VFNMI (1ULL << 8) +#define HCRX_CMOW (1ULL << 9) +#define HCRX_MCE2 (1ULL << 10) +#define HCRX_MSCEN (1ULL << 11) + #define HPFAR_NS (1ULL << 63) #define SCR_NS (1U << 0) @@ -2312,6 +2326,7 @@ static inline bool arm_is_el2_enabled(CPUARMState *env) * Not included here is HCR_RW. */ uint64_t arm_hcr_el2_eff(CPUARMState *env); +uint64_t arm_hcrx_el2_eff(CPUARMState *env); /* Return true if the specified exception level is running in AArch64 state. */ static inline bool arm_el_is_aa64(CPUARMState *env, int el) @@ -3933,6 +3948,11 @@ static inline bool isar_feature_aa64_ats1e1(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) >= 2; } +static inline bool isar_feature_aa64_hcx(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, HCX) != 0; +} + static inline bool isar_feature_aa64_uao(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, UAO) != 0; diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index a752b64856..3ff9219ca3 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -934,6 +934,7 @@ static void aarch64_max_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1); /* FEAT_LOR */ t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 2); /* FEAT_PAN2 */ t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1); /* FEAT_XNX */ + t = FIELD_DP64(t, ID_AA64MMFR1, HCX, 1); /* FEAT_HCX */ cpu->isar.id_aa64mmfr1 = t; t = cpu->isar.id_aa64mmfr2; diff --git a/target/arm/helper.c b/target/arm/helper.c index fdd51e5e75..7d983d7fff 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5288,6 +5288,52 @@ uint64_t arm_hcr_el2_eff(CPUARMState *env) return ret; } +static void hcrx_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + uint64_t valid_mask = 0; + + /* No features adding bits to HCRX are implemented. */ + + /* Clear RES0 bits. */ + env->cp15.hcrx_el2 = value & valid_mask; +} + +static CPAccessResult access_hxen(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + if (arm_current_el(env) < 3 + && arm_feature(env, ARM_FEATURE_EL3) + && !(env->cp15.scr_el3 & SCR_HXEN)) { + return CP_ACCESS_TRAP_EL3; + } + return CP_ACCESS_OK; +} + +static const ARMCPRegInfo hcrx_el2_reginfo = { + .name = "HCRX_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 2, + .access = PL2_RW, .writefn = hcrx_write, .accessfn = access_hxen, + .fieldoffset = offsetof(CPUARMState, cp15.hcrx_el2), +}; + +/* Return the effective value of HCRX_EL2. */ +uint64_t arm_hcrx_el2_eff(CPUARMState *env) +{ + /* + * The bits in this register behave as 0 for all purposes other than + * direct reads of the register if: + * - EL2 is not enabled in the current security state, + * - SCR_EL3.HXEn is 0. + */ + if (!arm_is_el2_enabled(env) + || (arm_feature(env, ARM_FEATURE_EL3) + && !(env->cp15.scr_el3 & SCR_HXEN))) { + return 0; + } + return env->cp15.hcrx_el2; +} + static void cptr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { @@ -8405,6 +8451,10 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_arm_cp_regs(cpu, zcr_reginfo); } + if (cpu_isar_feature(aa64_hcx, cpu)) { + define_one_arm_cp_reg(cpu, &hcrx_el2_reginfo); + } + #ifdef TARGET_AARCH64 if (cpu_isar_feature(aa64_pauth, cpu)) { define_arm_cp_regs(cpu, pauth_reginfo); From fab8ad39fb75a0d9f097db67b2a334444754e88e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 16 May 2022 22:48:45 -0700 Subject: [PATCH 453/935] target/arm: Use FIELD definitions for CPACR, CPTR_ELx We had a few CPTR_* bits defined, but missed quite a few. Complete all of the fields up to ARMv9.2. Use FIELD_EX64 instead of manual extract32. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220517054850.177016-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- hw/arm/boot.c | 2 +- target/arm/cpu.c | 11 ++++++--- target/arm/cpu.h | 44 +++++++++++++++++++++++++++++++----- target/arm/helper.c | 54 ++++++++++++++++++++++----------------------- 4 files changed, 75 insertions(+), 36 deletions(-) diff --git a/hw/arm/boot.c b/hw/arm/boot.c index a47f38dfc9..a8de33fd64 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -761,7 +761,7 @@ static void do_cpu_reset(void *opaque) env->cp15.scr_el3 |= SCR_ATA; } if (cpu_isar_feature(aa64_sve, cpu)) { - env->cp15.cptr_el[3] |= CPTR_EZ; + env->cp15.cptr_el[3] |= R_CPTR_EL3_EZ_MASK; } /* AArch64 kernels never boot in secure mode */ assert(!info->secure_boot); diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 029f644768..d2bd74c2ed 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -201,9 +201,11 @@ static void arm_cpu_reset(DeviceState *dev) /* Trap on btype=3 for PACIxSP. */ env->cp15.sctlr_el[1] |= SCTLR_BT0; /* and to the FP/Neon instructions */ - env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 20, 2, 3); + env->cp15.cpacr_el1 = FIELD_DP64(env->cp15.cpacr_el1, + CPACR_EL1, FPEN, 3); /* and to the SVE instructions */ - env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 16, 2, 3); + env->cp15.cpacr_el1 = FIELD_DP64(env->cp15.cpacr_el1, + CPACR_EL1, ZEN, 3); /* with reasonable vector length */ if (cpu_isar_feature(aa64_sve, cpu)) { env->vfp.zcr_el[1] = @@ -252,7 +254,10 @@ static void arm_cpu_reset(DeviceState *dev) } else { #if defined(CONFIG_USER_ONLY) /* Userspace expects access to cp10 and cp11 for FP/Neon */ - env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 20, 4, 0xf); + env->cp15.cpacr_el1 = FIELD_DP64(env->cp15.cpacr_el1, + CPACR, CP10, 3); + env->cp15.cpacr_el1 = FIELD_DP64(env->cp15.cpacr_el1, + CPACR, CP11, 3); #endif } diff --git a/target/arm/cpu.h b/target/arm/cpu.h index fac526a490..c1865ad5da 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1261,11 +1261,45 @@ void pmu_init(ARMCPU *cpu); #define SCTLR_SPINTMASK (1ULL << 62) /* FEAT_NMI */ #define SCTLR_TIDCP (1ULL << 63) /* FEAT_TIDCP1 */ -#define CPTR_TCPAC (1U << 31) -#define CPTR_TTA (1U << 20) -#define CPTR_TFP (1U << 10) -#define CPTR_TZ (1U << 8) /* CPTR_EL2 */ -#define CPTR_EZ (1U << 8) /* CPTR_EL3 */ +/* Bit definitions for CPACR (AArch32 only) */ +FIELD(CPACR, CP10, 20, 2) +FIELD(CPACR, CP11, 22, 2) +FIELD(CPACR, TRCDIS, 28, 1) /* matches CPACR_EL1.TTA */ +FIELD(CPACR, D32DIS, 30, 1) /* up to v7; RAZ in v8 */ +FIELD(CPACR, ASEDIS, 31, 1) + +/* Bit definitions for CPACR_EL1 (AArch64 only) */ +FIELD(CPACR_EL1, ZEN, 16, 2) +FIELD(CPACR_EL1, FPEN, 20, 2) +FIELD(CPACR_EL1, SMEN, 24, 2) +FIELD(CPACR_EL1, TTA, 28, 1) /* matches CPACR.TRCDIS */ + +/* Bit definitions for HCPTR (AArch32 only) */ +FIELD(HCPTR, TCP10, 10, 1) +FIELD(HCPTR, TCP11, 11, 1) +FIELD(HCPTR, TASE, 15, 1) +FIELD(HCPTR, TTA, 20, 1) +FIELD(HCPTR, TAM, 30, 1) /* matches CPTR_EL2.TAM */ +FIELD(HCPTR, TCPAC, 31, 1) /* matches CPTR_EL2.TCPAC */ + +/* Bit definitions for CPTR_EL2 (AArch64 only) */ +FIELD(CPTR_EL2, TZ, 8, 1) /* !E2H */ +FIELD(CPTR_EL2, TFP, 10, 1) /* !E2H, matches HCPTR.TCP10 */ +FIELD(CPTR_EL2, TSM, 12, 1) /* !E2H */ +FIELD(CPTR_EL2, ZEN, 16, 2) /* E2H */ +FIELD(CPTR_EL2, FPEN, 20, 2) /* E2H */ +FIELD(CPTR_EL2, SMEN, 24, 2) /* E2H */ +FIELD(CPTR_EL2, TTA, 28, 1) +FIELD(CPTR_EL2, TAM, 30, 1) /* matches HCPTR.TAM */ +FIELD(CPTR_EL2, TCPAC, 31, 1) /* matches HCPTR.TCPAC */ + +/* Bit definitions for CPTR_EL3 (AArch64 only) */ +FIELD(CPTR_EL3, EZ, 8, 1) +FIELD(CPTR_EL3, TFP, 10, 1) +FIELD(CPTR_EL3, ESM, 12, 1) +FIELD(CPTR_EL3, TTA, 20, 1) +FIELD(CPTR_EL3, TAM, 30, 1) +FIELD(CPTR_EL3, TCPAC, 31, 1) #define MDCR_EPMAD (1U << 21) #define MDCR_EDAD (1U << 20) diff --git a/target/arm/helper.c b/target/arm/helper.c index 7d983d7fff..40da63913c 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -766,11 +766,14 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri, */ if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) { /* VFP coprocessor: cp10 & cp11 [23:20] */ - mask |= (1 << 31) | (1 << 30) | (0xf << 20); + mask |= R_CPACR_ASEDIS_MASK | + R_CPACR_D32DIS_MASK | + R_CPACR_CP11_MASK | + R_CPACR_CP10_MASK; if (!arm_feature(env, ARM_FEATURE_NEON)) { /* ASEDIS [31] bit is RAO/WI */ - value |= (1 << 31); + value |= R_CPACR_ASEDIS_MASK; } /* VFPv3 and upwards with NEON implement 32 double precision @@ -778,7 +781,7 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri, */ if (!cpu_isar_feature(aa32_simd_r32, env_archcpu(env))) { /* D32DIS [30] is RAO/WI if D16-31 are not implemented. */ - value |= (1 << 30); + value |= R_CPACR_D32DIS_MASK; } } value &= mask; @@ -790,8 +793,8 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri, */ if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) && !arm_is_secure(env) && !extract32(env->cp15.nsacr, 10, 1)) { - value &= ~(0xf << 20); - value |= env->cp15.cpacr_el1 & (0xf << 20); + mask = R_CPACR_CP11_MASK | R_CPACR_CP10_MASK; + value = (value & ~mask) | (env->cp15.cpacr_el1 & mask); } env->cp15.cpacr_el1 = value; @@ -807,7 +810,7 @@ static uint64_t cpacr_read(CPUARMState *env, const ARMCPRegInfo *ri) if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) && !arm_is_secure(env) && !extract32(env->cp15.nsacr, 10, 1)) { - value &= ~(0xf << 20); + value = ~(R_CPACR_CP11_MASK | R_CPACR_CP10_MASK); } return value; } @@ -827,11 +830,11 @@ static CPAccessResult cpacr_access(CPUARMState *env, const ARMCPRegInfo *ri, if (arm_feature(env, ARM_FEATURE_V8)) { /* Check if CPACR accesses are to be trapped to EL2 */ if (arm_current_el(env) == 1 && arm_is_el2_enabled(env) && - (env->cp15.cptr_el[2] & CPTR_TCPAC)) { + FIELD_EX64(env->cp15.cptr_el[2], CPTR_EL2, TCPAC)) { return CP_ACCESS_TRAP_EL2; /* Check if CPACR accesses are to be trapped to EL3 */ } else if (arm_current_el(env) < 3 && - (env->cp15.cptr_el[3] & CPTR_TCPAC)) { + FIELD_EX64(env->cp15.cptr_el[3], CPTR_EL3, TCPAC)) { return CP_ACCESS_TRAP_EL3; } } @@ -843,7 +846,8 @@ static CPAccessResult cptr_access(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) { /* Check if CPTR accesses are set to trap to EL3 */ - if (arm_current_el(env) == 2 && (env->cp15.cptr_el[3] & CPTR_TCPAC)) { + if (arm_current_el(env) == 2 && + FIELD_EX64(env->cp15.cptr_el[3], CPTR_EL3, TCPAC)) { return CP_ACCESS_TRAP_EL3; } @@ -5343,8 +5347,8 @@ static void cptr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri, */ if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) && !arm_is_secure(env) && !extract32(env->cp15.nsacr, 10, 1)) { - value &= ~(0x3 << 10); - value |= env->cp15.cptr_el[2] & (0x3 << 10); + uint64_t mask = R_HCPTR_TCP11_MASK | R_HCPTR_TCP10_MASK; + value = (value & ~mask) | (env->cp15.cptr_el[2] & mask); } env->cp15.cptr_el[2] = value; } @@ -5359,7 +5363,7 @@ static uint64_t cptr_el2_read(CPUARMState *env, const ARMCPRegInfo *ri) if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) && !arm_is_secure(env) && !extract32(env->cp15.nsacr, 10, 1)) { - value |= 0x3 << 10; + value |= R_HCPTR_TCP11_MASK | R_HCPTR_TCP10_MASK; } return value; } @@ -6147,8 +6151,7 @@ int sve_exception_el(CPUARMState *env, int el) uint64_t hcr_el2 = arm_hcr_el2_eff(env); if (el <= 1 && (hcr_el2 & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) { - /* Check CPACR.ZEN. */ - switch (extract32(env->cp15.cpacr_el1, 16, 2)) { + switch (FIELD_EX64(env->cp15.cpacr_el1, CPACR_EL1, ZEN)) { case 1: if (el != 0) { break; @@ -6161,7 +6164,7 @@ int sve_exception_el(CPUARMState *env, int el) } /* Check CPACR.FPEN. */ - switch (extract32(env->cp15.cpacr_el1, 20, 2)) { + switch (FIELD_EX64(env->cp15.cpacr_el1, CPACR_EL1, FPEN)) { case 1: if (el != 0) { break; @@ -6178,8 +6181,7 @@ int sve_exception_el(CPUARMState *env, int el) */ if (el <= 2) { if (hcr_el2 & HCR_E2H) { - /* Check CPTR_EL2.ZEN. */ - switch (extract32(env->cp15.cptr_el[2], 16, 2)) { + switch (FIELD_EX64(env->cp15.cptr_el[2], CPTR_EL2, ZEN)) { case 1: if (el != 0 || !(hcr_el2 & HCR_TGE)) { break; @@ -6190,8 +6192,7 @@ int sve_exception_el(CPUARMState *env, int el) return 2; } - /* Check CPTR_EL2.FPEN. */ - switch (extract32(env->cp15.cptr_el[2], 20, 2)) { + switch (FIELD_EX32(env->cp15.cptr_el[2], CPTR_EL2, FPEN)) { case 1: if (el == 2 || !(hcr_el2 & HCR_TGE)) { break; @@ -6202,10 +6203,10 @@ int sve_exception_el(CPUARMState *env, int el) return 0; } } else if (arm_is_el2_enabled(env)) { - if (env->cp15.cptr_el[2] & CPTR_TZ) { + if (FIELD_EX64(env->cp15.cptr_el[2], CPTR_EL2, TZ)) { return 2; } - if (env->cp15.cptr_el[2] & CPTR_TFP) { + if (FIELD_EX64(env->cp15.cptr_el[2], CPTR_EL2, TFP)) { return 0; } } @@ -6213,7 +6214,7 @@ int sve_exception_el(CPUARMState *env, int el) /* CPTR_EL3. Since EZ is negative we must check for EL3. */ if (arm_feature(env, ARM_FEATURE_EL3) - && !(env->cp15.cptr_el[3] & CPTR_EZ)) { + && !FIELD_EX64(env->cp15.cptr_el[3], CPTR_EL3, EZ)) { return 3; } #endif @@ -13396,7 +13397,7 @@ int fp_exception_el(CPUARMState *env, int cur_el) * This register is ignored if E2H+TGE are both set. */ if ((hcr_el2 & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) { - int fpen = extract32(env->cp15.cpacr_el1, 20, 2); + int fpen = FIELD_EX64(env->cp15.cpacr_el1, CPACR_EL1, FPEN); switch (fpen) { case 0: @@ -13442,8 +13443,7 @@ int fp_exception_el(CPUARMState *env, int cur_el) */ if (cur_el <= 2) { if (hcr_el2 & HCR_E2H) { - /* Check CPTR_EL2.FPEN. */ - switch (extract32(env->cp15.cptr_el[2], 20, 2)) { + switch (FIELD_EX64(env->cp15.cptr_el[2], CPTR_EL2, FPEN)) { case 1: if (cur_el != 0 || !(hcr_el2 & HCR_TGE)) { break; @@ -13454,14 +13454,14 @@ int fp_exception_el(CPUARMState *env, int cur_el) return 2; } } else if (arm_is_el2_enabled(env)) { - if (env->cp15.cptr_el[2] & CPTR_TFP) { + if (FIELD_EX64(env->cp15.cptr_el[2], CPTR_EL2, TFP)) { return 2; } } } /* CPTR_EL3 : present in v8 */ - if (env->cp15.cptr_el[3] & CPTR_TFP) { + if (FIELD_EX64(env->cp15.cptr_el[3], CPTR_EL3, TFP)) { /* Trap all FP ops to EL3 */ return 3; } From 60f1c8017a2b137013a8ae83911d74700f692425 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 26 Apr 2022 19:51:29 -0700 Subject: [PATCH 454/935] linux-user: Clean up arg_start/arg_end confusion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We had two sets of variables: arg_start/arg_end, and arg_strings/env_strings. In linuxload.c, we set the first pair to the bounds of the argv strings, but in elfload.c, we set the first pair to the bounds of the argv pointers and the second pair to the bounds of the argv strings. Remove arg_start/arg_end, replacing them with the standard argc/argv/envc/envp values. Retain arg_strings/env_strings with the meaning we were using in elfload.c. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/714 Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-Id: <20220427025129.160184-1-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/elfload.c | 10 ++++++---- linux-user/linuxload.c | 12 ++++++++++-- linux-user/main.c | 4 ++-- linux-user/qemu.h | 12 ++++++++---- semihosting/arm-compat-semi.c | 4 ++-- 5 files changed, 28 insertions(+), 14 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 61063fd974..8c0765dd4b 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1516,8 +1516,8 @@ static inline void init_thread(struct target_pt_regs *regs, regs->iaoq[0] = infop->entry; regs->iaoq[1] = infop->entry + 4; regs->gr[23] = 0; - regs->gr[24] = infop->arg_start; - regs->gr[25] = (infop->arg_end - infop->arg_start) / sizeof(abi_ulong); + regs->gr[24] = infop->argv; + regs->gr[25] = infop->argc; /* The top-of-stack contains a linkage buffer. */ regs->gr[30] = infop->start_stack + 64; regs->gr[31] = infop->entry; @@ -2120,8 +2120,10 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, u_envp = u_argv + (argc + 1) * n; u_auxv = u_envp + (envc + 1) * n; info->saved_auxv = u_auxv; - info->arg_start = u_argv; - info->arg_end = u_argv + argc * n; + info->argc = argc; + info->envc = envc; + info->argv = u_argv; + info->envp = u_envp; /* This is correct because Linux defines * elf_addr_t as Elf32_Off / Elf64_Off diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index 2ed5fc45ed..745cce70ab 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -92,6 +92,11 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, envp = sp; sp -= (argc + 1) * n; argv = sp; + ts->info->envp = envp; + ts->info->envc = envc; + ts->info->argv = argv; + ts->info->argc = argc; + if (push_ptr) { /* FIXME - handle put_user() failures */ sp -= n; @@ -99,19 +104,22 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, sp -= n; put_user_ual(argv, sp); } + sp -= n; /* FIXME - handle put_user() failures */ put_user_ual(argc, sp); - ts->info->arg_start = stringp; + + ts->info->arg_strings = stringp; while (argc-- > 0) { /* FIXME - handle put_user() failures */ put_user_ual(stringp, argv); argv += n; stringp += target_strlen(stringp) + 1; } - ts->info->arg_end = stringp; /* FIXME - handle put_user() failures */ put_user_ual(0, argv); + + ts->info->env_strings = stringp; while (envc-- > 0) { /* FIXME - handle put_user() failures */ put_user_ual(stringp, envp); diff --git a/linux-user/main.c b/linux-user/main.c index 7ca48664e4..651e32f5f2 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -878,9 +878,9 @@ int main(int argc, char **argv, char **envp) fprintf(f, "entry 0x" TARGET_ABI_FMT_lx "\n", info->entry); fprintf(f, "argv_start 0x" TARGET_ABI_FMT_lx "\n", - info->arg_start); + info->argv); fprintf(f, "env_start 0x" TARGET_ABI_FMT_lx "\n", - info->arg_end + (abi_ulong)sizeof(abi_ulong)); + info->envp); fprintf(f, "auxv_start 0x" TARGET_ABI_FMT_lx "\n", info->saved_auxv); qemu_log_unlock(f); diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 46550f5e21..7d90de1b15 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -40,15 +40,19 @@ struct image_info { abi_ulong data_offset; abi_ulong saved_auxv; abi_ulong auxv_len; - abi_ulong arg_start; - abi_ulong arg_end; - abi_ulong arg_strings; - abi_ulong env_strings; + abi_ulong argc; + abi_ulong argv; + abi_ulong envc; + abi_ulong envp; abi_ulong file_string; uint32_t elf_flags; int personality; abi_ulong alignment; + /* Generic semihosting knows about these pointers. */ + abi_ulong arg_strings; /* strings for argv */ + abi_ulong env_strings; /* strings for envp; ends arg_strings */ + /* The fields below are used in FDPIC mode. */ abi_ulong loadmap_addr; uint16_t nsegs; diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c index 7a51fd0737..b6ddaf863a 100644 --- a/semihosting/arm-compat-semi.c +++ b/semihosting/arm-compat-semi.c @@ -1106,7 +1106,7 @@ target_ulong do_common_semihosting(CPUState *cs) #else unsigned int i; - output_size = ts->info->arg_end - ts->info->arg_start; + output_size = ts->info->env_strings - ts->info->arg_strings; if (!output_size) { /* * We special-case the "empty command line" case (argc==0). @@ -1146,7 +1146,7 @@ target_ulong do_common_semihosting(CPUState *cs) goto out; } - if (copy_from_user(output_buffer, ts->info->arg_start, + if (copy_from_user(output_buffer, ts->info->arg_strings, output_size)) { errno = EFAULT; status = set_swi_errno(cs, -1); From 3a7a27cffb5ed50840e26a2567e187b17958cc64 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Tue, 17 May 2022 11:50:24 -0400 Subject: [PATCH 455/935] target/i386: Remove LBREn bit check when access Arch LBR MSRs Live migration can happen when Arch LBR LBREn bit is cleared, e.g., when migration happens after guest entered SMM mode. In this case, we still need to migrate Arch LBR MSRs. Signed-off-by: Yang Weijiang Message-Id: <20220517155024.33270-1-weijiang.yang@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/kvm/kvm.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index a9ee8eebd7..e2d675115b 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -3373,15 +3373,14 @@ static int kvm_put_msrs(X86CPU *cpu, int level) int i, ret; /* - * Only migrate Arch LBR states when: 1) Arch LBR is enabled - * for migrated vcpu. 2) the host Arch LBR depth equals that - * of source guest's, this is to avoid mismatch of guest/host - * config for the msr hence avoid unexpected misbehavior. + * Only migrate Arch LBR states when the host Arch LBR depth + * equals that of source guest's, this is to avoid mismatch + * of guest/host config for the msr hence avoid unexpected + * misbehavior. */ ret = kvm_get_one_msr(cpu, MSR_ARCH_LBR_DEPTH, &depth); - if (ret == 1 && (env->msr_lbr_ctl & 0x1) && !!depth && - depth == env->msr_lbr_depth) { + if (ret == 1 && !!depth && depth == env->msr_lbr_depth) { kvm_msr_entry_add(cpu, MSR_ARCH_LBR_CTL, env->msr_lbr_ctl); kvm_msr_entry_add(cpu, MSR_ARCH_LBR_DEPTH, env->msr_lbr_depth); @@ -3801,13 +3800,11 @@ static int kvm_get_msrs(X86CPU *cpu) if (kvm_enabled() && cpu->enable_pmu && (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR)) { - uint64_t ctl, depth; - int i, ret2; + uint64_t depth; + int i, ret; - ret = kvm_get_one_msr(cpu, MSR_ARCH_LBR_CTL, &ctl); - ret2 = kvm_get_one_msr(cpu, MSR_ARCH_LBR_DEPTH, &depth); - if (ret == 1 && ret2 == 1 && (ctl & 0x1) && - depth == ARCH_LBR_NR_ENTRIES) { + ret = kvm_get_one_msr(cpu, MSR_ARCH_LBR_DEPTH, &depth); + if (ret == 1 && depth == ARCH_LBR_NR_ENTRIES) { kvm_msr_entry_add(cpu, MSR_ARCH_LBR_CTL, 0); kvm_msr_entry_add(cpu, MSR_ARCH_LBR_DEPTH, 0); From f8d426a6852c560fdd8648ae961c8189909a4b82 Mon Sep 17 00:00:00 2001 From: Jaroslav Jindrak Date: Tue, 17 May 2022 14:38:58 +0200 Subject: [PATCH 456/935] hostmem: default the amount of prealloc-threads to smp-cpus Prior to the introduction of the prealloc-threads property, the amount of threads used to preallocate memory was derived from the value of smp-cpus passed to qemu, the amount of physical cpus of the host and a hardcoded maximum value. When the prealloc-threads property was introduced, it included a default of 1 in backends/hostmem.c and a default of smp-cpus using the sugar API for the property itself. The latter default is not used when the property is not specified on qemu's command line, so guests that were not adjusted for this change suddenly started to use the default of 1 thread to preallocate memory, which resulted in observable slowdowns in guest boots for guests with large memory (e.g. when using libvirt <8.2.0 or managing guests manually). This commit restores the original behavior for these cases while not impacting guests started with the prealloc-threads property in any way. Fixes: 220c1fd864e9d ("hostmem: introduce "prealloc-threads" property") Signed-off-by: Jaroslav Jindrak Message-Id: <20220517123858.7933-1-dzejrou@gmail.com> Signed-off-by: Paolo Bonzini --- backends/hostmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/hostmem.c b/backends/hostmem.c index a7bae3d713..624bb7ecd3 100644 --- a/backends/hostmem.c +++ b/backends/hostmem.c @@ -274,7 +274,7 @@ static void host_memory_backend_init(Object *obj) backend->merge = machine_mem_merge(machine); backend->dump = machine_dump_guest_core(machine); backend->reserve = true; - backend->prealloc_threads = 1; + backend->prealloc_threads = machine->smp.cpus; } static void host_memory_backend_post_init(Object *obj) From c3a28d71221d30b1f58bf5efc88add20635ce46d Mon Sep 17 00:00:00 2001 From: Fabrice Fontaine Date: Mon, 23 May 2022 12:52:39 +0200 Subject: [PATCH 457/935] linux-user/syscall.c: fix build without RLIMIT_RTTIME RLIMIT_RTTIME is not provided by uclibc-ng or by musl prior to version 1.2.0 and https://github.com/bminor/musl/commit/2507e7f5312e79620f6337935d0a6c9045ccba09 resulting in the following build failure since https://git.qemu.org/?p=qemu.git;a=commit;h=244fd08323088db73590ff2317dfe86f810b51d7: ../linux-user/syscall.c: In function 'target_to_host_resource': ../linux-user/syscall.c:1057:16: error: 'RLIMIT_RTTIME' undeclared (first use in this function); did you mean 'RLIMIT_NOFILE'? 1057 | return RLIMIT_RTTIME; | ^~~~~~~~~~~~~ | RLIMIT_NOFILE Fixes: - http://autobuild.buildroot.org/results/22d3b584b704613d030e1ea9e6b709b713e4cc26 Signed-off-by: Fabrice Fontaine Reviewed-by: Laurent Vivier Message-Id: <20220523105239.1499162-1-fontaine.fabrice@gmail.com> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index dd0d92ba4e..488facb356 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1053,8 +1053,10 @@ static inline int target_to_host_resource(int code) return RLIMIT_RSS; case TARGET_RLIMIT_RTPRIO: return RLIMIT_RTPRIO; +#ifdef RLIMIT_RTTIME case TARGET_RLIMIT_RTTIME: return RLIMIT_RTTIME; +#endif case TARGET_RLIMIT_SIGPENDING: return RLIMIT_SIGPENDING; case TARGET_RLIMIT_STACK: From 2f6f4290e0f0f3a8ea49a81afebd2d41c327477f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 9 May 2022 22:57:26 +0200 Subject: [PATCH 458/935] linux-user/elfload: Remove pointless non-const CPUArchState cast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fill_thread_info() takes a pointer to const. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20220509205728.51912-2-philippe.mathieu.daude@gmail.com> Signed-off-by: Laurent Vivier --- linux-user/elfload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 8c0765dd4b..acc21748f9 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -3973,7 +3973,7 @@ static int fill_note_info(struct elf_note_info *info, if (cpu == thread_cpu) { continue; } - fill_thread_info(info, (CPUArchState *)cpu->env_ptr); + fill_thread_info(info, cpu->env_ptr); } cpu_list_unlock(); From a0939b89161a756a7f58cab2bec0a2410c5d0b5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 9 May 2022 22:57:27 +0200 Subject: [PATCH 459/935] linux-user: Have do_syscall() use CPUArchState* instead of void* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20220509205728.51912-3-philippe.mathieu.daude@gmail.com> Signed-off-by: Laurent Vivier --- linux-user/strace.c | 202 ++++++++++++++++++------------------ linux-user/strace.h | 4 +- linux-user/syscall.c | 32 +++--- linux-user/uname.c | 2 +- linux-user/uname.h | 2 +- linux-user/user-internals.h | 16 +-- 6 files changed, 129 insertions(+), 129 deletions(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 2cdbf030ba..9fa681dea9 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -22,10 +22,10 @@ struct syscallname { int nr; const char *name; const char *format; - void (*call)(void *, const struct syscallname *, + void (*call)(CPUArchState *, const struct syscallname *, abi_long, abi_long, abi_long, abi_long, abi_long, abi_long); - void (*result)(void *, const struct syscallname *, abi_long, + void (*result)(CPUArchState *, const struct syscallname *, abi_long, abi_long, abi_long, abi_long, abi_long, abi_long, abi_long); }; @@ -593,7 +593,7 @@ print_fdset(int n, abi_ulong target_fds_addr) /* select */ #ifdef TARGET_NR__newselect static void -print_newselect(void *cpu_env, const struct syscallname *name, +print_newselect(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { @@ -611,7 +611,7 @@ print_newselect(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_semctl static void -print_semctl(void *cpu_env, const struct syscallname *name, +print_semctl(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { @@ -623,7 +623,7 @@ print_semctl(void *cpu_env, const struct syscallname *name, #endif static void -print_execve(void *cpu_env, const struct syscallname *name, +print_execve(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { @@ -656,7 +656,7 @@ print_execve(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_ipc static void -print_ipc(void *cpu_env, const struct syscallname *name, +print_ipc(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { @@ -700,7 +700,7 @@ print_syscall_err(abi_long ret) } static void -print_syscall_ret_addr(void *cpu_env, const struct syscallname *name, +print_syscall_ret_addr(CPUArchState *cpu_env, const struct syscallname *name, abi_long ret, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) @@ -721,7 +721,7 @@ print_syscall_ret_raw(struct syscallname *name, abi_long ret) #ifdef TARGET_NR__newselect static void -print_syscall_ret_newselect(void *cpu_env, const struct syscallname *name, +print_syscall_ret_newselect(CPUArchState *cpu_env, const struct syscallname *name, abi_long ret, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) @@ -751,7 +751,7 @@ print_syscall_ret_newselect(void *cpu_env, const struct syscallname *name, #define TARGET_TIME_ERROR 5 /* clock not synchronized */ #ifdef TARGET_NR_adjtimex static void -print_syscall_ret_adjtimex(void *cpu_env, const struct syscallname *name, +print_syscall_ret_adjtimex(CPUArchState *cpu_env, const struct syscallname *name, abi_long ret, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) @@ -786,7 +786,7 @@ print_syscall_ret_adjtimex(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_clock_gettime) || defined(TARGET_NR_clock_getres) static void -print_syscall_ret_clock_gettime(void *cpu_env, const struct syscallname *name, +print_syscall_ret_clock_gettime(CPUArchState *cpu_env, const struct syscallname *name, abi_long ret, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) @@ -805,7 +805,7 @@ print_syscall_ret_clock_gettime(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_gettimeofday static void -print_syscall_ret_gettimeofday(void *cpu_env, const struct syscallname *name, +print_syscall_ret_gettimeofday(CPUArchState *cpu_env, const struct syscallname *name, abi_long ret, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) @@ -824,7 +824,7 @@ print_syscall_ret_gettimeofday(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_getitimer static void -print_syscall_ret_getitimer(void *cpu_env, const struct syscallname *name, +print_syscall_ret_getitimer(CPUArchState *cpu_env, const struct syscallname *name, abi_long ret, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) @@ -843,7 +843,7 @@ print_syscall_ret_getitimer(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_getitimer static void -print_syscall_ret_setitimer(void *cpu_env, const struct syscallname *name, +print_syscall_ret_setitimer(CPUArchState *cpu_env, const struct syscallname *name, abi_long ret, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) @@ -862,7 +862,7 @@ print_syscall_ret_setitimer(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_listxattr) || defined(TARGET_NR_llistxattr) \ || defined(TARGGET_NR_flistxattr) static void -print_syscall_ret_listxattr(void *cpu_env, const struct syscallname *name, +print_syscall_ret_listxattr(CPUArchState *cpu_env, const struct syscallname *name, abi_long ret, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) @@ -894,7 +894,7 @@ print_syscall_ret_listxattr(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_ioctl static void -print_syscall_ret_ioctl(void *cpu_env, const struct syscallname *name, +print_syscall_ret_ioctl(CPUArchState *cpu_env, const struct syscallname *name, abi_long ret, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) @@ -1760,7 +1760,7 @@ print_termios(void *arg) #ifdef TARGET_NR_accept static void -print_accept(void *cpu_env, const struct syscallname *name, +print_accept(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -1774,7 +1774,7 @@ print_accept(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_access static void -print_access(void *cpu_env, const struct syscallname *name, +print_access(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -1787,7 +1787,7 @@ print_access(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_acct static void -print_acct(void *cpu_env, const struct syscallname *name, +print_acct(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -1799,7 +1799,7 @@ print_acct(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_brk static void -print_brk(void *cpu_env, const struct syscallname *name, +print_brk(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -1811,7 +1811,7 @@ print_brk(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_chdir static void -print_chdir(void *cpu_env, const struct syscallname *name, +print_chdir(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -1823,7 +1823,7 @@ print_chdir(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_chroot static void -print_chroot(void *cpu_env, const struct syscallname *name, +print_chroot(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -1835,7 +1835,7 @@ print_chroot(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_chmod static void -print_chmod(void *cpu_env, const struct syscallname *name, +print_chmod(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -1848,7 +1848,7 @@ print_chmod(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_chown) || defined(TARGET_NR_lchown) static void -print_chown(void *cpu_env, const struct syscallname *name, +print_chown(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -1863,7 +1863,7 @@ print_chown(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_clock_adjtime static void -print_clock_adjtime(void *cpu_env, const struct syscallname *name, +print_clock_adjtime(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -1887,7 +1887,7 @@ static void do_print_clone(unsigned int flags, abi_ulong newsp, } static void -print_clone(void *cpu_env, const struct syscallname *name, +print_clone(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { @@ -1907,7 +1907,7 @@ print_clone(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_creat static void -print_creat(void *cpu_env, const struct syscallname *name, +print_creat(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -1920,7 +1920,7 @@ print_creat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_execv static void -print_execv(void *cpu_env, const struct syscallname *name, +print_execv(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -1933,7 +1933,7 @@ print_execv(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_faccessat static void -print_faccessat(void *cpu_env, const struct syscallname *name, +print_faccessat(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -1948,7 +1948,7 @@ print_faccessat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_fallocate static void -print_fallocate(void *cpu_env, const struct syscallname *name, +print_fallocate(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -1968,7 +1968,7 @@ print_fallocate(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_fchmodat static void -print_fchmodat(void *cpu_env, const struct syscallname *name, +print_fchmodat(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -1983,7 +1983,7 @@ print_fchmodat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_fchownat static void -print_fchownat(void *cpu_env, const struct syscallname *name, +print_fchownat(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -1999,7 +1999,7 @@ print_fchownat(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_fcntl) || defined(TARGET_NR_fcntl64) static void -print_fcntl(void *cpu_env, const struct syscallname *name, +print_fcntl(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2135,7 +2135,7 @@ print_fcntl(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_fgetxattr static void -print_fgetxattr(void *cpu_env, const struct syscallname *name, +print_fgetxattr(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2150,7 +2150,7 @@ print_fgetxattr(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_flistxattr static void -print_flistxattr(void *cpu_env, const struct syscallname *name, +print_flistxattr(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2164,7 +2164,7 @@ print_flistxattr(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_getxattr) || defined(TARGET_NR_lgetxattr) static void -print_getxattr(void *cpu_env, const struct syscallname *name, +print_getxattr(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2180,7 +2180,7 @@ print_getxattr(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_listxattr) || defined(TARGET_NR_llistxattr) static void -print_listxattr(void *cpu_env, const struct syscallname *name, +print_listxattr(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2195,7 +2195,7 @@ print_listxattr(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_fremovexattr) static void -print_fremovexattr(void *cpu_env, const struct syscallname *name, +print_fremovexattr(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2208,7 +2208,7 @@ print_fremovexattr(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_removexattr) || defined(TARGET_NR_lremovexattr) static void -print_removexattr(void *cpu_env, const struct syscallname *name, +print_removexattr(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2222,7 +2222,7 @@ print_removexattr(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_futimesat static void -print_futimesat(void *cpu_env, const struct syscallname *name, +print_futimesat(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2237,7 +2237,7 @@ print_futimesat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_gettimeofday static void -print_gettimeofday(void *cpu_env, const struct syscallname *name, +print_gettimeofday(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2250,7 +2250,7 @@ print_gettimeofday(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_settimeofday static void -print_settimeofday(void *cpu_env, const struct syscallname *name, +print_settimeofday(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2263,7 +2263,7 @@ print_settimeofday(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_clock_gettime) || defined(TARGET_NR_clock_getres) static void -print_clock_gettime(void *cpu_env, const struct syscallname *name, +print_clock_gettime(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2277,7 +2277,7 @@ print_clock_gettime(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_clock_settime static void -print_clock_settime(void *cpu_env, const struct syscallname *name, +print_clock_settime(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2290,7 +2290,7 @@ print_clock_settime(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_getitimer static void -print_getitimer(void *cpu_env, const struct syscallname *name, +print_getitimer(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2303,7 +2303,7 @@ print_getitimer(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_setitimer static void -print_setitimer(void *cpu_env, const struct syscallname *name, +print_setitimer(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2317,7 +2317,7 @@ print_setitimer(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_link static void -print_link(void *cpu_env, const struct syscallname *name, +print_link(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2330,7 +2330,7 @@ print_link(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_linkat static void -print_linkat(void *cpu_env, const struct syscallname *name, +print_linkat(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2346,7 +2346,7 @@ print_linkat(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR__llseek) || defined(TARGET_NR_llseek) static void -print__llseek(void *cpu_env, const struct syscallname *name, +print__llseek(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2369,7 +2369,7 @@ print__llseek(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_lseek static void -print_lseek(void *cpu_env, const struct syscallname *name, +print_lseek(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2400,7 +2400,7 @@ print_lseek(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_truncate static void -print_truncate(void *cpu_env, const struct syscallname *name, +print_truncate(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2413,7 +2413,7 @@ print_truncate(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_truncate64 static void -print_truncate64(void *cpu_env, const struct syscallname *name, +print_truncate64(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2430,7 +2430,7 @@ print_truncate64(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_ftruncate64 static void -print_ftruncate64(void *cpu_env, const struct syscallname *name, +print_ftruncate64(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2447,7 +2447,7 @@ print_ftruncate64(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_mlockall static void -print_mlockall(void *cpu_env, const struct syscallname *name, +print_mlockall(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2459,7 +2459,7 @@ print_mlockall(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_socket) static void -print_socket(void *cpu_env, const struct syscallname *name, +print_socket(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2920,7 +2920,7 @@ static struct { }; static void -print_socketcall(void *cpu_env, const struct syscallname *name, +print_socketcall(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2941,7 +2941,7 @@ print_socketcall(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_bind) static void -print_bind(void *cpu_env, const struct syscallname *name, +print_bind(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2955,7 +2955,7 @@ print_bind(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_stat) || defined(TARGET_NR_stat64) || \ defined(TARGET_NR_lstat) || defined(TARGET_NR_lstat64) static void -print_stat(void *cpu_env, const struct syscallname *name, +print_stat(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2971,7 +2971,7 @@ print_stat(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_fstat) || defined(TARGET_NR_fstat64) static void -print_fstat(void *cpu_env, const struct syscallname *name, +print_fstat(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2985,7 +2985,7 @@ print_fstat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_mkdir static void -print_mkdir(void *cpu_env, const struct syscallname *name, +print_mkdir(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -2998,7 +2998,7 @@ print_mkdir(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_mkdirat static void -print_mkdirat(void *cpu_env, const struct syscallname *name, +print_mkdirat(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3012,7 +3012,7 @@ print_mkdirat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_rmdir static void -print_rmdir(void *cpu_env, const struct syscallname *name, +print_rmdir(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3024,7 +3024,7 @@ print_rmdir(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_rt_sigaction static void -print_rt_sigaction(void *cpu_env, const struct syscallname *name, +print_rt_sigaction(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3038,7 +3038,7 @@ print_rt_sigaction(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_rt_sigprocmask static void -print_rt_sigprocmask(void *cpu_env, const struct syscallname *name, +print_rt_sigprocmask(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3058,7 +3058,7 @@ print_rt_sigprocmask(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_rt_sigqueueinfo static void -print_rt_sigqueueinfo(void *cpu_env, const struct syscallname *name, +print_rt_sigqueueinfo(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3083,7 +3083,7 @@ print_rt_sigqueueinfo(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_rt_tgsigqueueinfo static void -print_rt_tgsigqueueinfo(void *cpu_env, const struct syscallname *name, +print_rt_tgsigqueueinfo(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3167,7 +3167,7 @@ print_syslog_action(abi_ulong arg, int last) } static void -print_syslog(void *cpu_env, const struct syscallname *name, +print_syslog(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3181,7 +3181,7 @@ print_syslog(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_mknod static void -print_mknod(void *cpu_env, const struct syscallname *name, +print_mknod(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3200,7 +3200,7 @@ print_mknod(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_mknodat static void -print_mknodat(void *cpu_env, const struct syscallname *name, +print_mknodat(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3220,7 +3220,7 @@ print_mknodat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_mq_open static void -print_mq_open(void *cpu_env, const struct syscallname *name, +print_mq_open(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3239,7 +3239,7 @@ print_mq_open(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_open static void -print_open(void *cpu_env, const struct syscallname *name, +print_open(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3256,7 +3256,7 @@ print_open(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_openat static void -print_openat(void *cpu_env, const struct syscallname *name, +print_openat(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3274,7 +3274,7 @@ print_openat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_mq_unlink static void -print_mq_unlink(void *cpu_env, const struct syscallname *name, +print_mq_unlink(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3286,7 +3286,7 @@ print_mq_unlink(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat) static void -print_fstatat64(void *cpu_env, const struct syscallname *name, +print_fstatat64(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3302,7 +3302,7 @@ print_fstatat64(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_readlink static void -print_readlink(void *cpu_env, const struct syscallname *name, +print_readlink(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3316,7 +3316,7 @@ print_readlink(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_readlinkat static void -print_readlinkat(void *cpu_env, const struct syscallname *name, +print_readlinkat(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3331,7 +3331,7 @@ print_readlinkat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_rename static void -print_rename(void *cpu_env, const struct syscallname *name, +print_rename(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3344,7 +3344,7 @@ print_rename(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_renameat static void -print_renameat(void *cpu_env, const struct syscallname *name, +print_renameat(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3359,7 +3359,7 @@ print_renameat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_statfs static void -print_statfs(void *cpu_env, const struct syscallname *name, +print_statfs(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3372,7 +3372,7 @@ print_statfs(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_statfs64 static void -print_statfs64(void *cpu_env, const struct syscallname *name, +print_statfs64(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3385,7 +3385,7 @@ print_statfs64(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_symlink static void -print_symlink(void *cpu_env, const struct syscallname *name, +print_symlink(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3398,7 +3398,7 @@ print_symlink(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_symlinkat static void -print_symlinkat(void *cpu_env, const struct syscallname *name, +print_symlinkat(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3412,7 +3412,7 @@ print_symlinkat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_mount static void -print_mount(void *cpu_env, const struct syscallname *name, +print_mount(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3428,7 +3428,7 @@ print_mount(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_umount static void -print_umount(void *cpu_env, const struct syscallname *name, +print_umount(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3440,7 +3440,7 @@ print_umount(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_umount2 static void -print_umount2(void *cpu_env, const struct syscallname *name, +print_umount2(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3453,7 +3453,7 @@ print_umount2(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_unlink static void -print_unlink(void *cpu_env, const struct syscallname *name, +print_unlink(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3465,7 +3465,7 @@ print_unlink(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_unlinkat static void -print_unlinkat(void *cpu_env, const struct syscallname *name, +print_unlinkat(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3479,7 +3479,7 @@ print_unlinkat(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_unshare static void -print_unshare(void *cpu_env, const struct syscallname *name, +print_unshare(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3491,7 +3491,7 @@ print_unshare(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_utime static void -print_utime(void *cpu_env, const struct syscallname *name, +print_utime(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3504,7 +3504,7 @@ print_utime(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_utimes static void -print_utimes(void *cpu_env, const struct syscallname *name, +print_utimes(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3517,7 +3517,7 @@ print_utimes(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_utimensat static void -print_utimensat(void *cpu_env, const struct syscallname *name, +print_utimensat(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3532,7 +3532,7 @@ print_utimensat(void *cpu_env, const struct syscallname *name, #if defined(TARGET_NR_mmap) || defined(TARGET_NR_mmap2) static void -print_mmap(void *cpu_env, const struct syscallname *name, +print_mmap(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3550,7 +3550,7 @@ print_mmap(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_mprotect static void -print_mprotect(void *cpu_env, const struct syscallname *name, +print_mprotect(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3564,7 +3564,7 @@ print_mprotect(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_munmap static void -print_munmap(void *cpu_env, const struct syscallname *name, +print_munmap(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3617,7 +3617,7 @@ if( cmd == val ) { \ } static void -print_futex(void *cpu_env, const struct syscallname *name, +print_futex(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3634,7 +3634,7 @@ print_futex(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_kill static void -print_kill(void *cpu_env, const struct syscallname *name, +print_kill(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3647,7 +3647,7 @@ print_kill(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_tkill static void -print_tkill(void *cpu_env, const struct syscallname *name, +print_tkill(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3660,7 +3660,7 @@ print_tkill(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_tgkill static void -print_tgkill(void *cpu_env, const struct syscallname *name, +print_tgkill(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3674,7 +3674,7 @@ print_tgkill(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_statx static void -print_statx(void *cpu_env, const struct syscallname *name, +print_statx(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3690,7 +3690,7 @@ print_statx(void *cpu_env, const struct syscallname *name, #ifdef TARGET_NR_ioctl static void -print_ioctl(void *cpu_env, const struct syscallname *name, +print_ioctl(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { @@ -3775,7 +3775,7 @@ static int nsyscalls = ARRAY_SIZE(scnames); * The public interface to this module. */ void -print_syscall(void *cpu_env, int num, +print_syscall(CPUArchState *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { @@ -3804,7 +3804,7 @@ print_syscall(void *cpu_env, int num, void -print_syscall_ret(void *cpu_env, int num, abi_long ret, +print_syscall_ret(CPUArchState *cpu_env, int num, abi_long ret, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { diff --git a/linux-user/strace.h b/linux-user/strace.h index 1e232d07fc..d5e7f26bcb 100644 --- a/linux-user/strace.h +++ b/linux-user/strace.h @@ -18,10 +18,10 @@ #ifndef LINUX_USER_STRACE_H #define LINUX_USER_STRACE_H -void print_syscall(void *cpu_env, int num, +void print_syscall(CPUArchState *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6); -void print_syscall_ret(void *cpu_env, int num, abi_long ret, +void print_syscall_ret(CPUArchState *cpu_env, int num, abi_long ret, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6); /** diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 488facb356..2395988e66 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1598,7 +1598,7 @@ static abi_long do_pipe2(int host_pipe[], int flags) #endif } -static abi_long do_pipe(void *cpu_env, abi_ulong pipedes, +static abi_long do_pipe(CPUArchState *cpu_env, abi_ulong pipedes, int flags, int is_pipe2) { int host_pipe[2]; @@ -7252,7 +7252,7 @@ void syscall_init(void) } #ifdef TARGET_NR_truncate64 -static inline abi_long target_truncate64(void *cpu_env, const char *arg1, +static inline abi_long target_truncate64(CPUArchState *cpu_env, const char *arg1, abi_long arg2, abi_long arg3, abi_long arg4) @@ -7266,7 +7266,7 @@ static inline abi_long target_truncate64(void *cpu_env, const char *arg1, #endif #ifdef TARGET_NR_ftruncate64 -static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1, +static inline abi_long target_ftruncate64(CPUArchState *cpu_env, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4) @@ -7561,7 +7561,7 @@ static inline int target_to_host_mlockall_arg(int arg) #if (defined(TARGET_NR_stat64) || defined(TARGET_NR_lstat64) || \ defined(TARGET_NR_fstat64) || defined(TARGET_NR_fstatat64) || \ defined(TARGET_NR_newfstatat)) -static inline abi_long host_to_target_stat64(void *cpu_env, +static inline abi_long host_to_target_stat64(CPUArchState *cpu_env, abi_ulong target_addr, struct stat *host_st) { @@ -7963,7 +7963,7 @@ int host_to_target_waitstatus(int status) return status; } -static int open_self_cmdline(void *cpu_env, int fd) +static int open_self_cmdline(CPUArchState *cpu_env, int fd) { CPUState *cpu = env_cpu((CPUArchState *)cpu_env); struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm; @@ -7980,7 +7980,7 @@ static int open_self_cmdline(void *cpu_env, int fd) return 0; } -static int open_self_maps(void *cpu_env, int fd) +static int open_self_maps(CPUArchState *cpu_env, int fd) { CPUState *cpu = env_cpu((CPUArchState *)cpu_env); TaskState *ts = cpu->opaque; @@ -8042,7 +8042,7 @@ static int open_self_maps(void *cpu_env, int fd) return 0; } -static int open_self_stat(void *cpu_env, int fd) +static int open_self_stat(CPUArchState *cpu_env, int fd) { CPUState *cpu = env_cpu((CPUArchState *)cpu_env); TaskState *ts = cpu->opaque; @@ -8080,7 +8080,7 @@ static int open_self_stat(void *cpu_env, int fd) return 0; } -static int open_self_auxv(void *cpu_env, int fd) +static int open_self_auxv(CPUArchState *cpu_env, int fd) { CPUState *cpu = env_cpu((CPUArchState *)cpu_env); TaskState *ts = cpu->opaque; @@ -8143,7 +8143,7 @@ static int is_proc(const char *filename, const char *entry) #endif #if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN -static int open_net_route(void *cpu_env, int fd) +static int open_net_route(CPUArchState *cpu_env, int fd) { FILE *fp; char *line = NULL; @@ -8188,7 +8188,7 @@ static int open_net_route(void *cpu_env, int fd) #endif #if defined(TARGET_SPARC) -static int open_cpuinfo(void *cpu_env, int fd) +static int open_cpuinfo(CPUArchState *cpu_env, int fd) { dprintf(fd, "type\t\t: sun4u\n"); return 0; @@ -8196,7 +8196,7 @@ static int open_cpuinfo(void *cpu_env, int fd) #endif #if defined(TARGET_HPPA) -static int open_cpuinfo(void *cpu_env, int fd) +static int open_cpuinfo(CPUArchState *cpu_env, int fd) { dprintf(fd, "cpu family\t: PA-RISC 1.1e\n"); dprintf(fd, "cpu\t\t: PA7300LC (PCX-L2)\n"); @@ -8208,18 +8208,18 @@ static int open_cpuinfo(void *cpu_env, int fd) #endif #if defined(TARGET_M68K) -static int open_hardware(void *cpu_env, int fd) +static int open_hardware(CPUArchState *cpu_env, int fd) { dprintf(fd, "Model:\t\tqemu-m68k\n"); return 0; } #endif -static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode) +static int do_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode) { struct fake_open { const char *filename; - int (*fill)(void *cpu_env, int fd); + int (*fill)(CPUArchState *cpu_env, int fd); int (*cmp)(const char *s1, const char *s2); }; const struct fake_open *fake_open; @@ -8531,7 +8531,7 @@ _syscall2(int, pivot_root, const char *, new_root, const char *, put_old) * of syscall results, can be performed. * All errnos that do_syscall() returns must be -TARGET_. */ -static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, +static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, abi_long arg7, abi_long arg8) @@ -13155,7 +13155,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, return ret; } -abi_long do_syscall(void *cpu_env, int num, abi_long arg1, +abi_long do_syscall(CPUArchState *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, abi_long arg7, abi_long arg8) diff --git a/linux-user/uname.c b/linux-user/uname.c index 415fdf31b6..1e3e98156d 100644 --- a/linux-user/uname.c +++ b/linux-user/uname.c @@ -28,7 +28,7 @@ * NB: the default emulated CPU ("any") might not match any existing CPU, e.g. * on ARM it has all features turned on, so there is no perfect arch string to * return here */ -const char *cpu_to_uname_machine(void *cpu_env) +const char *cpu_to_uname_machine(CPUArchState *cpu_env) { #if defined(TARGET_ARM) && !defined(TARGET_AARCH64) diff --git a/linux-user/uname.h b/linux-user/uname.h index 4503094211..4ae563f46c 100644 --- a/linux-user/uname.h +++ b/linux-user/uname.h @@ -4,7 +4,7 @@ #include #include -const char *cpu_to_uname_machine(void *cpu_env); +const char *cpu_to_uname_machine(CPUArchState *cpu_env); int sys_uname(struct new_utsname *buf); #endif /* UNAME_H */ diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h index ddc260e465..0bb26331c1 100644 --- a/linux-user/user-internals.h +++ b/linux-user/user-internals.h @@ -59,7 +59,7 @@ int info_is_fdpic(struct image_info *info); void target_set_brk(abi_ulong new_brk); void syscall_init(void); -abi_long do_syscall(void *cpu_env, int num, abi_long arg1, +abi_long do_syscall(CPUArchState *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, abi_long arg7, abi_long arg8); @@ -132,22 +132,22 @@ void print_termios(void *arg); /* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */ #ifdef TARGET_ARM -static inline int regpairs_aligned(void *cpu_env, int num) +static inline int regpairs_aligned(CPUArchState *cpu_env, int num) { return ((((CPUARMState *)cpu_env)->eabi) == 1) ; } #elif defined(TARGET_MIPS) && defined(TARGET_ABI_MIPSO32) -static inline int regpairs_aligned(void *cpu_env, int num) { return 1; } +static inline int regpairs_aligned(CPUArchState *cpu_env, int num) { return 1; } #elif defined(TARGET_PPC) && !defined(TARGET_PPC64) /* * SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs * of registers which translates to the same as ARM/MIPS, because we start with * r3 as arg1 */ -static inline int regpairs_aligned(void *cpu_env, int num) { return 1; } +static inline int regpairs_aligned(CPUArchState *cpu_env, int num) { return 1; } #elif defined(TARGET_SH4) /* SH4 doesn't align register pairs, except for p{read,write}64 */ -static inline int regpairs_aligned(void *cpu_env, int num) +static inline int regpairs_aligned(CPUArchState *cpu_env, int num) { switch (num) { case TARGET_NR_pread64: @@ -159,11 +159,11 @@ static inline int regpairs_aligned(void *cpu_env, int num) } } #elif defined(TARGET_XTENSA) -static inline int regpairs_aligned(void *cpu_env, int num) { return 1; } +static inline int regpairs_aligned(CPUArchState *cpu_env, int num) { return 1; } #elif defined(TARGET_HEXAGON) -static inline int regpairs_aligned(void *cpu_env, int num) { return 1; } +static inline int regpairs_aligned(CPUArchState *cpu_env, int num) { return 1; } #else -static inline int regpairs_aligned(void *cpu_env, int num) { return 0; } +static inline int regpairs_aligned(CPUArchState *cpu_env, int num) { return 0; } #endif /** From 0effdc29b53240b1b2f25e48a61a287558e8ad6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 9 May 2022 22:57:28 +0200 Subject: [PATCH 460/935] linux-user: Remove pointless CPU{ARCH}State casts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20220509205728.51912-4-philippe.mathieu.daude@gmail.com> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 49 +++++++++++++++++-------------------- linux-user/uname.c | 2 +- linux-user/user-internals.h | 2 +- 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 2395988e66..f55cdebee5 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1612,16 +1612,16 @@ static abi_long do_pipe(CPUArchState *cpu_env, abi_ulong pipedes, pipe syscall, but didn't replicate this into the pipe2 syscall. */ if (!is_pipe2) { #if defined(TARGET_ALPHA) - ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1]; + cpu_env->ir[IR_A4] = host_pipe[1]; return host_pipe[0]; #elif defined(TARGET_MIPS) - ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1]; + cpu_env->active_tc.gpr[3] = host_pipe[1]; return host_pipe[0]; #elif defined(TARGET_SH4) - ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1]; + cpu_env->gregs[1] = host_pipe[1]; return host_pipe[0]; #elif defined(TARGET_SPARC) - ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1]; + cpu_env->regwptr[1] = host_pipe[1]; return host_pipe[0]; #endif } @@ -7566,7 +7566,7 @@ static inline abi_long host_to_target_stat64(CPUArchState *cpu_env, struct stat *host_st) { #if defined(TARGET_ARM) && defined(TARGET_ABI32) - if (((CPUARMState *)cpu_env)->eabi) { + if (cpu_env->eabi) { struct target_eabi_stat64 *target_st; if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) @@ -7965,7 +7965,7 @@ int host_to_target_waitstatus(int status) static int open_self_cmdline(CPUArchState *cpu_env, int fd) { - CPUState *cpu = env_cpu((CPUArchState *)cpu_env); + CPUState *cpu = env_cpu(cpu_env); struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm; int i; @@ -7982,7 +7982,7 @@ static int open_self_cmdline(CPUArchState *cpu_env, int fd) static int open_self_maps(CPUArchState *cpu_env, int fd) { - CPUState *cpu = env_cpu((CPUArchState *)cpu_env); + CPUState *cpu = env_cpu(cpu_env); TaskState *ts = cpu->opaque; GSList *map_info = read_self_maps(); GSList *s; @@ -8044,7 +8044,7 @@ static int open_self_maps(CPUArchState *cpu_env, int fd) static int open_self_stat(CPUArchState *cpu_env, int fd) { - CPUState *cpu = env_cpu((CPUArchState *)cpu_env); + CPUState *cpu = env_cpu(cpu_env); TaskState *ts = cpu->opaque; g_autoptr(GString) buf = g_string_new(NULL); int i; @@ -8082,7 +8082,7 @@ static int open_self_stat(CPUArchState *cpu_env, int fd) static int open_self_auxv(CPUArchState *cpu_env, int fd) { - CPUState *cpu = env_cpu((CPUArchState *)cpu_env); + CPUState *cpu = env_cpu(cpu_env); TaskState *ts = cpu->opaque; abi_ulong auxv = ts->info->saved_auxv; abi_ulong len = ts->info->auxv_len; @@ -8892,7 +8892,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA) /* Alpha specific */ case TARGET_NR_getxpid: - ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid(); + cpu_env->ir[IR_A4] = getppid(); return get_errno(getpid()); #endif #ifdef TARGET_NR_getpid @@ -9415,7 +9415,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, if (!is_error(ret)) { host_to_target_old_sigset(&mask, &oldset); ret = mask; - ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */ + cpu_env->ir[IR_V0] = 0; /* force no error */ } #else sigset_t set, oldset, *set_ptr; @@ -10035,7 +10035,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, } #ifdef TARGET_ALPHA /* Return value is the unbiased priority. Signal no error. */ - ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; + cpu_env->ir[IR_V0] = 0; #else /* Return value is a biased priority to avoid negative numbers. */ ret = 20 - ret; @@ -11415,7 +11415,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, { uid_t euid; euid=geteuid(); - ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid; + cpu_env->ir[IR_A4]=euid; } return get_errno(getuid()); #endif @@ -11425,7 +11425,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, { uid_t egid; egid=getegid(); - ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid; + cpu_env->ir[IR_A4]=egid; } return get_errno(getgid()); #endif @@ -11437,7 +11437,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, case TARGET_GSI_IEEE_FP_CONTROL: { uint64_t fpcr = cpu_alpha_load_fpcr(cpu_env); - uint64_t swcr = ((CPUAlphaState *)cpu_env)->swcr; + uint64_t swcr = cpu_env->swcr; swcr &= ~SWCR_STATUS_MASK; swcr |= (fpcr >> 35) & SWCR_STATUS_MASK; @@ -11479,8 +11479,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, * could be queried. Therefore, we store the status * bits only in FPCR. */ - ((CPUAlphaState *)cpu_env)->swcr - = swcr & (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK); + cpu_env->swcr = swcr & (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK); fpcr = cpu_alpha_load_fpcr(cpu_env); fpcr &= ((uint64_t)FPCR_DYN_MASK << 32); @@ -11504,7 +11503,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, fex = alpha_ieee_fpcr_to_swcr(fpcr); fex = exc & ~fex; fex >>= SWCR_STATUS_TO_EXCSUM_SHIFT; - fex &= ((CPUArchState *)cpu_env)->swcr; + fex &= (cpu_env)->swcr; /* Update the hardware fpcr. */ fpcr |= alpha_ieee_swcr_to_fpcr(exc); @@ -11536,9 +11535,8 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, info.si_signo = SIGFPE; info.si_errno = 0; info.si_code = si_code; - info._sifields._sigfault._addr - = ((CPUArchState *)cpu_env)->pc; - queue_signal((CPUArchState *)cpu_env, info.si_signo, + info._sifields._sigfault._addr = (cpu_env)->pc; + queue_signal(cpu_env, info.si_signo, QEMU_SI_FAULT, &info); } ret = 0; @@ -11824,7 +11822,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, to_flock64_fn *copyto = copy_to_user_flock64; #ifdef TARGET_ARM - if (!((CPUARMState *)cpu_env)->eabi) { + if (!cpu_env->eabi) { copyfrom = copy_from_user_oabi_flock64; copyto = copy_to_user_oabi_flock64; } @@ -12052,13 +12050,13 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_set_thread_area case TARGET_NR_set_thread_area: #if defined(TARGET_MIPS) - ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1; + cpu_env->active_tc.CP0_UserLocal = arg1; return 0; #elif defined(TARGET_CRIS) if (arg1 & 0xff) ret = -TARGET_EINVAL; else { - ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1; + cpu_env->pregs[PR_PID] = arg1; ret = 0; } return ret; @@ -12785,8 +12783,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = arg6; - queue_signal((CPUArchState *)cpu_env, info.si_signo, - QEMU_SI_FAULT, &info); + queue_signal(cpu_env, info.si_signo, QEMU_SI_FAULT, &info); ret = 0xdeadbeef; } diff --git a/linux-user/uname.c b/linux-user/uname.c index 1e3e98156d..32f71f2492 100644 --- a/linux-user/uname.c +++ b/linux-user/uname.c @@ -54,7 +54,7 @@ const char *cpu_to_uname_machine(CPUArchState *cpu_env) return "armv5te" utsname_suffix; #elif defined(TARGET_I386) && !defined(TARGET_X86_64) /* see arch/x86/kernel/cpu/bugs.c: check_bugs(), 386, 486, 586, 686 */ - CPUState *cpu = env_cpu((CPUX86State *)cpu_env); + CPUState *cpu = env_cpu(cpu_env); int family = object_property_get_int(OBJECT(cpu), "family", NULL); if (family == 4) { return "i486"; diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h index 0bb26331c1..6175ce53db 100644 --- a/linux-user/user-internals.h +++ b/linux-user/user-internals.h @@ -134,7 +134,7 @@ void print_termios(void *arg); #ifdef TARGET_ARM static inline int regpairs_aligned(CPUArchState *cpu_env, int num) { - return ((((CPUARMState *)cpu_env)->eabi) == 1) ; + return cpu_env->eabi == 1; } #elif defined(TARGET_MIPS) && defined(TARGET_ABI_MIPSO32) static inline int regpairs_aligned(CPUArchState *cpu_env, int num) { return 1; } From 9a12adc704f977b31d6cde6cb26e5424c128907b Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Wed, 4 May 2022 00:51:56 +0200 Subject: [PATCH 461/935] linux-user/s390x: Fix unwinding from signal handlers Commit 31330e6cecfd ("linux-user/s390x: Implement setup_sigtramp") removed an unused field from rt_sigframe, disturbing offsets of other fields and breaking unwinding from signal handlers (e.g. libgcc's s390_fallback_frame() relies on this struct having a specific layout). Restore the field and add a comment. Reported-by: Ulrich Weigand Signed-off-by: Ilya Leoshkevich Fixes: 31330e6cecfd ("linux-user/s390x: Implement setup_sigtramp") Reviewed-by: David Hildenbrand Reviewed-by: Richard Henderson Message-Id: <20220503225157.1696774-2-iii@linux.ibm.com> Signed-off-by: Laurent Vivier --- linux-user/s390x/signal.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index f47713e04a..4979c4b017 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -84,6 +84,11 @@ struct target_ucontext { typedef struct { uint8_t callee_used_stack[__SIGNAL_FRAMESIZE]; + /* + * This field is no longer initialized by the kernel, but it's still a part + * of the ABI. + */ + uint16_t svc_insn; struct target_siginfo info; struct target_ucontext uc; } rt_sigframe; From 1a75b14038bd77b0af7d2ddb0cf230b31f75623e Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Wed, 4 May 2022 00:51:57 +0200 Subject: [PATCH 462/935] tests/tcg/s390x: Test unwinding from signal handlers Add a small test to prevent regressions. Signed-off-by: Ilya Leoshkevich Message-Id: <20220503225157.1696774-3-iii@linux.ibm.com> Signed-off-by: Laurent Vivier --- tests/tcg/s390x/signals-s390x.c | 69 ++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 14 deletions(-) diff --git a/tests/tcg/s390x/signals-s390x.c b/tests/tcg/s390x/signals-s390x.c index dc2f8ee59a..48c3b6cdfd 100644 --- a/tests/tcg/s390x/signals-s390x.c +++ b/tests/tcg/s390x/signals-s390x.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -11,22 +12,28 @@ * inline asm is used instead. */ +#define DEFINE_ASM_FUNCTION(name, body) \ + asm(".globl " #name "\n" \ + #name ":\n" \ + ".cfi_startproc\n" \ + body "\n" \ + "br %r14\n" \ + ".cfi_endproc"); + void illegal_op(void); -void after_illegal_op(void); -asm(".globl\tillegal_op\n" - "illegal_op:\t.byte\t0x00,0x00\n" - "\t.globl\tafter_illegal_op\n" - "after_illegal_op:\tbr\t%r14"); +extern const char after_illegal_op; +DEFINE_ASM_FUNCTION(illegal_op, + ".byte 0x00,0x00\n" + ".globl after_illegal_op\n" + "after_illegal_op:") void stg(void *dst, unsigned long src); -asm(".globl\tstg\n" - "stg:\tstg\t%r3,0(%r2)\n" - "\tbr\t%r14"); +DEFINE_ASM_FUNCTION(stg, "stg %r3,0(%r2)") void mvc_8(void *dst, void *src); -asm(".globl\tmvc_8\n" - "mvc_8:\tmvc\t0(8,%r2),0(%r3)\n" - "\tbr\t%r14"); +DEFINE_ASM_FUNCTION(mvc_8, "mvc 0(8,%r2),0(%r3)") + +extern const char return_from_main_1; static void safe_puts(const char *s) { @@ -49,8 +56,9 @@ static struct { static void handle_signal(int sig, siginfo_t *info, void *ucontext) { + int err, i, n_frames; + void *frames[16]; void *page; - int err; if (sig != expected.sig) { safe_puts("[ FAILED ] wrong signal"); @@ -86,6 +94,17 @@ static void handle_signal(int sig, siginfo_t *info, void *ucontext) default: break; } + + n_frames = backtrace(frames, sizeof(frames) / sizeof(frames[0])); + for (i = 0; i < n_frames; i++) { + if (frames[i] == &return_from_main_1) { + break; + } + } + if (i == n_frames) { + safe_puts("[ FAILED ] backtrace() is broken"); + _exit(1); + } } static void check_sigsegv(void *func, enum exception exception, @@ -122,7 +141,7 @@ static void check_sigsegv(void *func, enum exception exception, assert(err == 0); } -int main(void) +int main_1(void) { struct sigaction act; int err; @@ -138,7 +157,7 @@ int main(void) safe_puts("[ RUN ] Operation exception"); expected.sig = SIGILL; expected.addr = illegal_op; - expected.psw_addr = (unsigned long)after_illegal_op; + expected.psw_addr = (unsigned long)&after_illegal_op; expected.exception = exception_operation; illegal_op(); safe_puts("[ OK ]"); @@ -163,3 +182,25 @@ int main(void) _exit(0); } + +/* + * Define main() in assembly in order to test that unwinding from signal + * handlers until main() works. This way we can define a specific point that + * the unwinder should reach. This is also better than defining main() in C + * and using inline assembly to call main_1(), since it's not easy to get all + * the clobbers right. + */ + +DEFINE_ASM_FUNCTION(main, + "stmg %r14,%r15,112(%r15)\n" + ".cfi_offset 14,-48\n" + ".cfi_offset 15,-40\n" + "lay %r15,-160(%r15)\n" + ".cfi_def_cfa_offset 320\n" + "brasl %r14,main_1\n" + ".globl return_from_main_1\n" + "return_from_main_1:\n" + "lmg %r14,%r15,272(%r15)\n" + ".cfi_restore 15\n" + ".cfi_restore 14\n" + ".cfi_def_cfa_offset 160"); From 565a84c1e61acb6e2bce03e5ca88b5ce400231ca Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Wed, 4 May 2022 13:48:19 +0200 Subject: [PATCH 463/935] linux-user/host/s390: Treat EX and EXRL as writes clang-built s390x branch-relative-long test fails on clang-built s390x QEMU due to the following sequence of events: - The test zeroes out a code page, clang generates exrl+xc for this. - do_helper_xc() is called. Clang generates exrl+xc there as well. - Since there already exists a TB for the code in question, its page is read-only and SIGSEGV is raised. - host_signal_handler() calls host_signal_write() and the latter does not recognize exrl as a write. Therefore page_unprotect() is not called and the signal is forwarded to the test. Fix by treating EXRL (and EX, just in case) as writes. There may be false positives, but they will lead only to an extra page_unprotect() call. Reported-by: Thomas Huth Signed-off-by: Ilya Leoshkevich Tested-by: Thomas Huth Reviewed-by: Richard Henderson Message-Id: <20220504114819.1729737-1-iii@linux.ibm.com> Signed-off-by: Laurent Vivier --- linux-user/include/host/s390/host-signal.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/linux-user/include/host/s390/host-signal.h b/linux-user/include/host/s390/host-signal.h index 6f191e64d7..25fefa00bd 100644 --- a/linux-user/include/host/s390/host-signal.h +++ b/linux-user/include/host/s390/host-signal.h @@ -50,6 +50,7 @@ static inline bool host_signal_write(siginfo_t *info, host_sigcontext *uc) case 0x50: /* ST */ case 0x42: /* STC */ case 0x40: /* STH */ + case 0x44: /* EX */ case 0xba: /* CS */ case 0xbb: /* CDS */ return true; @@ -61,6 +62,12 @@ static inline bool host_signal_write(siginfo_t *info, host_sigcontext *uc) return true; } break; + case 0xc6: /* RIL-b format insns */ + switch (pinsn[0] & 0xf) { + case 0x0: /* EXRL */ + return true; + } + break; case 0xc8: /* SSF format insns */ switch (pinsn[0] & 0xf) { case 0x2: /* CSST */ From d6cd3ae0ebdfab9922f932dc303e1faa618ea547 Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Fri, 6 May 2022 16:54:57 +0000 Subject: [PATCH 464/935] target/riscv: Fix VS mode hypervisor CSR access VS mode access to hypervisor CSRs should generate virtual, not illegal, instruction exceptions. Don't return early and indicate an illegal instruction exception when accessing a hypervisor CSR from VS mode. Instead, fall through to the `hmode` predicate to return the correct virtual instruction exception. Signed-off-by: Dylan Reid Reviewed-by: Alistair Francis Message-Id: <20220506165456.297058-1-dgreid@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/csr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 3500e07f92..4ea7df02c9 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -3141,13 +3141,13 @@ static inline RISCVException riscv_csrrw_check(CPURISCVState *env, #if !defined(CONFIG_USER_ONLY) int effective_priv = env->priv; - if (riscv_has_ext(env, RVH) && - env->priv == PRV_S && - !riscv_cpu_virt_enabled(env)) { + if (riscv_has_ext(env, RVH) && env->priv == PRV_S) { /* - * We are in S mode without virtualisation, therefore we are in HS Mode. + * We are in either HS or VS mode. * Add 1 to the effective privledge level to allow us to access the - * Hypervisor CSRs. + * Hypervisor CSRs. The `hmode` predicate will determine if access + * should be allowed(HS) or if a virtual instruction exception should be + * raised(VS). */ effective_priv++; } From 02b511985e33d71859943682860f629ead5bd20a Mon Sep 17 00:00:00 2001 From: eopXD Date: Thu, 5 May 2022 02:42:17 -0700 Subject: [PATCH 465/935] target/riscv: rvv: Fix early exit condition for whole register load/store Vector whole register load instructions have EEW encoded in the opcode, so we shouldn't take SEW here. Vector whole register store instructions are always EEW=8. Signed-off-by: eop Chen Reviewed-by: Frank Chang Acked-by: Alistair Francis Message-Id: <165181414065.18540.14828125053334599921-0@git.sr.ht> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.c.inc | 56 +++++++++++++------------ 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 90327509f7..391c61fe93 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -1118,10 +1118,10 @@ GEN_VEXT_TRANS(vle64ff_v, MO_64, r2nfvm, ldff_op, ld_us_check) typedef void gen_helper_ldst_whole(TCGv_ptr, TCGv, TCGv_env, TCGv_i32); static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf, - gen_helper_ldst_whole *fn, DisasContext *s, - bool is_store) + uint32_t width, gen_helper_ldst_whole *fn, + DisasContext *s, bool is_store) { - uint32_t evl = (s->cfg_ptr->vlen / 8) * nf / (1 << s->sew); + uint32_t evl = (s->cfg_ptr->vlen / 8) * nf / width; TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_GEU, cpu_vstart, evl, over); @@ -1153,38 +1153,42 @@ static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf, * load and store whole register instructions ignore vtype and vl setting. * Thus, we don't need to check vill bit. (Section 7.9) */ -#define GEN_LDST_WHOLE_TRANS(NAME, ARG_NF, IS_STORE) \ +#define GEN_LDST_WHOLE_TRANS(NAME, ARG_NF, WIDTH, IS_STORE) \ static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ { \ if (require_rvv(s) && \ QEMU_IS_ALIGNED(a->rd, ARG_NF)) { \ - return ldst_whole_trans(a->rd, a->rs1, ARG_NF, gen_helper_##NAME, \ - s, IS_STORE); \ + return ldst_whole_trans(a->rd, a->rs1, ARG_NF, WIDTH, \ + gen_helper_##NAME, s, IS_STORE); \ } \ return false; \ } -GEN_LDST_WHOLE_TRANS(vl1re8_v, 1, false) -GEN_LDST_WHOLE_TRANS(vl1re16_v, 1, false) -GEN_LDST_WHOLE_TRANS(vl1re32_v, 1, false) -GEN_LDST_WHOLE_TRANS(vl1re64_v, 1, false) -GEN_LDST_WHOLE_TRANS(vl2re8_v, 2, false) -GEN_LDST_WHOLE_TRANS(vl2re16_v, 2, false) -GEN_LDST_WHOLE_TRANS(vl2re32_v, 2, false) -GEN_LDST_WHOLE_TRANS(vl2re64_v, 2, false) -GEN_LDST_WHOLE_TRANS(vl4re8_v, 4, false) -GEN_LDST_WHOLE_TRANS(vl4re16_v, 4, false) -GEN_LDST_WHOLE_TRANS(vl4re32_v, 4, false) -GEN_LDST_WHOLE_TRANS(vl4re64_v, 4, false) -GEN_LDST_WHOLE_TRANS(vl8re8_v, 8, false) -GEN_LDST_WHOLE_TRANS(vl8re16_v, 8, false) -GEN_LDST_WHOLE_TRANS(vl8re32_v, 8, false) -GEN_LDST_WHOLE_TRANS(vl8re64_v, 8, false) +GEN_LDST_WHOLE_TRANS(vl1re8_v, 1, 1, false) +GEN_LDST_WHOLE_TRANS(vl1re16_v, 1, 2, false) +GEN_LDST_WHOLE_TRANS(vl1re32_v, 1, 4, false) +GEN_LDST_WHOLE_TRANS(vl1re64_v, 1, 8, false) +GEN_LDST_WHOLE_TRANS(vl2re8_v, 2, 1, false) +GEN_LDST_WHOLE_TRANS(vl2re16_v, 2, 2, false) +GEN_LDST_WHOLE_TRANS(vl2re32_v, 2, 4, false) +GEN_LDST_WHOLE_TRANS(vl2re64_v, 2, 8, false) +GEN_LDST_WHOLE_TRANS(vl4re8_v, 4, 1, false) +GEN_LDST_WHOLE_TRANS(vl4re16_v, 4, 2, false) +GEN_LDST_WHOLE_TRANS(vl4re32_v, 4, 4, false) +GEN_LDST_WHOLE_TRANS(vl4re64_v, 4, 8, false) +GEN_LDST_WHOLE_TRANS(vl8re8_v, 8, 1, false) +GEN_LDST_WHOLE_TRANS(vl8re16_v, 8, 2, false) +GEN_LDST_WHOLE_TRANS(vl8re32_v, 8, 4, false) +GEN_LDST_WHOLE_TRANS(vl8re64_v, 8, 8, false) -GEN_LDST_WHOLE_TRANS(vs1r_v, 1, true) -GEN_LDST_WHOLE_TRANS(vs2r_v, 2, true) -GEN_LDST_WHOLE_TRANS(vs4r_v, 4, true) -GEN_LDST_WHOLE_TRANS(vs8r_v, 8, true) +/* + * The vector whole register store instructions are encoded similar to + * unmasked unit-stride store of elements with EEW=8. + */ +GEN_LDST_WHOLE_TRANS(vs1r_v, 1, 1, true) +GEN_LDST_WHOLE_TRANS(vs2r_v, 2, 1, true) +GEN_LDST_WHOLE_TRANS(vs4r_v, 4, 1, true) +GEN_LDST_WHOLE_TRANS(vs8r_v, 8, 1, true) /* *** Vector Integer Arithmetic Instructions From 77046729f943ce2055648e8339ddd688dd67dd83 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Fri, 13 May 2022 15:14:58 -0700 Subject: [PATCH 466/935] hw/intc: Pass correct hartid while updating mtimecmp timecmp update function should be invoked with hartid for which timecmp is being updated. The following patch passes the incorrect hartid to the update function. Fixes: e2f01f3c2e13 ("hw/intc: Make RISC-V ACLINT mtime MMIO register writable") Signed-off-by: Atish Patra Reviewed-by: Frank Chang Reviewed-by: Anup Patel Reviewed-by: Alistair Francis Message-Id: <20220513221458.1192933-1-atishp@rivosinc.com> Signed-off-by: Alistair Francis --- hw/intc/riscv_aclint.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c index 0412edc982..e6bceceefd 100644 --- a/hw/intc/riscv_aclint.c +++ b/hw/intc/riscv_aclint.c @@ -233,7 +233,8 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr, continue; } riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), - i, env->timecmp); + mtimer->hartid_base + i, + env->timecmp); } return; } From 6047dcc2459fc6d1c49c4aa02e2e902dd3113856 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Tue, 10 May 2022 20:29:07 +0900 Subject: [PATCH 467/935] target/riscv: Move Zhinx* extensions on ISA string This commit moves ISA string conversion for Zhinx and Zhinxmin extensions. Because extension category ordering of "H" is going to be after "V", their ordering is going to be valid (on canonical order). Signed-off-by: Tsukasa OI Acked-by: Alistair Francis Message-Id: <7a988aedb249b6709f9ce5464ff359b60958ca54.1652181972.git.research_trasio@irq.a4lg.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index ccacdee215..9f38e56316 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -999,8 +999,6 @@ static void riscv_isa_string_ext(RISCVCPU *cpu, char **isa_str, int max_str_len) ISA_EDATA_ENTRY(zfh, ext_zfh), ISA_EDATA_ENTRY(zfhmin, ext_zfhmin), ISA_EDATA_ENTRY(zfinx, ext_zfinx), - ISA_EDATA_ENTRY(zhinx, ext_zhinx), - ISA_EDATA_ENTRY(zhinxmin, ext_zhinxmin), ISA_EDATA_ENTRY(zdinx, ext_zdinx), ISA_EDATA_ENTRY(zba, ext_zba), ISA_EDATA_ENTRY(zbb, ext_zbb), @@ -1021,6 +1019,8 @@ static void riscv_isa_string_ext(RISCVCPU *cpu, char **isa_str, int max_str_len) ISA_EDATA_ENTRY(zkt, ext_zkt), ISA_EDATA_ENTRY(zve32f, ext_zve32f), ISA_EDATA_ENTRY(zve64f, ext_zve64f), + ISA_EDATA_ENTRY(zhinx, ext_zhinx), + ISA_EDATA_ENTRY(zhinxmin, ext_zhinxmin), ISA_EDATA_ENTRY(svinval, ext_svinval), ISA_EDATA_ENTRY(svnapot, ext_svnapot), ISA_EDATA_ENTRY(svpbmt, ext_svpbmt), From a4a9a4432e2bf280a989ca344466d7375db7993f Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Tue, 10 May 2022 20:29:08 +0900 Subject: [PATCH 468/935] target/riscv: Add short-isa-string option Because some operating systems don't correctly parse long ISA extension string, this commit adds short-isa-string boolean option to disable generating long ISA extension strings on Device Tree. For instance, enabling Zfinx and Zdinx extensions and booting Linux (5.17 or earlier) with FPU support caused a kernel panic. Operating Systems which short-isa-string might be helpful: 1. Linux (5.17 or earlier) 2. FreeBSD (at least 14.0-CURRENT) 3. OpenBSD (at least current development version) Signed-off-by: Tsukasa OI Acked-by: Alistair Francis Message-Id: <7c1fe5f06b0a7646a47e9bcdddb1042bb60c69c8.1652181972.git.research_trasio@irq.a4lg.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 6 +++++- target/riscv/cpu.h | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 9f38e56316..dc93412395 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -879,6 +879,8 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_BOOL("x-aia", RISCVCPU, cfg.aia, false), DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC), + + DEFINE_PROP_BOOL("short-isa-string", RISCVCPU, cfg.short_isa_string, false), DEFINE_PROP_END_OF_LIST(), }; @@ -1049,7 +1051,9 @@ char *riscv_isa_string(RISCVCPU *cpu) } } *p = '\0'; - riscv_isa_string_ext(cpu, &isa_str, maxlen); + if (!cpu->cfg.short_isa_string) { + riscv_isa_string_ext(cpu, &isa_str, maxlen); + } return isa_str; } diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index fe6c9a2c92..f5ff7294c6 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -425,6 +425,8 @@ struct RISCVCPUConfig { bool aia; bool debug; uint64_t resetvec; + + bool short_isa_string; }; typedef struct RISCVCPUConfig RISCVCPUConfig; From 4bcfc391ac627155448951b45a8432eab91c2db9 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sat, 14 May 2022 15:29:40 +0900 Subject: [PATCH 469/935] hw/riscv: Make CPU config error handling generous (virt/spike) If specified CPU configuration is not valid, not just it prints error message, it aborts and generates core dumps (depends on the operating system). This kind of error handling should be used only when a serious runtime error occurs. This commit makes error handling on CPU configuration more generous on virt/spike machines. It now just prints error message and quits (without coredumps and aborts). Signed-off-by: Tsukasa OI Reviewed-by: Alistair Francis Message-Id: Signed-off-by: Alistair Francis --- hw/riscv/spike.c | 2 +- hw/riscv/virt.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 068ba3493e..e41b6aa9f0 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -230,7 +230,7 @@ static void spike_board_init(MachineState *machine) base_hartid, &error_abort); object_property_set_int(OBJECT(&s->soc[i]), "num-harts", hart_count, &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_fatal); /* Core Local Interruptor (timer and IPI) for each socket */ riscv_aclint_swi_create( diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 3326f4db96..244d6408b5 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1351,7 +1351,7 @@ static void virt_machine_init(MachineState *machine) base_hartid, &error_abort); object_property_set_int(OBJECT(&s->soc[i]), "num-harts", hart_count, &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_fatal); if (!kvm_enabled()) { if (s->have_aclint) { From 91a3387dc42b261e95eb402bf7d043b3a043209c Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sat, 14 May 2022 15:29:41 +0900 Subject: [PATCH 470/935] hw/riscv: Make CPU config error handling generous (sifive_e/u/opentitan) If specified CPU configuration is not valid, not just it prints error message, it aborts and generates core dumps (depends on the operating system). This kind of error handling should be used only when a serious runtime error occurs. This commit makes error handling on CPU configuration more generous on sifive_e/u and opentitan machines. It now just prints error message and quits (without coredumps and aborts). This is separate from spike/virt because it involves different type (TYPE_RISCV_HART_ARRAY) on sifive_e/u and opentitan machines. Signed-off-by: Tsukasa OI Reviewed-by: Alistair Francis Message-Id: <09e61e58a7543da44bdb0e0f5368afc8903b4aa6.1652509778.git.research_trasio@irq.a4lg.com> Signed-off-by: Alistair Francis --- hw/riscv/opentitan.c | 2 +- hw/riscv/sifive_e.c | 2 +- hw/riscv/sifive_u.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 2d401dcb23..4495a2c039 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -142,7 +142,7 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) object_property_set_int(OBJECT(&s->cpus), "num-harts", ms->smp.cpus, &error_abort); object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x8080, &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_fatal); /* Boot ROM */ memory_region_init_rom(&s->rom, OBJECT(dev_soc), "riscv.lowrisc.ibex.rom", diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index dcb87b6cfd..d65d2fd869 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -195,7 +195,7 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp) object_property_set_str(OBJECT(&s->cpus), "cpu-type", ms->cpu_type, &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_fatal); /* Mask ROM */ memory_region_init_rom(&s->mask_rom, OBJECT(dev), "riscv.sifive.e.mrom", diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index cc8c7637cb..a2495b5ae7 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -830,8 +830,8 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) qdev_prop_set_string(DEVICE(&s->u_cpus), "cpu-type", s->cpu_type); qdev_prop_set_uint64(DEVICE(&s->u_cpus), "resetvec", 0x1004); - sysbus_realize(SYS_BUS_DEVICE(&s->e_cpus), &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->u_cpus), &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->e_cpus), &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(&s->u_cpus), &error_fatal); /* * The cluster must be realized after the RISC-V hart array container, * as the container's CPU object is only created on realize, and the From 61cdf4593e4e1bf10cb58a5b8939414f4cd50834 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sun, 15 May 2022 11:56:07 +0900 Subject: [PATCH 471/935] target/riscv: Fix coding style on "G" expansion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because ext_? members are boolean variables, operator `&&' should be used instead of `&'. Signed-off-by: Tsukasa OI Reviewed-by: Alistair Francis Reviewed-by: Víctor Colombo Message-Id: <91633f8349253656dd08bc8dc36498a9c7538b10.1652583332.git.research_trasio@irq.a4lg.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index dc93412395..e439716337 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -596,8 +596,8 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) return; } - if (cpu->cfg.ext_g && !(cpu->cfg.ext_i & cpu->cfg.ext_m & - cpu->cfg.ext_a & cpu->cfg.ext_f & + if (cpu->cfg.ext_g && !(cpu->cfg.ext_i && cpu->cfg.ext_m && + cpu->cfg.ext_a && cpu->cfg.ext_f && cpu->cfg.ext_d)) { warn_report("Setting G will also set IMAFD"); cpu->cfg.ext_i = true; From 1d398ab9dcfb8f5fb4b9a285ea3167f7ba85976d Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sun, 15 May 2022 11:56:08 +0900 Subject: [PATCH 472/935] target/riscv: Disable "G" by default Because "G" virtual extension expands to "IMAFD", we cannot separately disable extensions like "F" or "D" without disabling "G". Because all "IMAFD" are enabled by default, it's harmless to disable "G" by default. Signed-off-by: Tsukasa OI Reviewed-by: Alistair Francis Message-Id: Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index e439716337..1fb76b4295 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -812,7 +812,7 @@ static Property riscv_cpu_properties[] = { /* Defaults for standard extensions */ DEFINE_PROP_BOOL("i", RISCVCPU, cfg.ext_i, true), DEFINE_PROP_BOOL("e", RISCVCPU, cfg.ext_e, false), - DEFINE_PROP_BOOL("g", RISCVCPU, cfg.ext_g, true), + DEFINE_PROP_BOOL("g", RISCVCPU, cfg.ext_g, false), DEFINE_PROP_BOOL("m", RISCVCPU, cfg.ext_m, true), DEFINE_PROP_BOOL("a", RISCVCPU, cfg.ext_a, true), DEFINE_PROP_BOOL("f", RISCVCPU, cfg.ext_f, true), From 9f6b7da5d27b744ddbdba98ba8b89c710dd3c1b7 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sun, 15 May 2022 11:56:09 +0900 Subject: [PATCH 473/935] target/riscv: Change "G" expansion On ISA version 20190608 or later, "G" expands to "IMAFD_Zicsr_Zifencei". Both "Zicsr" and "Zifencei" are enabled by default and "G" is supposed to be (virtually) enabled as well, it should be safe to change its expansion. Signed-off-by: Tsukasa OI Reviewed-by: Alistair Francis Message-Id: Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 1fb76b4295..4ca6a8623f 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -598,13 +598,16 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) if (cpu->cfg.ext_g && !(cpu->cfg.ext_i && cpu->cfg.ext_m && cpu->cfg.ext_a && cpu->cfg.ext_f && - cpu->cfg.ext_d)) { - warn_report("Setting G will also set IMAFD"); + cpu->cfg.ext_d && + cpu->cfg.ext_icsr && cpu->cfg.ext_ifencei)) { + warn_report("Setting G will also set IMAFD_Zicsr_Zifencei"); cpu->cfg.ext_i = true; cpu->cfg.ext_m = true; cpu->cfg.ext_a = true; cpu->cfg.ext_f = true; cpu->cfg.ext_d = true; + cpu->cfg.ext_icsr = true; + cpu->cfg.ext_ifencei = true; } if (cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinx || From 1086504c6f46a2b3be90e887dddb4741bf8c500d Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sun, 15 May 2022 11:56:10 +0900 Subject: [PATCH 474/935] target/riscv: FP extension requirements QEMU allowed inconsistent configurations that made floating point arithmetic effectively unusable. This commit adds certain checks for consistent FP arithmetic: - F requires Zicsr - Zfinx requires Zicsr - Zfh/Zfhmin require F - D requires F - V requires D Because F/D/Zicsr are enabled by default (and an error will not occur unless we manually disable one or more of prerequisites), this commit just enforces the user to give consistent combinations. Signed-off-by: Tsukasa OI Reviewed-by: Alistair Francis Message-Id: <00e7b1c6060dab32ac7d49813b1ca84d3eb63298.1652583332.git.research_trasio@irq.a4lg.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 4ca6a8623f..b960473f7d 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -610,11 +610,36 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) cpu->cfg.ext_ifencei = true; } + if (cpu->cfg.ext_f && !cpu->cfg.ext_icsr) { + error_setg(errp, "F extension requires Zicsr"); + return; + } + + if ((cpu->cfg.ext_zfh || cpu->cfg.ext_zfhmin) && !cpu->cfg.ext_f) { + error_setg(errp, "Zfh/Zfhmin extensions require F extension"); + return; + } + + if (cpu->cfg.ext_d && !cpu->cfg.ext_f) { + error_setg(errp, "D extension requires F extension"); + return; + } + + if (cpu->cfg.ext_v && !cpu->cfg.ext_d) { + error_setg(errp, "V extension requires D extension"); + return; + } + if (cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinx || cpu->cfg.ext_zhinxmin) { cpu->cfg.ext_zfinx = true; } + if (cpu->cfg.ext_zfinx && !cpu->cfg.ext_icsr) { + error_setg(errp, "Zfinx extension requires Zicsr"); + return; + } + if (cpu->cfg.ext_zk) { cpu->cfg.ext_zkn = true; cpu->cfg.ext_zkr = true; From bc573816692357e4c824d5c1df73987d3f0ea0c4 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sun, 15 May 2022 11:56:11 +0900 Subject: [PATCH 475/935] target/riscv: Move/refactor ISA extension checks We should separate "check" and "configure" steps as possible. This commit separates both steps except vector/Zfinx-related checks. Signed-off-by: Tsukasa OI Reviewed-by: Alistair Francis Message-Id: Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index b960473f7d..00a068668f 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -630,14 +630,27 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) return; } + if ((cpu->cfg.ext_zve32f || cpu->cfg.ext_zve64f) && !cpu->cfg.ext_f) { + error_setg(errp, "Zve32f/Zve64f extensions require F extension"); + return; + } + + /* Set the ISA extensions, checks should have happened above */ if (cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinx || cpu->cfg.ext_zhinxmin) { cpu->cfg.ext_zfinx = true; } - if (cpu->cfg.ext_zfinx && !cpu->cfg.ext_icsr) { - error_setg(errp, "Zfinx extension requires Zicsr"); - return; + if (cpu->cfg.ext_zfinx) { + if (!cpu->cfg.ext_icsr) { + error_setg(errp, "Zfinx extension requires Zicsr"); + return; + } + if (cpu->cfg.ext_f) { + error_setg(errp, + "Zfinx cannot be supported together with F extension"); + return; + } } if (cpu->cfg.ext_zk) { @@ -663,7 +676,6 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) cpu->cfg.ext_zksh = true; } - /* Set the ISA extensions, checks should have happened above */ if (cpu->cfg.ext_i) { ext |= RVI; } @@ -734,20 +746,9 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) } set_vext_version(env, vext_version); } - if ((cpu->cfg.ext_zve32f || cpu->cfg.ext_zve64f) && !cpu->cfg.ext_f) { - error_setg(errp, "Zve32f/Zve64f extension depends upon RVF."); - return; - } if (cpu->cfg.ext_j) { ext |= RVJ; } - if (cpu->cfg.ext_zfinx && ((ext & (RVF | RVD)) || cpu->cfg.ext_zfh || - cpu->cfg.ext_zfhmin)) { - error_setg(errp, - "'Zfinx' cannot be supported together with 'F', 'D', 'Zfh'," - " 'Zfhmin'"); - return; - } set_misa(env, env->misa_mxl, ext); } From 8f1b6087983ed417ca142c0a7fd7080cc279e0f5 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Tue, 1 Mar 2022 23:52:19 +0100 Subject: [PATCH 476/935] hw/vfio/pci-quirks: Resolve redundant property getters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QOM API already provides getters for uint64 and uint32 values, so reuse them. Signed-off-by: Bernhard Beschow Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20220301225220.239065-2-shentey@gmail.com> Signed-off-by: Alistair Francis --- hw/vfio/pci-quirks.c | 34 +++++++++------------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index 0cf69a8c6d..f0147a050a 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -1565,22 +1565,6 @@ static int vfio_add_nv_gpudirect_cap(VFIOPCIDevice *vdev, Error **errp) return 0; } -static void vfio_pci_nvlink2_get_tgt(Object *obj, Visitor *v, - const char *name, - void *opaque, Error **errp) -{ - uint64_t tgt = (uintptr_t) opaque; - visit_type_uint64(v, name, &tgt, errp); -} - -static void vfio_pci_nvlink2_get_link_speed(Object *obj, Visitor *v, - const char *name, - void *opaque, Error **errp) -{ - uint32_t link_speed = (uint32_t)(uintptr_t) opaque; - visit_type_uint32(v, name, &link_speed, errp); -} - int vfio_pci_nvidia_v100_ram_init(VFIOPCIDevice *vdev, Error **errp) { int ret; @@ -1618,9 +1602,9 @@ int vfio_pci_nvidia_v100_ram_init(VFIOPCIDevice *vdev, Error **errp) nv2reg->size, p); QLIST_INSERT_HEAD(&vdev->bars[0].quirks, quirk, next); - object_property_add(OBJECT(vdev), "nvlink2-tgt", "uint64", - vfio_pci_nvlink2_get_tgt, NULL, NULL, - (void *) (uintptr_t) cap->tgt); + object_property_add_uint64_ptr(OBJECT(vdev), "nvlink2-tgt", + (uint64_t *) &cap->tgt, + OBJ_PROP_FLAG_READ); trace_vfio_pci_nvidia_gpu_setup_quirk(vdev->vbasedev.name, cap->tgt, nv2reg->size); free_exit: @@ -1679,15 +1663,15 @@ int vfio_pci_nvlink2_init(VFIOPCIDevice *vdev, Error **errp) QLIST_INSERT_HEAD(&vdev->bars[0].quirks, quirk, next); } - object_property_add(OBJECT(vdev), "nvlink2-tgt", "uint64", - vfio_pci_nvlink2_get_tgt, NULL, NULL, - (void *) (uintptr_t) captgt->tgt); + object_property_add_uint64_ptr(OBJECT(vdev), "nvlink2-tgt", + (uint64_t *) &captgt->tgt, + OBJ_PROP_FLAG_READ); trace_vfio_pci_nvlink2_setup_quirk_ssatgt(vdev->vbasedev.name, captgt->tgt, atsdreg->size); - object_property_add(OBJECT(vdev), "nvlink2-link-speed", "uint32", - vfio_pci_nvlink2_get_link_speed, NULL, NULL, - (void *) (uintptr_t) capspeed->link_speed); + object_property_add_uint32_ptr(OBJECT(vdev), "nvlink2-link-speed", + &capspeed->link_speed, + OBJ_PROP_FLAG_READ); trace_vfio_pci_nvlink2_setup_quirk_lnkspd(vdev->vbasedev.name, capspeed->link_speed); free_exit: From 96c7fff703d56798bd5dcb1ef6d42ead144580a3 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Tue, 1 Mar 2022 23:52:20 +0100 Subject: [PATCH 477/935] hw/riscv/sifive_u: Resolve redundant property accessors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QOM API already provides accessors for uint32 values, so reuse them. Signed-off-by: Bernhard Beschow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-Id: <20220301225220.239065-3-shentey@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index a2495b5ae7..e4c814a3ea 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -713,36 +713,20 @@ static void sifive_u_machine_set_start_in_flash(Object *obj, bool value, Error * s->start_in_flash = value; } -static void sifive_u_machine_get_uint32_prop(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) -{ - visit_type_uint32(v, name, (uint32_t *)opaque, errp); -} - -static void sifive_u_machine_set_uint32_prop(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) -{ - visit_type_uint32(v, name, (uint32_t *)opaque, errp); -} - static void sifive_u_machine_instance_init(Object *obj) { SiFiveUState *s = RISCV_U_MACHINE(obj); s->start_in_flash = false; s->msel = 0; - object_property_add(obj, "msel", "uint32", - sifive_u_machine_get_uint32_prop, - sifive_u_machine_set_uint32_prop, NULL, &s->msel); + object_property_add_uint32_ptr(obj, "msel", &s->msel, + OBJ_PROP_FLAG_READWRITE); object_property_set_description(obj, "msel", "Mode Select (MSEL[3:0]) pin state"); s->serial = OTP_SERIAL; - object_property_add(obj, "serial", "uint32", - sifive_u_machine_get_uint32_prop, - sifive_u_machine_set_uint32_prop, NULL, &s->serial); + object_property_add_uint32_ptr(obj, "serial", &s->serial, + OBJ_PROP_FLAG_READWRITE); object_property_set_description(obj, "serial", "Board serial number"); } From bb06941f95edd8a231bee0ac52a8a1dbf6b08e6a Mon Sep 17 00:00:00 2001 From: Weiwei Li Date: Wed, 18 May 2022 09:26:11 +0800 Subject: [PATCH 478/935] target/riscv: check 'I' and 'E' after checking 'G' in riscv_cpu_realize - setting ext_g will implicitly set ext_i Signed-off-by: Weiwei Li Signed-off-by: Junqiang Wang Reviewed-by: Alistair Francis Message-Id: <20220518012611.6772-1-liweiwei@iscas.ac.cn> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 00a068668f..87e1eddce6 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -584,18 +584,6 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) uint32_t ext = 0; /* Do some ISA extension error checking */ - if (cpu->cfg.ext_i && cpu->cfg.ext_e) { - error_setg(errp, - "I and E extensions are incompatible"); - return; - } - - if (!cpu->cfg.ext_i && !cpu->cfg.ext_e) { - error_setg(errp, - "Either I or E extension must be set"); - return; - } - if (cpu->cfg.ext_g && !(cpu->cfg.ext_i && cpu->cfg.ext_m && cpu->cfg.ext_a && cpu->cfg.ext_f && cpu->cfg.ext_d && @@ -610,6 +598,18 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) cpu->cfg.ext_ifencei = true; } + if (cpu->cfg.ext_i && cpu->cfg.ext_e) { + error_setg(errp, + "I and E extensions are incompatible"); + return; + } + + if (!cpu->cfg.ext_i && !cpu->cfg.ext_e) { + error_setg(errp, + "Either I or E extension must be set"); + return; + } + if (cpu->cfg.ext_f && !cpu->cfg.ext_icsr) { error_setg(errp, "F extension requires Zicsr"); return; From 075eeda93166f1914097ffb84b33df4ecc50d63c Mon Sep 17 00:00:00 2001 From: Frank Chang Date: Mon, 23 May 2022 23:31:46 +0800 Subject: [PATCH 479/935] target/riscv: Fix typo of mimpid cpu option "mimpid" cpu option was mistyped to "mipid". Fixes: 9951ba94 ("target/riscv: Support configuarable marchid, mvendorid, mipid CSR values") Signed-off-by: Frank Chang Reviewed-by: Alistair Francis Message-Id: <20220523153147.15371-1-frank.chang@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 4 ++-- target/riscv/cpu.h | 2 +- target/riscv/csr.c | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 87e1eddce6..fe8ceb4133 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -37,7 +37,7 @@ #define RISCV_CPU_MARCHID ((QEMU_VERSION_MAJOR << 16) | \ (QEMU_VERSION_MINOR << 8) | \ (QEMU_VERSION_MICRO)) -#define RISCV_CPU_MIPID RISCV_CPU_MARCHID +#define RISCV_CPU_MIMPID RISCV_CPU_MARCHID static const char riscv_single_letter_exts[] = "IEMAFDQCPVH"; @@ -869,7 +869,7 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_UINT32("mvendorid", RISCVCPU, cfg.mvendorid, 0), DEFINE_PROP_UINT64("marchid", RISCVCPU, cfg.marchid, RISCV_CPU_MARCHID), - DEFINE_PROP_UINT64("mipid", RISCVCPU, cfg.mipid, RISCV_CPU_MIPID), + DEFINE_PROP_UINT64("mimpid", RISCVCPU, cfg.mimpid, RISCV_CPU_MIMPID), DEFINE_PROP_BOOL("svinval", RISCVCPU, cfg.ext_svinval, false), DEFINE_PROP_BOOL("svnapot", RISCVCPU, cfg.ext_svnapot, false), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index f5ff7294c6..44975e3e5a 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -408,7 +408,7 @@ struct RISCVCPUConfig { uint32_t mvendorid; uint64_t marchid; - uint64_t mipid; + uint64_t mimpid; /* Vendor-specific custom extensions */ bool ext_XVentanaCondOps; diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 4ea7df02c9..0d5bc2f41d 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -674,13 +674,13 @@ static RISCVException read_marchid(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static RISCVException read_mipid(CPURISCVState *env, int csrno, - target_ulong *val) +static RISCVException read_mimpid(CPURISCVState *env, int csrno, + target_ulong *val) { CPUState *cs = env_cpu(env); RISCVCPU *cpu = RISCV_CPU(cs); - *val = cpu->cfg.mipid; + *val = cpu->cfg.mimpid; return RISCV_EXCP_NONE; } @@ -3372,7 +3372,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { /* Machine Information Registers */ [CSR_MVENDORID] = { "mvendorid", any, read_mvendorid }, [CSR_MARCHID] = { "marchid", any, read_marchid }, - [CSR_MIMPID] = { "mimpid", any, read_mipid }, + [CSR_MIMPID] = { "mimpid", any, read_mimpid }, [CSR_MHARTID] = { "mhartid", any, read_mhartid }, [CSR_MCONFIGPTR] = { "mconfigptr", any, read_zero, From c1fbcecb3a97ecce2cde5052319df34ca6bcc988 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 11 May 2022 20:15:21 +0530 Subject: [PATCH 480/935] target/riscv: Fix csr number based privilege checking When hypervisor and VS CSRs are accessed from VS-mode or VU-mode, the riscv_csrrw_check() function should generate virtual instruction trap instead illegal instruction trap. Fixes: 0a42f4c44088 (" target/riscv: Fix CSR perm checking for HS mode") Signed-off-by: Anup Patel Reviewed-by: Alistair Francis Reviewed-by: Frank Chang Message-Id: <20220511144528.393530-2-apatel@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/csr.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 0d5bc2f41d..6dbe9b541f 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -3139,7 +3139,7 @@ static inline RISCVException riscv_csrrw_check(CPURISCVState *env, int read_only = get_field(csrno, 0xC00) == 3; int csr_min_priv = csr_ops[csrno].min_priv_ver; #if !defined(CONFIG_USER_ONLY) - int effective_priv = env->priv; + int csr_priv, effective_priv = env->priv; if (riscv_has_ext(env, RVH) && env->priv == PRV_S) { /* @@ -3152,7 +3152,11 @@ static inline RISCVException riscv_csrrw_check(CPURISCVState *env, effective_priv++; } - if (!env->debugger && (effective_priv < get_field(csrno, 0x300))) { + csr_priv = get_field(csrno, 0x300); + if (!env->debugger && (effective_priv < csr_priv)) { + if (csr_priv == (PRV_S + 1) && riscv_cpu_virt_enabled(env)) { + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } return RISCV_EXCP_ILLEGAL_INST; } #endif From 24826da0eeacb27a5da6be764c8e853b2cede25b Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 11 May 2022 20:15:22 +0530 Subject: [PATCH 481/935] target/riscv: Fix hstatus.GVA bit setting for traps taken from HS-mode Currently, QEMU does not set hstatus.GVA bit for traps taken from HS-mode into HS-mode which breaks the Xvisor nested MMU test suite on QEMU. This was working previously. This patch updates riscv_cpu_do_interrupt() to fix the above issue. Fixes: 86d0c457396b ("target/riscv: Fixup setting GVA") Signed-off-by: Anup Patel Reviewed-by: Alistair Francis Message-Id: <20220511144528.393530-3-apatel@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu_helper.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index e1aa4f2097..b16bfe0182 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -1367,7 +1367,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) case RISCV_EXCP_INST_PAGE_FAULT: case RISCV_EXCP_LOAD_PAGE_FAULT: case RISCV_EXCP_STORE_PAGE_FAULT: - write_gva = true; + write_gva = env->two_stage_lookup; tval = env->badaddr; break; case RISCV_EXCP_ILLEGAL_INST: @@ -1434,7 +1434,6 @@ void riscv_cpu_do_interrupt(CPUState *cs) /* Trap into HS mode */ env->hstatus = set_field(env->hstatus, HSTATUS_SPV, false); htval = env->guest_phys_fault_addr; - write_gva = false; } env->hstatus = set_field(env->hstatus, HSTATUS_GVA, write_gva); } From 62cf02451edb1d23bc44a35aca56a8347dfebff7 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 11 May 2022 20:15:23 +0530 Subject: [PATCH 482/935] target/riscv: Set [m|s]tval for both illegal and virtual instruction traps Currently, the [m|s]tval CSRs are set with trapping instruction encoding only for illegal instruction traps taken at the time of instruction decoding. In RISC-V world, a valid instructions might also trap as illegal or virtual instruction based to trapping bits in various CSRs (such as mstatus.TVM or hstatus.VTVM). We improve setting of [m|s]tval CSRs for all types of illegal and virtual instruction traps. Signed-off-by: Anup Patel Reviewed-by: Frank Chang Reviewed-by: Alistair Francis Message-Id: <20220511144528.393530-4-apatel@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 ++ target/riscv/cpu.h | 8 +++++++- target/riscv/cpu_helper.c | 1 + target/riscv/translate.c | 17 +++++++++++++---- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index fe8ceb4133..ce1c257eef 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -406,6 +406,7 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb, } else { env->pc = data[0]; } + env->bins = data[1]; } static void riscv_cpu_reset(DeviceState *dev) @@ -445,6 +446,7 @@ static void riscv_cpu_reset(DeviceState *dev) env->mcause = 0; env->miclaim = MIP_SGEIP; env->pc = env->resetvec; + env->bins = 0; env->two_stage_lookup = false; /* Initialized default priorities of local interrupts. */ diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 44975e3e5a..f08c3e8813 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -30,6 +30,12 @@ #define TCG_GUEST_DEFAULT_MO 0 +/* + * RISC-V-specific extra insn start words: + * 1: Original instruction opcode + */ +#define TARGET_INSN_START_EXTRA_WORDS 1 + #define TYPE_RISCV_CPU "riscv-cpu" #define RISCV_CPU_TYPE_SUFFIX "-" TYPE_RISCV_CPU @@ -140,7 +146,7 @@ struct CPUArchState { target_ulong frm; target_ulong badaddr; - uint32_t bins; + target_ulong bins; target_ulong guest_phys_fault_addr; diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index b16bfe0182..d99fac9d2d 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -1371,6 +1371,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) tval = env->badaddr; break; case RISCV_EXCP_ILLEGAL_INST: + case RISCV_EXCP_VIRT_INSTRUCTION_FAULT: tval = env->bins; break; default: diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 0cd1d9ee94..55a4713af2 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -107,6 +107,8 @@ typedef struct DisasContext { /* PointerMasking extension */ bool pm_mask_enabled; bool pm_base_enabled; + /* TCG of the current insn_start */ + TCGOp *insn_start; } DisasContext; static inline bool has_ext(DisasContext *ctx, uint32_t ext) @@ -236,9 +238,6 @@ static void generate_exception_mtval(DisasContext *ctx, int excp) static void gen_exception_illegal(DisasContext *ctx) { - tcg_gen_st_i32(tcg_constant_i32(ctx->opcode), cpu_env, - offsetof(CPURISCVState, bins)); - generate_exception(ctx, RISCV_EXCP_ILLEGAL_INST); } @@ -1017,6 +1016,13 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) /* Include decoders for factored-out extensions */ #include "decode-XVentanaCondOps.c.inc" +static inline void decode_save_opc(DisasContext *ctx, target_ulong opc) +{ + assert(ctx->insn_start != NULL); + tcg_set_insn_start_param(ctx->insn_start, 1, opc); + ctx->insn_start = NULL; +} + static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode) { /* @@ -1033,6 +1039,7 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode) /* Check for compressed insn */ if (extract16(opcode, 0, 2) != 3) { + decode_save_opc(ctx, opcode); if (!has_ext(ctx, RVC)) { gen_exception_illegal(ctx); } else { @@ -1047,6 +1054,7 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode) opcode32 = deposit32(opcode32, 16, 16, translator_lduw(env, &ctx->base, ctx->base.pc_next + 2)); + decode_save_opc(ctx, opcode32); ctx->opcode = opcode32; ctx->pc_succ_insn = ctx->base.pc_next + 4; @@ -1113,7 +1121,8 @@ static void riscv_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *ctx = container_of(dcbase, DisasContext, base); - tcg_gen_insn_start(ctx->base.pc_next); + tcg_gen_insn_start(ctx->base.pc_next, 0); + ctx->insn_start = tcg_last_op(); } static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) From d644e5e44ff627d6b4da73a65795f60335ba4cb9 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 11 May 2022 20:15:28 +0530 Subject: [PATCH 483/935] hw/riscv: virt: Fix interrupt parent for dynamic platform devices When both APLIC and IMSIC are present in virt machine, the APLIC should be used as parent interrupt controller for dynamic platform devices. In case of multiple sockets, we should prefer interrupt controller of socket0 for dynamic platform devices. Fixes: 3029fab64309 ("hw/riscv: virt: Add support for generating platform FDT entries") Signed-off-by: Anup Patel Reviewed-by: Alistair Francis Message-Id: <20220511144528.393530-9-apatel@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 244d6408b5..293e9c95b7 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -478,10 +478,12 @@ static void create_fdt_socket_plic(RISCVVirtState *s, qemu_fdt_setprop_cell(mc->fdt, plic_name, "phandle", plic_phandles[socket]); - platform_bus_add_all_fdt_nodes(mc->fdt, plic_name, - memmap[VIRT_PLATFORM_BUS].base, - memmap[VIRT_PLATFORM_BUS].size, - VIRT_PLATFORM_BUS_IRQ); + if (!socket) { + platform_bus_add_all_fdt_nodes(mc->fdt, plic_name, + memmap[VIRT_PLATFORM_BUS].base, + memmap[VIRT_PLATFORM_BUS].size, + VIRT_PLATFORM_BUS_IRQ); + } g_free(plic_name); @@ -561,11 +563,6 @@ static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap, } qemu_fdt_setprop_cell(mc->fdt, imsic_name, "phandle", *msi_m_phandle); - platform_bus_add_all_fdt_nodes(mc->fdt, imsic_name, - memmap[VIRT_PLATFORM_BUS].base, - memmap[VIRT_PLATFORM_BUS].size, - VIRT_PLATFORM_BUS_IRQ); - g_free(imsic_name); /* S-level IMSIC node */ @@ -704,10 +701,12 @@ static void create_fdt_socket_aplic(RISCVVirtState *s, riscv_socket_fdt_write_id(mc, mc->fdt, aplic_name, socket); qemu_fdt_setprop_cell(mc->fdt, aplic_name, "phandle", aplic_s_phandle); - platform_bus_add_all_fdt_nodes(mc->fdt, aplic_name, - memmap[VIRT_PLATFORM_BUS].base, - memmap[VIRT_PLATFORM_BUS].size, - VIRT_PLATFORM_BUS_IRQ); + if (!socket) { + platform_bus_add_all_fdt_nodes(mc->fdt, aplic_name, + memmap[VIRT_PLATFORM_BUS].base, + memmap[VIRT_PLATFORM_BUS].size, + VIRT_PLATFORM_BUS_IRQ); + } g_free(aplic_name); From 5160bacc0638088a7cb0180d2be3d8c2c8a21831 Mon Sep 17 00:00:00 2001 From: "Hongren (Zenithal) Zheng" Date: Wed, 18 May 2022 20:46:58 +0800 Subject: [PATCH 484/935] target/riscv: add zicsr/zifencei to isa_string Zicsr/Zifencei is not in 'I' since ISA version 20190608, thus to fully express the capability of the CPU, they should be exposed in isa_string. Signed-off-by: Hongren (Zenithal) Zheng Tested-by: Jiatai He Reviewed-by: Alistair Francis Message-Id: Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index ce1c257eef..a91253d4bd 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1029,6 +1029,8 @@ static void riscv_isa_string_ext(RISCVCPU *cpu, char **isa_str, int max_str_len) * extensions by an underscore. */ struct isa_ext_data isa_edata_arr[] = { + ISA_EDATA_ENTRY(zicsr, ext_icsr), + ISA_EDATA_ENTRY(zifencei, ext_ifencei), ISA_EDATA_ENTRY(zfh, ext_zfh), ISA_EDATA_ENTRY(zfhmin, ext_zfhmin), ISA_EDATA_ENTRY(zfinx, ext_zfinx), From d616889ece83d006ff630c72eb5bb38ad3b86645 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 24 Mar 2022 21:48:11 +0800 Subject: [PATCH 485/935] hw/core: Sync uboot_image.h from U-Boot v2022.01 Sync uboot_image.h from upstream U-Boot v2022.01 release [1]. [1] https://source.denx.de/u-boot/u-boot/-/blob/v2022.01/include/image.h Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <20220324134812.541274-1-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/core/uboot_image.h | 213 ++++++++++++++++++++++++++++-------------- 1 file changed, 142 insertions(+), 71 deletions(-) diff --git a/hw/core/uboot_image.h b/hw/core/uboot_image.h index 608022de6e..18ac293359 100644 --- a/hw/core/uboot_image.h +++ b/hw/core/uboot_image.h @@ -1,23 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* + * (C) Copyright 2008 Semihalf + * * (C) Copyright 2000-2005 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - * ******************************************************************** * NOTE: This header file defines an interface to U-Boot. Including * this (unmodified) header file in another file is considered normal @@ -31,50 +17,83 @@ /* * Operating System Codes + * + * The following are exposed to uImage header. + * New IDs *MUST* be appended at the end of the list and *NEVER* + * inserted for backward compatibility. */ -#define IH_OS_INVALID 0 /* Invalid OS */ -#define IH_OS_OPENBSD 1 /* OpenBSD */ -#define IH_OS_NETBSD 2 /* NetBSD */ -#define IH_OS_FREEBSD 3 /* FreeBSD */ -#define IH_OS_4_4BSD 4 /* 4.4BSD */ -#define IH_OS_LINUX 5 /* Linux */ -#define IH_OS_SVR4 6 /* SVR4 */ -#define IH_OS_ESIX 7 /* Esix */ -#define IH_OS_SOLARIS 8 /* Solaris */ -#define IH_OS_IRIX 9 /* Irix */ -#define IH_OS_SCO 10 /* SCO */ -#define IH_OS_DELL 11 /* Dell */ -#define IH_OS_NCR 12 /* NCR */ -#define IH_OS_LYNXOS 13 /* LynxOS */ -#define IH_OS_VXWORKS 14 /* VxWorks */ -#define IH_OS_PSOS 15 /* pSOS */ -#define IH_OS_QNX 16 /* QNX */ -#define IH_OS_U_BOOT 17 /* Firmware */ -#define IH_OS_RTEMS 18 /* RTEMS */ -#define IH_OS_ARTOS 19 /* ARTOS */ -#define IH_OS_UNITY 20 /* Unity OS */ +enum { + IH_OS_INVALID = 0, /* Invalid OS */ + IH_OS_OPENBSD, /* OpenBSD */ + IH_OS_NETBSD, /* NetBSD */ + IH_OS_FREEBSD, /* FreeBSD */ + IH_OS_4_4BSD, /* 4.4BSD */ + IH_OS_LINUX, /* Linux */ + IH_OS_SVR4, /* SVR4 */ + IH_OS_ESIX, /* Esix */ + IH_OS_SOLARIS, /* Solaris */ + IH_OS_IRIX, /* Irix */ + IH_OS_SCO, /* SCO */ + IH_OS_DELL, /* Dell */ + IH_OS_NCR, /* NCR */ + IH_OS_LYNXOS, /* LynxOS */ + IH_OS_VXWORKS, /* VxWorks */ + IH_OS_PSOS, /* pSOS */ + IH_OS_QNX, /* QNX */ + IH_OS_U_BOOT, /* Firmware */ + IH_OS_RTEMS, /* RTEMS */ + IH_OS_ARTOS, /* ARTOS */ + IH_OS_UNITY, /* Unity OS */ + IH_OS_INTEGRITY, /* INTEGRITY */ + IH_OS_OSE, /* OSE */ + IH_OS_PLAN9, /* Plan 9 */ + IH_OS_OPENRTOS, /* OpenRTOS */ + IH_OS_ARM_TRUSTED_FIRMWARE, /* ARM Trusted Firmware */ + IH_OS_TEE, /* Trusted Execution Environment */ + IH_OS_OPENSBI, /* RISC-V OpenSBI */ + IH_OS_EFI, /* EFI Firmware (e.g. GRUB2) */ + + IH_OS_COUNT, +}; /* * CPU Architecture Codes (supported by Linux) + * + * The following are exposed to uImage header. + * New IDs *MUST* be appended at the end of the list and *NEVER* + * inserted for backward compatibility. */ -#define IH_CPU_INVALID 0 /* Invalid CPU */ -#define IH_CPU_ALPHA 1 /* Alpha */ -#define IH_CPU_ARM 2 /* ARM */ -#define IH_CPU_I386 3 /* Intel x86 */ -#define IH_CPU_IA64 4 /* IA64 */ -#define IH_CPU_MIPS 5 /* MIPS */ -#define IH_CPU_MIPS64 6 /* MIPS 64 Bit */ -#define IH_CPU_PPC 7 /* PowerPC */ -#define IH_CPU_S390 8 /* IBM S390 */ -#define IH_CPU_SH 9 /* SuperH */ -#define IH_CPU_SPARC 10 /* Sparc */ -#define IH_CPU_SPARC64 11 /* Sparc 64 Bit */ -#define IH_CPU_M68K 12 /* M68K */ -#define IH_CPU_NIOS 13 /* Nios-32 */ -#define IH_CPU_MICROBLAZE 14 /* MicroBlaze */ -#define IH_CPU_NIOS2 15 /* Nios-II */ -#define IH_CPU_BLACKFIN 16 /* Blackfin */ -#define IH_CPU_AVR32 17 /* AVR32 */ +enum { + IH_ARCH_INVALID = 0, /* Invalid CPU */ + IH_ARCH_ALPHA, /* Alpha */ + IH_ARCH_ARM, /* ARM */ + IH_ARCH_I386, /* Intel x86 */ + IH_ARCH_IA64, /* IA64 */ + IH_ARCH_MIPS, /* MIPS */ + IH_ARCH_MIPS64, /* MIPS 64 Bit */ + IH_ARCH_PPC, /* PowerPC */ + IH_ARCH_S390, /* IBM S390 */ + IH_ARCH_SH, /* SuperH */ + IH_ARCH_SPARC, /* Sparc */ + IH_ARCH_SPARC64, /* Sparc 64 Bit */ + IH_ARCH_M68K, /* M68K */ + IH_ARCH_NIOS, /* Nios-32 */ + IH_ARCH_MICROBLAZE, /* MicroBlaze */ + IH_ARCH_NIOS2, /* Nios-II */ + IH_ARCH_BLACKFIN, /* Blackfin */ + IH_ARCH_AVR32, /* AVR32 */ + IH_ARCH_ST200, /* STMicroelectronics ST200 */ + IH_ARCH_SANDBOX, /* Sandbox architecture (test only) */ + IH_ARCH_NDS32, /* ANDES Technology - NDS32 */ + IH_ARCH_OPENRISC, /* OpenRISC 1000 */ + IH_ARCH_ARM64, /* ARM64 */ + IH_ARCH_ARC, /* Synopsys DesignWare ARC */ + IH_ARCH_X86_64, /* AMD x86_64, Intel and Via */ + IH_ARCH_XTENSA, /* Xtensa */ + IH_ARCH_RISCV, /* RISC-V */ + + IH_ARCH_COUNT, +}; /* * Image Types @@ -113,33 +132,85 @@ * U-Boot's command interpreter; this feature is especially * useful when you configure U-Boot to use a real shell (hush) * as command interpreter (=> Shell Scripts). + * + * The following are exposed to uImage header. + * New IDs *MUST* be appended at the end of the list and *NEVER* + * inserted for backward compatibility. */ -#define IH_TYPE_INVALID 0 /* Invalid Image */ -#define IH_TYPE_STANDALONE 1 /* Standalone Program */ -#define IH_TYPE_KERNEL 2 /* OS Kernel Image */ -#define IH_TYPE_RAMDISK 3 /* RAMDisk Image */ -#define IH_TYPE_MULTI 4 /* Multi-File Image */ -#define IH_TYPE_FIRMWARE 5 /* Firmware Image */ -#define IH_TYPE_SCRIPT 6 /* Script file */ -#define IH_TYPE_FILESYSTEM 7 /* Filesystem Image (any type) */ -#define IH_TYPE_FLATDT 8 /* Binary Flat Device Tree Blob */ -#define IH_TYPE_KERNEL_NOLOAD 14 /* OS Kernel Image (noload) */ +enum { + IH_TYPE_INVALID = 0, /* Invalid Image */ + IH_TYPE_STANDALONE, /* Standalone Program */ + IH_TYPE_KERNEL, /* OS Kernel Image */ + IH_TYPE_RAMDISK, /* RAMDisk Image */ + IH_TYPE_MULTI, /* Multi-File Image */ + IH_TYPE_FIRMWARE, /* Firmware Image */ + IH_TYPE_SCRIPT, /* Script file */ + IH_TYPE_FILESYSTEM, /* Filesystem Image (any type) */ + IH_TYPE_FLATDT, /* Binary Flat Device Tree Blob */ + IH_TYPE_KWBIMAGE, /* Kirkwood Boot Image */ + IH_TYPE_IMXIMAGE, /* Freescale IMXBoot Image */ + IH_TYPE_UBLIMAGE, /* Davinci UBL Image */ + IH_TYPE_OMAPIMAGE, /* TI OMAP Config Header Image */ + IH_TYPE_AISIMAGE, /* TI Davinci AIS Image */ + /* OS Kernel Image, can run from any load address */ + IH_TYPE_KERNEL_NOLOAD, + IH_TYPE_PBLIMAGE, /* Freescale PBL Boot Image */ + IH_TYPE_MXSIMAGE, /* Freescale MXSBoot Image */ + IH_TYPE_GPIMAGE, /* TI Keystone GPHeader Image */ + IH_TYPE_ATMELIMAGE, /* ATMEL ROM bootable Image */ + IH_TYPE_SOCFPGAIMAGE, /* Altera SOCFPGA CV/AV Preloader */ + IH_TYPE_X86_SETUP, /* x86 setup.bin Image */ + IH_TYPE_LPC32XXIMAGE, /* x86 setup.bin Image */ + IH_TYPE_LOADABLE, /* A list of typeless images */ + IH_TYPE_RKIMAGE, /* Rockchip Boot Image */ + IH_TYPE_RKSD, /* Rockchip SD card */ + IH_TYPE_RKSPI, /* Rockchip SPI image */ + IH_TYPE_ZYNQIMAGE, /* Xilinx Zynq Boot Image */ + IH_TYPE_ZYNQMPIMAGE, /* Xilinx ZynqMP Boot Image */ + IH_TYPE_ZYNQMPBIF, /* Xilinx ZynqMP Boot Image (bif) */ + IH_TYPE_FPGA, /* FPGA Image */ + IH_TYPE_VYBRIDIMAGE, /* VYBRID .vyb Image */ + IH_TYPE_TEE, /* Trusted Execution Environment OS Image */ + IH_TYPE_FIRMWARE_IVT, /* Firmware Image with HABv4 IVT */ + IH_TYPE_PMMC, /* TI Power Management Micro-Controller Firmware */ + IH_TYPE_STM32IMAGE, /* STMicroelectronics STM32 Image */ + IH_TYPE_SOCFPGAIMAGE_V1, /* Altera SOCFPGA A10 Preloader */ + IH_TYPE_MTKIMAGE, /* MediaTek BootROM loadable Image */ + IH_TYPE_IMX8MIMAGE, /* Freescale IMX8MBoot Image */ + IH_TYPE_IMX8IMAGE, /* Freescale IMX8Boot Image */ + IH_TYPE_COPRO, /* Coprocessor Image for remoteproc*/ + IH_TYPE_SUNXI_EGON, /* Allwinner eGON Boot Image */ + + IH_TYPE_COUNT, /* Number of image types */ +}; /* * Compression Types + * + * The following are exposed to uImage header. + * New IDs *MUST* be appended at the end of the list and *NEVER* + * inserted for backward compatibility. */ -#define IH_COMP_NONE 0 /* No Compression Used */ -#define IH_COMP_GZIP 1 /* gzip Compression Used */ -#define IH_COMP_BZIP2 2 /* bzip2 Compression Used */ +enum { + IH_COMP_NONE = 0, /* No Compression Used */ + IH_COMP_GZIP, /* gzip Compression Used */ + IH_COMP_BZIP2, /* bzip2 Compression Used */ + IH_COMP_LZMA, /* lzma Compression Used */ + IH_COMP_LZO, /* lzo Compression Used */ + IH_COMP_LZ4, /* lz4 Compression Used */ + IH_COMP_ZSTD, /* zstd Compression Used */ + + IH_COMP_COUNT, +}; #define IH_MAGIC 0x27051956 /* Image Magic Number */ #define IH_NMLEN 32 /* Image Name Length */ /* - * all data in network byte order (aka natural aka bigendian) + * Legacy format image header, + * all data in network byte order (aka natural aka bigendian). */ - typedef struct uboot_image_header { uint32_t ih_magic; /* Image Header Magic Number */ uint32_t ih_hcrc; /* Image Header CRC Checksum */ From 8fe63fe8e512d77583d6798acd2164f1fa1e40ab Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 24 Mar 2022 21:48:12 +0800 Subject: [PATCH 486/935] hw/core: loader: Set is_linux to true for VxWorks uImage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VxWorks 7 uses the same boot interface as the Linux kernel on Arm (64-bit only), PowerPC and RISC-V architectures. Add logic to set is_linux to true for VxWorks uImage for these architectures in load_uboot_image(). Signed-off-by: Bin Meng Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-Id: <20220324134812.541274-2-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/core/loader.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/hw/core/loader.c b/hw/core/loader.c index 8167301f04..edde657ac3 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -696,6 +696,21 @@ static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr, if (is_linux) { if (hdr->ih_os == IH_OS_LINUX) { *is_linux = 1; + } else if (hdr->ih_os == IH_OS_VXWORKS) { + /* + * VxWorks 7 uses the same boot interface as the Linux kernel + * on Arm (64-bit only), PowerPC and RISC-V architectures. + */ + switch (hdr->ih_arch) { + case IH_ARCH_ARM64: + case IH_ARCH_PPC: + case IH_ARCH_RISCV: + *is_linux = 1; + break; + default: + *is_linux = 0; + break; + } } else { *is_linux = 0; } From 3d393bb7d3348142868d2af651500949881d41f0 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Wed, 25 May 2022 10:31:33 +0200 Subject: [PATCH 487/935] docs: add minibmc section in aspeed document MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Message-Id: <20220506031521.13254-2-jamin_lin@aspeedtech.com> Signed-off-by: Cédric Le Goater --- docs/system/arm/aspeed.rst | 61 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst index 60ed94f187..6f2e4fb53d 100644 --- a/docs/system/arm/aspeed.rst +++ b/docs/system/arm/aspeed.rst @@ -120,3 +120,64 @@ FMC chip and a bigger (64M) SPI chip, use : .. code-block:: bash -M ast2500-evb,fmc-model=mx25l25635e,spi-model=mx66u51235f + + +Aspeed minibmc family boards (``ast1030-evb``) +================================================================== + +The QEMU Aspeed machines model mini BMCs of various Aspeed evaluation +boards. They are based on different releases of the +Aspeed SoC : the AST1030 integrating an ARM Cortex M4F CPU (200MHz). + +The SoC comes with SRAM, SPI, I2C, etc. + +AST1030 SoC based machines : + +- ``ast1030-evb`` Aspeed AST1030 Evaluation board (Cortex-M4F) + +Supported devices +----------------- + + * SMP (for the AST1030 Cortex-M4F) + * Interrupt Controller (VIC) + * Timer Controller + * I2C Controller + * System Control Unit (SCU) + * SRAM mapping + * Static Memory Controller (SMC or FMC) - Only SPI Flash support + * SPI Memory Controller + * USB 2.0 Controller + * Watchdog Controller + * GPIO Controller (Master only) + * UART + * LPC Peripheral Controller (a subset of subdevices are supported) + * Hash/Crypto Engine (HACE) - Hash support only. TODO: HMAC and RSA + * ADC + + +Missing devices +--------------- + + * PWM and Fan Controller + * Slave GPIO Controller + * PECI Controller + * Mailbox Controller + * Virtual UART + * eSPI Controller + * I3C Controller + +Boot options +------------ + +The Aspeed machines can be started using the ``-kernel`` to load a +Zephyr OS or from a firmware. Images can be downloaded from the +ASPEED GitHub release repository : + + https://github.com/AspeedTech-BMC/zephyr/releases + +To boot a kernel directly from a Zephyr build tree: + +.. code-block:: bash + + $ qemu-system-arm -M ast1030-evb -nographic \ + -kernel zephyr.elf From fa699e80a80950ed31661dc8ea36a8b9aee9b094 Mon Sep 17 00:00:00 2001 From: Peter Delevoryas Date: Wed, 25 May 2022 10:31:33 +0200 Subject: [PATCH 488/935] hw/arm/aspeed: Add fby35 machine type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the 'fby35-bmc' machine type based on the kernel DTS[1] and userspace i2c setup scripts[2]. Undefined values are inherited from the AST2600-EVB. Reference images can be found in Facebook OpenBMC Github Release assets as "fby35.mtd". [3] You can boot the reference images as follows (fby35 uses dual-flash): qemu-system-arm -machine fby35-bmc \ -drive file=fby35.mtd,format=raw,if=mtd \ -drive file=fby35.mtd,format=raw,if=mtd \ -nographic [1] https://github.com/facebook/openbmc-linux/blob/412d5053258007117e94b1e36015aefc1301474b/arch/arm/boot/dts/aspeed-bmc-facebook-fby35.dts [2] https://github.com/facebook/openbmc/blob/e2294ff5d31dd65c248fe396a385286d6d5c463d/meta-facebook/meta-fby35/recipes-fby35/plat-utils/files/setup-dev.sh [3] https://github.com/facebook/openbmc/releases Signed-off-by: Peter Delevoryas Reviewed-by: Cédric Le Goater Message-Id: <20220503225925.1798324-2-pdel@fb.com> Signed-off-by: Cédric Le Goater --- hw/arm/aspeed.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index a74c13ab0f..725c169488 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -21,6 +21,7 @@ #include "hw/misc/led.h" #include "hw/qdev-properties.h" #include "sysemu/block-backend.h" +#include "sysemu/reset.h" #include "hw/loader.h" #include "qemu/error-report.h" #include "qemu/units.h" @@ -951,6 +952,35 @@ static void bletchley_bmc_i2c_init(AspeedMachineState *bmc) i2c_slave_create_simple(i2c[12], TYPE_PCA9552, 0x67); } +static void fby35_i2c_init(AspeedMachineState *bmc) +{ + AspeedSoCState *soc = &bmc->soc; + I2CBus *i2c[16]; + + for (int i = 0; i < 16; i++) { + i2c[i] = aspeed_i2c_get_bus(&soc->i2c, i); + } + + i2c_slave_create_simple(i2c[2], TYPE_LM75, 0x4f); + i2c_slave_create_simple(i2c[8], TYPE_TMP421, 0x1f); + /* Hotswap controller is actually supposed to be mp5920 or ltc4282. */ + i2c_slave_create_simple(i2c[11], "adm1272", 0x44); + i2c_slave_create_simple(i2c[12], TYPE_LM75, 0x4e); + i2c_slave_create_simple(i2c[12], TYPE_LM75, 0x4f); + + aspeed_eeprom_init(i2c[4], 0x51, 128 * KiB); + aspeed_eeprom_init(i2c[6], 0x51, 128 * KiB); + aspeed_eeprom_init(i2c[8], 0x50, 32 * KiB); + aspeed_eeprom_init(i2c[11], 0x51, 128 * KiB); + aspeed_eeprom_init(i2c[11], 0x54, 128 * KiB); + + /* + * TODO: There is a multi-master i2c connection to an AST1030 MiniBMC on + * buses 0, 1, 2, 3, and 9. Source address 0x10, target address 0x20 on + * each. + */ +} + static bool aspeed_get_mmio_exec(Object *obj, Error **errp) { return ASPEED_MACHINE(obj)->mmio_exec; @@ -1293,6 +1323,35 @@ static void aspeed_machine_bletchley_class_init(ObjectClass *oc, void *data) aspeed_soc_num_cpus(amc->soc_name); } +static void fby35_reset(MachineState *state) +{ + AspeedMachineState *bmc = ASPEED_MACHINE(state); + AspeedGPIOState *gpio = &bmc->soc.gpio; + + qemu_devices_reset(); + + /* Board ID */ + object_property_set_bool(OBJECT(gpio), "gpioV4", true, &error_fatal); + object_property_set_bool(OBJECT(gpio), "gpioV5", true, &error_fatal); + object_property_set_bool(OBJECT(gpio), "gpioV6", true, &error_fatal); + object_property_set_bool(OBJECT(gpio), "gpioV7", false, &error_fatal); +} + +static void aspeed_machine_fby35_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); + + mc->desc = "Facebook fby35 BMC (Cortex-A7)"; + mc->reset = fby35_reset; + amc->fmc_model = "mx66l1g45g"; + amc->num_cs = 2; + amc->macs_mask = ASPEED_MAC3_ON; + amc->i2c_init = fby35_i2c_init; + /* FIXME: Replace this macro with something more general */ + mc->default_ram_size = FUJI_BMC_RAM_SIZE; +} + #define AST1030_INTERNAL_FLASH_SIZE (1024 * 1024) /* Main SYSCLK frequency in Hz (200MHz) */ #define SYSCLK_FRQ 200000000ULL @@ -1411,6 +1470,10 @@ static const TypeInfo aspeed_machine_types[] = { .name = MACHINE_TYPE_NAME("bletchley-bmc"), .parent = TYPE_ASPEED_MACHINE, .class_init = aspeed_machine_bletchley_class_init, + }, { + .name = MACHINE_TYPE_NAME("fby35-bmc"), + .parent = MACHINE_TYPE_NAME("ast2600-evb"), + .class_init = aspeed_machine_fby35_class_init, }, { .name = MACHINE_TYPE_NAME("ast1030-evb"), .parent = TYPE_ASPEED_MACHINE, From 264a360ae0981a22e35b3e68b3eded1cac666afd Mon Sep 17 00:00:00 2001 From: Peter Delevoryas Date: Wed, 25 May 2022 10:31:33 +0200 Subject: [PATCH 489/935] docs: aspeed: Add fby35 board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add fby35 to the list of Aspeed boards. Signed-off-by: Peter Delevoryas Message-Id: <20220506193354.990532-2-pdel@fb.com> Signed-off-by: Cédric Le Goater --- docs/system/arm/aspeed.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst index 6f2e4fb53d..5d0a7865d3 100644 --- a/docs/system/arm/aspeed.rst +++ b/docs/system/arm/aspeed.rst @@ -31,6 +31,7 @@ AST2600 SoC based machines : - ``tacoma-bmc`` OpenPOWER Witherspoon POWER9 AST2600 BMC - ``rainier-bmc`` IBM Rainier POWER10 BMC - ``fuji-bmc`` Facebook Fuji BMC +- ``fby35-bmc`` Facebook fby35 BMC Supported devices ----------------- From 188052a13377ff1f88b433255005eb9082d048e5 Mon Sep 17 00:00:00 2001 From: Iris Chen Date: Wed, 25 May 2022 10:31:33 +0200 Subject: [PATCH 490/935] hw: m25p80: allow write_enable latch get/set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The write_enable latch property is not currently exposed. This commit makes it a modifiable property. Signed-off-by: Iris Chen Acked-by: Thomas Huth Reviewed-by: Cédric Le Goater Reviewed-by: Francisco Iglesias Message-Id: <20220513055022.951759-1-irischenlj@fb.com> Signed-off-by: Cédric Le Goater --- hw/block/m25p80.c | 1 + tests/qtest/aspeed_gpio-test.c | 40 +++++++------------------------ tests/qtest/aspeed_smc-test.c | 43 ++++++++++++++++++++++++++++++++++ tests/qtest/libqtest.c | 24 +++++++++++++++++++ tests/qtest/libqtest.h | 22 +++++++++++++++++ 5 files changed, 98 insertions(+), 32 deletions(-) diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index 7d3d8b12e0..81ba3da4df 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -1533,6 +1533,7 @@ static int m25p80_pre_save(void *opaque) static Property m25p80_properties[] = { /* This is default value for Micron flash */ + DEFINE_PROP_BOOL("write-enable", Flash, write_enable, false), DEFINE_PROP_UINT32("nonvolatile-cfg", Flash, nonvolatile_cfg, 0x8FFF), DEFINE_PROP_UINT8("spansion-cr1nv", Flash, spansion_cr1nv, 0x0), DEFINE_PROP_UINT8("spansion-cr2nv", Flash, spansion_cr2nv, 0x8), diff --git a/tests/qtest/aspeed_gpio-test.c b/tests/qtest/aspeed_gpio-test.c index c1003f2d1b..bac63e8742 100644 --- a/tests/qtest/aspeed_gpio-test.c +++ b/tests/qtest/aspeed_gpio-test.c @@ -28,30 +28,6 @@ #include "qapi/qmp/qdict.h" #include "libqtest-single.h" -static bool qom_get_bool(QTestState *s, const char *path, const char *property) -{ - QDict *r; - bool b; - - r = qtest_qmp(s, "{ 'execute': 'qom-get', 'arguments': " - "{ 'path': %s, 'property': %s } }", path, property); - b = qdict_get_bool(r, "return"); - qobject_unref(r); - - return b; -} - -static void qom_set_bool(QTestState *s, const char *path, const char *property, - bool value) -{ - QDict *r; - - r = qtest_qmp(s, "{ 'execute': 'qom-set', 'arguments': " - "{ 'path': %s, 'property': %s, 'value': %i } }", - path, property, value); - qobject_unref(r); -} - static void test_set_colocated_pins(const void *data) { QTestState *s = (QTestState *)data; @@ -60,14 +36,14 @@ static void test_set_colocated_pins(const void *data) * gpioV4-7 occupy bits within a single 32-bit value, so we want to make * sure that modifying one doesn't affect the other. */ - qom_set_bool(s, "/machine/soc/gpio", "gpioV4", true); - qom_set_bool(s, "/machine/soc/gpio", "gpioV5", false); - qom_set_bool(s, "/machine/soc/gpio", "gpioV6", true); - qom_set_bool(s, "/machine/soc/gpio", "gpioV7", false); - g_assert(qom_get_bool(s, "/machine/soc/gpio", "gpioV4")); - g_assert(!qom_get_bool(s, "/machine/soc/gpio", "gpioV5")); - g_assert(qom_get_bool(s, "/machine/soc/gpio", "gpioV6")); - g_assert(!qom_get_bool(s, "/machine/soc/gpio", "gpioV7")); + qtest_qom_set_bool(s, "/machine/soc/gpio", "gpioV4", true); + qtest_qom_set_bool(s, "/machine/soc/gpio", "gpioV5", false); + qtest_qom_set_bool(s, "/machine/soc/gpio", "gpioV6", true); + qtest_qom_set_bool(s, "/machine/soc/gpio", "gpioV7", false); + g_assert(qtest_qom_get_bool(s, "/machine/soc/gpio", "gpioV4")); + g_assert(!qtest_qom_get_bool(s, "/machine/soc/gpio", "gpioV5")); + g_assert(qtest_qom_get_bool(s, "/machine/soc/gpio", "gpioV6")); + g_assert(!qtest_qom_get_bool(s, "/machine/soc/gpio", "gpioV7")); } int main(int argc, char **argv) diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c index 87b40a0ef1..ec233315e6 100644 --- a/tests/qtest/aspeed_smc-test.c +++ b/tests/qtest/aspeed_smc-test.c @@ -26,6 +26,7 @@ #include "qemu/osdep.h" #include "qemu/bswap.h" #include "libqtest-single.h" +#include "qemu/bitops.h" /* * ASPEED SPI Controller registers @@ -40,6 +41,7 @@ #define CTRL_FREADMODE 0x1 #define CTRL_WRITEMODE 0x2 #define CTRL_USERMODE 0x3 +#define SR_WEL BIT(1) #define ASPEED_FMC_BASE 0x1E620000 #define ASPEED_FLASH_BASE 0x20000000 @@ -49,6 +51,8 @@ */ enum { JEDEC_READ = 0x9f, + RDSR = 0x5, + WRDI = 0x4, BULK_ERASE = 0xc7, READ = 0x03, PP = 0x02, @@ -348,6 +352,44 @@ static void test_write_page_mem(void) flash_reset(); } +static void test_read_status_reg(void) +{ + uint8_t r; + + spi_conf(CONF_ENABLE_W0); + + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, RDSR); + r = readb(ASPEED_FLASH_BASE); + spi_ctrl_stop_user(); + + g_assert_cmphex(r & SR_WEL, ==, 0); + g_assert(!qtest_qom_get_bool + (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable")); + + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, WREN); + writeb(ASPEED_FLASH_BASE, RDSR); + r = readb(ASPEED_FLASH_BASE); + spi_ctrl_stop_user(); + + g_assert_cmphex(r & SR_WEL, ==, SR_WEL); + g_assert(qtest_qom_get_bool + (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable")); + + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, WRDI); + writeb(ASPEED_FLASH_BASE, RDSR); + r = readb(ASPEED_FLASH_BASE); + spi_ctrl_stop_user(); + + g_assert_cmphex(r & SR_WEL, ==, 0); + g_assert(!qtest_qom_get_bool + (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable")); + + flash_reset(); +} + static char tmp_path[] = "/tmp/qtest.m25p80.XXXXXX"; int main(int argc, char **argv) @@ -373,6 +415,7 @@ int main(int argc, char **argv) qtest_add_func("/ast2400/smc/write_page", test_write_page); qtest_add_func("/ast2400/smc/read_page_mem", test_read_page_mem); qtest_add_func("/ast2400/smc/write_page_mem", test_write_page_mem); + qtest_add_func("/ast2400/smc/read_status_reg", test_read_status_reg); ret = g_test_run(); diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 2e49618454..8c159eacf5 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -1440,3 +1440,27 @@ void qtest_client_inproc_recv(void *opaque, const char *str) g_string_append(qts->rx, str); return; } + +void qtest_qom_set_bool(QTestState *s, const char *path, const char *property, + bool value) +{ + QDict *r; + + r = qtest_qmp(s, "{ 'execute': 'qom-set', 'arguments': " + "{ 'path': %s, 'property': %s, 'value': %i } }", + path, property, value); + qobject_unref(r); +} + +bool qtest_qom_get_bool(QTestState *s, const char *path, const char *property) +{ + QDict *r; + bool b; + + r = qtest_qmp(s, "{ 'execute': 'qom-get', 'arguments': " + "{ 'path': %s, 'property': %s } }", path, property); + b = qdict_get_bool(r, "return"); + qobject_unref(r); + + return b; +} diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h index 4ab0cad326..94b187837d 100644 --- a/tests/qtest/libqtest.h +++ b/tests/qtest/libqtest.h @@ -783,4 +783,26 @@ QTestState *qtest_inproc_init(QTestState **s, bool log, const char* arch, void (*send)(void*, const char*)); void qtest_client_inproc_recv(void *opaque, const char *str); + +/** + * qtest_qom_set_bool: + * @s: QTestState instance to operate on. + * @path: Path to the property being set. + * @property: Property being set. + * @value: Value to set the property. + * + * Set the property with passed in value. + */ +void qtest_qom_set_bool(QTestState *s, const char *path, const char *property, + bool value); + +/** + * qtest_qom_get_bool: + * @s: QTestState instance to operate on. + * @path: Path to the property being retrieved. + * @property: Property from where the value is being retrieved. + * + * Returns: Value retrieved from property. + */ +bool qtest_qom_get_bool(QTestState *s, const char *path, const char *property); #endif From 699db71520502836efc0e9102b0ffa6b0e5d0758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 25 May 2022 10:31:33 +0200 Subject: [PATCH 491/935] aspeed: Introduce a get_irq AspeedSoCClass method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit and make routine aspeed_soc_get_irq() common to all SoCs. This will be useful to share code. Cc: Jamin Lin Cc: Peter Delevoryas Reviewed-by: Peter Delevoryas Signed-off-by: Cédric Le Goater Message-Id: <20220516055620.2380197-1-clg@kaod.org> Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast10x0.c | 5 +++-- hw/arm/aspeed_ast2600.c | 5 +++-- hw/arm/aspeed_soc.c | 13 ++++++++++--- include/hw/arm/aspeed_soc.h | 3 +++ 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c index 4271549282..9ae9efaac1 100644 --- a/hw/arm/aspeed_ast10x0.c +++ b/hw/arm/aspeed_ast10x0.c @@ -61,11 +61,11 @@ static const int aspeed_soc_ast1030_irqmap[] = { [ASPEED_DEV_KCS] = 138, /* 138 -> 142 */ }; -static qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int ctrl) +static qemu_irq aspeed_soc_ast1030_get_irq(AspeedSoCState *s, int dev) { AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); - return qdev_get_gpio_in(DEVICE(&s->armv7m), sc->irqmap[ctrl]); + return qdev_get_gpio_in(DEVICE(&s->armv7m), sc->irqmap[dev]); } static void aspeed_soc_ast1030_init(Object *obj) @@ -280,6 +280,7 @@ static void aspeed_soc_ast1030_class_init(ObjectClass *klass, void *data) sc->irqmap = aspeed_soc_ast1030_irqmap; sc->memmap = aspeed_soc_ast1030_memmap; sc->num_cpus = 1; + sc->get_irq = aspeed_soc_ast1030_get_irq; } static const TypeInfo aspeed_soc_ast1030_type_info = { diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index eedda7badc..4161a0cc4b 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -114,11 +114,11 @@ static const int aspeed_soc_ast2600_irqmap[] = { [ASPEED_DEV_I3C] = 102, /* 102 -> 107 */ }; -static qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int ctrl) +static qemu_irq aspeed_soc_ast2600_get_irq(AspeedSoCState *s, int dev) { AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); - return qdev_get_gpio_in(DEVICE(&s->a7mpcore), sc->irqmap[ctrl]); + return qdev_get_gpio_in(DEVICE(&s->a7mpcore), sc->irqmap[dev]); } static void aspeed_soc_ast2600_init(Object *obj) @@ -572,6 +572,7 @@ static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data) sc->irqmap = aspeed_soc_ast2600_irqmap; sc->memmap = aspeed_soc_ast2600_memmap; sc->num_cpus = 2; + sc->get_irq = aspeed_soc_ast2600_get_irq; } static const TypeInfo aspeed_soc_ast2600_type_info = { diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 58714cb2a0..c339b5c74d 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -121,11 +121,11 @@ static const int aspeed_soc_ast2400_irqmap[] = { #define aspeed_soc_ast2500_irqmap aspeed_soc_ast2400_irqmap -static qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int ctrl) +static qemu_irq aspeed_soc_ast2400_get_irq(AspeedSoCState *s, int dev) { AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); - return qdev_get_gpio_in(DEVICE(&s->vic), sc->irqmap[ctrl]); + return qdev_get_gpio_in(DEVICE(&s->vic), sc->irqmap[dev]); } static void aspeed_soc_init(Object *obj) @@ -487,6 +487,7 @@ static void aspeed_soc_ast2400_class_init(ObjectClass *oc, void *data) sc->irqmap = aspeed_soc_ast2400_irqmap; sc->memmap = aspeed_soc_ast2400_memmap; sc->num_cpus = 1; + sc->get_irq = aspeed_soc_ast2400_get_irq; } static const TypeInfo aspeed_soc_ast2400_type_info = { @@ -512,6 +513,7 @@ static void aspeed_soc_ast2500_class_init(ObjectClass *oc, void *data) sc->irqmap = aspeed_soc_ast2500_irqmap; sc->memmap = aspeed_soc_ast2500_memmap; sc->num_cpus = 1; + sc->get_irq = aspeed_soc_ast2400_get_irq; } static const TypeInfo aspeed_soc_ast2500_type_info = { @@ -528,4 +530,9 @@ static void aspeed_soc_register_types(void) type_register_static(&aspeed_soc_ast2500_type_info); }; -type_init(aspeed_soc_register_types) +type_init(aspeed_soc_register_types); + +qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev) +{ + return ASPEED_SOC_GET_CLASS(s)->get_irq(s, dev); +} diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index e13af374b9..3789f38603 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -94,6 +94,7 @@ struct AspeedSoCClass { const int *irqmap; const hwaddr *memmap; uint32_t num_cpus; + qemu_irq (*get_irq)(AspeedSoCState *s, int dev); }; @@ -153,4 +154,6 @@ enum { ASPEED_DEV_I3C, }; +qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev); + #endif /* ASPEED_SOC_H */ From ab5e86053d16721b5b92780e23bc3104fdcb1f05 Mon Sep 17 00:00:00 2001 From: Peter Delevoryas Date: Wed, 25 May 2022 10:31:33 +0200 Subject: [PATCH 492/935] hw: aspeed: Add missing UART's MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the missing UART memory and IRQ mappings for the AST2400, AST2500, AST2600, and AST1030. This also includes the new UART interfaces added in the AST2600 and AST1030 from UART6 to UART13. The addresses and interrupt numbers for these two later chips are identical. Signed-off-by: Peter Delevoryas Reviewed-by: Cédric Le Goater Message-Id: <20220516062328.298336-2-pdel@fb.com> Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast10x0.c | 24 ++++++++++++++++++++++++ hw/arm/aspeed_ast2600.c | 19 +++++++++++++++++++ hw/arm/aspeed_soc.c | 6 ++++++ include/hw/arm/aspeed_soc.h | 8 ++++++++ 4 files changed, 57 insertions(+) diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c index 9ae9efaac1..fa2cc4406c 100644 --- a/hw/arm/aspeed_ast10x0.c +++ b/hw/arm/aspeed_ast10x0.c @@ -33,14 +33,38 @@ static const hwaddr aspeed_soc_ast1030_memmap[] = { [ASPEED_DEV_SBC] = 0x7E6F2000, [ASPEED_DEV_GPIO] = 0x7E780000, [ASPEED_DEV_TIMER1] = 0x7E782000, + [ASPEED_DEV_UART1] = 0x7E783000, + [ASPEED_DEV_UART2] = 0x7E78D000, + [ASPEED_DEV_UART3] = 0x7E78E000, + [ASPEED_DEV_UART4] = 0x7E78F000, [ASPEED_DEV_UART5] = 0x7E784000, + [ASPEED_DEV_UART6] = 0x7E790000, + [ASPEED_DEV_UART7] = 0x7E790100, + [ASPEED_DEV_UART8] = 0x7E790200, + [ASPEED_DEV_UART9] = 0x7E790300, + [ASPEED_DEV_UART10] = 0x7E790400, + [ASPEED_DEV_UART11] = 0x7E790500, + [ASPEED_DEV_UART12] = 0x7E790600, + [ASPEED_DEV_UART13] = 0x7E790700, [ASPEED_DEV_WDT] = 0x7E785000, [ASPEED_DEV_LPC] = 0x7E789000, [ASPEED_DEV_I2C] = 0x7E7B0000, }; static const int aspeed_soc_ast1030_irqmap[] = { + [ASPEED_DEV_UART1] = 47, + [ASPEED_DEV_UART2] = 48, + [ASPEED_DEV_UART3] = 49, + [ASPEED_DEV_UART4] = 50, [ASPEED_DEV_UART5] = 8, + [ASPEED_DEV_UART6] = 57, + [ASPEED_DEV_UART7] = 58, + [ASPEED_DEV_UART8] = 59, + [ASPEED_DEV_UART9] = 60, + [ASPEED_DEV_UART10] = 61, + [ASPEED_DEV_UART11] = 62, + [ASPEED_DEV_UART12] = 63, + [ASPEED_DEV_UART13] = 64, [ASPEED_DEV_GPIO] = 11, [ASPEED_DEV_TIMER1] = 16, [ASPEED_DEV_TIMER2] = 17, diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 4161a0cc4b..f3ecc0f3b7 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -61,7 +61,18 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = { [ASPEED_DEV_IBT] = 0x1E789140, [ASPEED_DEV_I2C] = 0x1E78A000, [ASPEED_DEV_UART1] = 0x1E783000, + [ASPEED_DEV_UART2] = 0x1E78D000, + [ASPEED_DEV_UART3] = 0x1E78E000, + [ASPEED_DEV_UART4] = 0x1E78F000, [ASPEED_DEV_UART5] = 0x1E784000, + [ASPEED_DEV_UART6] = 0x1E790000, + [ASPEED_DEV_UART7] = 0x1E790100, + [ASPEED_DEV_UART8] = 0x1E790200, + [ASPEED_DEV_UART9] = 0x1E790300, + [ASPEED_DEV_UART10] = 0x1E790400, + [ASPEED_DEV_UART11] = 0x1E790500, + [ASPEED_DEV_UART12] = 0x1E790600, + [ASPEED_DEV_UART13] = 0x1E790700, [ASPEED_DEV_VUART] = 0x1E787000, [ASPEED_DEV_I3C] = 0x1E7A0000, [ASPEED_DEV_SDRAM] = 0x80000000, @@ -78,6 +89,14 @@ static const int aspeed_soc_ast2600_irqmap[] = { [ASPEED_DEV_UART3] = 49, [ASPEED_DEV_UART4] = 50, [ASPEED_DEV_UART5] = 8, + [ASPEED_DEV_UART6] = 57, + [ASPEED_DEV_UART7] = 58, + [ASPEED_DEV_UART8] = 59, + [ASPEED_DEV_UART9] = 60, + [ASPEED_DEV_UART10] = 61, + [ASPEED_DEV_UART11] = 62, + [ASPEED_DEV_UART12] = 63, + [ASPEED_DEV_UART13] = 64, [ASPEED_DEV_VUART] = 8, [ASPEED_DEV_FMC] = 39, [ASPEED_DEV_SDMC] = 0, diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index c339b5c74d..96bc060680 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -48,6 +48,9 @@ static const hwaddr aspeed_soc_ast2400_memmap[] = { [ASPEED_DEV_ETH1] = 0x1E660000, [ASPEED_DEV_ETH2] = 0x1E680000, [ASPEED_DEV_UART1] = 0x1E783000, + [ASPEED_DEV_UART2] = 0x1E78D000, + [ASPEED_DEV_UART3] = 0x1E78E000, + [ASPEED_DEV_UART4] = 0x1E78F000, [ASPEED_DEV_UART5] = 0x1E784000, [ASPEED_DEV_VUART] = 0x1E787000, [ASPEED_DEV_SDRAM] = 0x40000000, @@ -80,6 +83,9 @@ static const hwaddr aspeed_soc_ast2500_memmap[] = { [ASPEED_DEV_ETH1] = 0x1E660000, [ASPEED_DEV_ETH2] = 0x1E680000, [ASPEED_DEV_UART1] = 0x1E783000, + [ASPEED_DEV_UART2] = 0x1E78D000, + [ASPEED_DEV_UART3] = 0x1E78E000, + [ASPEED_DEV_UART4] = 0x1E78F000, [ASPEED_DEV_UART5] = 0x1E784000, [ASPEED_DEV_VUART] = 0x1E787000, [ASPEED_DEV_SDRAM] = 0x80000000, diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index 3789f38603..709a78285b 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -105,6 +105,14 @@ enum { ASPEED_DEV_UART3, ASPEED_DEV_UART4, ASPEED_DEV_UART5, + ASPEED_DEV_UART6, + ASPEED_DEV_UART7, + ASPEED_DEV_UART8, + ASPEED_DEV_UART9, + ASPEED_DEV_UART10, + ASPEED_DEV_UART11, + ASPEED_DEV_UART12, + ASPEED_DEV_UART13, ASPEED_DEV_VUART, ASPEED_DEV_FMC, ASPEED_DEV_SPI1, From c5e1bdb9e243ad5563196175415f42e459040367 Mon Sep 17 00:00:00 2001 From: Peter Delevoryas Date: Wed, 25 May 2022 10:31:33 +0200 Subject: [PATCH 493/935] hw: aspeed: Add uarts_num SoC attribute MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AST2400 and AST2500 have 5 UART's, while the AST2600 and AST1030 have 13. Signed-off-by: Peter Delevoryas Reviewed-by: Cédric Le Goater Message-Id: <20220516062328.298336-3-pdel@fb.com> Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast10x0.c | 1 + hw/arm/aspeed_ast2600.c | 1 + hw/arm/aspeed_soc.c | 2 ++ include/hw/arm/aspeed_soc.h | 1 + 4 files changed, 5 insertions(+) diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c index fa2cc4406c..bb8177e86c 100644 --- a/hw/arm/aspeed_ast10x0.c +++ b/hw/arm/aspeed_ast10x0.c @@ -301,6 +301,7 @@ static void aspeed_soc_ast1030_class_init(ObjectClass *klass, void *data) sc->ehcis_num = 0; sc->wdts_num = 4; sc->macs_num = 1; + sc->uarts_num = 13; sc->irqmap = aspeed_soc_ast1030_irqmap; sc->memmap = aspeed_soc_ast1030_memmap; sc->num_cpus = 1; diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index f3ecc0f3b7..a9523074a0 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -588,6 +588,7 @@ static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data) sc->ehcis_num = 2; sc->wdts_num = 4; sc->macs_num = 4; + sc->uarts_num = 13; sc->irqmap = aspeed_soc_ast2600_irqmap; sc->memmap = aspeed_soc_ast2600_memmap; sc->num_cpus = 2; diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 96bc060680..7008cd1af7 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -490,6 +490,7 @@ static void aspeed_soc_ast2400_class_init(ObjectClass *oc, void *data) sc->ehcis_num = 1; sc->wdts_num = 2; sc->macs_num = 2; + sc->uarts_num = 5; sc->irqmap = aspeed_soc_ast2400_irqmap; sc->memmap = aspeed_soc_ast2400_memmap; sc->num_cpus = 1; @@ -516,6 +517,7 @@ static void aspeed_soc_ast2500_class_init(ObjectClass *oc, void *data) sc->ehcis_num = 2; sc->wdts_num = 3; sc->macs_num = 2; + sc->uarts_num = 5; sc->irqmap = aspeed_soc_ast2500_irqmap; sc->memmap = aspeed_soc_ast2500_memmap; sc->num_cpus = 1; diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index 709a78285b..669bc49855 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -91,6 +91,7 @@ struct AspeedSoCClass { int ehcis_num; int wdts_num; int macs_num; + int uarts_num; const int *irqmap; const hwaddr *memmap; uint32_t num_cpus; From 94d10f42109a5ba23e26012722b16f0f479990cb Mon Sep 17 00:00:00 2001 From: Peter Delevoryas Date: Wed, 25 May 2022 10:31:33 +0200 Subject: [PATCH 494/935] hw: aspeed: Ensure AST1030 respects uart-default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AST1030 machine initialization was not respecting the Aspeed SoC property "uart-default", which specifies which UART should be connected to the first serial device, it was just always connecting UART5. This doesn't change any behavior, because the default value for "uart-default" is UART5, but it makes it possible to override this in new machine definitions using the AST1030. Signed-off-by: Peter Delevoryas Reviewed-by: Cédric Le Goater Message-Id: <20220516062328.298336-4-pdel@fb.com> Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast10x0.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c index bb8177e86c..faafb800f3 100644 --- a/hw/arm/aspeed_ast10x0.c +++ b/hw/arm/aspeed_ast10x0.c @@ -215,9 +215,9 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) qdev_get_gpio_in(DEVICE(&s->armv7m), sc->irqmap[ASPEED_DEV_KCS] + aspeed_lpc_kcs_4)); - /* UART5 - attach an 8250 to the IO space as our UART */ - serial_mm_init(get_system_memory(), sc->memmap[ASPEED_DEV_UART5], 2, - aspeed_soc_get_irq(s, ASPEED_DEV_UART5), + /* UART - attach an 8250 to the IO space as our UART */ + serial_mm_init(get_system_memory(), sc->memmap[s->uart_default], 2, + aspeed_soc_get_irq(s, s->uart_default), 38400, serial_hd(0), DEVICE_LITTLE_ENDIAN); /* Timer */ From 470253b6d05ecec4bf7c8f8616db779454414292 Mon Sep 17 00:00:00 2001 From: Peter Delevoryas Date: Wed, 25 May 2022 10:31:33 +0200 Subject: [PATCH 495/935] hw: aspeed: Introduce common UART init function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Peter Delevoryas Reviewed-by: Cédric Le Goater Message-Id: <20220516062328.298336-5-pdel@fb.com> Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast10x0.c | 7 ++----- hw/arm/aspeed_ast2600.c | 7 ++----- hw/arm/aspeed_soc.c | 16 ++++++++++++---- include/hw/arm/aspeed_soc.h | 1 + 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c index faafb800f3..938615d55f 100644 --- a/hw/arm/aspeed_ast10x0.c +++ b/hw/arm/aspeed_ast10x0.c @@ -15,7 +15,6 @@ #include "sysemu/sysemu.h" #include "hw/qdev-clock.h" #include "hw/misc/unimp.h" -#include "hw/char/serial.h" #include "hw/arm/aspeed_soc.h" #define ASPEED_SOC_IOMEM_SIZE 0x00200000 @@ -215,10 +214,8 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) qdev_get_gpio_in(DEVICE(&s->armv7m), sc->irqmap[ASPEED_DEV_KCS] + aspeed_lpc_kcs_4)); - /* UART - attach an 8250 to the IO space as our UART */ - serial_mm_init(get_system_memory(), sc->memmap[s->uart_default], 2, - aspeed_soc_get_irq(s, s->uart_default), - 38400, serial_hd(0), DEVICE_LITTLE_ENDIAN); + /* UART */ + aspeed_soc_uart_init(s); /* Timer */ object_property_set_link(OBJECT(&s->timerctrl), "scu", OBJECT(&s->scu), diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index a9523074a0..b0a4199b69 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -11,7 +11,6 @@ #include "qapi/error.h" #include "hw/misc/unimp.h" #include "hw/arm/aspeed_soc.h" -#include "hw/char/serial.h" #include "qemu/module.h" #include "qemu/error-report.h" #include "hw/i2c/aspeed_i2c.h" @@ -372,10 +371,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0, aspeed_soc_get_irq(s, ASPEED_DEV_ADC)); - /* UART - attach an 8250 to the IO space as our UART */ - serial_mm_init(get_system_memory(), sc->memmap[s->uart_default], 2, - aspeed_soc_get_irq(s, s->uart_default), 38400, - serial_hd(0), DEVICE_LITTLE_ENDIAN); + /* UART */ + aspeed_soc_uart_init(s); /* I2C */ object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr), diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 7008cd1af7..912798a9c9 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -303,10 +303,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0, aspeed_soc_get_irq(s, ASPEED_DEV_ADC)); - /* UART - attach an 8250 to the IO space as our UART */ - serial_mm_init(get_system_memory(), sc->memmap[s->uart_default], 2, - aspeed_soc_get_irq(s, s->uart_default), 38400, - serial_hd(0), DEVICE_LITTLE_ENDIAN); + /* UART */ + aspeed_soc_uart_init(s); /* I2C */ object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr), @@ -544,3 +542,13 @@ qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev) { return ASPEED_SOC_GET_CLASS(s)->get_irq(s, dev); } + +void aspeed_soc_uart_init(AspeedSoCState *s) +{ + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + + /* Attach an 8250 to the IO space as our UART */ + serial_mm_init(get_system_memory(), sc->memmap[s->uart_default], 2, + aspeed_soc_get_irq(s, s->uart_default), 38400, + serial_hd(0), DEVICE_LITTLE_ENDIAN); +} diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index 669bc49855..02a5a9ffcb 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -164,5 +164,6 @@ enum { }; qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev); +void aspeed_soc_uart_init(AspeedSoCState *s); #endif /* ASPEED_SOC_H */ From 6827ff20b2975e84045ba356ba3e6aadc686a53c Mon Sep 17 00:00:00 2001 From: Peter Delevoryas Date: Wed, 25 May 2022 10:31:33 +0200 Subject: [PATCH 496/935] hw: aspeed: Init all UART's with serial devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Background: AspeedMachineClass.uart_default specifies the serial console UART, which usually corresponds to the "stdout-path" in the device tree. The default value is UART5, since most boards use UART5 for this: amc->uart_default = ASPEED_DEV_UART5; Users can override AspeedMachineClass.uart_default in their board's machine class init to specify something besides UART5. For example, for fuji-bmc: amc->uart_default = ASPEED_DEV_UART1; We only connect this one UART, of the 5 UART's on the AST2400 and AST2500 and the 13 UART's on the AST2600 and AST1030, to a serial device that QEMU users can use. None of the other UART's are initialized, and the only way to override this attribute is by creating a specialized board definition, requiring QEMU source code changes and rebuilding. The result of this is that if you want to get serial console output on a board that uses UART3, you need to add a board definition. This was encountered by Zev in OpenBMC. [1] Changes: This commit initializes all of the UART's present on each Aspeed chip with serial devices and allows the QEMU user to connect as many or few as they like to serial devices. For example, you can still run QEMU and just connect stdout to the machine's default UART, without specifying any additional serial devices: qemu-system-arm -machine fuji-bmc \ -drive file=fuji.mtd,format=raw,if=mtd \ -nographic However, if you don't want to add a special machine definition, you can now manually configure UART1 to connect to stdout and get serial console output, even if the machine's default is UART5: qemu-system-arm -machine ast2600-evb \ -drive file=fuji.mtd,format=raw,if=mtd \ -serial null -serial mon:stdio -display none In the example above, the first "-serial null" argument is connected to UART5, and "-serial mon:stdio" is connected to UART1. Another example: you can get serial console output from Wedge100, which uses UART3, by reusing the palmetto AST2400 machine and rewiring the serial device arguments: qemu-system-arm -machine palmetto-bmc \ -drive file=wedge100.mtd,format=raw,if=mtd \ -serial null -serial null -serial null \ -serial mon:stdio -display none There is a slight change in behavior introduced with this change: now, each UART's memory-mapped IO region will have a serial device model connected to it. Previously, all reads and writes to those regions would be ineffective and return zero values, but now some values will be nonzero, even when the user doesn't connect a serial device backend (like a socket, file, etc). For example, the line status register might indicate that the transmit buffer is empty now, whereas previously it might have always indicated it was full. [1] https://lore.kernel.org/openbmc/YnzGnWjkYdMUUNyM@hatter.bewilderbeest.net/ [2] https://github.com/facebook/openbmc/releases/download/v2021.49.0/fuji.mtd [3] https://github.com/facebook/openbmc/releases/download/v2021.49.0/wedge100.mtd Signed-off-by: Peter Delevoryas Reviewed-by: Cédric Le Goater Message-Id: <20220516062328.298336-6-pdel@fb.com> Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_soc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 912798a9c9..30574d4276 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -546,9 +546,18 @@ qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev) void aspeed_soc_uart_init(AspeedSoCState *s) { AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + int i, uart; /* Attach an 8250 to the IO space as our UART */ serial_mm_init(get_system_memory(), sc->memmap[s->uart_default], 2, aspeed_soc_get_irq(s, s->uart_default), 38400, serial_hd(0), DEVICE_LITTLE_ENDIAN); + for (i = 1, uart = ASPEED_DEV_UART1; i < sc->uarts_num; i++, uart++) { + if (uart == s->uart_default) { + uart++; + } + serial_mm_init(get_system_memory(), sc->memmap[uart], 2, + aspeed_soc_get_irq(s, uart), 38400, + serial_hd(i), DEVICE_LITTLE_ENDIAN); + } } From 7b1d21a8ba1e6091f1e54c74e7c664e26300accc Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Wed, 25 May 2022 10:31:33 +0200 Subject: [PATCH 497/935] hw/gpio Add GPIO read/write trace event. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add GPIO read/write trace event for aspeed model. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Message-Id: <20220525053444.27228-2-jamin_lin@aspeedtech.com> Signed-off-by: Cédric Le Goater --- hw/gpio/aspeed_gpio.c | 54 +++++++++++++++++++++++++++++++------------ hw/gpio/trace-events | 4 ++++ 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index 9b736e7a9f..4620ea8e8b 100644 --- a/hw/gpio/aspeed_gpio.c +++ b/hw/gpio/aspeed_gpio.c @@ -15,6 +15,7 @@ #include "qapi/visitor.h" #include "hw/irq.h" #include "migration/vmstate.h" +#include "trace.h" #define GPIOS_PER_GROUP 8 @@ -523,11 +524,15 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr offset, uint32_t size) uint64_t idx = -1; const AspeedGPIOReg *reg; GPIOSets *set; + uint32_t value = 0; + uint64_t debounce_value; idx = offset >> 2; if (idx >= GPIO_DEBOUNCE_TIME_1 && idx <= GPIO_DEBOUNCE_TIME_3) { idx -= GPIO_DEBOUNCE_TIME_1; - return (uint64_t) s->debounce_regs[idx]; + debounce_value = (uint64_t) s->debounce_regs[idx]; + trace_aspeed_gpio_read(offset, debounce_value); + return debounce_value; } reg = &agc->reg_table[idx]; @@ -540,38 +545,55 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr offset, uint32_t size) set = &s->sets[reg->set_idx]; switch (reg->type) { case gpio_reg_data_value: - return set->data_value; + value = set->data_value; + break; case gpio_reg_direction: - return set->direction; + value = set->direction; + break; case gpio_reg_int_enable: - return set->int_enable; + value = set->int_enable; + break; case gpio_reg_int_sens_0: - return set->int_sens_0; + value = set->int_sens_0; + break; case gpio_reg_int_sens_1: - return set->int_sens_1; + value = set->int_sens_1; + break; case gpio_reg_int_sens_2: - return set->int_sens_2; + value = set->int_sens_2; + break; case gpio_reg_int_status: - return set->int_status; + value = set->int_status; + break; case gpio_reg_reset_tolerant: - return set->reset_tol; + value = set->reset_tol; + break; case gpio_reg_debounce_1: - return set->debounce_1; + value = set->debounce_1; + break; case gpio_reg_debounce_2: - return set->debounce_2; + value = set->debounce_2; + break; case gpio_reg_cmd_source_0: - return set->cmd_source_0; + value = set->cmd_source_0; + break; case gpio_reg_cmd_source_1: - return set->cmd_source_1; + value = set->cmd_source_1; + break; case gpio_reg_data_read: - return set->data_read; + value = set->data_read; + break; case gpio_reg_input_mask: - return set->input_mask; + value = set->input_mask; + break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: no getter for offset 0x%" HWADDR_PRIx"\n", __func__, offset); return 0; } + + trace_aspeed_gpio_read(offset, value); + return value; } static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data, @@ -585,6 +607,8 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data, GPIOSets *set; uint32_t cleared; + trace_aspeed_gpio_write(offset, data); + idx = offset >> 2; if (idx >= GPIO_DEBOUNCE_TIME_1 && idx <= GPIO_DEBOUNCE_TIME_3) { idx -= GPIO_DEBOUNCE_TIME_1; diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events index 1dab99c560..9736b362ac 100644 --- a/hw/gpio/trace-events +++ b/hw/gpio/trace-events @@ -27,3 +27,7 @@ sifive_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" P sifive_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64 sifive_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64 sifive_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64 + +# aspeed_gpio.c +aspeed_gpio_read(uint64_t offset, uint64_t value) "offset: 0x%" PRIx64 " value 0x%" PRIx64 +aspeed_gpio_write(uint64_t offset, uint64_t value) "offset: 0x%" PRIx64 " value 0x%" PRIx64 From 17075ef244d4ca52f7f097927c72b0e09f8d8a5c Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Wed, 25 May 2022 10:31:33 +0200 Subject: [PATCH 498/935] hw/gpio: Add ASPEED GPIO model for AST1030 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AST1030 integrates one set of Parallel GPIO Controller with maximum 151 control pins, which are 21 groups (A~U, exclude pin: M6 M7 Q5 Q6 Q7 R0 R1 R4 R5 R6 R7 S0 S3 S4 S5 S6 S7 ) and the group T and U are input only. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Message-Id: <20220525053444.27228-3-jamin_lin@aspeedtech.com> Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast10x0.c | 11 +++++++++++ hw/gpio/aspeed_gpio.c | 27 +++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c index 938615d55f..d534541684 100644 --- a/hw/arm/aspeed_ast10x0.c +++ b/hw/arm/aspeed_ast10x0.c @@ -136,6 +136,9 @@ static void aspeed_soc_ast1030_init(Object *obj) snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname); object_initialize_child(obj, "wdt[*]", &s->wdt[i], typename); } + + snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname); + object_initialize_child(obj, "gpio", &s->gpio, typename); } static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) @@ -281,6 +284,14 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, sc->memmap[ASPEED_DEV_WDT] + i * awc->offset); } + + /* GPIO */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, sc->memmap[ASPEED_DEV_GPIO]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0, + aspeed_soc_get_irq(s, ASPEED_DEV_GPIO)); } static void aspeed_soc_ast1030_class_init(ObjectClass *klass, void *data) diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index 4620ea8e8b..5138fe812b 100644 --- a/hw/gpio/aspeed_gpio.c +++ b/hw/gpio/aspeed_gpio.c @@ -819,6 +819,15 @@ static GPIOSetProperties ast2600_1_8v_set_props[ASPEED_GPIO_MAX_NR_SETS] = { [1] = {0x0000000f, 0x0000000f, {"18E"} }, }; +static GPIOSetProperties ast1030_set_props[ASPEED_GPIO_MAX_NR_SETS] = { + [0] = {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} }, + [1] = {0xffffffff, 0xffffffff, {"E", "F", "G", "H"} }, + [2] = {0xffffffff, 0xffffffff, {"I", "J", "K", "L"} }, + [3] = {0xffffff3f, 0xffffff3f, {"M", "N", "O", "P"} }, + [4] = {0xff060c1f, 0x00060c1f, {"Q", "R", "S", "T"} }, + [5] = {0x000000ff, 0x00000000, {"U"} }, +}; + static const MemoryRegionOps aspeed_gpio_ops = { .read = aspeed_gpio_read, .write = aspeed_gpio_write, @@ -971,6 +980,16 @@ static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data) agc->reg_table = aspeed_1_8v_gpios; } +static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data) +{ + AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass); + + agc->props = ast1030_set_props; + agc->nr_gpio_pins = 151; + agc->nr_gpio_sets = 6; + agc->reg_table = aspeed_3_3v_gpios; +} + static const TypeInfo aspeed_gpio_info = { .name = TYPE_ASPEED_GPIO, .parent = TYPE_SYS_BUS_DEVICE, @@ -1008,6 +1027,13 @@ static const TypeInfo aspeed_gpio_ast2600_1_8v_info = { .instance_init = aspeed_gpio_init, }; +static const TypeInfo aspeed_gpio_ast1030_info = { + .name = TYPE_ASPEED_GPIO "-ast1030", + .parent = TYPE_ASPEED_GPIO, + .class_init = aspeed_gpio_1030_class_init, + .instance_init = aspeed_gpio_init, +}; + static void aspeed_gpio_register_types(void) { type_register_static(&aspeed_gpio_info); @@ -1015,6 +1041,7 @@ static void aspeed_gpio_register_types(void) type_register_static(&aspeed_gpio_ast2500_info); type_register_static(&aspeed_gpio_ast2600_3_3v_info); type_register_static(&aspeed_gpio_ast2600_1_8v_info); + type_register_static(&aspeed_gpio_ast1030_info); } type_init(aspeed_gpio_register_types); From 247c00294a4b3cc694f24811eef07e57eb67aa82 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Wed, 25 May 2022 10:31:33 +0200 Subject: [PATCH 499/935] hw/gpio support GPIO index mode for write operation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It did not support GPIO index mode for read operation. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Message-Id: <20220525053444.27228-4-jamin_lin@aspeedtech.com> Signed-off-by: Cédric Le Goater --- hw/gpio/aspeed_gpio.c | 168 ++++++++++++++++++++++++++++++++++ include/hw/gpio/aspeed_gpio.h | 14 +++ 2 files changed, 182 insertions(+) diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index 5138fe812b..c834bf19f5 100644 --- a/hw/gpio/aspeed_gpio.c +++ b/hw/gpio/aspeed_gpio.c @@ -16,6 +16,7 @@ #include "hw/irq.h" #include "migration/vmstate.h" #include "trace.h" +#include "hw/registerfields.h" #define GPIOS_PER_GROUP 8 @@ -204,6 +205,28 @@ #define GPIO_1_8V_MEM_SIZE 0x1D8 #define GPIO_1_8V_REG_ARRAY_SIZE (GPIO_1_8V_MEM_SIZE >> 2) +/* + * GPIO index mode support + * It only supports write operation + */ +REG32(GPIO_INDEX_REG, 0x2AC) + FIELD(GPIO_INDEX_REG, NUMBER, 0, 8) + FIELD(GPIO_INDEX_REG, COMMAND, 12, 1) + FIELD(GPIO_INDEX_REG, TYPE, 16, 4) + FIELD(GPIO_INDEX_REG, DATA_VALUE, 20, 1) + FIELD(GPIO_INDEX_REG, DIRECTION, 20, 1) + FIELD(GPIO_INDEX_REG, INT_ENABLE, 20, 1) + FIELD(GPIO_INDEX_REG, INT_SENS_0, 21, 1) + FIELD(GPIO_INDEX_REG, INT_SENS_1, 22, 1) + FIELD(GPIO_INDEX_REG, INT_SENS_2, 23, 1) + FIELD(GPIO_INDEX_REG, INT_STATUS, 24, 1) + FIELD(GPIO_INDEX_REG, DEBOUNCE_1, 20, 1) + FIELD(GPIO_INDEX_REG, DEBOUNCE_2, 21, 1) + FIELD(GPIO_INDEX_REG, RESET_TOLERANT, 20, 1) + FIELD(GPIO_INDEX_REG, COMMAND_SRC_0, 20, 1) + FIELD(GPIO_INDEX_REG, COMMAND_SRC_1, 21, 1) + FIELD(GPIO_INDEX_REG, INPUT_MASK, 20, 1) + static int aspeed_evaluate_irq(GPIOSets *regs, int gpio_prev_high, int gpio) { uint32_t falling_edge = 0, rising_edge = 0; @@ -596,6 +619,144 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr offset, uint32_t size) return value; } +static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset, + uint64_t data, uint32_t size) +{ + + AspeedGPIOState *s = ASPEED_GPIO(opaque); + AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s); + const GPIOSetProperties *props; + GPIOSets *set; + uint32_t reg_idx_number = FIELD_EX32(data, GPIO_INDEX_REG, NUMBER); + uint32_t reg_idx_type = FIELD_EX32(data, GPIO_INDEX_REG, TYPE); + uint32_t reg_idx_command = FIELD_EX32(data, GPIO_INDEX_REG, COMMAND); + uint32_t set_idx = reg_idx_number / ASPEED_GPIOS_PER_SET; + uint32_t pin_idx = reg_idx_number % ASPEED_GPIOS_PER_SET; + uint32_t group_idx = pin_idx / GPIOS_PER_GROUP; + uint32_t reg_value = 0; + uint32_t cleared; + + set = &s->sets[set_idx]; + props = &agc->props[set_idx]; + + if (reg_idx_command) + qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%" PRIx64 "data 0x%" + PRIx64 "index mode wrong command 0x%x\n", + __func__, offset, data, reg_idx_command); + + switch (reg_idx_type) { + case gpio_reg_idx_data: + reg_value = set->data_read; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, DATA_VALUE)); + reg_value &= props->output; + reg_value = update_value_control_source(set, set->data_value, + reg_value); + set->data_read = reg_value; + aspeed_gpio_update(s, set, reg_value); + return; + case gpio_reg_idx_direction: + reg_value = set->direction; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, DIRECTION)); + /* + * where data is the value attempted to be written to the pin: + * pin type | input mask | output mask | expected value + * ------------------------------------------------------------ + * bidirectional | 1 | 1 | data + * input only | 1 | 0 | 0 + * output only | 0 | 1 | 1 + * no pin | 0 | 0 | 0 + * + * which is captured by: + * data = ( data | ~input) & output; + */ + reg_value = (reg_value | ~props->input) & props->output; + set->direction = update_value_control_source(set, set->direction, + reg_value); + break; + case gpio_reg_idx_interrupt: + reg_value = set->int_enable; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, INT_ENABLE)); + set->int_enable = update_value_control_source(set, set->int_enable, + reg_value); + reg_value = set->int_sens_0; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_0)); + set->int_sens_0 = update_value_control_source(set, set->int_sens_0, + reg_value); + reg_value = set->int_sens_1; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_1)); + set->int_sens_1 = update_value_control_source(set, set->int_sens_1, + reg_value); + reg_value = set->int_sens_2; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_2)); + set->int_sens_2 = update_value_control_source(set, set->int_sens_2, + reg_value); + /* set interrupt status */ + reg_value = set->int_status; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS)); + cleared = ctpop32(reg_value & set->int_status); + if (s->pending && cleared) { + assert(s->pending >= cleared); + s->pending -= cleared; + } + set->int_status &= ~reg_value; + break; + case gpio_reg_idx_debounce: + reg_value = set->debounce_1; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, DEBOUNCE_1)); + set->debounce_1 = update_value_control_source(set, set->debounce_1, + reg_value); + reg_value = set->debounce_2; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, DEBOUNCE_2)); + set->debounce_2 = update_value_control_source(set, set->debounce_2, + reg_value); + return; + case gpio_reg_idx_tolerance: + reg_value = set->reset_tol; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, RESET_TOLERANT)); + set->reset_tol = update_value_control_source(set, set->reset_tol, + reg_value); + return; + case gpio_reg_idx_cmd_src: + reg_value = set->cmd_source_0; + reg_value = deposit32(reg_value, GPIOS_PER_GROUP * group_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, COMMAND_SRC_0)); + set->cmd_source_0 = reg_value & ASPEED_CMD_SRC_MASK; + reg_value = set->cmd_source_1; + reg_value = deposit32(reg_value, GPIOS_PER_GROUP * group_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, COMMAND_SRC_1)); + set->cmd_source_1 = reg_value & ASPEED_CMD_SRC_MASK; + return; + case gpio_reg_idx_input_mask: + reg_value = set->input_mask; + reg_value = deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, INPUT_MASK)); + /* + * feeds into interrupt generation + * 0: read from data value reg will be updated + * 1: read from data value reg will not be updated + */ + set->input_mask = reg_value & props->input; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%" PRIx64 "data 0x%" + PRIx64 "index mode wrong type 0x%x\n", + __func__, offset, data, reg_idx_type); + return; + } + aspeed_gpio_update(s, set, set->data_value); + return; +} + static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data, uint32_t size) { @@ -610,6 +771,13 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data, trace_aspeed_gpio_write(offset, data); idx = offset >> 2; + + /* check gpio index mode */ + if (idx == R_GPIO_INDEX_REG) { + aspeed_gpio_write_index_mode(opaque, offset, data, size); + return; + } + if (idx >= GPIO_DEBOUNCE_TIME_1 && idx <= GPIO_DEBOUNCE_TIME_3) { idx -= GPIO_DEBOUNCE_TIME_1; s->debounce_regs[idx] = (uint32_t) data; diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h index 6dee3cd438..41b36524d0 100644 --- a/include/hw/gpio/aspeed_gpio.h +++ b/include/hw/gpio/aspeed_gpio.h @@ -50,6 +50,20 @@ enum GPIORegType { gpio_reg_input_mask, }; +/* GPIO index mode */ +enum GPIORegIndexType { + gpio_reg_idx_data = 0, + gpio_reg_idx_direction, + gpio_reg_idx_interrupt, + gpio_reg_idx_debounce, + gpio_reg_idx_tolerance, + gpio_reg_idx_cmd_src, + gpio_reg_idx_input_mask, + gpio_reg_idx_reserved, + gpio_reg_idx_new_w_cmd_src, + gpio_reg_idx_new_r_cmd_src, +}; + typedef struct AspeedGPIOReg { uint16_t set_idx; enum GPIORegType type; From 554c294514dc7445c5442266a50012ed774d63fe Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Wed, 25 May 2022 10:31:33 +0200 Subject: [PATCH 500/935] hw/gpio: replace HWADDR_PRIx with PRIx64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. replace HWADDR_PRIx with PRIx64 2. fix indent issue Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Message-Id: <20220525053444.27228-5-jamin_lin@aspeedtech.com> Signed-off-by: Cédric Le Goater --- hw/gpio/aspeed_gpio.c | 8 ++++---- include/hw/gpio/aspeed_gpio.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index c834bf19f5..a62a673857 100644 --- a/hw/gpio/aspeed_gpio.c +++ b/hw/gpio/aspeed_gpio.c @@ -561,7 +561,7 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr offset, uint32_t size) reg = &agc->reg_table[idx]; if (reg->set_idx >= agc->nr_gpio_sets) { qemu_log_mask(LOG_GUEST_ERROR, "%s: no getter for offset 0x%" - HWADDR_PRIx"\n", __func__, offset); + PRIx64"\n", __func__, offset); return 0; } @@ -611,7 +611,7 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr offset, uint32_t size) break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: no getter for offset 0x%" - HWADDR_PRIx"\n", __func__, offset); + PRIx64"\n", __func__, offset); return 0; } @@ -787,7 +787,7 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data, reg = &agc->reg_table[idx]; if (reg->set_idx >= agc->nr_gpio_sets) { qemu_log_mask(LOG_GUEST_ERROR, "%s: no setter for offset 0x%" - HWADDR_PRIx"\n", __func__, offset); + PRIx64"\n", __func__, offset); return; } @@ -872,7 +872,7 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data, break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: no setter for offset 0x%" - HWADDR_PRIx"\n", __func__, offset); + PRIx64"\n", __func__, offset); return; } aspeed_gpio_update(s, set, set->data_value); diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h index 41b36524d0..904eecf62c 100644 --- a/include/hw/gpio/aspeed_gpio.h +++ b/include/hw/gpio/aspeed_gpio.h @@ -67,7 +67,7 @@ enum GPIORegIndexType { typedef struct AspeedGPIOReg { uint16_t set_idx; enum GPIORegType type; - } AspeedGPIOReg; +} AspeedGPIOReg; struct AspeedGPIOClass { SysBusDevice parent_obj; From 3569664ee9f08c94a5a2c69f778f0d023e5e882f Mon Sep 17 00:00:00 2001 From: luzhipeng Date: Fri, 20 May 2022 10:19:35 +0800 Subject: [PATCH 501/935] qga: add guest-get-diskstats command for Linux guests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new 'guest-get-diskstats' command for report disk io statistics for Linux guests. This can be useful for getting io flow or handling IO fault, no need to enter guests. Signed-off-by: luzhipeng Message-Id: <20220520021935.676-1-luzhipeng@cestc.cn> Reviewed-by: Marc-André Lureau Reviewed-by: Konstantin Kostiuk Signed-off-by: Konstantin Kostiuk --- qga/commands-posix.c | 123 +++++++++++++++++++++++++++++++++++++++++++ qga/commands-win32.c | 6 +++ qga/qapi-schema.json | 86 ++++++++++++++++++++++++++++++ 3 files changed, 215 insertions(+) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 69f209af87..12b50b7124 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -2783,6 +2783,122 @@ GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp) return info; } +#define MAX_NAME_LEN 128 +static GuestDiskStatsInfoList *guest_get_diskstats(Error **errp) +{ +#ifdef CONFIG_LINUX + GuestDiskStatsInfoList *head = NULL, **tail = &head; + const char *diskstats = "/proc/diskstats"; + FILE *fp; + size_t n; + char *line = NULL; + + fp = fopen(diskstats, "r"); + if (fp == NULL) { + error_setg_errno(errp, errno, "open(\"%s\")", diskstats); + return NULL; + } + + while (getline(&line, &n, fp) != -1) { + g_autofree GuestDiskStatsInfo *diskstatinfo = NULL; + g_autofree GuestDiskStats *diskstat = NULL; + char dev_name[MAX_NAME_LEN]; + unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks, dc_ticks, fl_ticks; + unsigned long rd_ios, rd_merges_or_rd_sec, rd_ticks_or_wr_sec, wr_ios; + unsigned long wr_merges, rd_sec_or_wr_ios, wr_sec; + unsigned long dc_ios, dc_merges, dc_sec, fl_ios; + unsigned int major, minor; + int i; + + i = sscanf(line, "%u %u %s %lu %lu %lu" + "%lu %lu %lu %lu %u %u %u %u" + "%lu %lu %lu %u %lu %u", + &major, &minor, dev_name, + &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, + &rd_ticks_or_wr_sec, &wr_ios, &wr_merges, &wr_sec, + &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks, + &dc_ios, &dc_merges, &dc_sec, &dc_ticks, + &fl_ios, &fl_ticks); + + if (i < 7) { + continue; + } + + diskstatinfo = g_new0(GuestDiskStatsInfo, 1); + diskstatinfo->name = g_strdup(dev_name); + diskstatinfo->major = major; + diskstatinfo->minor = minor; + + diskstat = g_new0(GuestDiskStats, 1); + if (i == 7) { + diskstat->has_read_ios = true; + diskstat->read_ios = rd_ios; + diskstat->has_read_sectors = true; + diskstat->read_sectors = rd_merges_or_rd_sec; + diskstat->has_write_ios = true; + diskstat->write_ios = rd_sec_or_wr_ios; + diskstat->has_write_sectors = true; + diskstat->write_sectors = rd_ticks_or_wr_sec; + } + if (i >= 14) { + diskstat->has_read_ios = true; + diskstat->read_ios = rd_ios; + diskstat->has_read_sectors = true; + diskstat->read_sectors = rd_sec_or_wr_ios; + diskstat->has_read_merges = true; + diskstat->read_merges = rd_merges_or_rd_sec; + diskstat->has_read_ticks = true; + diskstat->read_ticks = rd_ticks_or_wr_sec; + diskstat->has_write_ios = true; + diskstat->write_ios = wr_ios; + diskstat->has_write_sectors = true; + diskstat->write_sectors = wr_sec; + diskstat->has_write_merges = true; + diskstat->write_merges = wr_merges; + diskstat->has_write_ticks = true; + diskstat->write_ticks = wr_ticks; + diskstat->has_ios_pgr = true; + diskstat->ios_pgr = ios_pgr; + diskstat->has_total_ticks = true; + diskstat->total_ticks = tot_ticks; + diskstat->has_weight_ticks = true; + diskstat->weight_ticks = rq_ticks; + } + if (i >= 18) { + diskstat->has_discard_ios = true; + diskstat->discard_ios = dc_ios; + diskstat->has_discard_merges = true; + diskstat->discard_merges = dc_merges; + diskstat->has_discard_sectors = true; + diskstat->discard_sectors = dc_sec; + diskstat->has_discard_ticks = true; + diskstat->discard_ticks = dc_ticks; + } + if (i >= 20) { + diskstat->has_flush_ios = true; + diskstat->flush_ios = fl_ios; + diskstat->has_flush_ticks = true; + diskstat->flush_ticks = fl_ticks; + } + + diskstatinfo->stats = g_steal_pointer(&diskstat); + QAPI_LIST_APPEND(tail, diskstatinfo); + diskstatinfo = NULL; + } + free(line); + fclose(fp); + return head; +#else + g_debug("disk stats reporting available only for Linux"); + return NULL; +#endif +} + +GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp) +{ + return guest_get_diskstats(errp); +} + #else /* defined(__linux__) */ void qmp_guest_suspend_disk(Error **errp) @@ -3131,6 +3247,13 @@ GuestDiskInfoList *qmp_guest_get_disks(Error **errp) return NULL; } +GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp) +{ + error_setg(errp, QERR_UNSUPPORTED); + return NULL; +} + + #endif /* CONFIG_FSFREEZE */ #if !defined(CONFIG_FSTRIM) diff --git a/qga/commands-win32.c b/qga/commands-win32.c index d56b5fd2a7..dcdeb76a68 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -2532,3 +2532,9 @@ char *qga_get_host_name(Error **errp) return g_utf16_to_utf8(tmp, size, NULL, NULL, NULL); } + +GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp) +{ + error_setg(errp, QERR_UNSUPPORTED); + return NULL; +} diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index f989597b0c..9fa20e791b 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -1490,3 +1490,89 @@ { 'command': 'guest-ssh-remove-authorized-keys', 'data': { 'username': 'str', 'keys': ['str'] }, 'if': 'CONFIG_POSIX' } + +## +# @GuestDiskStats: +# +# @read-sectors: sectors read +# +# @read-ios: reads completed successfully +# +# @read-merges: read requests merged +# +# @write-sectors: sectors written +# +# @write-ios: writes completed +# +# @write-merges: write requests merged +# +# @discard-sectors: sectors discarded +# +# @discard-ios: discards completed successfully +# +# @discard-merges: discard requests merged +# +# @flush-ios: flush requests completed successfully +# +# @read-ticks: time spent reading(ms) +# +# @write-ticks: time spent writing(ms) +# +# @discard-ticks: time spent discarding(ms) +# +# @flush-ticks: time spent flushing(ms) +# +# @ios-pgr: number of I/Os currently in flight +# +# @total-ticks: time spent doing I/Os (ms) +# +# @weight-ticks: weighted time spent doing I/Os since the last update of this field(ms) +# +# Since: 7.1 +## +{ 'struct': 'GuestDiskStats', + 'data': {'*read-sectors': 'uint64', + '*read-ios': 'uint64', + '*read-merges': 'uint64', + '*write-sectors': 'uint64', + '*write-ios': 'uint64', + '*write-merges': 'uint64', + '*discard-sectors': 'uint64', + '*discard-ios': 'uint64', + '*discard-merges': 'uint64', + '*flush-ios': 'uint64', + '*read-ticks': 'uint64', + '*write-ticks': 'uint64', + '*discard-ticks': 'uint64', + '*flush-ticks': 'uint64', + '*ios-pgr': 'uint64', + '*total-ticks': 'uint64', + '*weight-ticks': 'uint64' + } } + +## +# @GuestDiskStatsInfo: +# +# @name disk name +# +# @major major device number of disk +# +# @minor minor device number of disk +## +{ 'struct': 'GuestDiskStatsInfo', + 'data': {'name': 'str', + 'major': 'uint64', + 'minor': 'uint64', + 'stats': 'GuestDiskStats' } } + +## +# @guest-get-diskstats: +# +# Retrieve information about disk stats. +# Returns: List of disk stats of guest. +# +# Since: 7.1 +## +{ 'command': 'guest-get-diskstats', + 'returns': ['GuestDiskStatsInfo'] +} From 323f3a8f22ee4eecf427a9322bd0fb449c33abd7 Mon Sep 17 00:00:00 2001 From: Konstantin Kostiuk Date: Mon, 23 May 2022 22:16:44 +0300 Subject: [PATCH 502/935] trivial: qga: Log version on start MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Konstantin Kostiuk Reviewed-by: Marc-André Lureau Message-Id: <20220523191644.823726-2-kkostiuk@redhat.com> Signed-off-by: Konstantin Kostiuk --- qga/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qga/main.c b/qga/main.c index 3b9546c185..c373fec3ee 100644 --- a/qga/main.c +++ b/qga/main.c @@ -1271,6 +1271,8 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation) g_log_set_fatal_mask(NULL, G_LOG_LEVEL_ERROR); ga_enable_logging(s); + g_debug("Guest agent version %s started", QEMU_FULL_VERSION); + #ifdef _WIN32 /* On win32 the state directory is application specific (be it the default * or a user override). We got past the command line parsing; let's create From 2e7b2189582787ae4bedf698983b5a81f4ac4656 Mon Sep 17 00:00:00 2001 From: Konstantin Kostiuk Date: Wed, 25 May 2022 11:59:53 +0300 Subject: [PATCH 503/935] tests: Bump Fedora image version for cross-compilation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are 2 reason for the bump: - Fedora 33 is not supported anymore - Some changes in the guest agent required updates of mingw-headers Signed-off-by: Konstantin Kostiuk Reviewed-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Reviewed-by: Thomas Huth Message-Id: <20220525085953.940116-2-kkostiuk@redhat.com> Signed-off-by: Konstantin Kostiuk --- tests/docker/dockerfiles/fedora-win32-cross.docker | 2 +- tests/docker/dockerfiles/fedora-win64-cross.docker | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker index 84a8f5524d..a06bd29e8e 100644 --- a/tests/docker/dockerfiles/fedora-win32-cross.docker +++ b/tests/docker/dockerfiles/fedora-win32-cross.docker @@ -1,4 +1,4 @@ -FROM registry.fedoraproject.org/fedora:33 +FROM registry.fedoraproject.org/fedora:35 # Please keep this list sorted alphabetically ENV PACKAGES \ diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker index d7ed8eb1cf..b71624330f 100644 --- a/tests/docker/dockerfiles/fedora-win64-cross.docker +++ b/tests/docker/dockerfiles/fedora-win64-cross.docker @@ -1,4 +1,4 @@ -FROM registry.fedoraproject.org/fedora:33 +FROM registry.fedoraproject.org/fedora:35 # Please keep this list sorted alphabetically ENV PACKAGES \ From b9a002609fd887447eca8ee10777690d691f91d4 Mon Sep 17 00:00:00 2001 From: Konstantin Kostiuk Date: Tue, 24 May 2022 18:43:44 +0300 Subject: [PATCH 504/935] qga-win32: Add support for NVME bus type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bus type spaces (Indicates a storage spaces bus) is not supported, so return it as unknown. Signed-off-by: Konstantin Kostiuk Reviewed-by: Marc-André Lureau Message-Id: <20220524154344.869638-2-kkostiuk@redhat.com> Signed-off-by: Konstantin Kostiuk --- qga/commands-win32.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/qga/commands-win32.c b/qga/commands-win32.c index dcdeb76a68..36f94c0f9c 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -490,6 +490,11 @@ static GuestDiskBusType win2qemu[] = { #if (_WIN32_WINNT >= 0x0601) [BusTypeVirtual] = GUEST_DISK_BUS_TYPE_VIRTUAL, [BusTypeFileBackedVirtual] = GUEST_DISK_BUS_TYPE_FILE_BACKED_VIRTUAL, + /* + * BusTypeSpaces currently is not suported + */ + [BusTypeSpaces] = GUEST_DISK_BUS_TYPE_UNKNOWN, + [BusTypeNvme] = GUEST_DISK_BUS_TYPE_NVME, #endif }; From 29320530cf6684646b3a642fdbb5bc77ee8039de Mon Sep 17 00:00:00 2001 From: Liu Yiding Date: Wed, 13 Apr 2022 12:20:54 +0800 Subject: [PATCH 505/935] docs: Correct the default thread-pool-size Refer to 26ec190964 virtiofsd: Do not use a thread pool by default Signed-off-by: Liu Yiding Acked-by: Vivek Goyal Message-id: 20220413042054.1484640-1-liuyd.fnst@fujitsu.com Signed-off-by: Stefan Hajnoczi --- docs/tools/virtiofsd.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tools/virtiofsd.rst b/docs/tools/virtiofsd.rst index e457b13d56..5f5ac9dd56 100644 --- a/docs/tools/virtiofsd.rst +++ b/docs/tools/virtiofsd.rst @@ -132,7 +132,7 @@ Options .. option:: --thread-pool-size=NUM Restrict the number of worker threads per request queue to NUM. The default - is 64. + is 0. .. option:: --cache=none|auto|always From 52bcd997800fab67d57bea6d93e368f6f7a93b24 Mon Sep 17 00:00:00 2001 From: Howard Chiu Date: Wed, 25 May 2022 10:00:01 +0000 Subject: [PATCH 506/935] hw/arm/aspeed: Add i2c devices for AST2600 EVB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add EEPROM and LM75 temperature sensor according to hardware schematic Signed-off-by: Howard Chiu Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/arm/aspeed.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 725c169488..98dc185acd 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -527,8 +527,15 @@ static void ast2500_evb_i2c_init(AspeedMachineState *bmc) static void ast2600_evb_i2c_init(AspeedMachineState *bmc) { - /* Start with some devices on our I2C busses */ - ast2500_evb_i2c_init(bmc); + AspeedSoCState *soc = &bmc->soc; + uint8_t *eeprom_buf = g_malloc0(8 * 1024); + + smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 7), 0x50, + eeprom_buf); + + /* LM75 is compatible with TMP105 driver */ + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), + TYPE_TMP105, 0x4d); } static void romulus_bmc_i2c_init(AspeedMachineState *bmc) From 3c7b72ddca9ce85a9d1e8a98fd0996b74597b5ae Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 14 May 2022 08:50:10 +0200 Subject: [PATCH 507/935] thread-pool: optimize scheduling of completion bottom half The completion bottom half was scheduled within the pool->lock critical section. That actually results in worse performance, because the worker thread can run its own small critical section and go to sleep before the bottom half starts running. Note that this simple change does not produce an improvement without changing the thread pool QemuSemaphore to a condition variable. Reviewed-by: Stefan Hajnoczi Reviewed-by: Nicolas Saenz Julienne Message-Id: <20220514065012.1149539-2-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- util/thread-pool.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/util/thread-pool.c b/util/thread-pool.c index 196835b4d3..4979f30ca3 100644 --- a/util/thread-pool.c +++ b/util/thread-pool.c @@ -127,9 +127,8 @@ static void *worker_thread(void *opaque) smp_wmb(); req->state = THREAD_DONE; - qemu_mutex_lock(&pool->lock); - qemu_bh_schedule(pool->completion_bh); + qemu_mutex_lock(&pool->lock); } pool->cur_threads--; From 900fa208f50623672a6f879374222a7fd4717791 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 14 May 2022 08:50:11 +0200 Subject: [PATCH 508/935] thread-pool: replace semaphore with condition variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit f9fc8932b1 ("thread-posix: remove the posix semaphore support", 2022-04-06) QemuSemaphore has its own mutex and condition variable; this adds unnecessary overhead on I/O with small block sizes. Check the QTAILQ directly instead of adding the indirection of a semaphore's count. Using a semaphore has not been necessary since qemu_cond_timedwait was introduced; the new code has to be careful about spurious wakeups but it is simpler, for example thread_pool_cancel does not have to worry about synchronizing the semaphore count with the number of elements of pool->request_list. Note that the return value of qemu_cond_timedwait (0 for timeout, 1 for signal or spurious wakeup) is different from that of qemu_sem_timedwait (-1 for timeout, 0 for success). Reported-by: Lukáš Doktor Suggested-by: Stefan Hajnoczi Reviewed-by: Nicolas Saenz Julienne Message-Id: <20220514065012.1149539-3-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- util/thread-pool.c | 68 +++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 40 deletions(-) diff --git a/util/thread-pool.c b/util/thread-pool.c index 4979f30ca3..6e3d4e4a2f 100644 --- a/util/thread-pool.c +++ b/util/thread-pool.c @@ -57,7 +57,7 @@ struct ThreadPool { QEMUBH *completion_bh; QemuMutex lock; QemuCond worker_stopped; - QemuSemaphore sem; + QemuCond request_cond; QEMUBH *new_thread_bh; /* The following variables are only accessed from one AioContext. */ @@ -74,23 +74,6 @@ struct ThreadPool { int max_threads; }; -static inline bool back_to_sleep(ThreadPool *pool, int ret) -{ - /* - * The semaphore timed out, we should exit the loop except when: - * - There is work to do, we raced with the signal. - * - The max threads threshold just changed, we raced with the signal. - * - The thread pool forces a minimum number of readily available threads. - */ - if (ret == -1 && (!QTAILQ_EMPTY(&pool->request_list) || - pool->cur_threads > pool->max_threads || - pool->cur_threads <= pool->min_threads)) { - return true; - } - - return false; -} - static void *worker_thread(void *opaque) { ThreadPool *pool = opaque; @@ -99,20 +82,25 @@ static void *worker_thread(void *opaque) pool->pending_threads--; do_spawn_thread(pool); - while (!pool->stopping) { + while (!pool->stopping && pool->cur_threads <= pool->max_threads) { ThreadPoolElement *req; int ret; - do { + if (QTAILQ_EMPTY(&pool->request_list)) { pool->idle_threads++; - qemu_mutex_unlock(&pool->lock); - ret = qemu_sem_timedwait(&pool->sem, 10000); - qemu_mutex_lock(&pool->lock); + ret = qemu_cond_timedwait(&pool->request_cond, &pool->lock, 10000); pool->idle_threads--; - } while (back_to_sleep(pool, ret)); - if (ret == -1 || pool->stopping || - pool->cur_threads > pool->max_threads) { - break; + if (ret == 0 && + QTAILQ_EMPTY(&pool->request_list) && + pool->cur_threads > pool->min_threads) { + /* Timed out + no work to do + no need for warm threads = exit. */ + break; + } + /* + * Even if there was some work to do, check if there aren't + * too many worker threads before picking it up. + */ + continue; } req = QTAILQ_FIRST(&pool->request_list); @@ -134,6 +122,12 @@ static void *worker_thread(void *opaque) pool->cur_threads--; qemu_cond_signal(&pool->worker_stopped); qemu_mutex_unlock(&pool->lock); + + /* + * Wake up another thread, in case we got a wakeup but decided + * to exit due to pool->cur_threads > pool->max_threads. + */ + qemu_cond_signal(&pool->request_cond); return NULL; } @@ -229,13 +223,7 @@ static void thread_pool_cancel(BlockAIOCB *acb) trace_thread_pool_cancel(elem, elem->common.opaque); QEMU_LOCK_GUARD(&pool->lock); - if (elem->state == THREAD_QUEUED && - /* No thread has yet started working on elem. we can try to "steal" - * the item from the worker if we can get a signal from the - * semaphore. Because this is non-blocking, we can do it with - * the lock taken and ensure that elem will remain THREAD_QUEUED. - */ - qemu_sem_timedwait(&pool->sem, 0) == 0) { + if (elem->state == THREAD_QUEUED) { QTAILQ_REMOVE(&pool->request_list, elem, reqs); qemu_bh_schedule(pool->completion_bh); @@ -280,7 +268,7 @@ BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool, } QTAILQ_INSERT_TAIL(&pool->request_list, req, reqs); qemu_mutex_unlock(&pool->lock); - qemu_sem_post(&pool->sem); + qemu_cond_signal(&pool->request_cond); return &req->common; } @@ -323,7 +311,7 @@ void thread_pool_update_params(ThreadPool *pool, AioContext *ctx) * We either have to: * - Increase the number available of threads until over the min_threads * threshold. - * - Decrease the number of available threads until under the max_threads + * - Bump the worker threads so that they exit, until under the max_threads * threshold. * - Do nothing. The current number of threads fall in between the min and * max thresholds. We'll let the pool manage itself. @@ -333,7 +321,7 @@ void thread_pool_update_params(ThreadPool *pool, AioContext *ctx) } for (int i = pool->cur_threads; i > pool->max_threads; i--) { - qemu_sem_post(&pool->sem); + qemu_cond_signal(&pool->request_cond); } qemu_mutex_unlock(&pool->lock); @@ -350,7 +338,7 @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx) pool->completion_bh = aio_bh_new(ctx, thread_pool_completion_bh, pool); qemu_mutex_init(&pool->lock); qemu_cond_init(&pool->worker_stopped); - qemu_sem_init(&pool->sem, 0); + qemu_cond_init(&pool->request_cond); pool->new_thread_bh = aio_bh_new(ctx, spawn_thread_bh_fn, pool); QLIST_INIT(&pool->head); @@ -383,15 +371,15 @@ void thread_pool_free(ThreadPool *pool) /* Wait for worker threads to terminate */ pool->stopping = true; + qemu_cond_broadcast(&pool->request_cond); while (pool->cur_threads > 0) { - qemu_sem_post(&pool->sem); qemu_cond_wait(&pool->worker_stopped, &pool->lock); } qemu_mutex_unlock(&pool->lock); qemu_bh_delete(pool->completion_bh); - qemu_sem_destroy(&pool->sem); + qemu_cond_destroy(&pool->request_cond); qemu_cond_destroy(&pool->worker_stopped); qemu_mutex_destroy(&pool->lock); g_free(pool); From 232e9255478f3849957d2f4b083d6e5d4736ab04 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 14 May 2022 08:50:12 +0200 Subject: [PATCH 509/935] thread-pool: remove stopping variable Just setting the max threads to 0 is enough to stop all workers. Message-Id: <20220514065012.1149539-4-pbonzini@redhat.com> Reviewed-by: Stefan Hajnoczi Reviewed-by: Nicolas Saenz Julienne Signed-off-by: Paolo Bonzini --- util/thread-pool.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/util/thread-pool.c b/util/thread-pool.c index 6e3d4e4a2f..31113b5860 100644 --- a/util/thread-pool.c +++ b/util/thread-pool.c @@ -69,7 +69,6 @@ struct ThreadPool { int idle_threads; int new_threads; /* backlog of threads we need to create */ int pending_threads; /* threads created but not running yet */ - bool stopping; int min_threads; int max_threads; }; @@ -82,7 +81,7 @@ static void *worker_thread(void *opaque) pool->pending_threads--; do_spawn_thread(pool); - while (!pool->stopping && pool->cur_threads <= pool->max_threads) { + while (pool->cur_threads <= pool->max_threads) { ThreadPoolElement *req; int ret; @@ -370,7 +369,7 @@ void thread_pool_free(ThreadPool *pool) pool->new_threads = 0; /* Wait for worker threads to terminate */ - pool->stopping = true; + pool->max_threads = 0; qemu_cond_broadcast(&pool->request_cond); while (pool->cur_threads > 0) { qemu_cond_wait(&pool->worker_stopped, &pool->lock); From c06ebc0f1b13b9b3802b35969c00e19a31cde484 Mon Sep 17 00:00:00 2001 From: Viktor Prutyanov Date: Fri, 20 May 2022 11:43:39 +0300 Subject: [PATCH 510/935] contrib/elf2dmp: add ELF dump header checking Add ELF header checking to prevent processing input file which is not QEMU x86_64 guest memory dump or even not ELF. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1013 Signed-off-by: Viktor Prutyanov Reviewed-by: Richard Henderson Message-Id: <20220520084339.171684-1-viktor.prutyanov@redhat.com> Signed-off-by: Paolo Bonzini --- contrib/elf2dmp/qemu_elf.c | 53 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/contrib/elf2dmp/qemu_elf.c b/contrib/elf2dmp/qemu_elf.c index b601b6d7ba..ebda60dcb8 100644 --- a/contrib/elf2dmp/qemu_elf.c +++ b/contrib/elf2dmp/qemu_elf.c @@ -118,6 +118,53 @@ static void exit_states(QEMU_Elf *qe) free(qe->state); } +static bool check_ehdr(QEMU_Elf *qe) +{ + Elf64_Ehdr *ehdr = qe->map; + + if (sizeof(Elf64_Ehdr) > qe->size) { + eprintf("Invalid input dump file size\n"); + return false; + } + + if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) { + eprintf("Invalid ELF signature, input file is not ELF\n"); + return false; + } + + if (ehdr->e_ident[EI_CLASS] != ELFCLASS64 || + ehdr->e_ident[EI_DATA] != ELFDATA2LSB) { + eprintf("Invalid ELF class or byte order, must be 64-bit LE\n"); + return false; + } + + if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) { + eprintf("Invalid ELF version\n"); + return false; + } + + if (ehdr->e_machine != EM_X86_64) { + eprintf("Invalid input dump architecture, only x86_64 is supported\n"); + return false; + } + + if (ehdr->e_type != ET_CORE) { + eprintf("Invalid ELF type, must be core file\n"); + return false; + } + + /* + * ELF dump file must contain one PT_NOTE and at least one PT_LOAD to + * restore physical address space. + */ + if (ehdr->e_phnum < 2) { + eprintf("Invalid number of ELF program headers\n"); + return false; + } + + return true; +} + int QEMU_Elf_init(QEMU_Elf *qe, const char *filename) { GError *gerr = NULL; @@ -133,6 +180,12 @@ int QEMU_Elf_init(QEMU_Elf *qe, const char *filename) qe->map = g_mapped_file_get_contents(qe->gmf); qe->size = g_mapped_file_get_length(qe->gmf); + if (!check_ehdr(qe)) { + eprintf("Input file has the wrong format\n"); + err = 1; + goto out_unmap; + } + if (init_states(qe)) { eprintf("Failed to extract QEMU CPU states\n"); err = 1; From ab9f0f7d44d6795050187b3bb0fc28fe804a062b Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 23 Apr 2022 11:36:57 +0200 Subject: [PATCH 511/935] hw/audio/ac97: Coding style fixes to avoid checkpatch errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: BALATON Zoltan Reviewed-by: Víctor Colombo Message-Id: <62862a057e9c9ec0bb45248b2b9a3a1babb346a6.1650706617.git.balaton@eik.bme.hu> Signed-off-by: Paolo Bonzini --- hw/audio/ac97.c | 727 ++++++++++++++++++++++++------------------------ 1 file changed, 357 insertions(+), 370 deletions(-) diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c index 3cb8131060..6b1c12bece 100644 --- a/hw/audio/ac97.c +++ b/hw/audio/ac97.c @@ -87,39 +87,39 @@ enum { #define GC_CR 2 /* rw */ #define GC_VALID_MASK ((1 << 6) - 1) -#define GS_MD3 (1<<17) /* rw */ -#define GS_AD3 (1<<16) /* rw */ -#define GS_RCS (1<<15) /* rwc */ -#define GS_B3S12 (1<<14) /* ro */ -#define GS_B2S12 (1<<13) /* ro */ -#define GS_B1S12 (1<<12) /* ro */ -#define GS_S1R1 (1<<11) /* rwc */ -#define GS_S0R1 (1<<10) /* rwc */ -#define GS_S1CR (1<<9) /* ro */ -#define GS_S0CR (1<<8) /* ro */ -#define GS_MINT (1<<7) /* ro */ -#define GS_POINT (1<<6) /* ro */ -#define GS_PIINT (1<<5) /* ro */ -#define GS_RSRVD ((1<<4)|(1<<3)) -#define GS_MOINT (1<<2) /* ro */ -#define GS_MIINT (1<<1) /* ro */ +#define GS_MD3 (1 << 17) /* rw */ +#define GS_AD3 (1 << 16) /* rw */ +#define GS_RCS (1 << 15) /* rwc */ +#define GS_B3S12 (1 << 14) /* ro */ +#define GS_B2S12 (1 << 13) /* ro */ +#define GS_B1S12 (1 << 12) /* ro */ +#define GS_S1R1 (1 << 11) /* rwc */ +#define GS_S0R1 (1 << 10) /* rwc */ +#define GS_S1CR (1 << 9) /* ro */ +#define GS_S0CR (1 << 8) /* ro */ +#define GS_MINT (1 << 7) /* ro */ +#define GS_POINT (1 << 6) /* ro */ +#define GS_PIINT (1 << 5) /* ro */ +#define GS_RSRVD ((1 << 4) | (1 << 3)) +#define GS_MOINT (1 << 2) /* ro */ +#define GS_MIINT (1 << 1) /* ro */ #define GS_GSCI 1 /* rwc */ -#define GS_RO_MASK (GS_B3S12| \ - GS_B2S12| \ - GS_B1S12| \ - GS_S1CR| \ - GS_S0CR| \ - GS_MINT| \ - GS_POINT| \ - GS_PIINT| \ - GS_RSRVD| \ - GS_MOINT| \ +#define GS_RO_MASK (GS_B3S12 | \ + GS_B2S12 | \ + GS_B1S12 | \ + GS_S1CR | \ + GS_S0CR | \ + GS_MINT | \ + GS_POINT | \ + GS_PIINT | \ + GS_RSRVD | \ + GS_MOINT | \ GS_MIINT) #define GS_VALID_MASK ((1 << 18) - 1) -#define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI) +#define GS_WCLEAR_MASK (GS_RCS | GS_S1R1 | GS_S0R1 | GS_GSCI) -#define BD_IOC (1<<31) -#define BD_BUP (1<<30) +#define BD_IOC (1 << 31) +#define BD_BUP (1 << 30) #define EACS_VRA 1 #define EACS_VRM 8 @@ -183,7 +183,7 @@ enum { }; #ifdef DEBUG_AC97 -#define dolog(...) AUD_log ("ac97", __VA_ARGS__) +#define dolog(...) AUD_log("ac97", __VA_ARGS__) #else #define dolog(...) #endif @@ -206,9 +206,9 @@ enum { LAST_INDEX }; -MKREGS (PI, PI_INDEX * 16); -MKREGS (PO, PO_INDEX * 16); -MKREGS (MC, MC_INDEX * 16); +MKREGS(PI, PI_INDEX * 16); +MKREGS(PO, PO_INDEX * 16); +MKREGS(MC, MC_INDEX * 16); enum { GLOB_CNT = 0x2c, @@ -218,36 +218,35 @@ enum { #define GET_BM(index) (((index) >> 4) & 3) -static void po_callback (void *opaque, int free); -static void pi_callback (void *opaque, int avail); -static void mc_callback (void *opaque, int avail); +static void po_callback(void *opaque, int free); +static void pi_callback(void *opaque, int avail); +static void mc_callback(void *opaque, int avail); -static void warm_reset (AC97LinkState *s) +static void warm_reset(AC97LinkState *s) { - (void) s; + (void)s; } -static void cold_reset (AC97LinkState * s) +static void cold_reset(AC97LinkState *s) { - (void) s; + (void)s; } -static void fetch_bd (AC97LinkState *s, AC97BusMasterRegs *r) +static void fetch_bd(AC97LinkState *s, AC97BusMasterRegs *r) { uint8_t b[8]; - pci_dma_read (&s->dev, r->bdbar + r->civ * 8, b, 8); + pci_dma_read(&s->dev, r->bdbar + r->civ * 8, b, 8); r->bd_valid = 1; - r->bd.addr = le32_to_cpu (*(uint32_t *) &b[0]) & ~3; - r->bd.ctl_len = le32_to_cpu (*(uint32_t *) &b[4]); + r->bd.addr = le32_to_cpu(*(uint32_t *) &b[0]) & ~3; + r->bd.ctl_len = le32_to_cpu(*(uint32_t *) &b[4]); r->picb = r->bd.ctl_len & 0xffff; - dolog ("bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n", - r->civ, r->bd.addr, r->bd.ctl_len >> 16, - r->bd.ctl_len & 0xffff, - (r->bd.ctl_len & 0xffff) << 1); + dolog("bd %2d addr=0x%x ctl=0x%06x len=0x%x(%d bytes)\n", + r->civ, r->bd.addr, r->bd.ctl_len >> 16, + r->bd.ctl_len & 0xffff, (r->bd.ctl_len & 0xffff) << 1); } -static void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr) +static void update_sr(AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr) { int event = 0; int level = 0; @@ -260,8 +259,7 @@ static void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr) if (!new_mask) { event = 1; level = 0; - } - else { + } else { if ((new_mask & SR_LVBCI) && (r->cr & CR_LVBIE)) { event = 1; level = 1; @@ -275,69 +273,67 @@ static void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr) r->sr = new_sr; - dolog ("IOC%d LVB%d sr=%#x event=%d level=%d\n", - r->sr & SR_BCIS, r->sr & SR_LVBCI, - r->sr, - event, level); + dolog("IOC%d LVB%d sr=0x%x event=%d level=%d\n", + r->sr & SR_BCIS, r->sr & SR_LVBCI, r->sr, event, level); - if (!event) + if (!event) { return; + } if (level) { s->glob_sta |= masks[r - s->bm_regs]; - dolog ("set irq level=1\n"); + dolog("set irq level=1\n"); pci_irq_assert(&s->dev); - } - else { + } else { s->glob_sta &= ~masks[r - s->bm_regs]; - dolog ("set irq level=0\n"); + dolog("set irq level=0\n"); pci_irq_deassert(&s->dev); } } -static void voice_set_active (AC97LinkState *s, int bm_index, int on) +static void voice_set_active(AC97LinkState *s, int bm_index, int on) { switch (bm_index) { case PI_INDEX: - AUD_set_active_in (s->voice_pi, on); + AUD_set_active_in(s->voice_pi, on); break; case PO_INDEX: - AUD_set_active_out (s->voice_po, on); + AUD_set_active_out(s->voice_po, on); break; case MC_INDEX: - AUD_set_active_in (s->voice_mc, on); + AUD_set_active_in(s->voice_mc, on); break; default: - AUD_log ("ac97", "invalid bm_index(%d) in voice_set_active", bm_index); + AUD_log("ac97", "invalid bm_index(%d) in voice_set_active", bm_index); break; } } -static void reset_bm_regs (AC97LinkState *s, AC97BusMasterRegs *r) +static void reset_bm_regs(AC97LinkState *s, AC97BusMasterRegs *r) { - dolog ("reset_bm_regs\n"); + dolog("reset_bm_regs\n"); r->bdbar = 0; r->civ = 0; r->lvi = 0; /** todo do we need to do that? */ - update_sr (s, r, SR_DCH); + update_sr(s, r, SR_DCH); r->picb = 0; r->piv = 0; r->cr = r->cr & CR_DONT_CLEAR_MASK; r->bd_valid = 0; - voice_set_active (s, r - s->bm_regs, 0); - memset (s->silence, 0, sizeof (s->silence)); + voice_set_active(s, r - s->bm_regs, 0); + memset(s->silence, 0, sizeof(s->silence)); } -static void mixer_store (AC97LinkState *s, uint32_t i, uint16_t v) +static void mixer_store(AC97LinkState *s, uint32_t i, uint16_t v) { - if (i + 2 > sizeof (s->mixer_data)) { - dolog ("mixer_store: index %d out of bounds %zd\n", - i, sizeof (s->mixer_data)); + if (i + 2 > sizeof(s->mixer_data)) { + dolog("mixer_store: index %d out of bounds %zd\n", + i, sizeof(s->mixer_data)); return; } @@ -345,22 +341,21 @@ static void mixer_store (AC97LinkState *s, uint32_t i, uint16_t v) s->mixer_data[i + 1] = v >> 8; } -static uint16_t mixer_load (AC97LinkState *s, uint32_t i) +static uint16_t mixer_load(AC97LinkState *s, uint32_t i) { uint16_t val = 0xffff; - if (i + 2 > sizeof (s->mixer_data)) { - dolog ("mixer_load: index %d out of bounds %zd\n", - i, sizeof (s->mixer_data)); - } - else { + if (i + 2 > sizeof(s->mixer_data)) { + dolog("mixer_load: index %d out of bounds %zd\n", + i, sizeof(s->mixer_data)); + } else { val = s->mixer_data[i + 0] | (s->mixer_data[i + 1] << 8); } return val; } -static void open_voice (AC97LinkState *s, int index, int freq) +static void open_voice(AC97LinkState *s, int index, int freq) { struct audsettings as; @@ -373,7 +368,7 @@ static void open_voice (AC97LinkState *s, int index, int freq) s->invalid_freq[index] = 0; switch (index) { case PI_INDEX: - s->voice_pi = AUD_open_in ( + s->voice_pi = AUD_open_in( &s->card, s->voice_pi, "ac97.pi", @@ -384,7 +379,7 @@ static void open_voice (AC97LinkState *s, int index, int freq) break; case PO_INDEX: - s->voice_po = AUD_open_out ( + s->voice_po = AUD_open_out( &s->card, s->voice_po, "ac97.po", @@ -395,7 +390,7 @@ static void open_voice (AC97LinkState *s, int index, int freq) break; case MC_INDEX: - s->voice_mc = AUD_open_in ( + s->voice_mc = AUD_open_in( &s->card, s->voice_mc, "ac97.mc", @@ -405,47 +400,46 @@ static void open_voice (AC97LinkState *s, int index, int freq) ); break; } - } - else { + } else { s->invalid_freq[index] = freq; switch (index) { case PI_INDEX: - AUD_close_in (&s->card, s->voice_pi); + AUD_close_in(&s->card, s->voice_pi); s->voice_pi = NULL; break; case PO_INDEX: - AUD_close_out (&s->card, s->voice_po); + AUD_close_out(&s->card, s->voice_po); s->voice_po = NULL; break; case MC_INDEX: - AUD_close_in (&s->card, s->voice_mc); + AUD_close_in(&s->card, s->voice_mc); s->voice_mc = NULL; break; } } } -static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) +static void reset_voices(AC97LinkState *s, uint8_t active[LAST_INDEX]) { uint16_t freq; - freq = mixer_load (s, AC97_PCM_LR_ADC_Rate); - open_voice (s, PI_INDEX, freq); - AUD_set_active_in (s->voice_pi, active[PI_INDEX]); + freq = mixer_load(s, AC97_PCM_LR_ADC_Rate); + open_voice(s, PI_INDEX, freq); + AUD_set_active_in(s->voice_pi, active[PI_INDEX]); - freq = mixer_load (s, AC97_PCM_Front_DAC_Rate); - open_voice (s, PO_INDEX, freq); - AUD_set_active_out (s->voice_po, active[PO_INDEX]); + freq = mixer_load(s, AC97_PCM_Front_DAC_Rate); + open_voice(s, PO_INDEX, freq); + AUD_set_active_out(s->voice_po, active[PO_INDEX]); - freq = mixer_load (s, AC97_MIC_ADC_Rate); - open_voice (s, MC_INDEX, freq); - AUD_set_active_in (s->voice_mc, active[MC_INDEX]); + freq = mixer_load(s, AC97_MIC_ADC_Rate); + open_voice(s, MC_INDEX, freq); + AUD_set_active_in(s->voice_mc, active[MC_INDEX]); } -static void get_volume (uint16_t vol, uint16_t mask, int inverse, - int *mute, uint8_t *lvol, uint8_t *rvol) +static void get_volume(uint16_t vol, uint16_t mask, int inverse, + int *mute, uint8_t *lvol, uint8_t *rvol) { *mute = (vol >> MUTE_SHIFT) & 1; *rvol = (255 * (vol & mask)) / mask; @@ -457,120 +451,120 @@ static void get_volume (uint16_t vol, uint16_t mask, int inverse, } } -static void update_combined_volume_out (AC97LinkState *s) +static void update_combined_volume_out(AC97LinkState *s) { uint8_t lvol, rvol, plvol, prvol; int mute, pmute; - get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1, - &mute, &lvol, &rvol); - get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x1f, 1, - &pmute, &plvol, &prvol); + get_volume(mixer_load(s, AC97_Master_Volume_Mute), 0x3f, 1, + &mute, &lvol, &rvol); + get_volume(mixer_load(s, AC97_PCM_Out_Volume_Mute), 0x1f, 1, + &pmute, &plvol, &prvol); mute = mute | pmute; lvol = (lvol * plvol) / 255; rvol = (rvol * prvol) / 255; - AUD_set_volume_out (s->voice_po, mute, lvol, rvol); + AUD_set_volume_out(s->voice_po, mute, lvol, rvol); } -static void update_volume_in (AC97LinkState *s) +static void update_volume_in(AC97LinkState *s) { uint8_t lvol, rvol; int mute; - get_volume (mixer_load (s, AC97_Record_Gain_Mute), 0x0f, 0, - &mute, &lvol, &rvol); + get_volume(mixer_load(s, AC97_Record_Gain_Mute), 0x0f, 0, + &mute, &lvol, &rvol); - AUD_set_volume_in (s->voice_pi, mute, lvol, rvol); + AUD_set_volume_in(s->voice_pi, mute, lvol, rvol); } -static void set_volume (AC97LinkState *s, int index, uint32_t val) +static void set_volume(AC97LinkState *s, int index, uint32_t val) { switch (index) { case AC97_Master_Volume_Mute: val &= 0xbf3f; - mixer_store (s, index, val); - update_combined_volume_out (s); + mixer_store(s, index, val); + update_combined_volume_out(s); break; case AC97_PCM_Out_Volume_Mute: val &= 0x9f1f; - mixer_store (s, index, val); - update_combined_volume_out (s); + mixer_store(s, index, val); + update_combined_volume_out(s); break; case AC97_Record_Gain_Mute: val &= 0x8f0f; - mixer_store (s, index, val); - update_volume_in (s); + mixer_store(s, index, val); + update_volume_in(s); break; } } -static void record_select (AC97LinkState *s, uint32_t val) +static void record_select(AC97LinkState *s, uint32_t val) { uint8_t rs = val & REC_MASK; uint8_t ls = (val >> 8) & REC_MASK; - mixer_store (s, AC97_Record_Select, rs | (ls << 8)); + mixer_store(s, AC97_Record_Select, rs | (ls << 8)); } -static void mixer_reset (AC97LinkState *s) +static void mixer_reset(AC97LinkState *s) { uint8_t active[LAST_INDEX]; - dolog ("mixer_reset\n"); - memset (s->mixer_data, 0, sizeof (s->mixer_data)); - memset (active, 0, sizeof (active)); - mixer_store (s, AC97_Reset , 0x0000); /* 6940 */ - mixer_store (s, AC97_Headphone_Volume_Mute , 0x0000); - mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x0000); - mixer_store (s, AC97_Master_Tone_RL, 0x0000); - mixer_store (s, AC97_PC_BEEP_Volume_Mute , 0x0000); - mixer_store (s, AC97_Phone_Volume_Mute , 0x0000); - mixer_store (s, AC97_Mic_Volume_Mute , 0x0000); - mixer_store (s, AC97_Line_In_Volume_Mute , 0x0000); - mixer_store (s, AC97_CD_Volume_Mute , 0x0000); - mixer_store (s, AC97_Video_Volume_Mute , 0x0000); - mixer_store (s, AC97_Aux_Volume_Mute , 0x0000); - mixer_store (s, AC97_Record_Gain_Mic_Mute , 0x0000); - mixer_store (s, AC97_General_Purpose , 0x0000); - mixer_store (s, AC97_3D_Control , 0x0000); - mixer_store (s, AC97_Powerdown_Ctrl_Stat , 0x000f); + dolog("mixer_reset\n"); + memset(s->mixer_data, 0, sizeof(s->mixer_data)); + memset(active, 0, sizeof(active)); + mixer_store(s, AC97_Reset, 0x0000); /* 6940 */ + mixer_store(s, AC97_Headphone_Volume_Mute, 0x0000); + mixer_store(s, AC97_Master_Volume_Mono_Mute, 0x0000); + mixer_store(s, AC97_Master_Tone_RL, 0x0000); + mixer_store(s, AC97_PC_BEEP_Volume_Mute, 0x0000); + mixer_store(s, AC97_Phone_Volume_Mute, 0x0000); + mixer_store(s, AC97_Mic_Volume_Mute, 0x0000); + mixer_store(s, AC97_Line_In_Volume_Mute, 0x0000); + mixer_store(s, AC97_CD_Volume_Mute, 0x0000); + mixer_store(s, AC97_Video_Volume_Mute, 0x0000); + mixer_store(s, AC97_Aux_Volume_Mute, 0x0000); + mixer_store(s, AC97_Record_Gain_Mic_Mute, 0x0000); + mixer_store(s, AC97_General_Purpose, 0x0000); + mixer_store(s, AC97_3D_Control, 0x0000); + mixer_store(s, AC97_Powerdown_Ctrl_Stat, 0x000f); /* * Sigmatel 9700 (STAC9700) */ - mixer_store (s, AC97_Vendor_ID1 , 0x8384); - mixer_store (s, AC97_Vendor_ID2 , 0x7600); /* 7608 */ + mixer_store(s, AC97_Vendor_ID1, 0x8384); + mixer_store(s, AC97_Vendor_ID2, 0x7600); /* 7608 */ - mixer_store (s, AC97_Extended_Audio_ID , 0x0809); - mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, 0x0009); - mixer_store (s, AC97_PCM_Front_DAC_Rate , 0xbb80); - mixer_store (s, AC97_PCM_Surround_DAC_Rate , 0xbb80); - mixer_store (s, AC97_PCM_LFE_DAC_Rate , 0xbb80); - mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); - mixer_store (s, AC97_MIC_ADC_Rate , 0xbb80); + mixer_store(s, AC97_Extended_Audio_ID, 0x0809); + mixer_store(s, AC97_Extended_Audio_Ctrl_Stat, 0x0009); + mixer_store(s, AC97_PCM_Front_DAC_Rate, 0xbb80); + mixer_store(s, AC97_PCM_Surround_DAC_Rate, 0xbb80); + mixer_store(s, AC97_PCM_LFE_DAC_Rate, 0xbb80); + mixer_store(s, AC97_PCM_LR_ADC_Rate, 0xbb80); + mixer_store(s, AC97_MIC_ADC_Rate, 0xbb80); - record_select (s, 0); - set_volume (s, AC97_Master_Volume_Mute, 0x8000); - set_volume (s, AC97_PCM_Out_Volume_Mute, 0x8808); - set_volume (s, AC97_Record_Gain_Mute, 0x8808); + record_select(s, 0); + set_volume(s, AC97_Master_Volume_Mute, 0x8000); + set_volume(s, AC97_PCM_Out_Volume_Mute, 0x8808); + set_volume(s, AC97_Record_Gain_Mute, 0x8808); - reset_voices (s, active); + reset_voices(s, active); } /** * Native audio mixer * I/O Reads */ -static uint32_t nam_readb (void *opaque, uint32_t addr) +static uint32_t nam_readb(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; - dolog ("U nam readb %#x\n", addr); + dolog("U nam readb 0x%x\n", addr); s->cas = 0; return ~0U; } -static uint32_t nam_readw (void *opaque, uint32_t addr) +static uint32_t nam_readw(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; uint32_t index = addr; @@ -578,10 +572,10 @@ static uint32_t nam_readw (void *opaque, uint32_t addr) return mixer_load(s, index); } -static uint32_t nam_readl (void *opaque, uint32_t addr) +static uint32_t nam_readl(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; - dolog ("U nam readl %#x\n", addr); + dolog("U nam readl 0x%x\n", addr); s->cas = 0; return ~0U; } @@ -590,89 +584,84 @@ static uint32_t nam_readl (void *opaque, uint32_t addr) * Native audio mixer * I/O Writes */ -static void nam_writeb (void *opaque, uint32_t addr, uint32_t val) +static void nam_writeb(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; - dolog ("U nam writeb %#x <- %#x\n", addr, val); + dolog("U nam writeb 0x%x <- 0x%x\n", addr, val); s->cas = 0; } -static void nam_writew (void *opaque, uint32_t addr, uint32_t val) +static void nam_writew(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; uint32_t index = addr; s->cas = 0; switch (index) { case AC97_Reset: - mixer_reset (s); + mixer_reset(s); break; case AC97_Powerdown_Ctrl_Stat: val &= ~0x800f; - val |= mixer_load (s, index) & 0xf; - mixer_store (s, index, val); + val |= mixer_load(s, index) & 0xf; + mixer_store(s, index, val); break; case AC97_PCM_Out_Volume_Mute: case AC97_Master_Volume_Mute: case AC97_Record_Gain_Mute: - set_volume (s, index, val); + set_volume(s, index, val); break; case AC97_Record_Select: - record_select (s, val); + record_select(s, val); break; case AC97_Vendor_ID1: case AC97_Vendor_ID2: - dolog ("Attempt to write vendor ID to %#x\n", val); + dolog("Attempt to write vendor ID to 0x%x\n", val); break; case AC97_Extended_Audio_ID: - dolog ("Attempt to write extended audio ID to %#x\n", val); + dolog("Attempt to write extended audio ID to 0x%x\n", val); break; case AC97_Extended_Audio_Ctrl_Stat: if (!(val & EACS_VRA)) { - mixer_store (s, AC97_PCM_Front_DAC_Rate, 0xbb80); - mixer_store (s, AC97_PCM_LR_ADC_Rate, 0xbb80); - open_voice (s, PI_INDEX, 48000); - open_voice (s, PO_INDEX, 48000); + mixer_store(s, AC97_PCM_Front_DAC_Rate, 0xbb80); + mixer_store(s, AC97_PCM_LR_ADC_Rate, 0xbb80); + open_voice(s, PI_INDEX, 48000); + open_voice(s, PO_INDEX, 48000); } if (!(val & EACS_VRM)) { - mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80); - open_voice (s, MC_INDEX, 48000); + mixer_store(s, AC97_MIC_ADC_Rate, 0xbb80); + open_voice(s, MC_INDEX, 48000); } - dolog ("Setting extended audio control to %#x\n", val); - mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, val); + dolog("Setting extended audio control to 0x%x\n", val); + mixer_store(s, AC97_Extended_Audio_Ctrl_Stat, val); break; case AC97_PCM_Front_DAC_Rate: - if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { - mixer_store (s, index, val); - dolog ("Set front DAC rate to %d\n", val); - open_voice (s, PO_INDEX, val); - } - else { - dolog ("Attempt to set front DAC rate to %d, " - "but VRA is not set\n", - val); + if (mixer_load(s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { + mixer_store(s, index, val); + dolog("Set front DAC rate to %d\n", val); + open_voice(s, PO_INDEX, val); + } else { + dolog("Attempt to set front DAC rate to %d, but VRA is not set\n", + val); } break; case AC97_MIC_ADC_Rate: - if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM) { - mixer_store (s, index, val); - dolog ("Set MIC ADC rate to %d\n", val); - open_voice (s, MC_INDEX, val); - } - else { - dolog ("Attempt to set MIC ADC rate to %d, " - "but VRM is not set\n", - val); + if (mixer_load(s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM) { + mixer_store(s, index, val); + dolog("Set MIC ADC rate to %d\n", val); + open_voice(s, MC_INDEX, val); + } else { + dolog("Attempt to set MIC ADC rate to %d, but VRM is not set\n", + val); } break; case AC97_PCM_LR_ADC_Rate: - if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { - mixer_store (s, index, val); - dolog ("Set front LR ADC rate to %d\n", val); - open_voice (s, PI_INDEX, val); - } - else { - dolog ("Attempt to set LR ADC rate to %d, but VRA is not set\n", - val); + if (mixer_load(s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { + mixer_store(s, index, val); + dolog("Set front LR ADC rate to %d\n", val); + open_voice(s, PI_INDEX, val); + } else { + dolog("Attempt to set LR ADC rate to %d, but VRA is not set\n", + val); } break; case AC97_Headphone_Volume_Mute: @@ -693,16 +682,16 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) /* None of the features in these regs are emulated, so they are RO */ break; default: - dolog ("U nam writew %#x <- %#x\n", addr, val); - mixer_store (s, index, val); + dolog("U nam writew 0x%x <- 0x%x\n", addr, val); + mixer_store(s, index, val); break; } } -static void nam_writel (void *opaque, uint32_t addr, uint32_t val) +static void nam_writel(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; - dolog ("U nam writel %#x <- %#x\n", addr, val); + dolog("U nam writel 0x%x <- 0x%x\n", addr, val); s->cas = 0; } @@ -710,7 +699,7 @@ static void nam_writel (void *opaque, uint32_t addr, uint32_t val) * Native audio bus master * I/O Reads */ -static uint32_t nabm_readb (void *opaque, uint32_t addr) +static uint32_t nabm_readb(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; @@ -719,53 +708,53 @@ static uint32_t nabm_readb (void *opaque, uint32_t addr) switch (index) { case CAS: - dolog ("CAS %d\n", s->cas); + dolog("CAS %d\n", s->cas); val = s->cas; s->cas = 1; break; case PI_CIV: case PO_CIV: case MC_CIV: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->civ; - dolog ("CIV[%d] -> %#x\n", GET_BM (index), val); + dolog("CIV[%d] -> 0x%x\n", GET_BM(index), val); break; case PI_LVI: case PO_LVI: case MC_LVI: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->lvi; - dolog ("LVI[%d] -> %#x\n", GET_BM (index), val); + dolog("LVI[%d] -> 0x%x\n", GET_BM(index), val); break; case PI_PIV: case PO_PIV: case MC_PIV: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->piv; - dolog ("PIV[%d] -> %#x\n", GET_BM (index), val); + dolog("PIV[%d] -> 0x%x\n", GET_BM(index), val); break; case PI_CR: case PO_CR: case MC_CR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->cr; - dolog ("CR[%d] -> %#x\n", GET_BM (index), val); + dolog("CR[%d] -> 0x%x\n", GET_BM(index), val); break; case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->sr & 0xff; - dolog ("SRb[%d] -> %#x\n", GET_BM (index), val); + dolog("SRb[%d] -> 0x%x\n", GET_BM(index), val); break; default: - dolog ("U nabm readb %#x -> %#x\n", addr, val); + dolog("U nabm readb 0x%x -> 0x%x\n", addr, val); break; } return val; } -static uint32_t nabm_readw (void *opaque, uint32_t addr) +static uint32_t nabm_readw(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; @@ -776,25 +765,25 @@ static uint32_t nabm_readw (void *opaque, uint32_t addr) case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->sr; - dolog ("SR[%d] -> %#x\n", GET_BM (index), val); + dolog("SR[%d] -> 0x%x\n", GET_BM(index), val); break; case PI_PICB: case PO_PICB: case MC_PICB: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->picb; - dolog ("PICB[%d] -> %#x\n", GET_BM (index), val); + dolog("PICB[%d] -> 0x%x\n", GET_BM(index), val); break; default: - dolog ("U nabm readw %#x -> %#x\n", addr, val); + dolog("U nabm readw 0x%x -> 0x%x\n", addr, val); break; } return val; } -static uint32_t nabm_readl (void *opaque, uint32_t addr) +static uint32_t nabm_readl(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; @@ -805,36 +794,36 @@ static uint32_t nabm_readl (void *opaque, uint32_t addr) case PI_BDBAR: case PO_BDBAR: case MC_BDBAR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->bdbar; - dolog ("BMADDR[%d] -> %#x\n", GET_BM (index), val); + dolog("BMADDR[%d] -> 0x%x\n", GET_BM(index), val); break; case PI_CIV: case PO_CIV: case MC_CIV: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->civ | (r->lvi << 8) | (r->sr << 16); - dolog ("CIV LVI SR[%d] -> %#x, %#x, %#x\n", GET_BM (index), + dolog("CIV LVI SR[%d] -> 0x%x, 0x%x, 0x%x\n", GET_BM(index), r->civ, r->lvi, r->sr); break; case PI_PICB: case PO_PICB: case MC_PICB: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->picb | (r->piv << 16) | (r->cr << 24); - dolog ("PICB PIV CR[%d] -> %#x %#x %#x %#x\n", GET_BM (index), + dolog("PICB PIV CR[%d] -> 0x%x 0x%x 0x%x 0x%x\n", GET_BM(index), val, r->picb, r->piv, r->cr); break; case GLOB_CNT: val = s->glob_cnt; - dolog ("glob_cnt -> %#x\n", val); + dolog("glob_cnt -> 0x%x\n", val); break; case GLOB_STA: val = s->glob_sta | GS_S0CR; - dolog ("glob_sta -> %#x\n", val); + dolog("glob_sta -> 0x%x\n", val); break; default: - dolog ("U nabm readl %#x -> %#x\n", addr, val); + dolog("U nabm readl 0x%x -> 0x%x\n", addr, val); break; } return val; @@ -844,7 +833,7 @@ static uint32_t nabm_readl (void *opaque, uint32_t addr) * Native audio bus master * I/O Writes */ -static void nabm_writeb (void *opaque, uint32_t addr, uint32_t val) +static void nabm_writeb(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; @@ -853,54 +842,52 @@ static void nabm_writeb (void *opaque, uint32_t addr, uint32_t val) case PI_LVI: case PO_LVI: case MC_LVI: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; if ((r->cr & CR_RPBM) && (r->sr & SR_DCH)) { r->sr &= ~(SR_DCH | SR_CELV); r->civ = r->piv; r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); + fetch_bd(s, r); } r->lvi = val % 32; - dolog ("LVI[%d] <- %#x\n", GET_BM (index), val); + dolog("LVI[%d] <- 0x%x\n", GET_BM(index), val); break; case PI_CR: case PO_CR: case MC_CR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; if (val & CR_RR) { - reset_bm_regs (s, r); - } - else { + reset_bm_regs(s, r); + } else { r->cr = val & CR_VALID_MASK; if (!(r->cr & CR_RPBM)) { - voice_set_active (s, r - s->bm_regs, 0); + voice_set_active(s, r - s->bm_regs, 0); r->sr |= SR_DCH; - } - else { + } else { r->civ = r->piv; r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); + fetch_bd(s, r); r->sr &= ~SR_DCH; - voice_set_active (s, r - s->bm_regs, 1); + voice_set_active(s, r - s->bm_regs, 1); } } - dolog ("CR[%d] <- %#x (cr %#x)\n", GET_BM (index), val, r->cr); + dolog("CR[%d] <- 0x%x (cr 0x%x)\n", GET_BM(index), val, r->cr); break; case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK); - update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK)); - dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr); + update_sr(s, r, r->sr & ~(val & SR_WCLEAR_MASK)); + dolog("SR[%d] <- 0x%x (sr 0x%x)\n", GET_BM(index), val, r->sr); break; default: - dolog ("U nabm writeb %#x <- %#x\n", addr, val); + dolog("U nabm writeb 0x%x <- 0x%x\n", addr, val); break; } } -static void nabm_writew (void *opaque, uint32_t addr, uint32_t val) +static void nabm_writew(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; @@ -909,18 +896,18 @@ static void nabm_writew (void *opaque, uint32_t addr, uint32_t val) case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK); - update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK)); - dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr); + update_sr(s, r, r->sr & ~(val & SR_WCLEAR_MASK)); + dolog("SR[%d] <- 0x%x (sr 0x%x)\n", GET_BM(index), val, r->sr); break; default: - dolog ("U nabm writew %#x <- %#x\n", addr, val); + dolog("U nabm writew 0x%x <- 0x%x\n", addr, val); break; } } -static void nabm_writel (void *opaque, uint32_t addr, uint32_t val) +static void nabm_writel(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; @@ -929,40 +916,42 @@ static void nabm_writel (void *opaque, uint32_t addr, uint32_t val) case PI_BDBAR: case PO_BDBAR: case MC_BDBAR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; r->bdbar = val & ~3; - dolog ("BDBAR[%d] <- %#x (bdbar %#x)\n", - GET_BM (index), val, r->bdbar); + dolog("BDBAR[%d] <- 0x%x (bdbar 0x%x)\n", GET_BM(index), val, r->bdbar); break; case GLOB_CNT: - if (val & GC_WR) - warm_reset (s); - if (val & GC_CR) - cold_reset (s); - if (!(val & (GC_WR | GC_CR))) + if (val & GC_WR) { + warm_reset(s); + } + if (val & GC_CR) { + cold_reset(s); + } + if (!(val & (GC_WR | GC_CR))) { s->glob_cnt = val & GC_VALID_MASK; - dolog ("glob_cnt <- %#x (glob_cnt %#x)\n", val, s->glob_cnt); + } + dolog("glob_cnt <- 0x%x (glob_cnt 0x%x)\n", val, s->glob_cnt); break; case GLOB_STA: s->glob_sta &= ~(val & GS_WCLEAR_MASK); s->glob_sta |= (val & ~(GS_WCLEAR_MASK | GS_RO_MASK)) & GS_VALID_MASK; - dolog ("glob_sta <- %#x (glob_sta %#x)\n", val, s->glob_sta); + dolog("glob_sta <- 0x%x (glob_sta 0x%x)\n", val, s->glob_sta); break; default: - dolog ("U nabm writel %#x <- %#x\n", addr, val); + dolog("U nabm writel 0x%x <- 0x%x\n", addr, val); break; } } -static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, - int max, int *stop) +static int write_audio(AC97LinkState *s, AC97BusMasterRegs *r, + int max, int *stop) { uint8_t tmpbuf[4096]; uint32_t addr = r->bd.addr; uint32_t temp = r->picb << 1; uint32_t written = 0; int to_copy = 0; - temp = MIN (temp, max); + temp = MIN(temp, max); if (!temp) { *stop = 1; @@ -971,11 +960,11 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, while (temp) { int copied; - to_copy = MIN (temp, sizeof (tmpbuf)); - pci_dma_read (&s->dev, addr, tmpbuf, to_copy); - copied = AUD_write (s->voice_po, tmpbuf, to_copy); - dolog ("write_audio max=%x to_copy=%x copied=%x\n", - max, to_copy, copied); + to_copy = MIN(temp, sizeof(tmpbuf)); + pci_dma_read(&s->dev, addr, tmpbuf, to_copy); + copied = AUD_write(s->voice_po, tmpbuf, to_copy); + dolog("write_audio max=%x to_copy=%x copied=%x\n", + max, to_copy, copied); if (!copied) { *stop = 1; break; @@ -987,11 +976,10 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, if (!temp) { if (to_copy < 4) { - dolog ("whoops\n"); + dolog("whoops\n"); s->last_samp = 0; - } - else { - s->last_samp = *(uint32_t *) &tmpbuf[to_copy - 4]; + } else { + s->last_samp = *(uint32_t *)&tmpbuf[to_copy - 4]; } } @@ -999,37 +987,37 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, return written; } -static void write_bup (AC97LinkState *s, int elapsed) +static void write_bup(AC97LinkState *s, int elapsed) { - dolog ("write_bup\n"); + dolog("write_bup\n"); if (!(s->bup_flag & BUP_SET)) { if (s->bup_flag & BUP_LAST) { int i; uint8_t *p = s->silence; - for (i = 0; i < sizeof (s->silence) / 4; i++, p += 4) { + for (i = 0; i < sizeof(s->silence) / 4; i++, p += 4) { *(uint32_t *) p = s->last_samp; } - } - else { - memset (s->silence, 0, sizeof (s->silence)); + } else { + memset(s->silence, 0, sizeof(s->silence)); } s->bup_flag |= BUP_SET; } while (elapsed) { - int temp = MIN (elapsed, sizeof (s->silence)); + int temp = MIN(elapsed, sizeof(s->silence)); while (temp) { - int copied = AUD_write (s->voice_po, s->silence, temp); - if (!copied) + int copied = AUD_write(s->voice_po, s->silence, temp); + if (!copied) { return; + } temp -= copied; elapsed -= copied; } } } -static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r, - int max, int *stop) +static int read_audio(AC97LinkState *s, AC97BusMasterRegs *r, + int max, int *stop) { uint8_t tmpbuf[4096]; uint32_t addr = r->bd.addr; @@ -1038,7 +1026,7 @@ static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r, int to_copy = 0; SWVoiceIn *voice = (r - s->bm_regs) == MC_INDEX ? s->voice_mc : s->voice_pi; - temp = MIN (temp, max); + temp = MIN(temp, max); if (!temp) { *stop = 1; @@ -1047,13 +1035,13 @@ static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r, while (temp) { int acquired; - to_copy = MIN (temp, sizeof (tmpbuf)); - acquired = AUD_read (voice, tmpbuf, to_copy); + to_copy = MIN(temp, sizeof(tmpbuf)); + acquired = AUD_read(voice, tmpbuf, to_copy); if (!acquired) { *stop = 1; break; } - pci_dma_write (&s->dev, addr, tmpbuf, acquired); + pci_dma_write(&s->dev, addr, tmpbuf, acquired); temp -= acquired; addr += acquired; nread += acquired; @@ -1063,14 +1051,14 @@ static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r, return nread; } -static void transfer_audio (AC97LinkState *s, int index, int elapsed) +static void transfer_audio(AC97LinkState *s, int index, int elapsed) { AC97BusMasterRegs *r = &s->bm_regs[index]; int stop = 0; if (s->invalid_freq[index]) { - AUD_log ("ac97", "attempt to use voice %d with invalid frequency %d\n", - index, s->invalid_freq[index]); + AUD_log("ac97", "attempt to use voice %d with invalid frequency %d\n", + index, s->invalid_freq[index]); return; } @@ -1078,7 +1066,7 @@ static void transfer_audio (AC97LinkState *s, int index, int elapsed) if (r->cr & CR_RPBM) { switch (index) { case PO_INDEX: - write_bup (s, elapsed); + write_bup(s, elapsed); break; } } @@ -1089,13 +1077,13 @@ static void transfer_audio (AC97LinkState *s, int index, int elapsed) int temp; if (!r->bd_valid) { - dolog ("invalid bd\n"); - fetch_bd (s, r); + dolog("invalid bd\n"); + fetch_bd(s, r); } if (!r->picb) { - dolog ("fresh bd %d is empty %#x %#x\n", - r->civ, r->bd.addr, r->bd.ctl_len); + dolog("fresh bd %d is empty 0x%x 0x%x\n", + r->civ, r->bd.addr, r->bd.ctl_len); if (r->civ == r->lvi) { r->sr |= SR_DCH; /* CELV? */ s->bup_flag = 0; @@ -1104,20 +1092,20 @@ static void transfer_audio (AC97LinkState *s, int index, int elapsed) r->sr &= ~SR_CELV; r->civ = r->piv; r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); + fetch_bd(s, r); return; } switch (index) { case PO_INDEX: - temp = write_audio (s, r, elapsed, &stop); + temp = write_audio(s, r, elapsed, &stop); elapsed -= temp; r->picb -= (temp >> 1); break; case PI_INDEX: case MC_INDEX: - temp = read_audio (s, r, elapsed, &stop); + temp = read_audio(s, r, elapsed, &stop); elapsed -= temp; r->picb -= (temp >> 1); break; @@ -1131,36 +1119,35 @@ static void transfer_audio (AC97LinkState *s, int index, int elapsed) } if (r->civ == r->lvi) { - dolog ("Underrun civ (%d) == lvi (%d)\n", r->civ, r->lvi); + dolog("Underrun civ (%d) == lvi (%d)\n", r->civ, r->lvi); new_sr |= SR_LVBCI | SR_DCH | SR_CELV; stop = 1; s->bup_flag = (r->bd.ctl_len & BD_BUP) ? BUP_LAST : 0; - } - else { + } else { r->civ = r->piv; r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); + fetch_bd(s, r); } - update_sr (s, r, new_sr); + update_sr(s, r, new_sr); } } } -static void pi_callback (void *opaque, int avail) +static void pi_callback(void *opaque, int avail) { - transfer_audio (opaque, PI_INDEX, avail); + transfer_audio(opaque, PI_INDEX, avail); } -static void mc_callback (void *opaque, int avail) +static void mc_callback(void *opaque, int avail) { - transfer_audio (opaque, MC_INDEX, avail); + transfer_audio(opaque, MC_INDEX, avail); } -static void po_callback (void *opaque, int free) +static void po_callback(void *opaque, int free) { - transfer_audio (opaque, PO_INDEX, free); + transfer_audio(opaque, PO_INDEX, free); } static const VMStateDescription vmstate_ac97_bm_regs = { @@ -1168,44 +1155,44 @@ static const VMStateDescription vmstate_ac97_bm_regs = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT32 (bdbar, AC97BusMasterRegs), - VMSTATE_UINT8 (civ, AC97BusMasterRegs), - VMSTATE_UINT8 (lvi, AC97BusMasterRegs), - VMSTATE_UINT16 (sr, AC97BusMasterRegs), - VMSTATE_UINT16 (picb, AC97BusMasterRegs), - VMSTATE_UINT8 (piv, AC97BusMasterRegs), - VMSTATE_UINT8 (cr, AC97BusMasterRegs), - VMSTATE_UINT32 (bd_valid, AC97BusMasterRegs), - VMSTATE_UINT32 (bd.addr, AC97BusMasterRegs), - VMSTATE_UINT32 (bd.ctl_len, AC97BusMasterRegs), - VMSTATE_END_OF_LIST () + VMSTATE_UINT32(bdbar, AC97BusMasterRegs), + VMSTATE_UINT8(civ, AC97BusMasterRegs), + VMSTATE_UINT8(lvi, AC97BusMasterRegs), + VMSTATE_UINT16(sr, AC97BusMasterRegs), + VMSTATE_UINT16(picb, AC97BusMasterRegs), + VMSTATE_UINT8(piv, AC97BusMasterRegs), + VMSTATE_UINT8(cr, AC97BusMasterRegs), + VMSTATE_UINT32(bd_valid, AC97BusMasterRegs), + VMSTATE_UINT32(bd.addr, AC97BusMasterRegs), + VMSTATE_UINT32(bd.ctl_len, AC97BusMasterRegs), + VMSTATE_END_OF_LIST() } }; -static int ac97_post_load (void *opaque, int version_id) +static int ac97_post_load(void *opaque, int version_id) { uint8_t active[LAST_INDEX]; AC97LinkState *s = opaque; - record_select (s, mixer_load (s, AC97_Record_Select)); - set_volume (s, AC97_Master_Volume_Mute, - mixer_load (s, AC97_Master_Volume_Mute)); - set_volume (s, AC97_PCM_Out_Volume_Mute, - mixer_load (s, AC97_PCM_Out_Volume_Mute)); - set_volume (s, AC97_Record_Gain_Mute, - mixer_load (s, AC97_Record_Gain_Mute)); + record_select(s, mixer_load(s, AC97_Record_Select)); + set_volume(s, AC97_Master_Volume_Mute, + mixer_load(s, AC97_Master_Volume_Mute)); + set_volume(s, AC97_PCM_Out_Volume_Mute, + mixer_load(s, AC97_PCM_Out_Volume_Mute)); + set_volume(s, AC97_Record_Gain_Mute, + mixer_load(s, AC97_Record_Gain_Mute)); active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); - reset_voices (s, active); + reset_voices(s, active); s->bup_flag = 0; s->last_samp = 0; return 0; } -static bool is_version_2 (void *opaque, int version_id) +static bool is_version_2(void *opaque, int version_id) { return version_id == 2; } @@ -1216,15 +1203,15 @@ static const VMStateDescription vmstate_ac97 = { .minimum_version_id = 2, .post_load = ac97_post_load, .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE (dev, AC97LinkState), - VMSTATE_UINT32 (glob_cnt, AC97LinkState), - VMSTATE_UINT32 (glob_sta, AC97LinkState), - VMSTATE_UINT32 (cas, AC97LinkState), - VMSTATE_STRUCT_ARRAY (bm_regs, AC97LinkState, 3, 1, - vmstate_ac97_bm_regs, AC97BusMasterRegs), - VMSTATE_BUFFER (mixer_data, AC97LinkState), - VMSTATE_UNUSED_TEST (is_version_2, 3), - VMSTATE_END_OF_LIST () + VMSTATE_PCI_DEVICE(dev, AC97LinkState), + VMSTATE_UINT32(glob_cnt, AC97LinkState), + VMSTATE_UINT32(glob_sta, AC97LinkState), + VMSTATE_UINT32(cas, AC97LinkState), + VMSTATE_STRUCT_ARRAY(bm_regs, AC97LinkState, 3, 1, + vmstate_ac97_bm_regs, AC97BusMasterRegs), + VMSTATE_BUFFER(mixer_data, AC97LinkState), + VMSTATE_UNUSED_TEST(is_version_2, 3), + VMSTATE_END_OF_LIST() } }; @@ -1295,7 +1282,7 @@ static uint64_t nabm_read(void *opaque, hwaddr addr, unsigned size) } static void nabm_write(void *opaque, hwaddr addr, uint64_t val, - unsigned size) + unsigned size) { if ((addr / size) > 64) { return; @@ -1325,20 +1312,20 @@ static const MemoryRegionOps ac97_io_nabm_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static void ac97_on_reset (DeviceState *dev) +static void ac97_on_reset(DeviceState *dev) { AC97LinkState *s = container_of(dev, AC97LinkState, dev.qdev); - reset_bm_regs (s, &s->bm_regs[0]); - reset_bm_regs (s, &s->bm_regs[1]); - reset_bm_regs (s, &s->bm_regs[2]); + reset_bm_regs(s, &s->bm_regs[0]); + reset_bm_regs(s, &s->bm_regs[1]); + reset_bm_regs(s, &s->bm_regs[2]); /* * Reset the mixer too. The Windows XP driver seems to rely on * this. At least it wants to read the vendor id before it resets * the codec manually. */ - mixer_reset (s); + mixer_reset(s); } static void ac97_realize(PCIDevice *dev, Error **errp) @@ -1373,13 +1360,13 @@ static void ac97_realize(PCIDevice *dev, Error **errp) c[PCI_INTERRUPT_LINE] = 0x00; /* intr_ln interrupt line rw */ c[PCI_INTERRUPT_PIN] = 0x01; /* intr_pn interrupt pin ro */ - memory_region_init_io (&s->io_nam, OBJECT(s), &ac97_io_nam_ops, s, - "ac97-nam", 1024); - memory_region_init_io (&s->io_nabm, OBJECT(s), &ac97_io_nabm_ops, s, - "ac97-nabm", 256); - pci_register_bar (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nam); - pci_register_bar (&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nabm); - AUD_register_card ("ac97", &s->card); + memory_region_init_io(&s->io_nam, OBJECT(s), &ac97_io_nam_ops, s, + "ac97-nam", 1024); + memory_region_init_io(&s->io_nabm, OBJECT(s), &ac97_io_nabm_ops, s, + "ac97-nabm", 256); + pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nam); + pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nabm); + AUD_register_card("ac97", &s->card); ac97_on_reset(DEVICE(s)); } @@ -1395,13 +1382,13 @@ static void ac97_exit(PCIDevice *dev) static Property ac97_properties[] = { DEFINE_AUDIO_PROPERTIES(AC97LinkState, card), - DEFINE_PROP_END_OF_LIST (), + DEFINE_PROP_END_OF_LIST(), }; -static void ac97_class_init (ObjectClass *klass, void *data) +static void ac97_class_init(ObjectClass *klass, void *data) { - DeviceClass *dc = DEVICE_CLASS (klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS (klass); + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); k->realize = ac97_realize; k->exit = ac97_exit; @@ -1419,7 +1406,7 @@ static void ac97_class_init (ObjectClass *klass, void *data) static const TypeInfo ac97_info = { .name = TYPE_AC97, .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof (AC97LinkState), + .instance_size = sizeof(AC97LinkState), .class_init = ac97_class_init, .interfaces = (InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, @@ -1427,11 +1414,11 @@ static const TypeInfo ac97_info = { }, }; -static void ac97_register_types (void) +static void ac97_register_types(void) { - type_register_static (&ac97_info); + type_register_static(&ac97_info); deprecated_register_soundhw("ac97", "Intel 82801AA AC97 Audio", 0, TYPE_AC97); } -type_init (ac97_register_types) +type_init(ac97_register_types) From dafea9e2868a5349bb0f1650dd18fa1aac806ee4 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 23 Apr 2022 11:36:57 +0200 Subject: [PATCH 512/935] hw/audio/ac97: Remove unimplemented reset functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The warm_reset() and cold_reset() functions are not implemented and do nothing so no point in calling them or keep around as dead code. Therefore remove them for now. Signed-off-by: BALATON Zoltan Reviewed-by: Víctor Colombo Message-Id: Signed-off-by: Paolo Bonzini --- hw/audio/ac97.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c index 6b1c12bece..6584aa749e 100644 --- a/hw/audio/ac97.c +++ b/hw/audio/ac97.c @@ -222,16 +222,6 @@ static void po_callback(void *opaque, int free); static void pi_callback(void *opaque, int avail); static void mc_callback(void *opaque, int avail); -static void warm_reset(AC97LinkState *s) -{ - (void)s; -} - -static void cold_reset(AC97LinkState *s) -{ - (void)s; -} - static void fetch_bd(AC97LinkState *s, AC97BusMasterRegs *r) { uint8_t b[8]; @@ -921,12 +911,7 @@ static void nabm_writel(void *opaque, uint32_t addr, uint32_t val) dolog("BDBAR[%d] <- 0x%x (bdbar 0x%x)\n", GET_BM(index), val, r->bdbar); break; case GLOB_CNT: - if (val & GC_WR) { - warm_reset(s); - } - if (val & GC_CR) { - cold_reset(s); - } + /* TODO: Handle WR or CR being set (warm/cold reset requests) */ if (!(val & (GC_WR | GC_CR))) { s->glob_cnt = val & GC_VALID_MASK; } From dba2b2941ca2ebd5275b3b2c6e72678f98f83a8a Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 23 Apr 2022 11:36:57 +0200 Subject: [PATCH 513/935] hw/audio/ac97: Remove unneeded local variables Several functions have a local variable that is just a copy of one of the function parameters. This is unneeded complication so just get rid of these. Signed-off-by: BALATON Zoltan Reviewed-by: Peter Maydell Message-Id: Signed-off-by: Paolo Bonzini --- hw/audio/ac97.c | 102 +++++++++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 53 deletions(-) diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c index 6584aa749e..be2dd701a4 100644 --- a/hw/audio/ac97.c +++ b/hw/audio/ac97.c @@ -557,9 +557,8 @@ static uint32_t nam_readb(void *opaque, uint32_t addr) static uint32_t nam_readw(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; - uint32_t index = addr; s->cas = 0; - return mixer_load(s, index); + return mixer_load(s, addr); } static uint32_t nam_readl(void *opaque, uint32_t addr) @@ -584,21 +583,21 @@ static void nam_writeb(void *opaque, uint32_t addr, uint32_t val) static void nam_writew(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; - uint32_t index = addr; + s->cas = 0; - switch (index) { + switch (addr) { case AC97_Reset: mixer_reset(s); break; case AC97_Powerdown_Ctrl_Stat: val &= ~0x800f; - val |= mixer_load(s, index) & 0xf; - mixer_store(s, index, val); + val |= mixer_load(s, addr) & 0xf; + mixer_store(s, addr, val); break; case AC97_PCM_Out_Volume_Mute: case AC97_Master_Volume_Mute: case AC97_Record_Gain_Mute: - set_volume(s, index, val); + set_volume(s, addr, val); break; case AC97_Record_Select: record_select(s, val); @@ -626,7 +625,7 @@ static void nam_writew(void *opaque, uint32_t addr, uint32_t val) break; case AC97_PCM_Front_DAC_Rate: if (mixer_load(s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { - mixer_store(s, index, val); + mixer_store(s, addr, val); dolog("Set front DAC rate to %d\n", val); open_voice(s, PO_INDEX, val); } else { @@ -636,7 +635,7 @@ static void nam_writew(void *opaque, uint32_t addr, uint32_t val) break; case AC97_MIC_ADC_Rate: if (mixer_load(s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM) { - mixer_store(s, index, val); + mixer_store(s, addr, val); dolog("Set MIC ADC rate to %d\n", val); open_voice(s, MC_INDEX, val); } else { @@ -646,7 +645,7 @@ static void nam_writew(void *opaque, uint32_t addr, uint32_t val) break; case AC97_PCM_LR_ADC_Rate: if (mixer_load(s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { - mixer_store(s, index, val); + mixer_store(s, addr, val); dolog("Set front LR ADC rate to %d\n", val); open_voice(s, PI_INDEX, val); } else { @@ -673,7 +672,7 @@ static void nam_writew(void *opaque, uint32_t addr, uint32_t val) break; default: dolog("U nam writew 0x%x <- 0x%x\n", addr, val); - mixer_store(s, index, val); + mixer_store(s, addr, val); break; } } @@ -693,10 +692,9 @@ static uint32_t nabm_readb(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; - uint32_t index = addr; uint32_t val = ~0U; - switch (index) { + switch (addr) { case CAS: dolog("CAS %d\n", s->cas); val = s->cas; @@ -705,37 +703,37 @@ static uint32_t nabm_readb(void *opaque, uint32_t addr) case PI_CIV: case PO_CIV: case MC_CIV: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->civ; - dolog("CIV[%d] -> 0x%x\n", GET_BM(index), val); + dolog("CIV[%d] -> 0x%x\n", GET_BM(addr), val); break; case PI_LVI: case PO_LVI: case MC_LVI: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->lvi; - dolog("LVI[%d] -> 0x%x\n", GET_BM(index), val); + dolog("LVI[%d] -> 0x%x\n", GET_BM(addr), val); break; case PI_PIV: case PO_PIV: case MC_PIV: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->piv; - dolog("PIV[%d] -> 0x%x\n", GET_BM(index), val); + dolog("PIV[%d] -> 0x%x\n", GET_BM(addr), val); break; case PI_CR: case PO_CR: case MC_CR: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->cr; - dolog("CR[%d] -> 0x%x\n", GET_BM(index), val); + dolog("CR[%d] -> 0x%x\n", GET_BM(addr), val); break; case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->sr & 0xff; - dolog("SRb[%d] -> 0x%x\n", GET_BM(index), val); + dolog("SRb[%d] -> 0x%x\n", GET_BM(addr), val); break; default: dolog("U nabm readb 0x%x -> 0x%x\n", addr, val); @@ -748,23 +746,22 @@ static uint32_t nabm_readw(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; - uint32_t index = addr; uint32_t val = ~0U; - switch (index) { + switch (addr) { case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->sr; - dolog("SR[%d] -> 0x%x\n", GET_BM(index), val); + dolog("SR[%d] -> 0x%x\n", GET_BM(addr), val); break; case PI_PICB: case PO_PICB: case MC_PICB: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->picb; - dolog("PICB[%d] -> 0x%x\n", GET_BM(index), val); + dolog("PICB[%d] -> 0x%x\n", GET_BM(addr), val); break; default: dolog("U nabm readw 0x%x -> 0x%x\n", addr, val); @@ -777,31 +774,30 @@ static uint32_t nabm_readl(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; - uint32_t index = addr; uint32_t val = ~0U; - switch (index) { + switch (addr) { case PI_BDBAR: case PO_BDBAR: case MC_BDBAR: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->bdbar; - dolog("BMADDR[%d] -> 0x%x\n", GET_BM(index), val); + dolog("BMADDR[%d] -> 0x%x\n", GET_BM(addr), val); break; case PI_CIV: case PO_CIV: case MC_CIV: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->civ | (r->lvi << 8) | (r->sr << 16); - dolog("CIV LVI SR[%d] -> 0x%x, 0x%x, 0x%x\n", GET_BM(index), + dolog("CIV LVI SR[%d] -> 0x%x, 0x%x, 0x%x\n", GET_BM(addr), r->civ, r->lvi, r->sr); break; case PI_PICB: case PO_PICB: case MC_PICB: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->picb | (r->piv << 16) | (r->cr << 24); - dolog("PICB PIV CR[%d] -> 0x%x 0x%x 0x%x 0x%x\n", GET_BM(index), + dolog("PICB PIV CR[%d] -> 0x%x 0x%x 0x%x 0x%x\n", GET_BM(addr), val, r->picb, r->piv, r->cr); break; case GLOB_CNT: @@ -827,12 +823,12 @@ static void nabm_writeb(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; - uint32_t index = addr; - switch (index) { + + switch (addr) { case PI_LVI: case PO_LVI: case MC_LVI: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; if ((r->cr & CR_RPBM) && (r->sr & SR_DCH)) { r->sr &= ~(SR_DCH | SR_CELV); r->civ = r->piv; @@ -840,12 +836,12 @@ static void nabm_writeb(void *opaque, uint32_t addr, uint32_t val) fetch_bd(s, r); } r->lvi = val % 32; - dolog("LVI[%d] <- 0x%x\n", GET_BM(index), val); + dolog("LVI[%d] <- 0x%x\n", GET_BM(addr), val); break; case PI_CR: case PO_CR: case MC_CR: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; if (val & CR_RR) { reset_bm_regs(s, r); } else { @@ -861,15 +857,15 @@ static void nabm_writeb(void *opaque, uint32_t addr, uint32_t val) voice_set_active(s, r - s->bm_regs, 1); } } - dolog("CR[%d] <- 0x%x (cr 0x%x)\n", GET_BM(index), val, r->cr); + dolog("CR[%d] <- 0x%x (cr 0x%x)\n", GET_BM(addr), val, r->cr); break; case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK); update_sr(s, r, r->sr & ~(val & SR_WCLEAR_MASK)); - dolog("SR[%d] <- 0x%x (sr 0x%x)\n", GET_BM(index), val, r->sr); + dolog("SR[%d] <- 0x%x (sr 0x%x)\n", GET_BM(addr), val, r->sr); break; default: dolog("U nabm writeb 0x%x <- 0x%x\n", addr, val); @@ -881,15 +877,15 @@ static void nabm_writew(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; - uint32_t index = addr; - switch (index) { + + switch (addr) { case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK); update_sr(s, r, r->sr & ~(val & SR_WCLEAR_MASK)); - dolog("SR[%d] <- 0x%x (sr 0x%x)\n", GET_BM(index), val, r->sr); + dolog("SR[%d] <- 0x%x (sr 0x%x)\n", GET_BM(addr), val, r->sr); break; default: dolog("U nabm writew 0x%x <- 0x%x\n", addr, val); @@ -901,14 +897,14 @@ static void nabm_writel(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; - uint32_t index = addr; - switch (index) { + + switch (addr) { case PI_BDBAR: case PO_BDBAR: case MC_BDBAR: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; r->bdbar = val & ~3; - dolog("BDBAR[%d] <- 0x%x (bdbar 0x%x)\n", GET_BM(index), val, r->bdbar); + dolog("BDBAR[%d] <- 0x%x (bdbar 0x%x)\n", GET_BM(addr), val, r->bdbar); break; case GLOB_CNT: /* TODO: Handle WR or CR being set (warm/cold reset requests) */ From 267b5e7e378afd260004cb37a66a6fcd641e3b53 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 23 May 2022 18:26:58 +0200 Subject: [PATCH 514/935] target/i386/kvm: Fix disabling MPX on "-cpu host" with MPX-capable host Since KVM commit 5f76f6f5ff96 ("KVM: nVMX: Do not expose MPX VMX controls when guest MPX disabled") it is not possible to disable MPX on a "-cpu host" just by adding "-mpx" there if the host CPU does indeed support MPX. QEMU will fail to set MSR_IA32_VMX_TRUE_{EXIT,ENTRY}_CTLS MSRs in this case and so trigger an assertion failure. Instead, besides "-mpx" one has to explicitly add also "-vmx-exit-clear-bndcfgs" and "-vmx-entry-load-bndcfgs" to QEMU command line to make it work, which is a bit convoluted. Make the MPX-related bits in FEAT_VMX_{EXIT,ENTRY}_CTLS dependent on MPX being actually enabled so such workarounds are no longer necessary. Signed-off-by: Maciej S. Szmigiero Message-Id: <51aa2125c76363204cc23c27165e778097c33f0b.1653323077.git.maciej.szmigiero@oracle.com> Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 35c3475e6c..385691458f 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -1355,6 +1355,14 @@ static FeatureDep feature_dependencies[] = { .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_INVPCID }, .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_INVPCID }, }, + { + .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_MPX }, + .to = { FEAT_VMX_EXIT_CTLS, VMX_VM_EXIT_CLEAR_BNDCFGS }, + }, + { + .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_MPX }, + .to = { FEAT_VMX_ENTRY_CTLS, VMX_VM_ENTRY_LOAD_BNDCFGS }, + }, { .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_RDSEED }, .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_RDSEED_EXITING }, From 758c925ee04ecd9d2d543a60f3c389e4e814c6aa Mon Sep 17 00:00:00 2001 From: Lev Kujawski Date: Fri, 20 May 2022 23:52:00 +0000 Subject: [PATCH 515/935] ide_ioport_read: Return lower octet of data register instead of 0xFF Prior to this patch, the pre-GRUB Solaris x86 bootloader would fail to load on QEMU with the following screen output: SunOS Secondary Boot version 3.00 prom_panic: Could not mount filesystem. Entering boot debugger: [136419]: _ This occurs because the bootloader issues an ATA IDENTIFY DEVICE command, and then reads the resulting 256 words of parameter information using inb rather than the correct inw. As the previous behavior of QEMU was to return 0xFF and not advance the drive's sector buffer, DRQ would never be cleared and the bootloader would be blocked from selecting a secondary ATA device, such as an optical drive. Resolves: * [Bug 1639394] Unable to boot Solaris 8/9 x86 under Fedora 24 Signed-off-by: Lev Kujawski Message-Id: <20220520235200.1138450-1-lkujaw@member.fsf.org> Signed-off-by: Paolo Bonzini --- hw/ide/core.c | 6 +++++- hw/ide/macio.c | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index 3a5afff5d7..c2caa54285 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -2166,7 +2166,11 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr) hob = bus->cmd & (IDE_CTRL_HOB); switch (reg_num) { case ATA_IOPORT_RR_DATA: - ret = 0xff; + /* + * The pre-GRUB Solaris x86 bootloader relies upon inb + * consuming a word from the drive's sector buffer. + */ + ret = ide_data_readw(bus, addr) & 0xff; break; case ATA_IOPORT_RR_ERROR: if ((!bus->ifs[0].blk && !bus->ifs[1].blk) || diff --git a/hw/ide/macio.c b/hw/ide/macio.c index f08318cf97..1c15c37ec5 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -267,7 +267,9 @@ static uint64_t pmac_ide_read(void *opaque, hwaddr addr, unsigned size) switch (reg) { case 0x0: - if (size == 2) { + if (size == 1) { + retval = ide_data_readw(&d->bus, 0) & 0xFF; + } else if (size == 2) { retval = ide_data_readw(&d->bus, 0); } else if (size == 4) { retval = ide_data_readl(&d->bus, 0); From 7110fe56c1f69b9e1bdf838558fdcb75d1568964 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 25 May 2022 13:59:44 +0200 Subject: [PATCH 516/935] i386: Use hv_build_cpuid_leaf() for HV_CPUID_NESTED_FEATURES Previously, HV_CPUID_NESTED_FEATURES.EAX CPUID leaf was handled differently as it was only used to encode the supported eVMCS version range. In fact, there are also feature (e.g. Enlightened MSR-Bitmap) bits there. In preparation to adding these features, move HV_CPUID_NESTED_FEATURES leaf handling to hv_build_cpuid_leaf() and drop now-unneeded 'hyperv_nested'. No functional change intended. Signed-off-by: Vitaly Kuznetsov Message-Id: <20220525115949.1294004-2-vkuznets@redhat.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 1 - target/i386/kvm/kvm.c | 25 +++++++++++++++---------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 0d528ac58f..2e918daf6b 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1804,7 +1804,6 @@ struct ArchCPU { uint32_t hyperv_vendor_id[3]; uint32_t hyperv_interface_id[4]; uint32_t hyperv_limits[3]; - uint32_t hyperv_nested[4]; bool hyperv_enforce_cpuid; uint32_t hyperv_ver_id_build; uint16_t hyperv_ver_id_major; diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index e2d675115b..38af0e4f04 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -831,6 +831,8 @@ static bool tsc_is_stable_and_known(CPUX86State *env) || env->user_tsc_khz; } +#define DEFAULT_EVMCS_VERSION ((1 << 8) | 1) + static struct { const char *desc; struct { @@ -1254,6 +1256,13 @@ static uint32_t hv_build_cpuid_leaf(CPUState *cs, uint32_t func, int reg) } } + /* HV_CPUID_NESTED_FEATURES.EAX also encodes the supported eVMCS range */ + if (func == HV_CPUID_NESTED_FEATURES && reg == R_EAX) { + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS)) { + r |= DEFAULT_EVMCS_VERSION; + } + } + return r; } @@ -1384,11 +1393,11 @@ static int hyperv_fill_cpuids(CPUState *cs, struct kvm_cpuid_entry2 *c; uint32_t signature[3]; uint32_t cpuid_i = 0, max_cpuid_leaf = 0; + uint32_t nested_eax = + hv_build_cpuid_leaf(cs, HV_CPUID_NESTED_FEATURES, R_EAX); - max_cpuid_leaf = HV_CPUID_IMPLEMENT_LIMITS; - if (hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS)) { - max_cpuid_leaf = MAX(max_cpuid_leaf, HV_CPUID_NESTED_FEATURES); - } + max_cpuid_leaf = nested_eax ? HV_CPUID_NESTED_FEATURES : + HV_CPUID_IMPLEMENT_LIMITS; if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNDBG)) { max_cpuid_leaf = @@ -1461,7 +1470,7 @@ static int hyperv_fill_cpuids(CPUState *cs, c->ecx = cpu->hyperv_limits[1]; c->edx = cpu->hyperv_limits[2]; - if (hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS)) { + if (nested_eax) { uint32_t function; /* Create zeroed 0x40000006..0x40000009 leaves */ @@ -1473,7 +1482,7 @@ static int hyperv_fill_cpuids(CPUState *cs, c = &cpuid_ent[cpuid_i++]; c->function = HV_CPUID_NESTED_FEATURES; - c->eax = cpu->hyperv_nested[0]; + c->eax = nested_eax; } if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNDBG)) { @@ -1522,8 +1531,6 @@ static bool evmcs_version_supported(uint16_t evmcs_version, (max_version <= max_supported_version); } -#define DEFAULT_EVMCS_VERSION ((1 << 8) | 1) - static int hyperv_init_vcpu(X86CPU *cpu) { CPUState *cs = CPU(cpu); @@ -1620,8 +1627,6 @@ static int hyperv_init_vcpu(X86CPU *cpu) supported_evmcs_version >> 8); return -ENOTSUP; } - - cpu->hyperv_nested[0] = evmcs_version; } if (cpu->hyperv_enforce_cpuid) { From 869840d26c929b99694e31b1a18e83bdea6e97ca Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 25 May 2022 13:59:45 +0200 Subject: [PATCH 517/935] i386: Hyper-V Enlightened MSR bitmap feature The newly introduced enlightenment allow L0 (KVM) and L1 (Hyper-V) hypervisors to collaborate to avoid unnecessary updates to L2 MSR-Bitmap upon vmexits. Signed-off-by: Vitaly Kuznetsov Message-Id: <20220525115949.1294004-3-vkuznets@redhat.com> Signed-off-by: Paolo Bonzini --- docs/hyperv.txt | 9 +++++++++ target/i386/cpu.c | 2 ++ target/i386/cpu.h | 1 + target/i386/kvm/hyperv-proto.h | 5 +++++ target/i386/kvm/kvm.c | 7 +++++++ 5 files changed, 24 insertions(+) diff --git a/docs/hyperv.txt b/docs/hyperv.txt index 33588a0396..5d85569b99 100644 --- a/docs/hyperv.txt +++ b/docs/hyperv.txt @@ -239,6 +239,15 @@ This enlightenment requires a VMBus device (-device vmbus-bridge,irq=15) and the follow enlightenments to work: hv-relaxed,hv_time,hv-vapic,hv-vpindex,hv-synic,hv-runtime,hv-stimer +3.22. hv-emsr-bitmap +===================== +The enlightenment is nested specific, it targets Hyper-V on KVM guests. When +enabled, it allows L0 (KVM) and L1 (Hyper-V) hypervisors to collaborate to +avoid unnecessary updates to L2 MSR-Bitmap upon vmexits. While the protocol is +supported for both VMX (Intel) and SVM (AMD), the VMX implementation requires +Enlightened VMCS ('hv-evmcs') feature to also be enabled. + +Recommended: hv-evmcs (Intel) 4. Supplementary features ========================= diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 385691458f..474e9b582e 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6968,6 +6968,8 @@ static Property x86_cpu_properties[] = { HYPERV_FEAT_STIMER_DIRECT, 0), DEFINE_PROP_BIT64("hv-avic", X86CPU, hyperv_features, HYPERV_FEAT_AVIC, 0), + DEFINE_PROP_BIT64("hv-emsr-bitmap", X86CPU, hyperv_features, + HYPERV_FEAT_MSR_BITMAP, 0), DEFINE_PROP_ON_OFF_AUTO("hv-no-nonarch-coresharing", X86CPU, hyperv_no_nonarch_cs, ON_OFF_AUTO_OFF), DEFINE_PROP_BIT64("hv-syndbg", X86CPU, hyperv_features, diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 2e918daf6b..c788285736 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1106,6 +1106,7 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, #define HYPERV_FEAT_STIMER_DIRECT 14 #define HYPERV_FEAT_AVIC 15 #define HYPERV_FEAT_SYNDBG 16 +#define HYPERV_FEAT_MSR_BITMAP 17 #ifndef HYPERV_SPINLOCK_NEVER_NOTIFY #define HYPERV_SPINLOCK_NEVER_NOTIFY 0xFFFFFFFF diff --git a/target/i386/kvm/hyperv-proto.h b/target/i386/kvm/hyperv-proto.h index e40e59411c..cea18dbc0e 100644 --- a/target/i386/kvm/hyperv-proto.h +++ b/target/i386/kvm/hyperv-proto.h @@ -86,6 +86,11 @@ */ #define HV_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING (1u << 1) +/* + * HV_CPUID_NESTED_FEATURES.EAX bits + */ +#define HV_NESTED_MSR_BITMAP (1u << 19) + /* * Basic virtualized MSRs */ diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 38af0e4f04..f389bbedf2 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -973,6 +973,13 @@ static struct { .dependencies = BIT(HYPERV_FEAT_SYNIC) | BIT(HYPERV_FEAT_RELAXED) }, #endif + [HYPERV_FEAT_MSR_BITMAP] = { + .desc = "enlightened MSR-Bitmap (hv-emsr-bitmap)", + .flags = { + {.func = HV_CPUID_NESTED_FEATURES, .reg = R_EAX, + .bits = HV_NESTED_MSR_BITMAP} + } + }, }; static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max, From 9411e8b6faeb1d88d4441c63c5ec072a01b2914e Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 25 May 2022 13:59:46 +0200 Subject: [PATCH 518/935] i386: Hyper-V XMM fast hypercall input feature Hyper-V specification allows to pass parameters for certain hypercalls using XMM registers ("XMM Fast Hypercall Input"). When the feature is in use, it allows for faster hypercalls processing as KVM can avoid reading guest's memory. KVM supports the feature since v5.14. Rename HV_HYPERCALL_{PARAMS_XMM_AVAILABLE -> XMM_INPUT_AVAILABLE} to comply with KVM. Signed-off-by: Vitaly Kuznetsov Message-Id: <20220525115949.1294004-4-vkuznets@redhat.com> Signed-off-by: Paolo Bonzini --- docs/hyperv.txt | 6 ++++++ target/i386/cpu.c | 2 ++ target/i386/cpu.h | 1 + target/i386/kvm/hyperv-proto.h | 2 +- target/i386/kvm/kvm.c | 7 +++++++ 5 files changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/hyperv.txt b/docs/hyperv.txt index 5d85569b99..af1b10c0b3 100644 --- a/docs/hyperv.txt +++ b/docs/hyperv.txt @@ -249,6 +249,12 @@ Enlightened VMCS ('hv-evmcs') feature to also be enabled. Recommended: hv-evmcs (Intel) +3.23. hv-xmm-input +=================== +Hyper-V specification allows to pass parameters for certain hypercalls using XMM +registers ("XMM Fast Hypercall Input"). When the feature is in use, it allows +for faster hypercalls processing as KVM can avoid reading guest's memory. + 4. Supplementary features ========================= diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 474e9b582e..63cec0ea68 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6970,6 +6970,8 @@ static Property x86_cpu_properties[] = { HYPERV_FEAT_AVIC, 0), DEFINE_PROP_BIT64("hv-emsr-bitmap", X86CPU, hyperv_features, HYPERV_FEAT_MSR_BITMAP, 0), + DEFINE_PROP_BIT64("hv-xmm-input", X86CPU, hyperv_features, + HYPERV_FEAT_XMM_INPUT, 0), DEFINE_PROP_ON_OFF_AUTO("hv-no-nonarch-coresharing", X86CPU, hyperv_no_nonarch_cs, ON_OFF_AUTO_OFF), DEFINE_PROP_BIT64("hv-syndbg", X86CPU, hyperv_features, diff --git a/target/i386/cpu.h b/target/i386/cpu.h index c788285736..37e9553584 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1107,6 +1107,7 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, #define HYPERV_FEAT_AVIC 15 #define HYPERV_FEAT_SYNDBG 16 #define HYPERV_FEAT_MSR_BITMAP 17 +#define HYPERV_FEAT_XMM_INPUT 18 #ifndef HYPERV_SPINLOCK_NEVER_NOTIFY #define HYPERV_SPINLOCK_NEVER_NOTIFY 0xFFFFFFFF diff --git a/target/i386/kvm/hyperv-proto.h b/target/i386/kvm/hyperv-proto.h index cea18dbc0e..f5f16474fa 100644 --- a/target/i386/kvm/hyperv-proto.h +++ b/target/i386/kvm/hyperv-proto.h @@ -54,7 +54,7 @@ #define HV_GUEST_DEBUGGING_AVAILABLE (1u << 1) #define HV_PERF_MONITOR_AVAILABLE (1u << 2) #define HV_CPU_DYNAMIC_PARTITIONING_AVAILABLE (1u << 3) -#define HV_HYPERCALL_PARAMS_XMM_AVAILABLE (1u << 4) +#define HV_HYPERCALL_XMM_INPUT_AVAILABLE (1u << 4) #define HV_GUEST_IDLE_STATE_AVAILABLE (1u << 5) #define HV_FREQUENCY_MSRS_AVAILABLE (1u << 8) #define HV_GUEST_CRASH_MSR_AVAILABLE (1u << 10) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index f389bbedf2..7e6f934eda 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -980,6 +980,13 @@ static struct { .bits = HV_NESTED_MSR_BITMAP} } }, + [HYPERV_FEAT_XMM_INPUT] = { + .desc = "XMM fast hypercall input (hv-xmm-input)", + .flags = { + {.func = HV_CPUID_FEATURES, .reg = R_EDX, + .bits = HV_HYPERCALL_XMM_INPUT_AVAILABLE} + } + }, }; static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max, From aa6bb5fad58d049c6ea97448d4caba4499d60634 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 25 May 2022 13:59:47 +0200 Subject: [PATCH 519/935] i386: Hyper-V Support extended GVA ranges for TLB flush hypercalls KVM kind of supported "extended GVA ranges" (up to 4095 additional GFNs per hypercall) since the implementation of Hyper-V PV TLB flush feature (Linux-4.18) as regardless of the request, full TLB flush was always performed. "Extended GVA ranges for TLB flush hypercalls" feature bit wasn't exposed then. Now, as KVM gains support for fine-grained TLB flush handling, exposing this feature starts making sense. Signed-off-by: Vitaly Kuznetsov Message-Id: <20220525115949.1294004-5-vkuznets@redhat.com> Signed-off-by: Paolo Bonzini --- docs/hyperv.txt | 7 +++++++ target/i386/cpu.c | 2 ++ target/i386/cpu.h | 1 + target/i386/kvm/hyperv-proto.h | 1 + target/i386/kvm/kvm.c | 8 ++++++++ 5 files changed, 19 insertions(+) diff --git a/docs/hyperv.txt b/docs/hyperv.txt index af1b10c0b3..4b132b1c94 100644 --- a/docs/hyperv.txt +++ b/docs/hyperv.txt @@ -255,6 +255,13 @@ Hyper-V specification allows to pass parameters for certain hypercalls using XMM registers ("XMM Fast Hypercall Input"). When the feature is in use, it allows for faster hypercalls processing as KVM can avoid reading guest's memory. +3.24. hv-tlbflush-ext +===================== +Allow for extended GVA ranges to be passed to Hyper-V TLB flush hypercalls +(HvFlushVirtualAddressList/HvFlushVirtualAddressListEx). + +Requires: hv-tlbflush + 4. Supplementary features ========================= diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 63cec0ea68..3429a4e455 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6972,6 +6972,8 @@ static Property x86_cpu_properties[] = { HYPERV_FEAT_MSR_BITMAP, 0), DEFINE_PROP_BIT64("hv-xmm-input", X86CPU, hyperv_features, HYPERV_FEAT_XMM_INPUT, 0), + DEFINE_PROP_BIT64("hv-tlbflush-ext", X86CPU, hyperv_features, + HYPERV_FEAT_TLBFLUSH_EXT, 0), DEFINE_PROP_ON_OFF_AUTO("hv-no-nonarch-coresharing", X86CPU, hyperv_no_nonarch_cs, ON_OFF_AUTO_OFF), DEFINE_PROP_BIT64("hv-syndbg", X86CPU, hyperv_features, diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 37e9553584..5ff48257e5 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1108,6 +1108,7 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, #define HYPERV_FEAT_SYNDBG 16 #define HYPERV_FEAT_MSR_BITMAP 17 #define HYPERV_FEAT_XMM_INPUT 18 +#define HYPERV_FEAT_TLBFLUSH_EXT 19 #ifndef HYPERV_SPINLOCK_NEVER_NOTIFY #define HYPERV_SPINLOCK_NEVER_NOTIFY 0xFFFFFFFF diff --git a/target/i386/kvm/hyperv-proto.h b/target/i386/kvm/hyperv-proto.h index f5f16474fa..c7854ed6d3 100644 --- a/target/i386/kvm/hyperv-proto.h +++ b/target/i386/kvm/hyperv-proto.h @@ -59,6 +59,7 @@ #define HV_FREQUENCY_MSRS_AVAILABLE (1u << 8) #define HV_GUEST_CRASH_MSR_AVAILABLE (1u << 10) #define HV_FEATURE_DEBUG_MSRS_AVAILABLE (1u << 11) +#define HV_EXT_GVA_RANGES_FLUSH_AVAILABLE (1u << 14) #define HV_STIMER_DIRECT_MODE_AVAILABLE (1u << 19) /* diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 7e6f934eda..a11c8e88f6 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -987,6 +987,14 @@ static struct { .bits = HV_HYPERCALL_XMM_INPUT_AVAILABLE} } }, + [HYPERV_FEAT_TLBFLUSH_EXT] = { + .desc = "Extended gva ranges for TLB flush hypercalls (hv-tlbflush-ext)", + .flags = { + {.func = HV_CPUID_FEATURES, .reg = R_EDX, + .bits = HV_EXT_GVA_RANGES_FLUSH_AVAILABLE} + }, + .dependencies = BIT(HYPERV_FEAT_TLBFLUSH) + }, }; static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max, From 3aae0854b26aff303202c6f9542445f58b2539fe Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 25 May 2022 13:59:48 +0200 Subject: [PATCH 520/935] i386: Hyper-V Direct TLB flush hypercall Hyper-V TLFS allows for L0 and L1 hypervisors to collaborate on L2's TLB flush hypercalls handling. With the correct setup, L2's TLB flush hypercalls can be handled by L0 directly, without the need to exit to L1. Signed-off-by: Vitaly Kuznetsov Message-Id: <20220525115949.1294004-6-vkuznets@redhat.com> Signed-off-by: Paolo Bonzini --- docs/hyperv.txt | 11 +++++++++++ target/i386/cpu.c | 2 ++ target/i386/cpu.h | 1 + target/i386/kvm/hyperv-proto.h | 1 + target/i386/kvm/kvm.c | 8 ++++++++ 5 files changed, 23 insertions(+) diff --git a/docs/hyperv.txt b/docs/hyperv.txt index 4b132b1c94..14a7f449ea 100644 --- a/docs/hyperv.txt +++ b/docs/hyperv.txt @@ -262,6 +262,17 @@ Allow for extended GVA ranges to be passed to Hyper-V TLB flush hypercalls Requires: hv-tlbflush +3.25. hv-tlbflush-direct +========================= +The enlightenment is nested specific, it targets Hyper-V on KVM guests. When +enabled, it allows L0 (KVM) to directly handle TLB flush hypercalls from L2 +guest without the need to exit to L1 (Hyper-V) hypervisor. While the feature is +supported for both VMX (Intel) and SVM (AMD), the VMX implementation requires +Enlightened VMCS ('hv-evmcs') feature to also be enabled. + +Requires: hv-vapic +Recommended: hv-evmcs (Intel) + 4. Supplementary features ========================= diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 3429a4e455..bb6a5dd498 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6974,6 +6974,8 @@ static Property x86_cpu_properties[] = { HYPERV_FEAT_XMM_INPUT, 0), DEFINE_PROP_BIT64("hv-tlbflush-ext", X86CPU, hyperv_features, HYPERV_FEAT_TLBFLUSH_EXT, 0), + DEFINE_PROP_BIT64("hv-tlbflush-direct", X86CPU, hyperv_features, + HYPERV_FEAT_TLBFLUSH_DIRECT, 0), DEFINE_PROP_ON_OFF_AUTO("hv-no-nonarch-coresharing", X86CPU, hyperv_no_nonarch_cs, ON_OFF_AUTO_OFF), DEFINE_PROP_BIT64("hv-syndbg", X86CPU, hyperv_features, diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 5ff48257e5..82004b65b9 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1109,6 +1109,7 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, #define HYPERV_FEAT_MSR_BITMAP 17 #define HYPERV_FEAT_XMM_INPUT 18 #define HYPERV_FEAT_TLBFLUSH_EXT 19 +#define HYPERV_FEAT_TLBFLUSH_DIRECT 20 #ifndef HYPERV_SPINLOCK_NEVER_NOTIFY #define HYPERV_SPINLOCK_NEVER_NOTIFY 0xFFFFFFFF diff --git a/target/i386/kvm/hyperv-proto.h b/target/i386/kvm/hyperv-proto.h index c7854ed6d3..464fbf09e3 100644 --- a/target/i386/kvm/hyperv-proto.h +++ b/target/i386/kvm/hyperv-proto.h @@ -90,6 +90,7 @@ /* * HV_CPUID_NESTED_FEATURES.EAX bits */ +#define HV_NESTED_DIRECT_FLUSH (1u << 17) #define HV_NESTED_MSR_BITMAP (1u << 19) /* diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index a11c8e88f6..f148a6d52f 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -995,6 +995,14 @@ static struct { }, .dependencies = BIT(HYPERV_FEAT_TLBFLUSH) }, + [HYPERV_FEAT_TLBFLUSH_DIRECT] = { + .desc = "direct TLB flush (hv-tlbflush-direct)", + .flags = { + {.func = HV_CPUID_NESTED_FEATURES, .reg = R_EAX, + .bits = HV_NESTED_DIRECT_FLUSH} + }, + .dependencies = BIT(HYPERV_FEAT_VAPIC) + }, }; static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max, From 9ad6634ec956bcf3558059aae8c6b2b5ee985307 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 25 May 2022 13:59:49 +0200 Subject: [PATCH 521/935] i386: docs: Convert hyperv.txt to rST rSTify docs/hyperv.txt and link it from docs/system/target-i386.rst. Signed-off-by: Vitaly Kuznetsov Message-Id: <20220525115949.1294004-7-vkuznets@redhat.com> Signed-off-by: Paolo Bonzini --- docs/hyperv.txt | 303 ------------------------------------ docs/system/i386/hyperv.rst | 288 ++++++++++++++++++++++++++++++++++ docs/system/target-i386.rst | 1 + 3 files changed, 289 insertions(+), 303 deletions(-) delete mode 100644 docs/hyperv.txt create mode 100644 docs/system/i386/hyperv.rst diff --git a/docs/hyperv.txt b/docs/hyperv.txt deleted file mode 100644 index 14a7f449ea..0000000000 --- a/docs/hyperv.txt +++ /dev/null @@ -1,303 +0,0 @@ -Hyper-V Enlightenments -====================== - - -1. Description -=============== -In some cases when implementing a hardware interface in software is slow, KVM -implements its own paravirtualized interfaces. This works well for Linux as -guest support for such features is added simultaneously with the feature itself. -It may, however, be hard-to-impossible to add support for these interfaces to -proprietary OSes, namely, Microsoft Windows. - -KVM on x86 implements Hyper-V Enlightenments for Windows guests. These features -make Windows and Hyper-V guests think they're running on top of a Hyper-V -compatible hypervisor and use Hyper-V specific features. - - -2. Setup -========= -No Hyper-V enlightenments are enabled by default by either KVM or QEMU. In -QEMU, individual enlightenments can be enabled through CPU flags, e.g: - - qemu-system-x86_64 --enable-kvm --cpu host,hv_relaxed,hv_vpindex,hv_time, ... - -Sometimes there are dependencies between enlightenments, QEMU is supposed to -check that the supplied configuration is sane. - -When any set of the Hyper-V enlightenments is enabled, QEMU changes hypervisor -identification (CPUID 0x40000000..0x4000000A) to Hyper-V. KVM identification -and features are kept in leaves 0x40000100..0x40000101. - - -3. Existing enlightenments -=========================== - -3.1. hv-relaxed -================ -This feature tells guest OS to disable watchdog timeouts as it is running on a -hypervisor. It is known that some Windows versions will do this even when they -see 'hypervisor' CPU flag. - -3.2. hv-vapic -============== -Provides so-called VP Assist page MSR to guest allowing it to work with APIC -more efficiently. In particular, this enlightenment allows paravirtualized -(exit-less) EOI processing. - -3.3. hv-spinlocks=xxx -====================== -Enables paravirtualized spinlocks. The parameter indicates how many times -spinlock acquisition should be attempted before indicating the situation to the -hypervisor. A special value 0xffffffff indicates "never notify". - -3.4. hv-vpindex -================ -Provides HV_X64_MSR_VP_INDEX (0x40000002) MSR to the guest which has Virtual -processor index information. This enlightenment makes sense in conjunction with -hv-synic, hv-stimer and other enlightenments which require the guest to know its -Virtual Processor indices (e.g. when VP index needs to be passed in a -hypercall). - -3.5. hv-runtime -================ -Provides HV_X64_MSR_VP_RUNTIME (0x40000010) MSR to the guest. The MSR keeps the -virtual processor run time in 100ns units. This gives guest operating system an -idea of how much time was 'stolen' from it (when the virtual CPU was preempted -to perform some other work). - -3.6. hv-crash -============== -Provides HV_X64_MSR_CRASH_P0..HV_X64_MSR_CRASH_P5 (0x40000100..0x40000105) and -HV_X64_MSR_CRASH_CTL (0x40000105) MSRs to the guest. These MSRs are written to -by the guest when it crashes, HV_X64_MSR_CRASH_P0..HV_X64_MSR_CRASH_P5 MSRs -contain additional crash information. This information is outputted in QEMU log -and through QAPI. -Note: unlike under genuine Hyper-V, write to HV_X64_MSR_CRASH_CTL causes guest -to shutdown. This effectively blocks crash dump generation by Windows. - -3.7. hv-time -============= -Enables two Hyper-V-specific clocksources available to the guest: MSR-based -Hyper-V clocksource (HV_X64_MSR_TIME_REF_COUNT, 0x40000020) and Reference TSC -page (enabled via MSR HV_X64_MSR_REFERENCE_TSC, 0x40000021). Both clocksources -are per-guest, Reference TSC page clocksource allows for exit-less time stamp -readings. Using this enlightenment leads to significant speedup of all timestamp -related operations. - -3.8. hv-synic -============== -Enables Hyper-V Synthetic interrupt controller - an extension of a local APIC. -When enabled, this enlightenment provides additional communication facilities -to the guest: SynIC messages and Events. This is a pre-requisite for -implementing VMBus devices (not yet in QEMU). Additionally, this enlightenment -is needed to enable Hyper-V synthetic timers. SynIC is controlled through MSRs -HV_X64_MSR_SCONTROL..HV_X64_MSR_EOM (0x40000080..0x40000084) and -HV_X64_MSR_SINT0..HV_X64_MSR_SINT15 (0x40000090..0x4000009F) - -Requires: hv-vpindex - -3.9. hv-stimer -=============== -Enables Hyper-V synthetic timers. There are four synthetic timers per virtual -CPU controlled through HV_X64_MSR_STIMER0_CONFIG..HV_X64_MSR_STIMER3_COUNT -(0x400000B0..0x400000B7) MSRs. These timers can work either in single-shot or -periodic mode. It is known that certain Windows versions revert to using HPET -(or even RTC when HPET is unavailable) extensively when this enlightenment is -not provided; this can lead to significant CPU consumption, even when virtual -CPU is idle. - -Requires: hv-vpindex, hv-synic, hv-time - -3.10. hv-tlbflush -================== -Enables paravirtualized TLB shoot-down mechanism. On x86 architecture, remote -TLB flush procedure requires sending IPIs and waiting for other CPUs to perform -local TLB flush. In virtualized environment some virtual CPUs may not even be -scheduled at the time of the call and may not require flushing (or, flushing -may be postponed until the virtual CPU is scheduled). hv-tlbflush enlightenment -implements TLB shoot-down through hypervisor enabling the optimization. - -Requires: hv-vpindex - -3.11. hv-ipi -============= -Enables paravirtualized IPI send mechanism. HvCallSendSyntheticClusterIpi -hypercall may target more than 64 virtual CPUs simultaneously, doing the same -through APIC requires more than one access (and thus exit to the hypervisor). - -Requires: hv-vpindex - -3.12. hv-vendor-id=xxx -======================= -This changes Hyper-V identification in CPUID 0x40000000.EBX-EDX from the default -"Microsoft Hv". The parameter should be no longer than 12 characters. According -to the specification, guests shouldn't use this information and it is unknown -if there is a Windows version which acts differently. -Note: hv-vendor-id is not an enlightenment and thus doesn't enable Hyper-V -identification when specified without some other enlightenment. - -3.13. hv-reset -=============== -Provides HV_X64_MSR_RESET (0x40000003) MSR to the guest allowing it to reset -itself by writing to it. Even when this MSR is enabled, it is not a recommended -way for Windows to perform system reboot and thus it may not be used. - -3.14. hv-frequencies -============================================ -Provides HV_X64_MSR_TSC_FREQUENCY (0x40000022) and HV_X64_MSR_APIC_FREQUENCY -(0x40000023) allowing the guest to get its TSC/APIC frequencies without doing -measurements. - -3.15 hv-reenlightenment -======================== -The enlightenment is nested specific, it targets Hyper-V on KVM guests. When -enabled, it provides HV_X64_MSR_REENLIGHTENMENT_CONTROL (0x40000106), -HV_X64_MSR_TSC_EMULATION_CONTROL (0x40000107)and HV_X64_MSR_TSC_EMULATION_STATUS -(0x40000108) MSRs allowing the guest to get notified when TSC frequency changes -(only happens on migration) and keep using old frequency (through emulation in -the hypervisor) until it is ready to switch to the new one. This, in conjunction -with hv-frequencies, allows Hyper-V on KVM to pass stable clocksource (Reference -TSC page) to its own guests. - -Note, KVM doesn't fully support re-enlightenment notifications and doesn't -emulate TSC accesses after migration so 'tsc-frequency=' CPU option also has to -be specified to make migration succeed. The destination host has to either have -the same TSC frequency or support TSC scaling CPU feature. - -Recommended: hv-frequencies - -3.16. hv-evmcs -=============== -The enlightenment is nested specific, it targets Hyper-V on KVM guests. When -enabled, it provides Enlightened VMCS version 1 feature to the guest. The feature -implements paravirtualized protocol between L0 (KVM) and L1 (Hyper-V) -hypervisors making L2 exits to the hypervisor faster. The feature is Intel-only. -Note: some virtualization features (e.g. Posted Interrupts) are disabled when -hv-evmcs is enabled. It may make sense to measure your nested workload with and -without the feature to find out if enabling it is beneficial. - -Requires: hv-vapic - -3.17. hv-stimer-direct -======================= -Hyper-V specification allows synthetic timer operation in two modes: "classic", -when expiration event is delivered as SynIC message and "direct", when the event -is delivered via normal interrupt. It is known that nested Hyper-V can only -use synthetic timers in direct mode and thus 'hv-stimer-direct' needs to be -enabled. - -Requires: hv-vpindex, hv-synic, hv-time, hv-stimer - -3.18. hv-avic (hv-apicv) -======================= -The enlightenment allows to use Hyper-V SynIC with hardware APICv/AVIC enabled. -Normally, Hyper-V SynIC disables these hardware feature and suggests the guest -to use paravirtualized AutoEOI feature. -Note: enabling this feature on old hardware (without APICv/AVIC support) may -have negative effect on guest's performance. - -3.19. hv-no-nonarch-coresharing=on/off/auto -=========================================== -This enlightenment tells guest OS that virtual processors will never share a -physical core unless they are reported as sibling SMT threads. This information -is required by Windows and Hyper-V guests to properly mitigate SMT related CPU -vulnerabilities. -When the option is set to 'auto' QEMU will enable the feature only when KVM -reports that non-architectural coresharing is impossible, this means that -hyper-threading is not supported or completely disabled on the host. This -setting also prevents migration as SMT settings on the destination may differ. -When the option is set to 'on' QEMU will always enable the feature, regardless -of host setup. To keep guests secure, this can only be used in conjunction with -exposing correct vCPU topology and vCPU pinning. - -3.20. hv-version-id-{build,major,minor,spack,sbranch,snumber} -============================================================= -This changes Hyper-V version identification in CPUID 0x40000002.EAX-EDX from the -default (WS2016). -- hv-version-id-build sets 'Build Number' (32 bits) -- hv-version-id-major sets 'Major Version' (16 bits) -- hv-version-id-minor sets 'Minor Version' (16 bits) -- hv-version-id-spack sets 'Service Pack' (32 bits) -- hv-version-id-sbranch sets 'Service Branch' (8 bits) -- hv-version-id-snumber sets 'Service Number' (24 bits) - -Note: hv-version-id-* are not enlightenments and thus don't enable Hyper-V -identification when specified without any other enlightenments. - -3.21. hv-syndbg -=============== -Enables Hyper-V synthetic debugger interface, this is a special interface used -by Windows Kernel debugger to send the packets through, rather than sending -them via serial/network . -When enabled, this enlightenment provides additional communication facilities -to the guest: SynDbg messages. -This new communication is used by Windows Kernel debugger rather than sending -packets via serial/network, adding significant performance boost over the other -comm channels. -This enlightenment requires a VMBus device (-device vmbus-bridge,irq=15) -and the follow enlightenments to work: -hv-relaxed,hv_time,hv-vapic,hv-vpindex,hv-synic,hv-runtime,hv-stimer - -3.22. hv-emsr-bitmap -===================== -The enlightenment is nested specific, it targets Hyper-V on KVM guests. When -enabled, it allows L0 (KVM) and L1 (Hyper-V) hypervisors to collaborate to -avoid unnecessary updates to L2 MSR-Bitmap upon vmexits. While the protocol is -supported for both VMX (Intel) and SVM (AMD), the VMX implementation requires -Enlightened VMCS ('hv-evmcs') feature to also be enabled. - -Recommended: hv-evmcs (Intel) - -3.23. hv-xmm-input -=================== -Hyper-V specification allows to pass parameters for certain hypercalls using XMM -registers ("XMM Fast Hypercall Input"). When the feature is in use, it allows -for faster hypercalls processing as KVM can avoid reading guest's memory. - -3.24. hv-tlbflush-ext -===================== -Allow for extended GVA ranges to be passed to Hyper-V TLB flush hypercalls -(HvFlushVirtualAddressList/HvFlushVirtualAddressListEx). - -Requires: hv-tlbflush - -3.25. hv-tlbflush-direct -========================= -The enlightenment is nested specific, it targets Hyper-V on KVM guests. When -enabled, it allows L0 (KVM) to directly handle TLB flush hypercalls from L2 -guest without the need to exit to L1 (Hyper-V) hypervisor. While the feature is -supported for both VMX (Intel) and SVM (AMD), the VMX implementation requires -Enlightened VMCS ('hv-evmcs') feature to also be enabled. - -Requires: hv-vapic -Recommended: hv-evmcs (Intel) - -4. Supplementary features -========================= - -4.1. hv-passthrough -=================== -In some cases (e.g. during development) it may make sense to use QEMU in -'pass-through' mode and give Windows guests all enlightenments currently -supported by KVM. This pass-through mode is enabled by "hv-passthrough" CPU -flag. -Note: "hv-passthrough" flag only enables enlightenments which are known to QEMU -(have corresponding "hv-*" flag) and copies "hv-spinlocks="/"hv-vendor-id=" -values from KVM to QEMU. "hv-passthrough" overrides all other "hv-*" settings on -the command line. Also, enabling this flag effectively prevents migration as the -list of enabled enlightenments may differ between target and destination hosts. - -4.2. hv-enforce-cpuid -===================== -By default, KVM allows the guest to use all currently supported Hyper-V -enlightenments when Hyper-V CPUID interface was exposed, regardless of if -some features were not announced in guest visible CPUIDs. 'hv-enforce-cpuid' -feature alters this behavior and only allows the guest to use exposed Hyper-V -enlightenments. - - -5. Useful links -================ -Hyper-V Top Level Functional specification and other information: -https://github.com/MicrosoftDocs/Virtualization-Documentation diff --git a/docs/system/i386/hyperv.rst b/docs/system/i386/hyperv.rst new file mode 100644 index 0000000000..2505dc4c86 --- /dev/null +++ b/docs/system/i386/hyperv.rst @@ -0,0 +1,288 @@ +Hyper-V Enlightenments +====================== + + +Description +----------- + +In some cases when implementing a hardware interface in software is slow, KVM +implements its own paravirtualized interfaces. This works well for Linux as +guest support for such features is added simultaneously with the feature itself. +It may, however, be hard-to-impossible to add support for these interfaces to +proprietary OSes, namely, Microsoft Windows. + +KVM on x86 implements Hyper-V Enlightenments for Windows guests. These features +make Windows and Hyper-V guests think they're running on top of a Hyper-V +compatible hypervisor and use Hyper-V specific features. + + +Setup +----- + +No Hyper-V enlightenments are enabled by default by either KVM or QEMU. In +QEMU, individual enlightenments can be enabled through CPU flags, e.g: + +.. parsed-literal:: + + |qemu_system| --enable-kvm --cpu host,hv_relaxed,hv_vpindex,hv_time, ... + +Sometimes there are dependencies between enlightenments, QEMU is supposed to +check that the supplied configuration is sane. + +When any set of the Hyper-V enlightenments is enabled, QEMU changes hypervisor +identification (CPUID 0x40000000..0x4000000A) to Hyper-V. KVM identification +and features are kept in leaves 0x40000100..0x40000101. + + +Existing enlightenments +----------------------- + +``hv-relaxed`` + This feature tells guest OS to disable watchdog timeouts as it is running on a + hypervisor. It is known that some Windows versions will do this even when they + see 'hypervisor' CPU flag. + +``hv-vapic`` + Provides so-called VP Assist page MSR to guest allowing it to work with APIC + more efficiently. In particular, this enlightenment allows paravirtualized + (exit-less) EOI processing. + +``hv-spinlocks`` = xxx + Enables paravirtualized spinlocks. The parameter indicates how many times + spinlock acquisition should be attempted before indicating the situation to the + hypervisor. A special value 0xffffffff indicates "never notify". + +``hv-vpindex`` + Provides HV_X64_MSR_VP_INDEX (0x40000002) MSR to the guest which has Virtual + processor index information. This enlightenment makes sense in conjunction with + hv-synic, hv-stimer and other enlightenments which require the guest to know its + Virtual Processor indices (e.g. when VP index needs to be passed in a + hypercall). + +``hv-runtime`` + Provides HV_X64_MSR_VP_RUNTIME (0x40000010) MSR to the guest. The MSR keeps the + virtual processor run time in 100ns units. This gives guest operating system an + idea of how much time was 'stolen' from it (when the virtual CPU was preempted + to perform some other work). + +``hv-crash`` + Provides HV_X64_MSR_CRASH_P0..HV_X64_MSR_CRASH_P5 (0x40000100..0x40000105) and + HV_X64_MSR_CRASH_CTL (0x40000105) MSRs to the guest. These MSRs are written to + by the guest when it crashes, HV_X64_MSR_CRASH_P0..HV_X64_MSR_CRASH_P5 MSRs + contain additional crash information. This information is outputted in QEMU log + and through QAPI. + Note: unlike under genuine Hyper-V, write to HV_X64_MSR_CRASH_CTL causes guest + to shutdown. This effectively blocks crash dump generation by Windows. + +``hv-time`` + Enables two Hyper-V-specific clocksources available to the guest: MSR-based + Hyper-V clocksource (HV_X64_MSR_TIME_REF_COUNT, 0x40000020) and Reference TSC + page (enabled via MSR HV_X64_MSR_REFERENCE_TSC, 0x40000021). Both clocksources + are per-guest, Reference TSC page clocksource allows for exit-less time stamp + readings. Using this enlightenment leads to significant speedup of all timestamp + related operations. + +``hv-synic`` + Enables Hyper-V Synthetic interrupt controller - an extension of a local APIC. + When enabled, this enlightenment provides additional communication facilities + to the guest: SynIC messages and Events. This is a pre-requisite for + implementing VMBus devices (not yet in QEMU). Additionally, this enlightenment + is needed to enable Hyper-V synthetic timers. SynIC is controlled through MSRs + HV_X64_MSR_SCONTROL..HV_X64_MSR_EOM (0x40000080..0x40000084) and + HV_X64_MSR_SINT0..HV_X64_MSR_SINT15 (0x40000090..0x4000009F) + + Requires: ``hv-vpindex`` + +``hv-stimer`` + Enables Hyper-V synthetic timers. There are four synthetic timers per virtual + CPU controlled through HV_X64_MSR_STIMER0_CONFIG..HV_X64_MSR_STIMER3_COUNT + (0x400000B0..0x400000B7) MSRs. These timers can work either in single-shot or + periodic mode. It is known that certain Windows versions revert to using HPET + (or even RTC when HPET is unavailable) extensively when this enlightenment is + not provided; this can lead to significant CPU consumption, even when virtual + CPU is idle. + + Requires: ``hv-vpindex``, ``hv-synic``, ``hv-time`` + +``hv-tlbflush`` + Enables paravirtualized TLB shoot-down mechanism. On x86 architecture, remote + TLB flush procedure requires sending IPIs and waiting for other CPUs to perform + local TLB flush. In virtualized environment some virtual CPUs may not even be + scheduled at the time of the call and may not require flushing (or, flushing + may be postponed until the virtual CPU is scheduled). hv-tlbflush enlightenment + implements TLB shoot-down through hypervisor enabling the optimization. + + Requires: ``hv-vpindex`` + +``hv-ipi`` + Enables paravirtualized IPI send mechanism. HvCallSendSyntheticClusterIpi + hypercall may target more than 64 virtual CPUs simultaneously, doing the same + through APIC requires more than one access (and thus exit to the hypervisor). + + Requires: ``hv-vpindex`` + +``hv-vendor-id`` = xxx + This changes Hyper-V identification in CPUID 0x40000000.EBX-EDX from the default + "Microsoft Hv". The parameter should be no longer than 12 characters. According + to the specification, guests shouldn't use this information and it is unknown + if there is a Windows version which acts differently. + Note: hv-vendor-id is not an enlightenment and thus doesn't enable Hyper-V + identification when specified without some other enlightenment. + +``hv-reset`` + Provides HV_X64_MSR_RESET (0x40000003) MSR to the guest allowing it to reset + itself by writing to it. Even when this MSR is enabled, it is not a recommended + way for Windows to perform system reboot and thus it may not be used. + +``hv-frequencies`` + Provides HV_X64_MSR_TSC_FREQUENCY (0x40000022) and HV_X64_MSR_APIC_FREQUENCY + (0x40000023) allowing the guest to get its TSC/APIC frequencies without doing + measurements. + +``hv-reenlightenment`` + The enlightenment is nested specific, it targets Hyper-V on KVM guests. When + enabled, it provides HV_X64_MSR_REENLIGHTENMENT_CONTROL (0x40000106), + HV_X64_MSR_TSC_EMULATION_CONTROL (0x40000107)and HV_X64_MSR_TSC_EMULATION_STATUS + (0x40000108) MSRs allowing the guest to get notified when TSC frequency changes + (only happens on migration) and keep using old frequency (through emulation in + the hypervisor) until it is ready to switch to the new one. This, in conjunction + with ``hv-frequencies``, allows Hyper-V on KVM to pass stable clocksource + (Reference TSC page) to its own guests. + + Note, KVM doesn't fully support re-enlightenment notifications and doesn't + emulate TSC accesses after migration so 'tsc-frequency=' CPU option also has to + be specified to make migration succeed. The destination host has to either have + the same TSC frequency or support TSC scaling CPU feature. + + Recommended: ``hv-frequencies`` + +``hv-evmcs`` + The enlightenment is nested specific, it targets Hyper-V on KVM guests. When + enabled, it provides Enlightened VMCS version 1 feature to the guest. The feature + implements paravirtualized protocol between L0 (KVM) and L1 (Hyper-V) + hypervisors making L2 exits to the hypervisor faster. The feature is Intel-only. + + Note: some virtualization features (e.g. Posted Interrupts) are disabled when + hv-evmcs is enabled. It may make sense to measure your nested workload with and + without the feature to find out if enabling it is beneficial. + + Requires: ``hv-vapic`` + +``hv-stimer-direct`` + Hyper-V specification allows synthetic timer operation in two modes: "classic", + when expiration event is delivered as SynIC message and "direct", when the event + is delivered via normal interrupt. It is known that nested Hyper-V can only + use synthetic timers in direct mode and thus ``hv-stimer-direct`` needs to be + enabled. + + Requires: ``hv-vpindex``, ``hv-synic``, ``hv-time``, ``hv-stimer`` + +``hv-avic`` (``hv-apicv``) + The enlightenment allows to use Hyper-V SynIC with hardware APICv/AVIC enabled. + Normally, Hyper-V SynIC disables these hardware feature and suggests the guest + to use paravirtualized AutoEOI feature. + Note: enabling this feature on old hardware (without APICv/AVIC support) may + have negative effect on guest's performance. + +``hv-no-nonarch-coresharing`` = on/off/auto + This enlightenment tells guest OS that virtual processors will never share a + physical core unless they are reported as sibling SMT threads. This information + is required by Windows and Hyper-V guests to properly mitigate SMT related CPU + vulnerabilities. + + When the option is set to 'auto' QEMU will enable the feature only when KVM + reports that non-architectural coresharing is impossible, this means that + hyper-threading is not supported or completely disabled on the host. This + setting also prevents migration as SMT settings on the destination may differ. + When the option is set to 'on' QEMU will always enable the feature, regardless + of host setup. To keep guests secure, this can only be used in conjunction with + exposing correct vCPU topology and vCPU pinning. + +``hv-version-id-build``, ``hv-version-id-major``, ``hv-version-id-minor``, ``hv-version-id-spack``, ``hv-version-id-sbranch``, ``hv-version-id-snumber`` + This changes Hyper-V version identification in CPUID 0x40000002.EAX-EDX from the + default (WS2016). + + - ``hv-version-id-build`` sets 'Build Number' (32 bits) + - ``hv-version-id-major`` sets 'Major Version' (16 bits) + - ``hv-version-id-minor`` sets 'Minor Version' (16 bits) + - ``hv-version-id-spack`` sets 'Service Pack' (32 bits) + - ``hv-version-id-sbranch`` sets 'Service Branch' (8 bits) + - ``hv-version-id-snumber`` sets 'Service Number' (24 bits) + + Note: hv-version-id-* are not enlightenments and thus don't enable Hyper-V + identification when specified without any other enlightenments. + +``hv-syndbg`` + Enables Hyper-V synthetic debugger interface, this is a special interface used + by Windows Kernel debugger to send the packets through, rather than sending + them via serial/network . + When enabled, this enlightenment provides additional communication facilities + to the guest: SynDbg messages. + This new communication is used by Windows Kernel debugger rather than sending + packets via serial/network, adding significant performance boost over the other + comm channels. + This enlightenment requires a VMBus device (-device vmbus-bridge,irq=15). + + Requires: ``hv-relaxed``, ``hv_time``, ``hv-vapic``, ``hv-vpindex``, ``hv-synic``, ``hv-runtime``, ``hv-stimer`` + +``hv-emsr-bitmap`` + The enlightenment is nested specific, it targets Hyper-V on KVM guests. When + enabled, it allows L0 (KVM) and L1 (Hyper-V) hypervisors to collaborate to + avoid unnecessary updates to L2 MSR-Bitmap upon vmexits. While the protocol is + supported for both VMX (Intel) and SVM (AMD), the VMX implementation requires + Enlightened VMCS (``hv-evmcs``) feature to also be enabled. + + Recommended: ``hv-evmcs`` (Intel) + +``hv-xmm-input`` + Hyper-V specification allows to pass parameters for certain hypercalls using XMM + registers ("XMM Fast Hypercall Input"). When the feature is in use, it allows + for faster hypercalls processing as KVM can avoid reading guest's memory. + +``hv-tlbflush-ext`` + Allow for extended GVA ranges to be passed to Hyper-V TLB flush hypercalls + (HvFlushVirtualAddressList/HvFlushVirtualAddressListEx). + + Requires: ``hv-tlbflush`` + +``hv-tlbflush-direct`` + The enlightenment is nested specific, it targets Hyper-V on KVM guests. When + enabled, it allows L0 (KVM) to directly handle TLB flush hypercalls from L2 + guest without the need to exit to L1 (Hyper-V) hypervisor. While the feature is + supported for both VMX (Intel) and SVM (AMD), the VMX implementation requires + Enlightened VMCS (``hv-evmcs``) feature to also be enabled. + + Requires: ``hv-vapic`` + + Recommended: ``hv-evmcs`` (Intel) + +Supplementary features +---------------------- + +``hv-passthrough`` + In some cases (e.g. during development) it may make sense to use QEMU in + 'pass-through' mode and give Windows guests all enlightenments currently + supported by KVM. This pass-through mode is enabled by "hv-passthrough" CPU + flag. + + Note: ``hv-passthrough`` flag only enables enlightenments which are known to QEMU + (have corresponding 'hv-' flag) and copies ``hv-spinlocks`` and ``hv-vendor-id`` + values from KVM to QEMU. ``hv-passthrough`` overrides all other 'hv-' settings on + the command line. Also, enabling this flag effectively prevents migration as the + list of enabled enlightenments may differ between target and destination hosts. + +``hv-enforce-cpuid`` + By default, KVM allows the guest to use all currently supported Hyper-V + enlightenments when Hyper-V CPUID interface was exposed, regardless of if + some features were not announced in guest visible CPUIDs. ``hv-enforce-cpuid`` + feature alters this behavior and only allows the guest to use exposed Hyper-V + enlightenments. + + +Useful links +------------ +Hyper-V Top Level Functional specification and other information: + +- https://github.com/MicrosoftDocs/Virtualization-Documentation +- https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/tlfs + diff --git a/docs/system/target-i386.rst b/docs/system/target-i386.rst index 96bf54889a..e64c013077 100644 --- a/docs/system/target-i386.rst +++ b/docs/system/target-i386.rst @@ -26,6 +26,7 @@ Architectural features :maxdepth: 1 i386/cpu + i386/hyperv i386/kvm-pv i386/sgx i386/amd-memory-encryption From daa55f3ecf2d413295eb2d539e7629fc05d7bc92 Mon Sep 17 00:00:00 2001 From: Lei He Date: Wed, 25 May 2022 17:01:11 +0800 Subject: [PATCH 522/935] qapi: crypto-akcipher: Introduce akcipher types to qapi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce akcipher types, also include RSA related types. Signed-off-by: Lei He Signed-off-by: zhenwei pi Signed-off-by: Daniel P. Berrangé --- qapi/crypto.json | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/qapi/crypto.json b/qapi/crypto.json index 15c24f0078..653e6e3f3d 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -534,3 +534,67 @@ 'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] }, '*sanity-check': 'bool', '*passwordid': 'str' } } +## +# @QCryptoAkCipherAlgorithm: +# +# The supported algorithms for asymmetric encryption ciphers +# +# @rsa: RSA algorithm +# +# Since: 7.1 +## +{ 'enum': 'QCryptoAkCipherAlgorithm', + 'prefix': 'QCRYPTO_AKCIPHER_ALG', + 'data': ['rsa']} + +## +# @QCryptoAkCipherKeyType: +# +# The type of asymmetric keys. +# +# Since: 7.1 +## +{ 'enum': 'QCryptoAkCipherKeyType', + 'prefix': 'QCRYPTO_AKCIPHER_KEY_TYPE', + 'data': ['public', 'private']} + +## +# @QCryptoRSAPaddingAlgorithm: +# +# The padding algorithm for RSA. +# +# @raw: no padding used +# @pkcs1: pkcs1#v1.5 +# +# Since: 7.1 +## +{ 'enum': 'QCryptoRSAPaddingAlgorithm', + 'prefix': 'QCRYPTO_RSA_PADDING_ALG', + 'data': ['raw', 'pkcs1']} + +## +# @QCryptoAkCipherOptionsRSA: +# +# Specific parameters for RSA algorithm. +# +# @hash-alg: QCryptoHashAlgorithm +# @padding-alg: QCryptoRSAPaddingAlgorithm +# +# Since: 7.1 +## +{ 'struct': 'QCryptoAkCipherOptionsRSA', + 'data': { 'hash-alg':'QCryptoHashAlgorithm', + 'padding-alg': 'QCryptoRSAPaddingAlgorithm'}} + +## +# @QCryptoAkCipherOptions: +# +# The options that are available for all asymmetric key algorithms +# when creating a new QCryptoAkCipher. +# +# Since: 7.1 +## +{ 'union': 'QCryptoAkCipherOptions', + 'base': { 'alg': 'QCryptoAkCipherAlgorithm' }, + 'discriminator': 'alg', + 'data': { 'rsa': 'QCryptoAkCipherOptionsRSA' }} From db5ca5fbfa6597ac9dd1ae40f986696db9c8b9dd Mon Sep 17 00:00:00 2001 From: zhenwei pi Date: Wed, 25 May 2022 17:01:12 +0800 Subject: [PATCH 523/935] crypto: Introduce akcipher crypto class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce new akcipher crypto class 'QCryptoAkCIpher', which supports basic asymmetric operations: encrypt, decrypt, sign and verify. Suggested by Daniel P. Berrangé, also add autoptr cleanup for the new class. Thanks to Daniel! Co-developed-by: lei he Signed-off-by: lei he Signed-off-by: zhenwei pi Signed-off-by: Daniel P. Berrangé --- crypto/akcipher.c | 102 ++++++++++++++++++++++++ crypto/akcipherpriv.h | 55 +++++++++++++ crypto/meson.build | 1 + include/crypto/akcipher.h | 158 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 316 insertions(+) create mode 100644 crypto/akcipher.c create mode 100644 crypto/akcipherpriv.h create mode 100644 include/crypto/akcipher.h diff --git a/crypto/akcipher.c b/crypto/akcipher.c new file mode 100644 index 0000000000..ab28bf415b --- /dev/null +++ b/crypto/akcipher.c @@ -0,0 +1,102 @@ +/* + * QEMU Crypto akcipher algorithms + * + * Copyright (c) 2022 Bytedance + * Author: zhenwei pi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#include "qemu/osdep.h" +#include "crypto/akcipher.h" +#include "akcipherpriv.h" + +QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts, + QCryptoAkCipherKeyType type, + const uint8_t *key, size_t keylen, + Error **errp) +{ + QCryptoAkCipher *akcipher = NULL; + + return akcipher; +} + +bool qcrypto_akcipher_supports(QCryptoAkCipherOptions *opts) +{ + return false; +} + +int qcrypto_akcipher_encrypt(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, Error **errp) +{ + const QCryptoAkCipherDriver *drv = akcipher->driver; + + return drv->encrypt(akcipher, in, in_len, out, out_len, errp); +} + +int qcrypto_akcipher_decrypt(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, Error **errp) +{ + const QCryptoAkCipherDriver *drv = akcipher->driver; + + return drv->decrypt(akcipher, in, in_len, out, out_len, errp); +} + +int qcrypto_akcipher_sign(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, Error **errp) +{ + const QCryptoAkCipherDriver *drv = akcipher->driver; + + return drv->sign(akcipher, in, in_len, out, out_len, errp); +} + +int qcrypto_akcipher_verify(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + const void *in2, size_t in2_len, Error **errp) +{ + const QCryptoAkCipherDriver *drv = akcipher->driver; + + return drv->verify(akcipher, in, in_len, in2, in2_len, errp); +} + +int qcrypto_akcipher_max_plaintext_len(QCryptoAkCipher *akcipher) +{ + return akcipher->max_plaintext_len; +} + +int qcrypto_akcipher_max_ciphertext_len(QCryptoAkCipher *akcipher) +{ + return akcipher->max_ciphertext_len; +} + +int qcrypto_akcipher_max_signature_len(QCryptoAkCipher *akcipher) +{ + return akcipher->max_signature_len; +} + +int qcrypto_akcipher_max_dgst_len(QCryptoAkCipher *akcipher) +{ + return akcipher->max_dgst_len; +} + +void qcrypto_akcipher_free(QCryptoAkCipher *akcipher) +{ + const QCryptoAkCipherDriver *drv = akcipher->driver; + + drv->free(akcipher); +} diff --git a/crypto/akcipherpriv.h b/crypto/akcipherpriv.h new file mode 100644 index 0000000000..739f639bcf --- /dev/null +++ b/crypto/akcipherpriv.h @@ -0,0 +1,55 @@ +/* + * QEMU Crypto asymmetric algorithms + * + * Copyright (c) 2022 Bytedance + * Author: zhenwei pi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#ifndef QCRYPTO_AKCIPHERPRIV_H +#define QCRYPTO_AKCIPHERPRIV_H + +#include "qapi/qapi-types-crypto.h" + +typedef struct QCryptoAkCipherDriver QCryptoAkCipherDriver; + +struct QCryptoAkCipher { + QCryptoAkCipherAlgorithm alg; + QCryptoAkCipherKeyType type; + int max_plaintext_len; + int max_ciphertext_len; + int max_signature_len; + int max_dgst_len; + QCryptoAkCipherDriver *driver; +}; + +struct QCryptoAkCipherDriver { + int (*encrypt)(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, Error **errp); + int (*decrypt)(QCryptoAkCipher *akcipher, + const void *out, size_t out_len, + void *in, size_t in_len, Error **errp); + int (*sign)(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, Error **errp); + int (*verify)(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + const void *in2, size_t in2_len, Error **errp); + void (*free)(QCryptoAkCipher *akcipher); +}; + +#endif /* QCRYPTO_AKCIPHER_H */ diff --git a/crypto/meson.build b/crypto/meson.build index 685fb37097..313f935f27 100644 --- a/crypto/meson.build +++ b/crypto/meson.build @@ -1,6 +1,7 @@ crypto_ss.add(genh) crypto_ss.add(files( 'afsplit.c', + 'akcipher.c', 'block-luks.c', 'block-qcow.c', 'block.c', diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h new file mode 100644 index 0000000000..51f5fa2774 --- /dev/null +++ b/include/crypto/akcipher.h @@ -0,0 +1,158 @@ +/* + * QEMU Crypto asymmetric algorithms + * + * Copyright (c) 2022 Bytedance + * Author: zhenwei pi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#ifndef QCRYPTO_AKCIPHER_H +#define QCRYPTO_AKCIPHER_H + +#include "qapi/qapi-types-crypto.h" + +typedef struct QCryptoAkCipher QCryptoAkCipher; + +/** + * qcrypto_akcipher_supports: + * @opts: the asymmetric key algorithm and related options + * + * Determine if asymmetric key cipher decribed with @opts is + * supported by the current configured build + * + * Returns: true if it is supported, false otherwise. + */ +bool qcrypto_akcipher_supports(QCryptoAkCipherOptions *opts); + +/** + * qcrypto_akcipher_new: + * @opts: specify the algorithm and the related arguments + * @type: private or public key type + * @key: buffer to store the key + * @key_len: the length of key buffer + * @errp: error pointer + * + * Create akcipher context + * + * Returns: On success, a new QCryptoAkCipher initialized with @opt + * is created and returned, otherwise NULL is returned. + */ + +QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts, + QCryptoAkCipherKeyType type, + const uint8_t *key, size_t key_len, + Error **errp); + +/** + * qcrypto_akcipher_encrypt: + * @akcipher: akcipher context + * @in: plaintext pending to be encrypted + * @in_len: length of plaintext, less or equal to the size reported + * by a call to qcrypto_akcipher_max_plaintext_len() + * @out: buffer to store the ciphertext + * @out_len: length of ciphertext, less or equal to the size reported + * by a call to qcrypto_akcipher_max_ciphertext_len() + * @errp: error pointer + * + * Encrypt @in and write ciphertext into @out + * + * Returns: length of ciphertext if encrypt succeed, + * otherwise -1 is returned + */ +int qcrypto_akcipher_encrypt(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, Error **errp); + +/** + * qcrypto_akcipher_decrypt: + * @akcipher: akcipher context + * @in: ciphertext to be decrypted + * @in_len: the length of ciphertext, less or equal to the size reported + * by a call to qcrypto_akcipher_max_ciphertext_len() + * @out: buffer to store the plaintext + * @out_len: length of the plaintext buffer, less or equal to the size + * reported by a call to qcrypto_akcipher_max_plaintext_len() + * @errp: error pointer + * + * Decrypt @in and write plaintext into @out + * + * Returns: length of plaintext if decrypt succeed, + * otherwise -1 is returned + */ +int qcrypto_akcipher_decrypt(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, Error **errp); + +/** + * qcrypto_akcipher_sign: + * @akcipher: akcipher context + * @in: data to be signed + * @in_len: the length of data, less or equal to the size reported + * by a call to qcrypto_akcipher_max_dgst_len() + * @out: buffer to store the signature + * @out_len: length of the signature buffer, less or equal to the size + * by a call to qcrypto_akcipher_max_signature_len() + * @errp: error pointer + * + * Generate signature for @in, write into @out + * + * Returns: length of signature if succeed, + * otherwise -1 is returned + */ +int qcrypto_akcipher_sign(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, Error **errp); + +/** + * qcrypto_akcipher_verify: + * @akcipher: akcipher context + * @in: pointer to the signature + * @in_len: length of signature, ess or equal to the size reported + * by a call to qcrypto_akcipher_max_signature_len() + * @in2: pointer to original data + * @in2_len: the length of original data, less or equal to the size + * by a call to qcrypto_akcipher_max_dgst_len() + * @errp: error pointer + * + * Verify @in and @in2 match or not + * + * Returns: 0 for succeed, + * otherwise -1 is returned + */ +int qcrypto_akcipher_verify(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + const void *in2, size_t in2_len, Error **errp); + +int qcrypto_akcipher_max_plaintext_len(QCryptoAkCipher *akcipher); + +int qcrypto_akcipher_max_ciphertext_len(QCryptoAkCipher *akcipher); + +int qcrypto_akcipher_max_signature_len(QCryptoAkCipher *akcipher); + +int qcrypto_akcipher_max_dgst_len(QCryptoAkCipher *akcipher); + +/** + * qcrypto_akcipher_free: + * @akcipher: akcipher context + * + * Free the akcipher context + * + */ +void qcrypto_akcipher_free(QCryptoAkCipher *akcipher); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoAkCipher, qcrypto_akcipher_free) + +#endif /* QCRYPTO_AKCIPHER_H */ From 99d423f10c636c39405924e68584f50f78a0bb8c Mon Sep 17 00:00:00 2001 From: Lei He Date: Wed, 25 May 2022 17:01:13 +0800 Subject: [PATCH 524/935] crypto: add ASN.1 DER decoder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an ANS.1 DER decoder which is used to parse asymmetric cipher keys Signed-off-by: zhenwei pi Signed-off-by: lei he Signed-off-by: Daniel P. Berrangé --- crypto/der.c | 189 +++++++++++++++++++++++ crypto/der.h | 81 ++++++++++ crypto/meson.build | 1 + tests/unit/meson.build | 1 + tests/unit/test-crypto-der.c | 290 +++++++++++++++++++++++++++++++++++ 5 files changed, 562 insertions(+) create mode 100644 crypto/der.c create mode 100644 crypto/der.h create mode 100644 tests/unit/test-crypto-der.c diff --git a/crypto/der.c b/crypto/der.c new file mode 100644 index 0000000000..f877390bbb --- /dev/null +++ b/crypto/der.c @@ -0,0 +1,189 @@ +/* + * QEMU Crypto ASN.1 DER decoder + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#include "qemu/osdep.h" +#include "crypto/der.h" + +enum QCryptoDERTypeTag { + QCRYPTO_DER_TYPE_TAG_BOOL = 0x1, + QCRYPTO_DER_TYPE_TAG_INT = 0x2, + QCRYPTO_DER_TYPE_TAG_BIT_STR = 0x3, + QCRYPTO_DER_TYPE_TAG_OCT_STR = 0x4, + QCRYPTO_DER_TYPE_TAG_OCT_NULL = 0x5, + QCRYPTO_DER_TYPE_TAG_OCT_OID = 0x6, + QCRYPTO_DER_TYPE_TAG_SEQ = 0x10, + QCRYPTO_DER_TYPE_TAG_SET = 0x11, +}; + +#define QCRYPTO_DER_CONSTRUCTED_MASK 0x20 +#define QCRYPTO_DER_SHORT_LEN_MASK 0x80 + +static uint8_t qcrypto_der_peek_byte(const uint8_t **data, size_t *dlen) +{ + return **data; +} + +static void qcrypto_der_cut_nbytes(const uint8_t **data, + size_t *dlen, + size_t nbytes) +{ + *data += nbytes; + *dlen -= nbytes; +} + +static uint8_t qcrypto_der_cut_byte(const uint8_t **data, size_t *dlen) +{ + uint8_t val = qcrypto_der_peek_byte(data, dlen); + + qcrypto_der_cut_nbytes(data, dlen, 1); + + return val; +} + +static int qcrypto_der_invoke_callback(QCryptoDERDecodeCb cb, void *ctx, + const uint8_t *value, size_t vlen, + Error **errp) +{ + if (!cb) { + return 0; + } + + return cb(ctx, value, vlen, errp); +} + +static int qcrypto_der_extract_definite_data(const uint8_t **data, size_t *dlen, + QCryptoDERDecodeCb cb, void *ctx, + Error **errp) +{ + const uint8_t *value; + size_t vlen = 0; + uint8_t byte_count = qcrypto_der_cut_byte(data, dlen); + + /* short format of definite-length */ + if (!(byte_count & QCRYPTO_DER_SHORT_LEN_MASK)) { + if (byte_count > *dlen) { + error_setg(errp, "Invalid content length: %u", byte_count); + return -1; + } + + value = *data; + vlen = byte_count; + qcrypto_der_cut_nbytes(data, dlen, vlen); + + if (qcrypto_der_invoke_callback(cb, ctx, value, vlen, errp) != 0) { + return -1; + } + return vlen; + } + + /* Ignore highest bit */ + byte_count &= ~QCRYPTO_DER_SHORT_LEN_MASK; + + /* + * size_t is enough to store the value of length, although the DER + * encoding standard supports larger length. + */ + if (byte_count > sizeof(size_t)) { + error_setg(errp, "Invalid byte count of content length: %u", + byte_count); + return -1; + } + + if (byte_count > *dlen) { + error_setg(errp, "Invalid content length: %u", byte_count); + return -1; + } + while (byte_count--) { + vlen <<= 8; + vlen += qcrypto_der_cut_byte(data, dlen); + } + + if (vlen > *dlen) { + error_setg(errp, "Invalid content length: %zu", vlen); + return -1; + } + + value = *data; + qcrypto_der_cut_nbytes(data, dlen, vlen); + + if (qcrypto_der_invoke_callback(cb, ctx, value, vlen, errp) != 0) { + return -1; + } + return vlen; +} + +static int qcrypto_der_extract_data(const uint8_t **data, size_t *dlen, + QCryptoDERDecodeCb cb, void *ctx, + Error **errp) +{ + uint8_t val; + if (*dlen < 1) { + error_setg(errp, "Need more data"); + return -1; + } + val = qcrypto_der_peek_byte(data, dlen); + + /* must use definite length format */ + if (val == QCRYPTO_DER_SHORT_LEN_MASK) { + error_setg(errp, "Only definite length format is allowed"); + return -1; + } + + return qcrypto_der_extract_definite_data(data, dlen, cb, ctx, errp); +} + +int qcrypto_der_decode_int(const uint8_t **data, size_t *dlen, + QCryptoDERDecodeCb cb, void *ctx, Error **errp) +{ + uint8_t tag; + if (*dlen < 1) { + error_setg(errp, "Need more data"); + return -1; + } + tag = qcrypto_der_cut_byte(data, dlen); + + /* INTEGER must encoded in primitive-form */ + if (tag != QCRYPTO_DER_TYPE_TAG_INT) { + error_setg(errp, "Invalid integer type tag: %u", tag); + return -1; + } + + return qcrypto_der_extract_data(data, dlen, cb, ctx, errp); +} + +int qcrypto_der_decode_seq(const uint8_t **data, size_t *dlen, + QCryptoDERDecodeCb cb, void *ctx, Error **errp) +{ + uint8_t tag; + if (*dlen < 1) { + error_setg(errp, "Need more data"); + return -1; + } + tag = qcrypto_der_cut_byte(data, dlen); + + /* SEQUENCE must use constructed form */ + if (tag != (QCRYPTO_DER_TYPE_TAG_SEQ | QCRYPTO_DER_CONSTRUCTED_MASK)) { + error_setg(errp, "Invalid type sequence tag: %u", tag); + return -1; + } + + return qcrypto_der_extract_data(data, dlen, cb, ctx, errp); +} diff --git a/crypto/der.h b/crypto/der.h new file mode 100644 index 0000000000..e3d3aeacdc --- /dev/null +++ b/crypto/der.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#ifndef QCRYPTO_ASN1_DECODER_H +#define QCRYPTO_ASN1_DECODER_H + +#include "qapi/error.h" + +/* Simple decoder used to parse DER encoded rsa keys. */ + +/** + * @opaque: user context. + * @value: the starting address of |value| part of 'Tag-Length-Value' pattern. + * @vlen: length of the |value|. + * Returns: 0 for success, any other value is considered an error. + */ +typedef int (*QCryptoDERDecodeCb) (void *opaque, const uint8_t *value, + size_t vlen, Error **errp); + +/** + * qcrypto_der_decode_int: + * @data: pointer to address of input data + * @dlen: pointer to length of input data + * @cb: callback invoked when decode succeed, if cb equals NULL, no + * callback will be invoked + * @opaque: parameter passed to cb + * + * Decode integer from DER-encoded data. + * + * Returns: On success, *data points to rest data, and *dlen + * will be set to the rest length of data, if cb is not NULL, must + * return 0 to make decode success, at last, the length of the data + * part of the decoded INTEGER will be returned. Otherwise, -1 is + * returned. + */ +int qcrypto_der_decode_int(const uint8_t **data, + size_t *dlen, + QCryptoDERDecodeCb cb, + void *opaque, + Error **errp); + +/** + * qcrypto_der_decode_seq: + * + * Decode sequence from DER-encoded data, similar with der_decode_int. + * + * @data: pointer to address of input data + * @dlen: pointer to length of input data + * @cb: callback invoked when decode succeed, if cb equals NULL, no + * callback will be invoked + * @opaque: parameter passed to cb + * + * Returns: On success, *data points to rest data, and *dlen + * will be set to the rest length of data, if cb is not NULL, must + * return 0 to make decode success, at last, the length of the data + * part of the decoded SEQUENCE will be returned. Otherwise, -1 is + * returned. + */ +int qcrypto_der_decode_seq(const uint8_t **data, + size_t *dlen, + QCryptoDERDecodeCb cb, + void *opaque, + Error **errp); + +#endif /* QCRYPTO_ASN1_DECODER_H */ diff --git a/crypto/meson.build b/crypto/meson.build index 313f935f27..b8152ae7cb 100644 --- a/crypto/meson.build +++ b/crypto/meson.build @@ -6,6 +6,7 @@ crypto_ss.add(files( 'block-qcow.c', 'block.c', 'cipher.c', + 'der.c', 'hash.c', 'hmac.c', 'ivgen-essiv.c', diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 264f2bc0c8..5a7993e56c 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -78,6 +78,7 @@ if have_block 'test-crypto-hmac': [crypto], 'test-crypto-cipher': [crypto], 'test-crypto-secret': [crypto, keyutils], + 'test-crypto-der': [crypto], 'test-authz-simple': [authz], 'test-authz-list': [authz], 'test-authz-listfile': [authz], diff --git a/tests/unit/test-crypto-der.c b/tests/unit/test-crypto-der.c new file mode 100644 index 0000000000..aed0f28d68 --- /dev/null +++ b/tests/unit/test-crypto-der.c @@ -0,0 +1,290 @@ +/* + * QEMU Crypto akcipher algorithms + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#include "qemu/osdep.h" +#include "crypto/der.h" + +/* rsa(512) private key, generated by openssl */ +static const uint8_t test_rsa512_priv_key[] = + "\x30\x82\x01\x39" /* SEQUENCE, offset: 0, length: 313 */ + "\x02\x01\x00" /* INTEGER, offset: 4, length: 1 */ + "\x02\x41" /* INTEGER, offset: 7, length: 65 */ + "\x00\xb9\xe1\x22\xdb\x56\x2f\xb6\xf7\xf0\x0a\x87\x43\x07\x12\xdb" + "\x6d\xb6\x2b\x41\x8d\x2c\x3c\xa5\xdd\x78\x9a\x8f\xab\x8e\xf2\x4a" + "\xc8\x34\x0c\x12\x4f\x11\x90\xc6\xc2\xa5\xd0\xcd\xfb\xfc\x2c\x95" + "\x56\x82\xdf\x39\xf3\x3b\x1d\x62\x26\x97\xb7\x93\x25\xc7\xec\x7e" + "\xf7" + "\x02\x03\x01\x00\x01" /* INTEGER, offset: 74, length: 3 */ + "\x02\x40" /* INTEGER, offset: 79, length: 64 */ + "\x1e\x80\xfe\xda\x65\xdb\x70\xb8\x61\x91\x28\xbf\x6c\x32\xc1\x05" + "\xd1\x26\x6a\x1c\x83\xcc\xf4\x1f\x53\x42\x72\x1f\x62\x57\x0a\xc4" + "\x66\x76\x30\x87\xb9\xb1\xb9\x6a\x63\xfd\x8f\x3e\xfc\x35\x3f\xd6" + "\x2e\x6c\xc8\x70\x8a\x17\xc1\x28\x6a\xfe\x51\x56\xb3\x92\x6f\x09" + "\x02\x21" /* INTEGER, offset: 145, length: 33 */ + "\x00\xe3\x2e\x2d\x8d\xba\x1c\x34\x4c\x49\x9f\xc1\xa6\xdd\xd7\x13" + "\x8d\x05\x48\xdd\xff\x5c\x30\xbc\x6b\xc4\x18\x9d\xfc\xa2\xd0\x9b" + "\x4d" + "\x02\x21" /* INTEGER, offset: 180, length: 33 */ + "\x00\xd1\x75\xaf\x4b\xc6\x1a\xb0\x98\x14\x42\xae\x33\xf3\x44\xde" + "\x21\xcb\x04\xda\xfb\x1e\x35\x92\xcd\x69\xc0\x83\x06\x83\x8e\x39" + "\x53" + "\x02\x20" /* INTEGER, offset: 215, length: 32 */ + "\x68\x8d\x2a\xf7\xcb\xcc\x09\x21\x86\xcc\x98\x21\xc4\x7c\xa4\x09" + "\xc5\x81\xd8\x71\x1a\x2b\x6f\xbb\xa4\xde\xb3\x6e\xbe\x3b\x85\x0d" + "\x02\x20" /* INTEGER, offset: 249, length: 32 */ + "\x64\x06\x0e\xef\xe0\x6a\x5e\x6a\x41\x42\x96\x6d\xb8\x7d\xea\x95" + "\xb8\x9d\x58\xf5\x12\x38\x03\x22\x94\x9d\x99\xf4\x42\x5e\x68\x81" + "\x02\x20" /* INTEGER, offset: 283, length: 32 */ + "\x7f\x1d\x87\xe8\x55\x30\x75\xc7\x29\xec\xc9\x65\x76\x5a\x6a\xa3" + "\x4a\x6e\xe1\x26\x65\xd1\x76\xd5\xb9\xd1\x8b\xa8\x73\xe2\x6a\x9e"; + +static const uint8_t test_rsa2048_priv_key[] = + "\x30\x82\x04\xa6" /* SEQUENCE, offset: 0, length 1190 */ + "\x02\x01\x00" /* INTEGER, offset: 4, length: 1 */ + "\x02\x82\x01\x01" /* INTEGER, offset: 7, length: 257 */ + "\x00\xd1\x48\xc2\xc1\x1d\x4f\x94\xf2\xbb\x9b\xe2\x2d\xe1\xea\x4c" + "\xce\x41\x72\xe3\x41\x7e\x9d\x91\x85\xa3\x4e\xe1\x2c\xf6\x52\x6d" + "\xf9\x84\x64\xdf\x87\x28\x4a\xc9\x9d\x78\x93\x47\xc8\xd9\x66\x2e" + "\xf4\xc6\xf0\x32\x15\x1a\xe8\xaf\x5a\xca\x3a\xd3\x3e\xf6\xde\x86" + "\xdd\x9b\xa6\x4d\x74\x58\xf0\x11\x7f\x66\xd5\x1c\xd8\xde\xa3\xf8" + "\xa3\xfc\x33\x55\x89\xa9\xc3\xea\x5b\x2e\x31\x06\xf8\xcb\x9e\x6e" + "\xb2\x68\x0d\xe6\xc3\x5c\x2d\xf8\xa2\xbd\x00\x1a\xf6\xb6\xdd\x14" + "\x8d\x11\x6d\x2d\xc6\x0c\x09\xe6\xf6\xb9\x8b\x87\x4c\x9f\x4d\x63" + "\xd3\x94\xf4\x32\xca\xcf\x5e\xbf\xe2\x7f\x73\x5a\x65\xec\x82\x0d" + "\x7f\x30\x25\x03\xd4\x3a\xff\xa2\xe8\xd6\xb5\x1f\x4f\x36\x64\x61" + "\xc3\x5f\xb2\x9e\x0c\x53\x04\x19\x34\x99\xe8\xe3\xe6\xd3\x2f\x45" + "\x58\x8e\x5d\x54\x5a\xa0\xc0\x5e\x51\x9b\x22\x15\xec\x26\x6f\x72" + "\x68\xe9\xbf\x5d\x1d\xb5\xd9\xe4\x81\x1a\x92\x66\xa8\xcb\x73\x46" + "\xab\x96\x7b\xf8\x9c\xf5\xb5\x9e\x2b\x13\x71\xe0\x01\x0c\x59\x1b" + "\x63\x9f\xb7\xd1\xcd\x47\x8e\xc7\x3a\xbe\xcb\x47\xa7\x23\x43\xa7" + "\x7d\xbd\x2c\x4e\x22\x37\xcc\xf9\x1b\x1b\xbb\xed\xec\xf0\x47\x92" + "\x43" + "\x02\x03\x01\x00\x01" /* INTEGER, offset 268, length 3 */ + "\x02\x82\x01\x01" /* INTEGER, offset 273, length 257 */ + "\x00\x8d\x21\x97\x0c\x29\x9a\xf8\x23\xf4\x76\x3b\xc1\x9b\x3e\xa8" + "\x8a\xd2\xc2\x0a\x14\xa9\xb0\xd2\x68\x9f\x67\x5b\x1c\x3a\x03\xfe" + "\x5b\xac\x77\x65\xf1\xbc\x2f\x2a\xe5\x01\x61\xb8\x9f\xee\x53\x25" + "\x49\x36\x3a\xd6\x5b\x3b\x29\x3c\xcf\x69\xde\xdf\x83\xef\x70\xc2" + "\xdc\x00\xd1\xd6\x1b\xa6\xba\x45\xe2\x77\x53\x31\xbf\xe1\xec\x0b" + "\x89\x72\x52\x9f\xd5\x54\xe1\x64\x52\x16\xc5\x43\x21\x56\x16\xc2" + "\x29\x97\x58\x00\x8d\x2f\xc5\x64\x8d\x42\x0d\x27\x21\xc6\xd1\x31" + "\xc1\xab\xc5\xc7\x7f\x6d\xb0\xe3\xca\xef\xf6\xf2\xc7\xae\x09\xbf" + "\x4d\xc0\x4e\x90\x2c\x28\xb9\xcc\x22\x74\xf2\xd5\xff\x4d\x86\xf6" + "\xec\x45\x1f\xbf\x25\x4c\x30\x26\x76\x4f\x09\x13\x83\xef\x35\x73" + "\xa3\xa2\xb1\x40\xcf\x07\x7a\x83\xae\xea\x00\xea\x74\xc7\x54\x6a" + "\x88\x19\xed\x35\xd3\x7e\x5e\xac\x51\xc1\x1e\x5e\x2c\x57\x72\x20" + "\x10\x6a\x0c\x47\xe1\xf0\x36\x70\xd2\xa7\x57\x64\x47\x46\x9f\xca" + "\x23\x8a\x48\x50\x1d\x33\x6a\x86\x46\x69\xed\x54\x65\x6b\x9e\xab" + "\x1f\x84\x87\xf4\x92\x8a\x6c\x44\x20\xaa\x8d\xd8\x50\xde\x45\x74" + "\xe0\xa8\xc7\xb9\x38\x74\x24\x51\x33\xf0\x39\x54\x6c\x11\xae\xc2" + "\x29" + "\x02\x81\x81" /* INTEGER, offset 534, length 129 */ + "\x00\xe8\x26\xd1\xf9\xa0\xd3\x0e\x3f\x2f\x89\x9b\x94\x16\x12\xd1" + "\xae\x3c\x53\x9c\xcf\xc6\xf7\x03\xf5\xdf\x39\xdc\x25\x5d\xcb\xb8" + "\xb9\x74\x3e\x3b\x36\xf6\xa0\x8d\xb1\x0e\xd8\xfe\x8c\xcd\x01\x13" + "\x77\x73\x08\x0f\x32\xbd\xe6\x95\xdc\xd0\x14\x7d\x44\xdc\x3e\xd9" + "\xaa\x8a\x32\xe6\x0e\x76\xb6\x05\xc5\x6b\x87\x78\x9a\x32\xe2\xf8" + "\x78\xba\x58\x75\x58\xd5\x26\x9d\x9a\x0f\xb6\xca\xb5\x27\xd8\x58" + "\xae\x3f\x49\x54\xd2\x2b\xac\x28\x39\x88\x31\x42\x12\x08\xea\x0b" + "\x39\x58\xae\xf3\x82\xa0\xe2\x75\x7c\x96\xa9\xb8\x57\x29\x6d\xd7" + "\x37" + "\x02\x81\x81" /* INTEGER, offset 666, length 129 */ + "\x00\xe6\xc8\x91\x50\x49\x97\x56\x70\x6e\x25\xf5\x77\x25\xa5\x41" + "\xfe\xd7\x25\x1b\xc1\x4a\xff\x37\x44\x2b\x46\xa0\xdf\xe8\x02\x09" + "\xdd\xa8\x41\xa1\x12\x84\x3c\xf8\xc2\x13\x3e\xb8\x4b\x22\x01\xac" + "\xa6\x09\xb2\xe9\xcd\xc8\x51\xee\xde\xa3\x1e\x6b\xfe\xb1\xf8\xb6" + "\x9e\x48\x36\x62\x0b\x05\xfa\x38\xc1\x06\x04\x58\x95\x4d\x25\x13" + "\x6d\x0b\x12\x0b\xc9\x6d\x59\xfc\x33\x03\x36\x01\x12\x09\x72\x74" + "\x5e\x98\x65\x66\x2f\x3a\xde\xd8\xd4\xee\x6f\x82\xe6\x36\x49\x12" + "\x6a\x94\x28\xe9\x28\x9e\xef\x29\xdc\xdf\xab\x94\x65\x02\x4e\x4b" + "\x55" + "\x02\x81\x81" /* INTEGER, offset 798, length 129 */ + "\x00\xc9\xda\xb7\x48\x6e\x66\x15\x45\x2b\x78\x63\x26\x67\xeb\x05" + "\x16\x92\xad\xc0\xf3\x88\xf4\xcf\x24\xc2\x6b\xf4\xd7\x28\xaf\x32" + "\x77\x4e\x73\xad\xd9\x24\xa8\x85\x8b\x26\x75\xd7\x1f\x66\x41\x41" + "\x43\xe3\x69\x66\x8d\xa0\x41\x16\x9d\x60\xef\xef\xdc\x28\x05\x1e" + "\x0e\x03\x0c\x2e\xac\xf4\xdb\x60\x39\x40\x3e\x12\xc7\x40\xe7\xc9" + "\x54\x6f\xf2\xea\x55\xcb\x40\x40\x58\xec\xc0\xeb\x90\x88\x8c\xbc" + "\xcf\x05\x88\x25\x90\x79\x18\xc0\x01\x06\x42\x8e\x48\x50\x27\xf0" + "\x8a\x74\x69\xea\xa1\xf2\x71\xf5\xe5\xd6\xba\xcb\xe6\x3d\xc7\x9c" + "\x11" + "\x02\x81\x81" /* INTEGER, offset 930, length 129 */ + "\x00\xc9\xf5\x04\xad\x34\xe9\x39\xdc\x83\x97\xb6\x3a\x40\xf8\x60" + "\x4b\x69\xec\xf0\x5f\xf3\x88\x69\xcd\xbe\xed\x3c\xc5\x14\x5c\x0c" + "\x54\x2b\xf4\xda\xc6\xc0\x70\x36\xe4\x67\x41\x00\xb7\xc7\x17\x9e" + "\x05\x63\x01\x6d\x77\x06\x71\x24\xcf\x32\x01\xe2\x51\xed\x5e\x90" + "\x38\xed\x4a\xa1\xfb\xb1\x8c\x69\xf4\x08\x96\xef\x0a\x20\x8b\x6c" + "\x77\x85\x33\x92\x9a\xff\x95\xba\x8c\xcd\xa7\x89\xc2\x46\x00\x21" + "\xf3\xd1\xfb\x12\x34\x0c\x99\x8d\x38\xb1\x3b\x66\x5a\x9d\x70\xce" + "\xab\xf3\xe1\xe5\x40\x05\xed\x97\x3d\xd1\x82\x6e\x07\x02\xc0\x8f" + "\x4d" + "\x02\x81\x81" /* INTEGER, offset 1062, length 129 */ + "\x00\xe4\x96\x79\xa8\x6a\x70\xdd\x67\x42\xff\x15\x11\x9e\x01\x71" + "\xac\xf1\x70\x7d\x87\xe2\x6e\x0c\x4d\xbb\x21\x15\xbb\xa7\x4e\x0c" + "\x09\x7e\x82\xca\x91\xbe\xd0\xdd\x9c\x8c\xb0\x77\x64\x30\x1b\x7e" + "\xbb\x69\xcb\x4c\xde\xd6\x6a\xb9\x72\x15\x79\xdc\x05\x99\x69\x8b" + "\x24\xa1\xad\x13\x35\x31\xc0\x0b\xf1\xd2\x06\x7c\x94\x1a\x21\x2f" + "\x02\xb9\xf0\xd0\xbb\xf7\xb7\x78\xf9\x3d\x76\x60\xd6\x6b\x5f\x35" + "\x88\x14\x33\xe6\xbc\xca\x6b\x88\x90\x57\x3b\x0c\xa3\x6e\x47\xdf" + "\x4e\x2f\x4c\xf9\xab\x97\x38\xe4\x20\x32\x32\x96\xc8\x9e\x79\xd3" + "\x12"; + +#define MAX_CHECKER_COUNT 32 + +typedef struct QCryptoAns1DecoderResultChecker QCryptoAns1DecoderResultChecker; +struct QCryptoAns1DecoderResultChecker { + int (*action) (const uint8_t **data, size_t *dlen, + QCryptoDERDecodeCb cb, void *opaque, Error **errp); + QCryptoDERDecodeCb cb; + const uint8_t *exp_value; + size_t exp_vlen; +}; + +typedef struct QCryptoAns1DecoderTestData QCryptoAns1DecoderTestData; +struct QCryptoAns1DecoderTestData { + const char *path; + const uint8_t *test_data; + size_t test_data_len; + QCryptoAns1DecoderResultChecker checker[MAX_CHECKER_COUNT]; +}; + +typedef struct QCryptoAns1DecoderTestContext QCryptoAns1DecoderTestContext; +struct QCryptoAns1DecoderTestContext { + const uint8_t *data; + size_t dlen; +}; + +static int checker_callback(void *opaque, const uint8_t *value, + size_t vlen, Error **errp) +{ + QCryptoAns1DecoderResultChecker *checker = + (QCryptoAns1DecoderResultChecker *)opaque; + + g_assert(value == checker->exp_value); + g_assert(vlen == checker->exp_vlen); + return 0; +} + +static void test_ans1(const void *opaque) +{ + const QCryptoAns1DecoderTestData *test_data = + (QCryptoAns1DecoderTestData *)opaque; + QCryptoAns1DecoderTestContext ctx[MAX_CHECKER_COUNT]; + int seq_depth = 0, checker_idx = 0; + ctx[seq_depth].data = test_data->test_data; + ctx[seq_depth].dlen = test_data->test_data_len; + bool all_checker_completed = false; + + do { + const QCryptoAns1DecoderResultChecker *checker = + &test_data->checker[checker_idx++]; + QCryptoAns1DecoderTestContext *c = &ctx[seq_depth]; + if (!checker->action) { + all_checker_completed = true; + break; + } + g_assert(checker->action(&c->data, &c->dlen, checker_callback, + (void *)checker, &error_abort) + == checker->exp_vlen); + if (checker->action == qcrypto_der_decode_seq) { + ++seq_depth; + ctx[seq_depth].data = checker->exp_value; + ctx[seq_depth].dlen = checker->exp_vlen; + } + while (seq_depth != 0 && ctx[seq_depth].dlen == 0) { + --seq_depth; + } + + } while (true); + g_assert(seq_depth == 0); + g_assert(ctx[seq_depth].dlen == 0); + g_assert(all_checker_completed); +} + +static QCryptoAns1DecoderTestData test_data[] = { +{ + .path = "/crypto/der/parse-rsa512-priv-key", + .test_data = test_rsa512_priv_key, + .test_data_len = sizeof(test_rsa512_priv_key) - 1, + .checker = { + { qcrypto_der_decode_seq, checker_callback, + test_rsa512_priv_key + 4, 313 }, + { qcrypto_der_decode_int, checker_callback, + test_rsa512_priv_key + 4 + 2, 1 }, + { qcrypto_der_decode_int, checker_callback, + test_rsa512_priv_key + 7 + 2, 65 }, + { qcrypto_der_decode_int, checker_callback, + test_rsa512_priv_key + 74 + 2, 3 }, + { qcrypto_der_decode_int, checker_callback, + test_rsa512_priv_key + 79 + 2, 64 }, + { qcrypto_der_decode_int, checker_callback, + test_rsa512_priv_key + 145 + 2, 33 }, + { qcrypto_der_decode_int, checker_callback, + test_rsa512_priv_key + 180 + 2, 33 }, + { qcrypto_der_decode_int, checker_callback, + test_rsa512_priv_key + 215 + 2, 32 }, + { qcrypto_der_decode_int, checker_callback, + test_rsa512_priv_key + 249 + 2, 32 }, + { qcrypto_der_decode_int, checker_callback, + test_rsa512_priv_key + 283 + 2, 32 }, + }, +}, +{ + .path = "/crypto/der/parse-rsa2048-priv-key", + .test_data = test_rsa2048_priv_key, + .test_data_len = sizeof(test_rsa2048_priv_key) - 1, + .checker = { + { qcrypto_der_decode_seq, checker_callback, + test_rsa2048_priv_key + 4, 1190 }, + { qcrypto_der_decode_int, checker_callback, + test_rsa2048_priv_key + 4 + 2, 1 }, + { qcrypto_der_decode_int, checker_callback, + test_rsa2048_priv_key + 7 + 4, 257 }, + { qcrypto_der_decode_int, checker_callback, + test_rsa2048_priv_key + 268 + 2, 3 }, + { qcrypto_der_decode_int, checker_callback, + test_rsa2048_priv_key + 273 + 4, 257 }, + { qcrypto_der_decode_int, checker_callback, + test_rsa2048_priv_key + 534 + 3, 129 }, + { qcrypto_der_decode_int, checker_callback, + test_rsa2048_priv_key + 666 + 3, 129 }, + { qcrypto_der_decode_int, checker_callback, + test_rsa2048_priv_key + 798 + 3, 129 }, + { qcrypto_der_decode_int, checker_callback, + test_rsa2048_priv_key + 930 + 3, 129 }, + { qcrypto_der_decode_int, checker_callback, + test_rsa2048_priv_key + 1062 + 3, 129 }, + }, +}, + +}; + +int main(int argc, char **argv) +{ + size_t i; + g_test_init(&argc, &argv, NULL); + + for (i = 0; i < G_N_ELEMENTS(test_data); i++) { + g_test_add_data_func(test_data[i].path, &test_data[i], test_ans1); + } + + return g_test_run(); +} From 4c5e512ee0c49efb42286600aef31739c0dcee5d Mon Sep 17 00:00:00 2001 From: Lei He Date: Wed, 25 May 2022 17:01:14 +0800 Subject: [PATCH 525/935] crypto: Implement RSA algorithm by hogweed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement RSA algorithm by hogweed from nettle. Thus QEMU supports a 'real' RSA backend to handle request from guest side. It's important to test RSA offload case without OS & hardware requirement. Signed-off-by: lei he Signed-off-by: zhenwei pi Signed-off-by: Daniel P. Berrangé --- crypto/akcipher-nettle.c.inc | 451 +++++++++++++++++++++++++++++++++++ crypto/akcipher.c | 4 + crypto/meson.build | 4 + crypto/rsakey-builtin.c.inc | 200 ++++++++++++++++ crypto/rsakey-nettle.c.inc | 158 ++++++++++++ crypto/rsakey.c | 44 ++++ crypto/rsakey.h | 92 +++++++ meson.build | 11 + 8 files changed, 964 insertions(+) create mode 100644 crypto/akcipher-nettle.c.inc create mode 100644 crypto/rsakey-builtin.c.inc create mode 100644 crypto/rsakey-nettle.c.inc create mode 100644 crypto/rsakey.c create mode 100644 crypto/rsakey.h diff --git a/crypto/akcipher-nettle.c.inc b/crypto/akcipher-nettle.c.inc new file mode 100644 index 0000000000..a7c0c6a1ee --- /dev/null +++ b/crypto/akcipher-nettle.c.inc @@ -0,0 +1,451 @@ +/* + * QEMU Crypto akcipher algorithms + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#include + +#include "qemu/osdep.h" +#include "qemu/host-utils.h" +#include "crypto/akcipher.h" +#include "crypto/random.h" +#include "qapi/error.h" +#include "sysemu/cryptodev.h" +#include "rsakey.h" + +typedef struct QCryptoNettleRSA { + QCryptoAkCipher akcipher; + struct rsa_public_key pub; + struct rsa_private_key priv; + QCryptoRSAPaddingAlgorithm padding_alg; + QCryptoHashAlgorithm hash_alg; +} QCryptoNettleRSA; + +static void qcrypto_nettle_rsa_free(QCryptoAkCipher *akcipher) +{ + QCryptoNettleRSA *rsa = (QCryptoNettleRSA *)akcipher; + if (!rsa) { + return; + } + + rsa_public_key_clear(&rsa->pub); + rsa_private_key_clear(&rsa->priv); + g_free(rsa); +} + +static QCryptoAkCipher *qcrypto_nettle_rsa_new( + const QCryptoAkCipherOptionsRSA *opt, + QCryptoAkCipherKeyType type, + const uint8_t *key, size_t keylen, + Error **errp); + +QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts, + QCryptoAkCipherKeyType type, + const uint8_t *key, size_t keylen, + Error **errp) +{ + switch (opts->alg) { + case QCRYPTO_AKCIPHER_ALG_RSA: + return qcrypto_nettle_rsa_new(&opts->u.rsa, type, key, keylen, errp); + + default: + error_setg(errp, "Unsupported algorithm: %u", opts->alg); + return NULL; + } + + return NULL; +} + +static void qcrypto_nettle_rsa_set_akcipher_size(QCryptoAkCipher *akcipher, + int key_size) +{ + akcipher->max_plaintext_len = key_size; + akcipher->max_ciphertext_len = key_size; + akcipher->max_signature_len = key_size; + akcipher->max_dgst_len = key_size; +} + +static int qcrypt_nettle_parse_rsa_private_key(QCryptoNettleRSA *rsa, + const uint8_t *key, + size_t keylen, + Error **errp) +{ + g_autoptr(QCryptoAkCipherRSAKey) rsa_key = qcrypto_akcipher_rsakey_parse( + QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, key, keylen, errp); + + if (!rsa_key) { + return -1; + } + + nettle_mpz_init_set_str_256_u(rsa->pub.n, rsa_key->n.len, rsa_key->n.data); + nettle_mpz_init_set_str_256_u(rsa->pub.e, rsa_key->e.len, rsa_key->e.data); + nettle_mpz_init_set_str_256_u(rsa->priv.d, rsa_key->d.len, rsa_key->d.data); + nettle_mpz_init_set_str_256_u(rsa->priv.p, rsa_key->p.len, rsa_key->p.data); + nettle_mpz_init_set_str_256_u(rsa->priv.q, rsa_key->q.len, rsa_key->q.data); + nettle_mpz_init_set_str_256_u(rsa->priv.a, rsa_key->dp.len, + rsa_key->dp.data); + nettle_mpz_init_set_str_256_u(rsa->priv.b, rsa_key->dq.len, + rsa_key->dq.data); + nettle_mpz_init_set_str_256_u(rsa->priv.c, rsa_key->u.len, rsa_key->u.data); + + if (!rsa_public_key_prepare(&rsa->pub)) { + error_setg(errp, "Failed to check RSA key"); + return -1; + } + + /** + * Since in the kernel's unit test, the p, q, a, b, c of some + * private keys is 0, only the simplest length check is done here + */ + if (rsa_key->p.len > 1 && + rsa_key->q.len > 1 && + rsa_key->dp.len > 1 && + rsa_key->dq.len > 1 && + rsa_key->u.len > 1) { + if (!rsa_private_key_prepare(&rsa->priv)) { + error_setg(errp, "Failed to check RSA key"); + return -1; + } + } else { + rsa->priv.size = rsa->pub.size; + } + qcrypto_nettle_rsa_set_akcipher_size( + (QCryptoAkCipher *)rsa, rsa->priv.size); + + return 0; +} + +static int qcrypt_nettle_parse_rsa_public_key(QCryptoNettleRSA *rsa, + const uint8_t *key, + size_t keylen, + Error **errp) +{ + g_autoptr(QCryptoAkCipherRSAKey) rsa_key = qcrypto_akcipher_rsakey_parse( + QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, key, keylen, errp); + + if (!rsa_key) { + return -1; + } + nettle_mpz_init_set_str_256_u(rsa->pub.n, rsa_key->n.len, rsa_key->n.data); + nettle_mpz_init_set_str_256_u(rsa->pub.e, rsa_key->e.len, rsa_key->e.data); + + if (!rsa_public_key_prepare(&rsa->pub)) { + error_setg(errp, "Failed to check RSA key"); + return -1; + } + qcrypto_nettle_rsa_set_akcipher_size( + (QCryptoAkCipher *)rsa, rsa->pub.size); + + return 0; +} + +static void wrap_nettle_random_func(void *ctx, size_t len, uint8_t *out) +{ + qcrypto_random_bytes(out, len, &error_abort); +} + +static int qcrypto_nettle_rsa_encrypt(QCryptoAkCipher *akcipher, + const void *data, size_t data_len, + void *enc, size_t enc_len, + Error **errp) +{ + + QCryptoNettleRSA *rsa = (QCryptoNettleRSA *)akcipher; + mpz_t c; + int ret = -1; + + if (data_len > rsa->pub.size) { + error_setg(errp, "Plaintext length %zu is greater than key size: %zu" + data_len, rsa->pub.size); + return ret; + } + + if (enc_len < rsa->pub.size) { + error_setg(errp, "Ciphertext buffer length %zu is less than " + "key size: %zu", rsa->pub.size); + return ret; + } + + /* Nettle do not support RSA encryption without any padding */ + switch (rsa->padding_alg) { + case QCRYPTO_RSA_PADDING_ALG_RAW: + error_setg(errp, "RSA with raw padding is not supported"); + break; + + case QCRYPTO_RSA_PADDING_ALG_PKCS1: + mpz_init(c); + if (rsa_encrypt(&rsa->pub, NULL, wrap_nettle_random_func, + data_len, (uint8_t *)data, c) != 1) { + error_setg(errp, "Failed to encrypt"); + } else { + nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, c); + ret = nettle_mpz_sizeinbase_256_u(c); + } + mpz_clear(c); + break; + + default: + error_setg(errp, "Unknown padding"); + } + + return ret; +} + +static int qcrypto_nettle_rsa_decrypt(QCryptoAkCipher *akcipher, + const void *enc, size_t enc_len, + void *data, size_t data_len, + Error **errp) +{ + QCryptoNettleRSA *rsa = (QCryptoNettleRSA *)akcipher; + mpz_t c; + int ret = -1; + + if (enc_len > rsa->priv.size) { + error_setg(errp, "Ciphertext length %zu is greater than key size: %zu", + rsa->priv.size); + return ret; + } + + switch (rsa->padding_alg) { + case QCRYPTO_RSA_PADDING_ALG_RAW: + error_setg(errp, "RSA with raw padding is not supported"); + break; + + case QCRYPTO_RSA_PADDING_ALG_PKCS1: + nettle_mpz_init_set_str_256_u(c, enc_len, enc); + if (!rsa_decrypt(&rsa->priv, &data_len, (uint8_t *)data, c)) { + error_setg(errp, "Failed to decrypt"); + } else { + ret = data_len; + } + + mpz_clear(c); + break; + + default: + error_setg(errp, "Unknown padding algorithm: %d", rsa->padding_alg); + } + + return ret; +} + +static int qcrypto_nettle_rsa_sign(QCryptoAkCipher *akcipher, + const void *data, size_t data_len, + void *sig, size_t sig_len, Error **errp) +{ + QCryptoNettleRSA *rsa = (QCryptoNettleRSA *)akcipher; + int ret = -1, rv; + mpz_t s; + + /** + * The RSA algorithm cannot be used for signature/verification + * without padding. + */ + if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALG_RAW) { + error_setg(errp, "Try to make signature without padding"); + return ret; + } + + if (data_len > rsa->priv.size) { + error_setg(errp, "Data length %zu is greater than key size: %zu", + rsa->priv.size); + return ret; + } + + if (sig_len < rsa->priv.size) { + error_setg(errp, "Signature buffer length %zu is less than " + "key size: %zu", rsa->priv.size); + return ret; + } + + mpz_init(s); + switch (rsa->hash_alg) { + case QCRYPTO_HASH_ALG_MD5: + rv = rsa_md5_sign_digest(&rsa->priv, data, s); + break; + + case QCRYPTO_HASH_ALG_SHA1: + rv = rsa_sha1_sign_digest(&rsa->priv, data, s); + break; + + case QCRYPTO_HASH_ALG_SHA256: + rv = rsa_sha256_sign_digest(&rsa->priv, data, s); + break; + + case QCRYPTO_HASH_ALG_SHA512: + rv = rsa_sha512_sign_digest(&rsa->priv, data, s); + break; + + default: + error_setg(errp, "Unknown hash algorithm: %d", rsa->hash_alg); + goto cleanup; + } + + if (rv != 1) { + error_setg(errp, "Failed to make signature"); + goto cleanup; + } + nettle_mpz_get_str_256(sig_len, (uint8_t *)sig, s); + ret = nettle_mpz_sizeinbase_256_u(s); + +cleanup: + mpz_clear(s); + + return ret; +} + +static int qcrypto_nettle_rsa_verify(QCryptoAkCipher *akcipher, + const void *sig, size_t sig_len, + const void *data, size_t data_len, + Error **errp) +{ + QCryptoNettleRSA *rsa = (QCryptoNettleRSA *)akcipher; + + int ret = -1, rv; + mpz_t s; + + /** + * The RSA algorithm cannot be used for signature/verification + * without padding. + */ + if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALG_RAW) { + error_setg(errp, "Try to verify signature without padding"); + return ret; + } + if (data_len > rsa->pub.size) { + error_setg(errp, "Data length %zu is greater than key size: %zu", + rsa->pub.size); + return ret; + } + if (sig_len < rsa->pub.size) { + error_setg(errp, "Signature length %zu is greater than key size: %zu", + rsa->pub.size); + return ret; + } + + nettle_mpz_init_set_str_256_u(s, sig_len, sig); + switch (rsa->hash_alg) { + case QCRYPTO_HASH_ALG_MD5: + rv = rsa_md5_verify_digest(&rsa->pub, data, s); + break; + + case QCRYPTO_HASH_ALG_SHA1: + rv = rsa_sha1_verify_digest(&rsa->pub, data, s); + break; + + case QCRYPTO_HASH_ALG_SHA256: + rv = rsa_sha256_verify_digest(&rsa->pub, data, s); + break; + + case QCRYPTO_HASH_ALG_SHA512: + rv = rsa_sha512_verify_digest(&rsa->pub, data, s); + break; + + default: + error_setg(errp, "Unsupported hash algorithm: %d", rsa->hash_alg); + goto cleanup; + } + + if (rv != 1) { + error_setg(errp, "Failed to verify signature"); + goto cleanup; + } + ret = 0; + +cleanup: + mpz_clear(s); + + return ret; +} + +QCryptoAkCipherDriver nettle_rsa = { + .encrypt = qcrypto_nettle_rsa_encrypt, + .decrypt = qcrypto_nettle_rsa_decrypt, + .sign = qcrypto_nettle_rsa_sign, + .verify = qcrypto_nettle_rsa_verify, + .free = qcrypto_nettle_rsa_free, +}; + +static QCryptoAkCipher *qcrypto_nettle_rsa_new( + const QCryptoAkCipherOptionsRSA *opt, + QCryptoAkCipherKeyType type, + const uint8_t *key, size_t keylen, + Error **errp) +{ + QCryptoNettleRSA *rsa = g_new0(QCryptoNettleRSA, 1); + + rsa->padding_alg = opt->padding_alg; + rsa->hash_alg = opt->hash_alg; + rsa->akcipher.driver = &nettle_rsa; + rsa_public_key_init(&rsa->pub); + rsa_private_key_init(&rsa->priv); + + switch (type) { + case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE: + if (qcrypt_nettle_parse_rsa_private_key(rsa, key, keylen, errp) != 0) { + goto error; + } + break; + + case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC: + if (qcrypt_nettle_parse_rsa_public_key(rsa, key, keylen, errp) != 0) { + goto error; + } + break; + + default: + error_setg(errp, "Unknown akcipher key type %d", type); + goto error; + } + + return (QCryptoAkCipher *)rsa; + +error: + qcrypto_nettle_rsa_free((QCryptoAkCipher *)rsa); + return NULL; +} + + +bool qcrypto_akcipher_supports(QCryptoAkCipherOptions *opts) +{ + switch (opts->alg) { + case QCRYPTO_AKCIPHER_ALG_RSA: + switch (opts->u.rsa.padding_alg) { + case QCRYPTO_RSA_PADDING_ALG_PKCS1: + switch (opts->u.rsa.hash_alg) { + case QCRYPTO_HASH_ALG_MD5: + case QCRYPTO_HASH_ALG_SHA1: + case QCRYPTO_HASH_ALG_SHA256: + case QCRYPTO_HASH_ALG_SHA512: + return true; + + default: + return false; + } + + case QCRYPTO_RSA_PADDING_ALG_RAW: + default: + return false; + } + break; + + default: + return false; + } +} diff --git a/crypto/akcipher.c b/crypto/akcipher.c index ab28bf415b..f287083f92 100644 --- a/crypto/akcipher.c +++ b/crypto/akcipher.c @@ -23,6 +23,9 @@ #include "crypto/akcipher.h" #include "akcipherpriv.h" +#if defined(CONFIG_NETTLE) && defined(CONFIG_HOGWEED) +#include "akcipher-nettle.c.inc" +#else QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts, QCryptoAkCipherKeyType type, const uint8_t *key, size_t keylen, @@ -37,6 +40,7 @@ bool qcrypto_akcipher_supports(QCryptoAkCipherOptions *opts) { return false; } +#endif int qcrypto_akcipher_encrypt(QCryptoAkCipher *akcipher, const void *in, size_t in_len, diff --git a/crypto/meson.build b/crypto/meson.build index b8152ae7cb..5f03a30d34 100644 --- a/crypto/meson.build +++ b/crypto/meson.build @@ -21,10 +21,14 @@ crypto_ss.add(files( 'tlscredspsk.c', 'tlscredsx509.c', 'tlssession.c', + 'rsakey.c', )) if nettle.found() crypto_ss.add(nettle, files('hash-nettle.c', 'hmac-nettle.c', 'pbkdf-nettle.c')) + if hogweed.found() + crypto_ss.add(gmp, hogweed) + endif if xts == 'private' crypto_ss.add(files('xts.c')) endif diff --git a/crypto/rsakey-builtin.c.inc b/crypto/rsakey-builtin.c.inc new file mode 100644 index 0000000000..aeeacc8f9b --- /dev/null +++ b/crypto/rsakey-builtin.c.inc @@ -0,0 +1,200 @@ +/* + * QEMU Crypto akcipher algorithms + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#include "der.h" +#include "rsakey.h" + +static int extract_mpi(void *ctx, const uint8_t *value, + size_t vlen, Error **errp) +{ + QCryptoAkCipherMPI *mpi = (QCryptoAkCipherMPI *)ctx; + if (vlen == 0) { + error_setg(errp, "Empty mpi field"); + return -1; + } + mpi->data = g_memdup2(value, vlen); + mpi->len = vlen; + return 0; +} + +static int extract_version(void *ctx, const uint8_t *value, + size_t vlen, Error **errp) +{ + uint8_t *version = (uint8_t *)ctx; + if (vlen != 1 || *value > 1) { + error_setg(errp, "Invalid rsakey version"); + return -1; + } + *version = *value; + return 0; +} + +static int extract_seq_content(void *ctx, const uint8_t *value, + size_t vlen, Error **errp) +{ + const uint8_t **content = (const uint8_t **)ctx; + if (vlen == 0) { + error_setg(errp, "Empty sequence"); + return -1; + } + *content = value; + return 0; +} + +/** + * + * RsaPubKey ::= SEQUENCE { + * n INTEGER + * e INTEGER + * } + */ +static QCryptoAkCipherRSAKey *qcrypto_builtin_rsa_public_key_parse( + const uint8_t *key, size_t keylen, Error **errp) +{ + QCryptoAkCipherRSAKey *rsa = g_new0(QCryptoAkCipherRSAKey, 1); + const uint8_t *seq; + size_t seq_length; + int decode_ret; + + decode_ret = qcrypto_der_decode_seq(&key, &keylen, + extract_seq_content, &seq, errp); + if (decode_ret < 0 || keylen != 0) { + goto error; + } + seq_length = decode_ret; + + if (qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, + &rsa->n, errp) < 0 || + qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, + &rsa->e, errp) < 0) { + goto error; + } + if (seq_length != 0) { + goto error; + } + + return rsa; + +error: + if (errp && !*errp) { + error_setg(errp, "Invalid RSA public key"); + } + qcrypto_akcipher_rsakey_free(rsa); + return NULL; +} + +/** + * RsaPrivKey ::= SEQUENCE { + * version INTEGER + * n INTEGER + * e INTEGER + * d INTEGER + * p INTEGER + * q INTEGER + * dp INTEGER + * dq INTEGER + * u INTEGER + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + */ +static QCryptoAkCipherRSAKey *qcrypto_builtin_rsa_private_key_parse( + const uint8_t *key, size_t keylen, Error **errp) +{ + QCryptoAkCipherRSAKey *rsa = g_new0(QCryptoAkCipherRSAKey, 1); + uint8_t version; + const uint8_t *seq; + int decode_ret; + size_t seq_length; + + decode_ret = qcrypto_der_decode_seq(&key, &keylen, extract_seq_content, + &seq, errp); + if (decode_ret < 0 || keylen != 0) { + goto error; + } + seq_length = decode_ret; + + decode_ret = qcrypto_der_decode_int(&seq, &seq_length, extract_version, + &version, errp); + + if (qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, + &rsa->n, errp) < 0 || + qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, + &rsa->e, errp) < 0 || + qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, + &rsa->d, errp) < 0 || + qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->p, + errp) < 0 || + qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->q, + errp) < 0 || + qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->dp, + errp) < 0 || + qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->dq, + errp) < 0 || + qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->u, + errp) < 0) { + goto error; + } + + /** + * According to the standard, otherPrimeInfos must be present for version 1. + * There is no strict verification here, this is to be compatible with + * the unit test of the kernel. TODO: remove this until linux kernel's + * unit-test is fixed. + */ + if (version == 1 && seq_length != 0) { + if (qcrypto_der_decode_seq(&seq, &seq_length, NULL, NULL, errp) < 0) { + goto error; + } + if (seq_length != 0) { + goto error; + } + return rsa; + } + if (seq_length != 0) { + goto error; + } + + return rsa; + +error: + if (errp && !*errp) { + error_setg(errp, "Invalid RSA private key"); + } + qcrypto_akcipher_rsakey_free(rsa); + return NULL; +} + +QCryptoAkCipherRSAKey *qcrypto_akcipher_rsakey_parse( + QCryptoAkCipherKeyType type, const uint8_t *key, + size_t keylen, Error **errp) +{ + switch (type) { + case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE: + return qcrypto_builtin_rsa_private_key_parse(key, keylen, errp); + + case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC: + return qcrypto_builtin_rsa_public_key_parse(key, keylen, errp); + + default: + error_setg(errp, "Unknown key type: %d", type); + return NULL; + } +} diff --git a/crypto/rsakey-nettle.c.inc b/crypto/rsakey-nettle.c.inc new file mode 100644 index 0000000000..cc49872e78 --- /dev/null +++ b/crypto/rsakey-nettle.c.inc @@ -0,0 +1,158 @@ +/* + * QEMU Crypto akcipher algorithms + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#include + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "rsakey.h" + +static bool DumpMPI(struct asn1_der_iterator *i, QCryptoAkCipherMPI *mpi) +{ + mpi->data = g_memdup2(i->data, i->length); + mpi->len = i->length; + return true; +} + +static bool GetMPI(struct asn1_der_iterator *i, QCryptoAkCipherMPI *mpi) +{ + if (asn1_der_iterator_next(i) != ASN1_ITERATOR_PRIMITIVE || + i->type != ASN1_INTEGER) { + return false; + } + return DumpMPI(i, mpi); +} + +/** + * RsaPrivKey ::= SEQUENCE { + * version INTEGER + * n INTEGER + * e INTEGER + * d INTEGER + * p INTEGER + * q INTEGER + * dp INTEGER + * dq INTEGER + * u INTEGER + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + */ +static QCryptoAkCipherRSAKey *qcrypto_nettle_rsa_private_key_parse( + const uint8_t *key, size_t keylen, Error **errp) +{ + QCryptoAkCipherRSAKey *rsa = g_new0(QCryptoAkCipherRSAKey, 1); + struct asn1_der_iterator i; + uint32_t version; + int tag; + + /* Parse entire struct */ + if (asn1_der_iterator_first(&i, keylen, key) != ASN1_ITERATOR_CONSTRUCTED || + i.type != ASN1_SEQUENCE || + asn1_der_decode_constructed_last(&i) != ASN1_ITERATOR_PRIMITIVE || + i.type != ASN1_INTEGER || + !asn1_der_get_uint32(&i, &version) || + version > 1 || + !GetMPI(&i, &rsa->n) || + !GetMPI(&i, &rsa->e) || + !GetMPI(&i, &rsa->d) || + !GetMPI(&i, &rsa->p) || + !GetMPI(&i, &rsa->q) || + !GetMPI(&i, &rsa->dp) || + !GetMPI(&i, &rsa->dq) || + !GetMPI(&i, &rsa->u)) { + goto error; + } + + if (version == 1) { + tag = asn1_der_iterator_next(&i); + /** + * According to the standard otherPrimeInfos must be present for + * version 1. There is no strict verification here, this is to be + * compatible with the unit test of the kernel. TODO: remove this + * until linux-kernel's unit-test is fixed; + */ + if (tag == ASN1_ITERATOR_END) { + return rsa; + } + if (tag != ASN1_ITERATOR_CONSTRUCTED || + i.type != ASN1_SEQUENCE) { + goto error; + } + } + + if (asn1_der_iterator_next(&i) != ASN1_ITERATOR_END) { + goto error; + } + + return rsa; + +error: + error_setg(errp, "Failed to parse RSA private key"); + qcrypto_akcipher_rsakey_free(rsa); + return NULL; +} + +/** + * RsaPubKey ::= SEQUENCE { + * n INTEGER + * e INTEGER + * } + */ +static QCryptoAkCipherRSAKey *qcrypto_nettle_rsa_public_key_parse( + const uint8_t *key, size_t keylen, Error **errp) +{ + + QCryptoAkCipherRSAKey *rsa = g_new0(QCryptoAkCipherRSAKey, 1); + struct asn1_der_iterator i; + + if (asn1_der_iterator_first(&i, keylen, key) != ASN1_ITERATOR_CONSTRUCTED || + i.type != ASN1_SEQUENCE || + asn1_der_decode_constructed_last(&i) != ASN1_ITERATOR_PRIMITIVE || + !DumpMPI(&i, &rsa->n) || + !GetMPI(&i, &rsa->e) || + asn1_der_iterator_next(&i) != ASN1_ITERATOR_END) { + goto error; + } + + return rsa; + +error: + error_setg(errp, "Failed to parse RSA public key"); + qcrypto_akcipher_rsakey_free(rsa); + return NULL; +} + +QCryptoAkCipherRSAKey *qcrypto_akcipher_rsakey_parse( + QCryptoAkCipherKeyType type, const uint8_t *key, + size_t keylen, Error **errp) +{ + switch (type) { + case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE: + return qcrypto_nettle_rsa_private_key_parse(key, keylen, errp); + + case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC: + return qcrypto_nettle_rsa_public_key_parse(key, keylen, errp); + + default: + error_setg(errp, "Unknown key type: %d", type); + return NULL; + } +} diff --git a/crypto/rsakey.c b/crypto/rsakey.c new file mode 100644 index 0000000000..cc40e072f0 --- /dev/null +++ b/crypto/rsakey.c @@ -0,0 +1,44 @@ +/* + * QEMU Crypto RSA key parser + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#include "rsakey.h" + +void qcrypto_akcipher_rsakey_free(QCryptoAkCipherRSAKey *rsa_key) +{ + if (!rsa_key) { + return; + } + g_free(rsa_key->n.data); + g_free(rsa_key->e.data); + g_free(rsa_key->d.data); + g_free(rsa_key->p.data); + g_free(rsa_key->q.data); + g_free(rsa_key->dp.data); + g_free(rsa_key->dq.data); + g_free(rsa_key->u.data); + g_free(rsa_key); +} + +#if defined(CONFIG_NETTLE) && defined(CONFIG_HOGWEED) +#include "rsakey-nettle.c.inc" +#else +#include "rsakey-builtin.c.inc" +#endif diff --git a/crypto/rsakey.h b/crypto/rsakey.h new file mode 100644 index 0000000000..974b76f659 --- /dev/null +++ b/crypto/rsakey.h @@ -0,0 +1,92 @@ +/* + * QEMU Crypto RSA key parser + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#ifndef QCRYPTO_RSAKEY_H +#define QCRYPTO_RSAKEY_H + +#include "qemu/osdep.h" +#include "qemu/host-utils.h" +#include "crypto/akcipher.h" + +typedef struct QCryptoAkCipherRSAKey QCryptoAkCipherRSAKey; +typedef struct QCryptoAkCipherMPI QCryptoAkCipherMPI; + +/** + * Multiple precious integer, encoded as two' complement, + * copied directly from DER encoded ASN.1 structures. + */ +struct QCryptoAkCipherMPI { + uint8_t *data; + size_t len; +}; + +/* See rfc2437: https://datatracker.ietf.org/doc/html/rfc2437 */ +struct QCryptoAkCipherRSAKey { + /* The modulus */ + QCryptoAkCipherMPI n; + /* The public exponent */ + QCryptoAkCipherMPI e; + /* The private exponent */ + QCryptoAkCipherMPI d; + /* The first factor */ + QCryptoAkCipherMPI p; + /* The second factor */ + QCryptoAkCipherMPI q; + /* The first factor's exponent */ + QCryptoAkCipherMPI dp; + /* The second factor's exponent */ + QCryptoAkCipherMPI dq; + /* The CRT coefficient */ + QCryptoAkCipherMPI u; +}; + +/** + * Parse DER encoded ASN.1 RSA keys, expected ASN.1 schemas: + * RsaPrivKey ::= SEQUENCE { + * version INTEGER + * n INTEGER + * e INTEGER + * d INTEGER + * p INTEGER + * q INTEGER + * dp INTEGER + * dq INTEGER + * u INTEGER + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + * + * RsaPubKey ::= SEQUENCE { + * n INTEGER + * e INTEGER + * } + * + * Returns: On success QCryptoAkCipherRSAKey is returned, otherwise returns NULL + */ +QCryptoAkCipherRSAKey *qcrypto_akcipher_rsakey_parse( + QCryptoAkCipherKeyType type, + const uint8_t *key, size_t keylen, Error **errp); + +void qcrypto_akcipher_rsakey_free(QCryptoAkCipherRSAKey *key); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoAkCipherRSAKey, + qcrypto_akcipher_rsakey_free); + +#endif diff --git a/meson.build b/meson.build index 9ebc00f032..df7c34b076 100644 --- a/meson.build +++ b/meson.build @@ -1121,6 +1121,7 @@ endif # gcrypt over nettle for performance reasons. gcrypt = not_found nettle = not_found +hogweed = not_found xts = 'none' if get_option('nettle').enabled() and get_option('gcrypt').enabled() @@ -1158,6 +1159,15 @@ if not gnutls_crypto.found() endif endif +gmp = dependency('gmp', required: false, method: 'pkg-config', kwargs: static_kwargs) +if nettle.found() and gmp.found() + hogweed = dependency('hogweed', version: '>=3.4', + method: 'pkg-config', + required: get_option('nettle'), + kwargs: static_kwargs) +endif + + gtk = not_found gtkx11 = not_found vte = not_found @@ -1769,6 +1779,7 @@ config_host_data.set('CONFIG_GNUTLS_CRYPTO', gnutls_crypto.found()) config_host_data.set('CONFIG_TASN1', tasn1.found()) config_host_data.set('CONFIG_GCRYPT', gcrypt.found()) config_host_data.set('CONFIG_NETTLE', nettle.found()) +config_host_data.set('CONFIG_HOGWEED', hogweed.found()) config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private') config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim) config_host_data.set('CONFIG_STATX', has_statx) From e09d1c274782e30dcc0ab5e4d62b624d0028d718 Mon Sep 17 00:00:00 2001 From: Lei He Date: Wed, 25 May 2022 17:01:15 +0800 Subject: [PATCH 526/935] crypto: Implement RSA algorithm by gcrypt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added gcryt implementation of RSA algorithm, RSA algorithm implemented by gcrypt has a higher priority than nettle because it supports raw padding. Signed-off-by: lei he Signed-off-by: Daniel P. Berrangé --- crypto/akcipher-gcrypt.c.inc | 595 +++++++++++++++++++++++++++++++++++ crypto/akcipher.c | 4 +- 2 files changed, 598 insertions(+), 1 deletion(-) create mode 100644 crypto/akcipher-gcrypt.c.inc diff --git a/crypto/akcipher-gcrypt.c.inc b/crypto/akcipher-gcrypt.c.inc new file mode 100644 index 0000000000..abb1fb272e --- /dev/null +++ b/crypto/akcipher-gcrypt.c.inc @@ -0,0 +1,595 @@ +/* + * QEMU Crypto akcipher algorithms + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#include + +#include "qemu/osdep.h" +#include "qemu/host-utils.h" +#include "crypto/akcipher.h" +#include "crypto/random.h" +#include "qapi/error.h" +#include "sysemu/cryptodev.h" +#include "rsakey.h" + +typedef struct QCryptoGcryptRSA { + QCryptoAkCipher akcipher; + gcry_sexp_t key; + QCryptoRSAPaddingAlgorithm padding_alg; + QCryptoHashAlgorithm hash_alg; +} QCryptoGcryptRSA; + +static void qcrypto_gcrypt_rsa_free(QCryptoAkCipher *akcipher) +{ + QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher; + if (!rsa) { + return; + } + + gcry_sexp_release(rsa->key); + g_free(rsa); +} + +static QCryptoGcryptRSA *qcrypto_gcrypt_rsa_new( + const QCryptoAkCipherOptionsRSA *opt, + QCryptoAkCipherKeyType type, + const uint8_t *key, size_t keylen, + Error **errp); + +QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts, + QCryptoAkCipherKeyType type, + const uint8_t *key, size_t keylen, + Error **errp) +{ + switch (opts->alg) { + case QCRYPTO_AKCIPHER_ALG_RSA: + return (QCryptoAkCipher *)qcrypto_gcrypt_rsa_new( + &opts->u.rsa, type, key, keylen, errp); + + default: + error_setg(errp, "Unsupported algorithm: %u", opts->alg); + return NULL; + } + + return NULL; +} + +static void qcrypto_gcrypt_set_rsa_size(QCryptoAkCipher *akcipher, gcry_mpi_t n) +{ + size_t key_size = (gcry_mpi_get_nbits(n) + 7) / 8; + akcipher->max_plaintext_len = key_size; + akcipher->max_ciphertext_len = key_size; + akcipher->max_dgst_len = key_size; + akcipher->max_signature_len = key_size; +} + +static int qcrypto_gcrypt_parse_rsa_private_key( + QCryptoGcryptRSA *rsa, + const uint8_t *key, size_t keylen, Error **errp) +{ + g_autoptr(QCryptoAkCipherRSAKey) rsa_key = qcrypto_akcipher_rsakey_parse( + QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, key, keylen, errp); + gcry_mpi_t n = NULL, e = NULL, d = NULL, p = NULL, q = NULL, u = NULL; + bool compute_mul_inv = false; + int ret = -1; + gcry_error_t err; + + if (!rsa_key) { + return ret; + } + + err = gcry_mpi_scan(&n, GCRYMPI_FMT_STD, + rsa_key->n.data, rsa_key->n.len, NULL); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to parse RSA parameter n: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_mpi_scan(&e, GCRYMPI_FMT_STD, + rsa_key->e.data, rsa_key->e.len, NULL); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to parse RSA parameter e: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_mpi_scan(&d, GCRYMPI_FMT_STD, + rsa_key->d.data, rsa_key->d.len, NULL); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to parse RSA parameter d: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_mpi_scan(&p, GCRYMPI_FMT_STD, + rsa_key->p.data, rsa_key->p.len, NULL); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to parse RSA parameter p: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_mpi_scan(&q, GCRYMPI_FMT_STD, + rsa_key->q.data, rsa_key->q.len, NULL); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to parse RSA parameter q: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + if (gcry_mpi_cmp_ui(p, 0) > 0 && gcry_mpi_cmp_ui(q, 0) > 0) { + compute_mul_inv = true; + + u = gcry_mpi_new(0); + if (gcry_mpi_cmp(p, q) > 0) { + gcry_mpi_swap(p, q); + } + gcry_mpi_invm(u, p, q); + } + + if (compute_mul_inv) { + err = gcry_sexp_build(&rsa->key, NULL, + "(private-key (rsa (n %m) (e %m) (d %m) (p %m) (q %m) (u %m)))", + n, e, d, p, q, u); + } else { + err = gcry_sexp_build(&rsa->key, NULL, + "(private-key (rsa (n %m) (e %m) (d %m)))", n, e, d); + } + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to build RSA private key: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + qcrypto_gcrypt_set_rsa_size((QCryptoAkCipher *)rsa, n); + ret = 0; + +cleanup: + gcry_mpi_release(n); + gcry_mpi_release(e); + gcry_mpi_release(d); + gcry_mpi_release(p); + gcry_mpi_release(q); + gcry_mpi_release(u); + return ret; +} + +static int qcrypto_gcrypt_parse_rsa_public_key(QCryptoGcryptRSA *rsa, + const uint8_t *key, + size_t keylen, + Error **errp) +{ + + g_autoptr(QCryptoAkCipherRSAKey) rsa_key = qcrypto_akcipher_rsakey_parse( + QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, key, keylen, errp); + gcry_mpi_t n = NULL, e = NULL; + int ret = -1; + gcry_error_t err; + + if (!rsa_key) { + return ret; + } + + err = gcry_mpi_scan(&n, GCRYMPI_FMT_STD, + rsa_key->n.data, rsa_key->n.len, NULL); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to parse RSA parameter n: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_mpi_scan(&e, GCRYMPI_FMT_STD, + rsa_key->e.data, rsa_key->e.len, NULL); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to parse RSA parameter e: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_sexp_build(&rsa->key, NULL, + "(public-key (rsa (n %m) (e %m)))", n, e); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to build RSA public key: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + qcrypto_gcrypt_set_rsa_size((QCryptoAkCipher *)rsa, n); + ret = 0; + +cleanup: + gcry_mpi_release(n); + gcry_mpi_release(e); + return ret; +} + +static int qcrypto_gcrypt_rsa_encrypt(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, + Error **errp) +{ + QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher; + int ret = -1; + gcry_sexp_t data_sexp = NULL, cipher_sexp = NULL; + gcry_sexp_t cipher_sexp_item = NULL; + gcry_mpi_t cipher_mpi = NULL; + const char *result; + gcry_error_t err; + size_t actual_len; + + if (in_len > akcipher->max_plaintext_len) { + error_setg(errp, "Plaintext length is greater than key size: %d", + akcipher->max_plaintext_len); + return ret; + } + + err = gcry_sexp_build(&data_sexp, NULL, + "(data (flags %s) (value %b))", + QCryptoRSAPaddingAlgorithm_str(rsa->padding_alg), + in_len, in); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to build plaintext: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_pk_encrypt(&cipher_sexp, data_sexp, rsa->key); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to encrypt: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + /* S-expression of cipher: (enc-val (rsa (a a-mpi))) */ + cipher_sexp_item = gcry_sexp_find_token(cipher_sexp, "a", 0); + if (!cipher_sexp_item || gcry_sexp_length(cipher_sexp_item) != 2) { + error_setg(errp, "Invalid ciphertext result"); + goto cleanup; + } + + if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALG_RAW) { + cipher_mpi = gcry_sexp_nth_mpi(cipher_sexp_item, 1, GCRYMPI_FMT_USG); + if (!cipher_mpi) { + error_setg(errp, "Invalid ciphertext result"); + goto cleanup; + } + err = gcry_mpi_print(GCRYMPI_FMT_USG, out, out_len, + &actual_len, cipher_mpi); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to print MPI: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + if (actual_len > out_len) { + error_setg(errp, "Ciphertext buffer length is too small"); + goto cleanup; + } + + /* We always padding leading-zeros for RSA-RAW */ + if (actual_len < out_len) { + memmove((uint8_t *)out + (out_len - actual_len), out, actual_len); + memset(out, 0, out_len - actual_len); + } + ret = out_len; + + } else { + result = gcry_sexp_nth_data(cipher_sexp_item, 1, &actual_len); + if (!result) { + error_setg(errp, "Invalid ciphertext result"); + goto cleanup; + } + if (actual_len > out_len) { + error_setg(errp, "Ciphertext buffer length is too small"); + goto cleanup; + } + memcpy(out, result, actual_len); + ret = actual_len; + } + +cleanup: + gcry_sexp_release(data_sexp); + gcry_sexp_release(cipher_sexp); + gcry_sexp_release(cipher_sexp_item); + gcry_mpi_release(cipher_mpi); + return ret; +} + +static int qcrypto_gcrypt_rsa_decrypt(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, + Error **errp) +{ + QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher; + int ret = -1; + gcry_sexp_t data_sexp = NULL, cipher_sexp = NULL; + gcry_mpi_t data_mpi = NULL; + gcry_error_t err; + size_t actual_len; + const char *result; + + if (in_len > akcipher->max_ciphertext_len) { + error_setg(errp, "Ciphertext length is greater than key size: %d", + akcipher->max_ciphertext_len); + return ret; + } + + err = gcry_sexp_build(&cipher_sexp, NULL, + "(enc-val (flags %s) (rsa (a %b) ))", + QCryptoRSAPaddingAlgorithm_str(rsa->padding_alg), + in_len, in); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to build ciphertext: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_pk_decrypt(&data_sexp, cipher_sexp, rsa->key); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to decrypt: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + /* S-expression of plaintext: (value plaintext) */ + if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALG_RAW) { + data_mpi = gcry_sexp_nth_mpi(data_sexp, 1, GCRYMPI_FMT_USG); + if (!data_mpi) { + error_setg(errp, "Invalid plaintext result"); + goto cleanup; + } + err = gcry_mpi_print(GCRYMPI_FMT_USG, out, out_len, + &actual_len, data_mpi); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to print MPI: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + if (actual_len > out_len) { + error_setg(errp, "Plaintext buffer length is too small"); + goto cleanup; + } + /* We always padding leading-zeros for RSA-RAW */ + if (actual_len < out_len) { + memmove((uint8_t *)out + (out_len - actual_len), out, actual_len); + memset(out, 0, out_len - actual_len); + } + ret = out_len; + } else { + result = gcry_sexp_nth_data(data_sexp, 1, &actual_len); + if (!result) { + error_setg(errp, "Invalid plaintext result"); + goto cleanup; + } + if (actual_len > out_len) { + error_setg(errp, "Plaintext buffer length is too small"); + goto cleanup; + } + memcpy(out, result, actual_len); + ret = actual_len; + } + +cleanup: + gcry_sexp_release(cipher_sexp); + gcry_sexp_release(data_sexp); + gcry_mpi_release(data_mpi); + return ret; +} + +static int qcrypto_gcrypt_rsa_sign(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + void *out, size_t out_len, Error **errp) +{ + QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher; + int ret = -1; + gcry_sexp_t dgst_sexp = NULL, sig_sexp = NULL; + gcry_sexp_t sig_sexp_item = NULL; + const char *result; + gcry_error_t err; + size_t actual_len; + + if (in_len > akcipher->max_dgst_len) { + error_setg(errp, "Data length is greater than key size: %d", + akcipher->max_dgst_len); + return ret; + } + + if (rsa->padding_alg != QCRYPTO_RSA_PADDING_ALG_PKCS1) { + error_setg(errp, "Invalid padding %u", rsa->padding_alg); + return ret; + } + + err = gcry_sexp_build(&dgst_sexp, NULL, + "(data (flags pkcs1) (hash %s %b))", + QCryptoHashAlgorithm_str(rsa->hash_alg), + in_len, in); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to build dgst: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_pk_sign(&sig_sexp, dgst_sexp, rsa->key); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to make signature: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + /* S-expression of signature: (sig-val (rsa (s s-mpi))) */ + sig_sexp_item = gcry_sexp_find_token(sig_sexp, "s", 0); + if (!sig_sexp_item || gcry_sexp_length(sig_sexp_item) != 2) { + error_setg(errp, "Invalid signature result"); + goto cleanup; + } + + result = gcry_sexp_nth_data(sig_sexp_item, 1, &actual_len); + if (!result) { + error_setg(errp, "Invalid signature result"); + goto cleanup; + } + + if (actual_len > out_len) { + error_setg(errp, "Signature buffer length is too small"); + goto cleanup; + } + memcpy(out, result, actual_len); + ret = actual_len; + +cleanup: + gcry_sexp_release(dgst_sexp); + gcry_sexp_release(sig_sexp); + gcry_sexp_release(sig_sexp_item); + + return ret; +} + +static int qcrypto_gcrypt_rsa_verify(QCryptoAkCipher *akcipher, + const void *in, size_t in_len, + const void *in2, size_t in2_len, + Error **errp) +{ + QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher; + int ret = -1; + gcry_sexp_t sig_sexp = NULL, dgst_sexp = NULL; + gcry_error_t err; + + if (in_len > akcipher->max_signature_len) { + error_setg(errp, "Signature length is greater than key size: %d", + akcipher->max_signature_len); + return ret; + } + + if (in2_len > akcipher->max_dgst_len) { + error_setg(errp, "Data length is greater than key size: %d", + akcipher->max_dgst_len); + return ret; + } + + if (rsa->padding_alg != QCRYPTO_RSA_PADDING_ALG_PKCS1) { + error_setg(errp, "Invalid padding %u", rsa->padding_alg); + return ret; + } + + err = gcry_sexp_build(&sig_sexp, NULL, + "(sig-val (rsa (s %b)))", in_len, in); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to build signature: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_sexp_build(&dgst_sexp, NULL, + "(data (flags pkcs1) (hash %s %b))", + QCryptoHashAlgorithm_str(rsa->hash_alg), + in2_len, in2); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to build dgst: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + + err = gcry_pk_verify(sig_sexp, dgst_sexp, rsa->key); + if (gcry_err_code(err) != 0) { + error_setg(errp, "Failed to verify signature: %s/%s", + gcry_strsource(err), gcry_strerror(err)); + goto cleanup; + } + ret = 0; + +cleanup: + gcry_sexp_release(dgst_sexp); + gcry_sexp_release(sig_sexp); + + return ret; +} + +QCryptoAkCipherDriver gcrypt_rsa = { + .encrypt = qcrypto_gcrypt_rsa_encrypt, + .decrypt = qcrypto_gcrypt_rsa_decrypt, + .sign = qcrypto_gcrypt_rsa_sign, + .verify = qcrypto_gcrypt_rsa_verify, + .free = qcrypto_gcrypt_rsa_free, +}; + +static QCryptoGcryptRSA *qcrypto_gcrypt_rsa_new( + const QCryptoAkCipherOptionsRSA *opt, + QCryptoAkCipherKeyType type, + const uint8_t *key, size_t keylen, + Error **errp) +{ + QCryptoGcryptRSA *rsa = g_new0(QCryptoGcryptRSA, 1); + rsa->padding_alg = opt->padding_alg; + rsa->hash_alg = opt->hash_alg; + rsa->akcipher.driver = &gcrypt_rsa; + + switch (type) { + case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE: + if (qcrypto_gcrypt_parse_rsa_private_key(rsa, key, keylen, errp) != 0) { + goto error; + } + break; + + case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC: + if (qcrypto_gcrypt_parse_rsa_public_key(rsa, key, keylen, errp) != 0) { + goto error; + } + break; + + default: + error_setg(errp, "Unknown akcipher key type %d", type); + goto error; + } + + return rsa; + +error: + qcrypto_gcrypt_rsa_free((QCryptoAkCipher *)rsa); + return NULL; +} + + +bool qcrypto_akcipher_supports(QCryptoAkCipherOptions *opts) +{ + switch (opts->alg) { + case QCRYPTO_AKCIPHER_ALG_RSA: + switch (opts->u.rsa.padding_alg) { + case QCRYPTO_RSA_PADDING_ALG_RAW: + return true; + + case QCRYPTO_RSA_PADDING_ALG_PKCS1: + switch (opts->u.rsa.hash_alg) { + case QCRYPTO_HASH_ALG_MD5: + case QCRYPTO_HASH_ALG_SHA1: + case QCRYPTO_HASH_ALG_SHA256: + case QCRYPTO_HASH_ALG_SHA512: + return true; + + default: + return false; + } + + default: + return false; + } + + default: + return true; + } +} diff --git a/crypto/akcipher.c b/crypto/akcipher.c index f287083f92..ad88379c1e 100644 --- a/crypto/akcipher.c +++ b/crypto/akcipher.c @@ -23,7 +23,9 @@ #include "crypto/akcipher.h" #include "akcipherpriv.h" -#if defined(CONFIG_NETTLE) && defined(CONFIG_HOGWEED) +#if defined(CONFIG_GCRYPT) +#include "akcipher-gcrypt.c.inc" +#elif defined(CONFIG_NETTLE) && defined(CONFIG_HOGWEED) #include "akcipher-nettle.c.inc" #else QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts, From 689309c4ac40f01b93f29d66282d044c10d8e2e1 Mon Sep 17 00:00:00 2001 From: Lei He Date: Wed, 25 May 2022 17:01:16 +0800 Subject: [PATCH 527/935] test/crypto: Add test suite for crypto akcipher MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add unit test and benchmark test for crypto akcipher. Signed-off-by: lei he Signed-off-by: zhenwei pi Signed-off-by: Daniel P. Berrangé --- crypto/akcipher-nettle.c.inc | 14 +- tests/bench/benchmark-crypto-akcipher.c | 137 +++++ tests/bench/meson.build | 1 + tests/bench/test_akcipher_keys.inc | 537 ++++++++++++++++++ tests/unit/meson.build | 1 + tests/unit/test-crypto-akcipher.c | 711 ++++++++++++++++++++++++ 6 files changed, 1394 insertions(+), 7 deletions(-) create mode 100644 tests/bench/benchmark-crypto-akcipher.c create mode 100644 tests/bench/test_akcipher_keys.inc create mode 100644 tests/unit/test-crypto-akcipher.c diff --git a/crypto/akcipher-nettle.c.inc b/crypto/akcipher-nettle.c.inc index a7c0c6a1ee..02699e6e6d 100644 --- a/crypto/akcipher-nettle.c.inc +++ b/crypto/akcipher-nettle.c.inc @@ -171,14 +171,14 @@ static int qcrypto_nettle_rsa_encrypt(QCryptoAkCipher *akcipher, int ret = -1; if (data_len > rsa->pub.size) { - error_setg(errp, "Plaintext length %zu is greater than key size: %zu" + error_setg(errp, "Plaintext length %zu is greater than key size: %zu", data_len, rsa->pub.size); return ret; } if (enc_len < rsa->pub.size) { error_setg(errp, "Ciphertext buffer length %zu is less than " - "key size: %zu", rsa->pub.size); + "key size: %zu", enc_len, rsa->pub.size); return ret; } @@ -218,7 +218,7 @@ static int qcrypto_nettle_rsa_decrypt(QCryptoAkCipher *akcipher, if (enc_len > rsa->priv.size) { error_setg(errp, "Ciphertext length %zu is greater than key size: %zu", - rsa->priv.size); + enc_len, rsa->priv.size); return ret; } @@ -264,13 +264,13 @@ static int qcrypto_nettle_rsa_sign(QCryptoAkCipher *akcipher, if (data_len > rsa->priv.size) { error_setg(errp, "Data length %zu is greater than key size: %zu", - rsa->priv.size); + data_len, rsa->priv.size); return ret; } if (sig_len < rsa->priv.size) { error_setg(errp, "Signature buffer length %zu is less than " - "key size: %zu", rsa->priv.size); + "key size: %zu", sig_len, rsa->priv.size); return ret; } @@ -330,12 +330,12 @@ static int qcrypto_nettle_rsa_verify(QCryptoAkCipher *akcipher, } if (data_len > rsa->pub.size) { error_setg(errp, "Data length %zu is greater than key size: %zu", - rsa->pub.size); + data_len, rsa->pub.size); return ret; } if (sig_len < rsa->pub.size) { error_setg(errp, "Signature length %zu is greater than key size: %zu", - rsa->pub.size); + sig_len, rsa->pub.size); return ret; } diff --git a/tests/bench/benchmark-crypto-akcipher.c b/tests/bench/benchmark-crypto-akcipher.c new file mode 100644 index 0000000000..15e69557ed --- /dev/null +++ b/tests/bench/benchmark-crypto-akcipher.c @@ -0,0 +1,137 @@ +/* + * QEMU Crypto akcipher speed benchmark + * + * Copyright (c) 2022 Bytedance + * + * Authors: + * lei he + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "qemu/osdep.h" +#include "crypto/init.h" +#include "crypto/akcipher.h" +#include "standard-headers/linux/virtio_crypto.h" + +#include "test_akcipher_keys.inc" + +static QCryptoAkCipher *create_rsa_akcipher(const uint8_t *priv_key, + size_t keylen, + QCryptoRSAPaddingAlgorithm padding, + QCryptoHashAlgorithm hash) +{ + QCryptoAkCipherOptions opt; + QCryptoAkCipher *rsa; + + opt.alg = QCRYPTO_AKCIPHER_ALG_RSA; + opt.u.rsa.padding_alg = padding; + opt.u.rsa.hash_alg = hash; + rsa = qcrypto_akcipher_new(&opt, QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, + priv_key, keylen, &error_abort); + return rsa; +} + +static void test_rsa_speed(const uint8_t *priv_key, size_t keylen, + size_t key_size) +{ +#define BYTE 8 +#define SHA1_DGST_LEN 20 +#define SIGN_TIMES 10000 +#define VERIFY_TIMES 100000 +#define PADDING QCRYPTO_RSA_PADDING_ALG_PKCS1 +#define HASH QCRYPTO_HASH_ALG_SHA1 + + g_autoptr(QCryptoAkCipher) rsa = + create_rsa_akcipher(priv_key, keylen, PADDING, HASH); + g_autofree uint8_t *dgst = NULL; + g_autofree uint8_t *signature = NULL; + size_t count; + + dgst = g_new0(uint8_t, SHA1_DGST_LEN); + memset(dgst, g_test_rand_int(), SHA1_DGST_LEN); + signature = g_new0(uint8_t, key_size / BYTE); + + g_test_message("benchmark rsa%zu (%s-%s) sign...", key_size, + QCryptoRSAPaddingAlgorithm_str(PADDING), + QCryptoHashAlgorithm_str(HASH)); + g_test_timer_start(); + for (count = 0; count < SIGN_TIMES; ++count) { + g_assert(qcrypto_akcipher_sign(rsa, dgst, SHA1_DGST_LEN, + signature, key_size / BYTE, + &error_abort) > 0); + } + g_test_timer_elapsed(); + g_test_message("rsa%zu (%s-%s) sign %zu times in %.2f seconds," + " %.2f times/sec ", + key_size, QCryptoRSAPaddingAlgorithm_str(PADDING), + QCryptoHashAlgorithm_str(HASH), + count, g_test_timer_last(), + (double)count / g_test_timer_last()); + + g_test_message("benchmark rsa%zu (%s-%s) verification...", key_size, + QCryptoRSAPaddingAlgorithm_str(PADDING), + QCryptoHashAlgorithm_str(HASH)); + g_test_timer_start(); + for (count = 0; count < VERIFY_TIMES; ++count) { + g_assert(qcrypto_akcipher_verify(rsa, signature, key_size / BYTE, + dgst, SHA1_DGST_LEN, + &error_abort) == 0); + } + g_test_timer_elapsed(); + g_test_message("rsa%zu (%s-%s) verify %zu times in %.2f seconds," + " %.2f times/sec ", + key_size, QCryptoRSAPaddingAlgorithm_str(PADDING), + QCryptoHashAlgorithm_str(HASH), + count, g_test_timer_last(), + (double)count / g_test_timer_last()); +} + +static void test_rsa_1024_speed(const void *opaque) +{ + size_t key_size = (size_t)opaque; + test_rsa_speed(rsa1024_priv_key, sizeof(rsa1024_priv_key), key_size); +} + +static void test_rsa_2048_speed(const void *opaque) +{ + size_t key_size = (size_t)opaque; + test_rsa_speed(rsa2048_priv_key, sizeof(rsa2048_priv_key), key_size); +} + +static void test_rsa_4096_speed(const void *opaque) +{ + size_t key_size = (size_t)opaque; + test_rsa_speed(rsa4096_priv_key, sizeof(rsa4096_priv_key), key_size); +} + +int main(int argc, char **argv) +{ + char *alg = NULL; + char *size = NULL; + g_test_init(&argc, &argv, NULL); + g_assert(qcrypto_init(NULL) == 0); + +#define ADD_TEST(asym_alg, keysize) \ + if ((!alg || g_str_equal(alg, #asym_alg)) && \ + (!size || g_str_equal(size, #keysize))) \ + g_test_add_data_func( \ + "/crypto/akcipher/" #asym_alg "-" #keysize, \ + (void *)keysize, \ + test_ ## asym_alg ## _ ## keysize ## _speed) + + if (argc >= 2) { + alg = argv[1]; + } + if (argc >= 3) { + size = argv[2]; + } + + ADD_TEST(rsa, 1024); + ADD_TEST(rsa, 2048); + ADD_TEST(rsa, 4096); + + return g_test_run(); +} diff --git a/tests/bench/meson.build b/tests/bench/meson.build index 00b3c209dc..279a8fcc33 100644 --- a/tests/bench/meson.build +++ b/tests/bench/meson.build @@ -20,6 +20,7 @@ if have_block 'benchmark-crypto-hash': [crypto], 'benchmark-crypto-hmac': [crypto], 'benchmark-crypto-cipher': [crypto], + 'benchmark-crypto-akcipher': [crypto], } endif diff --git a/tests/bench/test_akcipher_keys.inc b/tests/bench/test_akcipher_keys.inc new file mode 100644 index 0000000000..df3eccb45e --- /dev/null +++ b/tests/bench/test_akcipher_keys.inc @@ -0,0 +1,537 @@ +/* + * Copyright (c) 2022 Bytedance, and/or its affiliates + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + * Author: lei he + */ + +/* RSA test keys, generated by OpenSSL */ +static const uint8_t rsa1024_priv_key[] = { + 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, + 0x81, 0x81, 0x00, 0xe6, 0x4d, 0x76, 0x4f, 0xb2, + 0x97, 0x09, 0xad, 0x9d, 0x17, 0x33, 0xf2, 0x30, + 0x42, 0x83, 0xa9, 0xcb, 0x49, 0xa4, 0x2e, 0x59, + 0x5e, 0x75, 0x51, 0xd1, 0xac, 0xc8, 0x86, 0x3e, + 0xdb, 0x72, 0x2e, 0xb2, 0xf7, 0xc3, 0x5b, 0xc7, + 0xea, 0xed, 0x30, 0xd1, 0xf7, 0x37, 0xee, 0x9d, + 0x36, 0x59, 0x6f, 0xf8, 0xce, 0xc0, 0x5c, 0x82, + 0x80, 0x37, 0x83, 0xd7, 0x45, 0x6a, 0xe9, 0xea, + 0xc5, 0x3a, 0x59, 0x6b, 0x34, 0x31, 0x44, 0x00, + 0x74, 0xa7, 0x29, 0xab, 0x79, 0x4a, 0xbd, 0xe8, + 0x25, 0x35, 0x01, 0x11, 0x40, 0xbf, 0x31, 0xbd, + 0xd3, 0xe0, 0x68, 0x1e, 0xd5, 0x5b, 0x2f, 0xe9, + 0x20, 0xf2, 0x9f, 0x46, 0x35, 0x30, 0xa8, 0xf1, + 0xfe, 0xef, 0xd8, 0x76, 0x23, 0x46, 0x34, 0x70, + 0xa1, 0xce, 0xc6, 0x65, 0x6d, 0xb0, 0x94, 0x7e, + 0xe5, 0x92, 0x45, 0x7b, 0xaa, 0xbb, 0x95, 0x97, + 0x77, 0xcd, 0xd3, 0x02, 0x03, 0x01, 0x00, 0x01, + 0x02, 0x81, 0x80, 0x30, 0x6a, 0xc4, 0x9e, 0xc8, + 0xba, 0xfc, 0x2b, 0xe5, 0xc4, 0xc5, 0x04, 0xfb, + 0xa4, 0x60, 0x2d, 0xc8, 0x31, 0x39, 0x35, 0x0d, + 0x50, 0xd0, 0x75, 0x5d, 0x11, 0x68, 0x2e, 0xe0, + 0xf4, 0x1d, 0xb3, 0x37, 0xa8, 0xe3, 0x07, 0x5e, + 0xa6, 0x43, 0x2b, 0x6a, 0x59, 0x01, 0x07, 0x47, + 0x41, 0xef, 0xd7, 0x9c, 0x85, 0x4a, 0xe7, 0xa7, + 0xff, 0xf0, 0xab, 0xe5, 0x0c, 0x11, 0x08, 0x10, + 0x75, 0x5a, 0x68, 0xa0, 0x08, 0x03, 0xc9, 0x40, + 0x79, 0x67, 0x1d, 0x65, 0x89, 0x2d, 0x08, 0xf9, + 0xb5, 0x1b, 0x7d, 0xd2, 0x41, 0x3b, 0x33, 0xf2, + 0x47, 0x2f, 0x9c, 0x0b, 0xd5, 0xaf, 0xcb, 0xdb, + 0xbb, 0x37, 0x63, 0x03, 0xf8, 0xe7, 0x2e, 0xc7, + 0x3c, 0x86, 0x9f, 0xc2, 0x9b, 0xb4, 0x70, 0x6a, + 0x4d, 0x7c, 0xe4, 0x1b, 0x3a, 0xa9, 0xae, 0xd7, + 0xce, 0x7f, 0x56, 0xc2, 0x73, 0x5e, 0x58, 0x63, + 0xd5, 0x86, 0x41, 0x02, 0x41, 0x00, 0xf6, 0x56, + 0x69, 0xec, 0xef, 0x65, 0x95, 0xdc, 0x25, 0x47, + 0xe0, 0x6f, 0xb0, 0x4f, 0x79, 0x77, 0x0a, 0x5e, + 0x46, 0xcb, 0xbd, 0x0b, 0x71, 0x51, 0x2a, 0xa4, + 0x65, 0x29, 0x18, 0xc6, 0x30, 0xa0, 0x95, 0x4c, + 0x4b, 0xbe, 0x8c, 0x40, 0xe3, 0x9c, 0x23, 0x02, + 0x14, 0x43, 0xe9, 0x64, 0xea, 0xe3, 0xa8, 0xe2, + 0x1a, 0xd5, 0xf9, 0x5c, 0xe0, 0x36, 0x2c, 0x97, + 0xda, 0xd5, 0xc7, 0x46, 0xce, 0x11, 0x02, 0x41, + 0x00, 0xef, 0x56, 0x08, 0xb8, 0x29, 0xa5, 0xa6, + 0x7c, 0xf7, 0x5f, 0xb4, 0xf5, 0x63, 0xe7, 0xeb, + 0x45, 0xfd, 0x89, 0xaa, 0x94, 0xa6, 0x3d, 0x0b, + 0xd9, 0x04, 0x6f, 0x78, 0xe0, 0xbb, 0xa2, 0xd4, + 0x29, 0x83, 0x17, 0x95, 0x6f, 0x50, 0x3d, 0x40, + 0x5d, 0xe5, 0x24, 0xda, 0xc2, 0x23, 0x50, 0x86, + 0xa8, 0x34, 0xc8, 0x6f, 0xec, 0x7f, 0xb6, 0x45, + 0x3a, 0xdd, 0x78, 0x9b, 0xee, 0xa1, 0xe4, 0x09, + 0xa3, 0x02, 0x40, 0x5c, 0xd6, 0x66, 0x67, 0x58, + 0x35, 0xc5, 0xcb, 0xc8, 0xf5, 0x14, 0xbd, 0xa3, + 0x09, 0xe0, 0xb2, 0x1f, 0x63, 0x36, 0x75, 0x34, + 0x52, 0xea, 0xaa, 0xf7, 0x52, 0x2b, 0x99, 0xd8, + 0x6f, 0x61, 0x06, 0x34, 0x1e, 0x23, 0xf1, 0xb5, + 0x34, 0x03, 0x53, 0xe5, 0xd1, 0xb3, 0xc7, 0x80, + 0x5f, 0x7b, 0x32, 0xbf, 0x84, 0x2f, 0x2e, 0xf3, + 0x22, 0xb0, 0x91, 0x5a, 0x2f, 0x04, 0xd7, 0x4a, + 0x9a, 0x01, 0xb1, 0x02, 0x40, 0x34, 0x0b, 0x26, + 0x4c, 0x3d, 0xaa, 0x2a, 0xc0, 0xe3, 0xdd, 0xe8, + 0xf0, 0xaf, 0x6f, 0xe0, 0x06, 0x51, 0x32, 0x9d, + 0x68, 0x43, 0x99, 0xe4, 0xb8, 0xa5, 0x31, 0x44, + 0x3c, 0xc2, 0x30, 0x8f, 0x28, 0x13, 0xbc, 0x8e, + 0x1f, 0x2d, 0x78, 0x94, 0x45, 0x96, 0xad, 0x63, + 0xf0, 0x71, 0x53, 0x72, 0x64, 0xa3, 0x4d, 0xae, + 0xa0, 0xe3, 0xc8, 0x93, 0xd7, 0x50, 0x0f, 0x89, + 0x00, 0xe4, 0x2d, 0x3d, 0x37, 0x02, 0x41, 0x00, + 0xbe, 0xa6, 0x08, 0xe0, 0xc8, 0x15, 0x2a, 0x47, + 0xcb, 0xd5, 0xec, 0x93, 0xd3, 0xaa, 0x12, 0x82, + 0xaf, 0xac, 0x51, 0x5a, 0x5b, 0xa7, 0x93, 0x4b, + 0xb9, 0xab, 0x00, 0xfa, 0x5a, 0xea, 0x34, 0xe4, + 0x80, 0xf1, 0x44, 0x6a, 0x65, 0xe4, 0x33, 0x99, + 0xfb, 0x54, 0xd7, 0x89, 0x5a, 0x1b, 0xd6, 0x2b, + 0xcc, 0x6e, 0x4b, 0x19, 0xa0, 0x6d, 0x93, 0x9f, + 0xc3, 0x91, 0x7a, 0xa5, 0xd8, 0x59, 0x0e, 0x9e, +}; + +static const uint8_t rsa2048_priv_key[] = { + 0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, + 0x82, 0x01, 0x01, 0x00, 0xbd, 0x9c, 0x83, 0x6b, + 0x0e, 0x8e, 0xcf, 0xfa, 0xaa, 0x4f, 0x6a, 0xf4, + 0xe3, 0x52, 0x0f, 0xa5, 0xd0, 0xbe, 0x5e, 0x7f, + 0x08, 0x24, 0xba, 0x87, 0x46, 0xfb, 0x28, 0x93, + 0xe5, 0xe5, 0x81, 0x42, 0xc0, 0xf9, 0x17, 0xc7, + 0x81, 0x01, 0xf4, 0x18, 0x6a, 0x17, 0xf5, 0x57, + 0x20, 0x37, 0xcf, 0xf9, 0x74, 0x5e, 0xe1, 0x48, + 0x6a, 0x71, 0x0a, 0x0f, 0x79, 0x72, 0x2b, 0x46, + 0x10, 0x53, 0xdc, 0x14, 0x43, 0xbd, 0xbc, 0x6d, + 0x15, 0x6f, 0x15, 0x4e, 0xf0, 0x0d, 0x89, 0x39, + 0x02, 0xc3, 0x68, 0x5c, 0xa8, 0xfc, 0xed, 0x64, + 0x9d, 0x98, 0xb7, 0xcd, 0x83, 0x66, 0x93, 0xc3, + 0xd9, 0x57, 0xa0, 0x21, 0x93, 0xad, 0x5c, 0x75, + 0x69, 0x88, 0x9e, 0x81, 0xdc, 0x7f, 0x1d, 0xd5, + 0xbd, 0x1c, 0xc1, 0x30, 0x56, 0xa5, 0xda, 0x99, + 0x46, 0xa6, 0x6d, 0x0e, 0x6f, 0x5e, 0x51, 0x34, + 0x49, 0x73, 0xc3, 0x67, 0x49, 0x7e, 0x21, 0x2a, + 0x20, 0xa7, 0x2b, 0x92, 0x73, 0x1d, 0xa5, 0x25, + 0x2a, 0xd0, 0x3a, 0x89, 0x75, 0xb2, 0xbb, 0x19, + 0x37, 0x78, 0x48, 0xd2, 0xf2, 0x2a, 0x6d, 0x9e, + 0xc6, 0x26, 0xca, 0x46, 0x8c, 0xf1, 0x42, 0x2a, + 0x31, 0xb2, 0xfc, 0xe7, 0x55, 0x51, 0xff, 0x07, + 0x13, 0x5b, 0x36, 0x59, 0x2b, 0x43, 0x30, 0x4b, + 0x05, 0x5c, 0xd2, 0x45, 0xa0, 0xa0, 0x7c, 0x17, + 0x5b, 0x07, 0xbb, 0x5d, 0x83, 0x80, 0x92, 0x6d, + 0x87, 0x1a, 0x43, 0xac, 0xc7, 0x6b, 0x8d, 0x11, + 0x60, 0x27, 0xd2, 0xdf, 0xdb, 0x71, 0x02, 0x55, + 0x6e, 0xb5, 0xca, 0x4d, 0xda, 0x59, 0x0d, 0xb8, + 0x8c, 0xcd, 0xd3, 0x0e, 0x55, 0xa0, 0xa4, 0x8d, + 0xa0, 0x14, 0x10, 0x48, 0x42, 0x35, 0x56, 0x08, + 0xf7, 0x29, 0x5f, 0xa2, 0xea, 0xa4, 0x5e, 0x8e, + 0x99, 0x56, 0xaa, 0x5a, 0x8c, 0x23, 0x8f, 0x35, + 0x22, 0x8a, 0xff, 0xed, 0x02, 0x03, 0x01, 0x00, + 0x01, 0x02, 0x82, 0x01, 0x00, 0x4e, 0x4a, 0xf3, + 0x44, 0xe0, 0x64, 0xfd, 0xe1, 0xde, 0x33, 0x1e, + 0xd1, 0xf1, 0x8f, 0x6f, 0xe0, 0xa2, 0xfa, 0x08, + 0x60, 0xe1, 0xc6, 0xf0, 0xb2, 0x6d, 0x0f, 0xc6, + 0x28, 0x93, 0xb4, 0x19, 0x94, 0xab, 0xc3, 0xef, + 0x1a, 0xb4, 0xdd, 0x4e, 0xa2, 0x4a, 0x24, 0x8c, + 0x6c, 0xa6, 0x64, 0x05, 0x5f, 0x56, 0xba, 0xda, + 0xc1, 0x21, 0x1a, 0x7d, 0xf1, 0xf7, 0xce, 0xb9, + 0xa9, 0x9b, 0x92, 0x54, 0xfc, 0x95, 0x20, 0x22, + 0x4e, 0xd4, 0x9b, 0xe2, 0xab, 0x8e, 0x99, 0xb8, + 0x40, 0xaf, 0x30, 0x6a, 0xc6, 0x60, 0x0c, 0xd8, + 0x25, 0x44, 0xa1, 0xcb, 0xbb, 0x73, 0x77, 0x86, + 0xaa, 0x46, 0xf3, 0x54, 0xae, 0xa8, 0xa0, 0xdb, + 0xdd, 0xab, 0x6e, 0xfb, 0x2c, 0x5a, 0x14, 0xaf, + 0x08, 0x13, 0xa7, 0x6c, 0xe9, 0xfd, 0xcd, 0x4c, + 0x1f, 0x20, 0x3a, 0x16, 0x2b, 0xf0, 0xb6, 0x7c, + 0x47, 0x5f, 0xd1, 0x0a, 0x2c, 0xc4, 0xa5, 0x68, + 0xd0, 0x43, 0x75, 0x6b, 0x65, 0xaa, 0x32, 0xc6, + 0x99, 0x06, 0xcb, 0x8f, 0xe6, 0x8d, 0xce, 0xbf, + 0x4d, 0x0d, 0x7b, 0x22, 0x2a, 0x8a, 0xcb, 0x7d, + 0x7f, 0x16, 0x48, 0x85, 0xf1, 0x86, 0xcb, 0x54, + 0xb9, 0x39, 0xd4, 0xbc, 0xe3, 0x2d, 0x27, 0x59, + 0xf6, 0x81, 0x5e, 0x94, 0x45, 0xdf, 0xb9, 0x22, + 0xaf, 0x64, 0x0d, 0x14, 0xec, 0x8c, 0xeb, 0x71, + 0xac, 0xee, 0x09, 0x4c, 0xbf, 0x34, 0xf9, 0xf4, + 0x66, 0x77, 0x36, 0x3b, 0x41, 0x74, 0x01, 0x4f, + 0xfc, 0x56, 0x83, 0xba, 0x14, 0xb0, 0x2f, 0xdd, + 0x4d, 0xb9, 0x3f, 0xdf, 0x71, 0xbe, 0x7b, 0xba, + 0x66, 0xc8, 0xc5, 0x42, 0xc9, 0xba, 0x18, 0x63, + 0x45, 0x07, 0x2f, 0x84, 0x3e, 0xc3, 0xfb, 0x47, + 0xda, 0xd4, 0x1d, 0x0e, 0x9d, 0x96, 0xc0, 0xea, + 0xee, 0x45, 0x2f, 0xe1, 0x62, 0x23, 0xee, 0xef, + 0x3d, 0x5e, 0x55, 0xa1, 0x0d, 0x02, 0x81, 0x81, + 0x00, 0xeb, 0x76, 0x88, 0xd3, 0xae, 0x3f, 0x1d, + 0xf2, 0x49, 0xe0, 0x37, 0x49, 0x83, 0x82, 0x6c, + 0xf7, 0xf1, 0x17, 0x30, 0x75, 0x2e, 0x89, 0x06, + 0x88, 0x56, 0x32, 0xf6, 0xfa, 0x58, 0xcb, 0x3c, + 0x98, 0x67, 0xc3, 0xde, 0x10, 0x82, 0xe5, 0xfa, + 0xfa, 0x52, 0x47, 0x8d, 0xd7, 0x00, 0xc6, 0xcb, + 0xf7, 0xf6, 0x57, 0x9b, 0x6e, 0x0c, 0xac, 0xe8, + 0x3b, 0xd1, 0xde, 0xb5, 0x34, 0xaf, 0x8b, 0x2a, + 0xb0, 0x2d, 0x01, 0xeb, 0x7c, 0xa0, 0x42, 0x26, + 0xbb, 0x2b, 0x43, 0x0e, 0x1d, 0xe2, 0x4e, 0xc9, + 0xc1, 0x0a, 0x67, 0x1d, 0xfc, 0x83, 0x25, 0xce, + 0xb2, 0x18, 0xd9, 0x0d, 0x70, 0xf5, 0xa3, 0x5a, + 0x9c, 0x99, 0xdd, 0x47, 0xa1, 0x57, 0xe7, 0x20, + 0xde, 0xa1, 0x29, 0x8d, 0x96, 0x62, 0xf9, 0x26, + 0x95, 0x51, 0xa6, 0xe7, 0x09, 0x8b, 0xba, 0x16, + 0x8b, 0x19, 0x5b, 0xf9, 0x27, 0x0d, 0xc5, 0xd6, + 0x5f, 0x02, 0x81, 0x81, 0x00, 0xce, 0x26, 0x31, + 0xb5, 0x43, 0x53, 0x95, 0x39, 0xdd, 0x01, 0x98, + 0x8b, 0x3d, 0x27, 0xeb, 0x0b, 0x87, 0x1c, 0x95, + 0xfc, 0x3e, 0x36, 0x51, 0x31, 0xb5, 0xea, 0x59, + 0x56, 0xc0, 0x97, 0x62, 0xf0, 0x63, 0x2b, 0xb6, + 0x30, 0x9b, 0xdf, 0x19, 0x10, 0xe9, 0xa0, 0x3d, + 0xea, 0x54, 0x5a, 0xe6, 0xc6, 0x9e, 0x7e, 0xb5, + 0xf0, 0xb0, 0x54, 0xef, 0xc3, 0xe1, 0x47, 0xa6, + 0x95, 0xc7, 0xe4, 0xa3, 0x4a, 0x30, 0x68, 0x24, + 0x98, 0x7d, 0xc1, 0x34, 0xa9, 0xcb, 0xbc, 0x3c, + 0x08, 0x9c, 0x7d, 0x0c, 0xa2, 0xb7, 0x60, 0xaa, + 0x38, 0x08, 0x16, 0xa6, 0x7f, 0xdb, 0xd2, 0xb1, + 0x67, 0xe7, 0x93, 0x8e, 0xbb, 0x7e, 0xb9, 0xb5, + 0xd0, 0xd0, 0x9f, 0x7b, 0xcc, 0x46, 0xe6, 0x74, + 0x78, 0x1a, 0x96, 0xd6, 0xd7, 0x74, 0x34, 0x54, + 0x3b, 0x54, 0x55, 0x7f, 0x89, 0x81, 0xbc, 0x40, + 0x55, 0x87, 0x24, 0x95, 0x33, 0x02, 0x81, 0x81, + 0x00, 0xb0, 0x18, 0x5d, 0x2a, 0x1a, 0x95, 0x9f, + 0x9a, 0xd5, 0x3f, 0x37, 0x79, 0xe6, 0x3d, 0x83, + 0xab, 0x46, 0x86, 0x36, 0x3a, 0x5d, 0x0c, 0x23, + 0x73, 0x91, 0x2b, 0xda, 0x63, 0xce, 0x46, 0x68, + 0xd1, 0xfe, 0x40, 0x90, 0xf2, 0x3e, 0x43, 0x2b, + 0x19, 0x4c, 0xb1, 0xb0, 0xd5, 0x8c, 0x02, 0x21, + 0x07, 0x18, 0x17, 0xda, 0xe9, 0x49, 0xd7, 0x82, + 0x73, 0x42, 0x78, 0xd1, 0x82, 0x4e, 0x8a, 0xc0, + 0xe9, 0x33, 0x2f, 0xcd, 0x62, 0xce, 0x23, 0xca, + 0xfd, 0x8d, 0xd4, 0x3f, 0x59, 0x80, 0x27, 0xb6, + 0x61, 0x85, 0x9b, 0x2a, 0xe4, 0xef, 0x5c, 0x36, + 0x22, 0x21, 0xcd, 0x2a, 0x6d, 0x41, 0x77, 0xe2, + 0xcb, 0x5d, 0x93, 0x0d, 0x00, 0x10, 0x52, 0x8d, + 0xd5, 0x92, 0x28, 0x16, 0x78, 0xd3, 0x1a, 0x4c, + 0x8d, 0xbd, 0x9c, 0x1a, 0x0b, 0x9c, 0x91, 0x16, + 0x4c, 0xff, 0x31, 0x36, 0xbb, 0xcb, 0x64, 0x1a, + 0xf7, 0x02, 0x81, 0x80, 0x32, 0x65, 0x09, 0xdf, + 0xca, 0xee, 0xa2, 0xdb, 0x3b, 0x58, 0xc9, 0x86, + 0xb8, 0x53, 0x8a, 0xd5, 0x0d, 0x99, 0x82, 0x5c, + 0xe0, 0x84, 0x7c, 0xc2, 0xcf, 0x3a, 0xd3, 0xce, + 0x2e, 0x54, 0x93, 0xbe, 0x3a, 0x30, 0x14, 0x60, + 0xbb, 0xaa, 0x05, 0x41, 0xaa, 0x2b, 0x1f, 0x17, + 0xaa, 0xb9, 0x72, 0x12, 0xf9, 0xe9, 0xf5, 0xe6, + 0x39, 0xe4, 0xf9, 0x9c, 0x03, 0xf5, 0x75, 0x16, + 0xc6, 0x7f, 0xf1, 0x1f, 0x10, 0xc8, 0x54, 0xb1, + 0xe6, 0x84, 0x15, 0xb0, 0xb0, 0x7a, 0x7a, 0x9e, + 0x8c, 0x4a, 0xd1, 0x8c, 0xf1, 0x91, 0x32, 0xeb, + 0x71, 0xa6, 0xbf, 0xdb, 0x1f, 0xcc, 0xd8, 0xcb, + 0x92, 0xc3, 0xf2, 0xaf, 0x89, 0x22, 0x32, 0xfd, + 0x32, 0x12, 0xda, 0xbb, 0xac, 0x55, 0x68, 0x01, + 0x78, 0x56, 0x89, 0x7c, 0xb0, 0x0e, 0x9e, 0xcc, + 0xc6, 0x28, 0x04, 0x7e, 0x83, 0xf5, 0x96, 0x30, + 0x92, 0x51, 0xf2, 0x1b, 0x02, 0x81, 0x81, 0x00, + 0x83, 0x6d, 0xd1, 0x98, 0x90, 0x41, 0x8c, 0xa7, + 0x92, 0x83, 0xac, 0x89, 0x05, 0x0c, 0x79, 0x67, + 0x90, 0xb6, 0xa1, 0xf3, 0x2f, 0xca, 0xf0, 0x15, + 0xe0, 0x30, 0x58, 0xe9, 0x4f, 0xcb, 0x4c, 0x56, + 0x56, 0x56, 0x14, 0x3f, 0x1b, 0x79, 0xb6, 0xef, + 0x57, 0x4b, 0x28, 0xbd, 0xb0, 0xe6, 0x0c, 0x49, + 0x4b, 0xbe, 0xe1, 0x57, 0x28, 0x2a, 0x23, 0x5e, + 0xc4, 0xa2, 0x19, 0x4b, 0x00, 0x67, 0x78, 0xd9, + 0x26, 0x6e, 0x17, 0x25, 0xce, 0xe4, 0xfd, 0xde, + 0x86, 0xa8, 0x5a, 0x67, 0x47, 0x6b, 0x15, 0x09, + 0xe1, 0xec, 0x8e, 0x62, 0x98, 0x91, 0x6f, 0xc0, + 0x98, 0x0c, 0x70, 0x0e, 0x7d, 0xbe, 0x63, 0xbd, + 0x12, 0x5a, 0x98, 0x1c, 0xe3, 0x0c, 0xfb, 0xc7, + 0xfb, 0x1b, 0xbd, 0x02, 0x87, 0xcc, 0x0c, 0xbb, + 0xc2, 0xd4, 0xb6, 0xc1, 0xa1, 0x23, 0xd3, 0x1e, + 0x21, 0x6f, 0x48, 0xba, 0x0e, 0x2e, 0xc7, 0x42 +}; + +static const uint8_t rsa4096_priv_key[] = { + 0x30, 0x82, 0x09, 0x29, 0x02, 0x01, 0x00, 0x02, + 0x82, 0x02, 0x01, 0x00, 0xcc, 0x30, 0xc6, 0x90, + 0x49, 0x2b, 0x86, 0xe7, 0x7a, 0xa5, 0x7a, 0x9a, + 0x4f, 0xee, 0x0e, 0xa1, 0x5c, 0x43, 0x64, 0xd0, + 0x76, 0xe1, 0xfd, 0x0b, 0xfd, 0x43, 0x7a, 0x65, + 0xe6, 0x20, 0xbd, 0xf2, 0x0e, 0xbe, 0x76, 0x54, + 0xae, 0x37, 0xbe, 0xa0, 0x02, 0x96, 0xae, 0x8d, + 0x8a, 0xae, 0x3b, 0x88, 0xbb, 0x67, 0xce, 0x7c, + 0x20, 0xbf, 0x14, 0xc3, 0x71, 0x51, 0x87, 0x03, + 0x34, 0xaa, 0x3c, 0x09, 0xff, 0xe9, 0xeb, 0xb7, + 0x85, 0x5c, 0xbb, 0x8d, 0xce, 0x8e, 0x3f, 0xd1, + 0x16, 0x30, 0x00, 0x32, 0x2f, 0x25, 0x8d, 0xef, + 0x71, 0xd9, 0xea, 0x6b, 0x45, 0x53, 0x49, 0xc3, + 0x09, 0x4f, 0xb0, 0xa8, 0xa5, 0x89, 0x76, 0x59, + 0x31, 0xa5, 0xf1, 0x5c, 0x42, 0x54, 0x57, 0x70, + 0x57, 0xad, 0xd8, 0xeb, 0x89, 0xa6, 0x87, 0xa2, + 0x6c, 0x95, 0x58, 0x8f, 0xb6, 0x82, 0xc7, 0xde, + 0xc2, 0x3a, 0xdc, 0x5b, 0xe8, 0x02, 0xcc, 0x26, + 0x4b, 0x01, 0xaa, 0xe6, 0xf3, 0x66, 0x4d, 0x90, + 0x85, 0xde, 0xf4, 0x5d, 0x80, 0x98, 0xc6, 0x65, + 0xcf, 0x44, 0x4c, 0xde, 0xb5, 0x4a, 0xfc, 0xda, + 0x0a, 0x0a, 0x10, 0x26, 0xa3, 0xcb, 0x9d, 0xe4, + 0x8d, 0xab, 0x2c, 0x04, 0xfd, 0xaa, 0xfc, 0x3b, + 0xac, 0x4e, 0x56, 0xb8, 0x4c, 0x9f, 0x22, 0x49, + 0xcb, 0x76, 0x45, 0x24, 0x36, 0x2d, 0xbb, 0xe6, + 0x7e, 0xa9, 0x93, 0x13, 0x96, 0x1e, 0xfc, 0x4b, + 0x75, 0xd4, 0x54, 0xc8, 0x8c, 0x55, 0xe6, 0x3f, + 0x09, 0x5a, 0x03, 0x74, 0x7c, 0x8a, 0xc8, 0xe7, + 0x49, 0x0b, 0x86, 0x7c, 0x97, 0xa0, 0xf2, 0x0d, + 0xf1, 0x5c, 0x0e, 0x7a, 0xc0, 0x3f, 0x78, 0x2d, + 0x9b, 0xe2, 0x26, 0xa0, 0x89, 0x49, 0x0c, 0xad, + 0x79, 0xa6, 0x82, 0x98, 0xa6, 0xb7, 0x74, 0xb4, + 0x45, 0xc8, 0xed, 0xea, 0x81, 0xcd, 0xf0, 0x3b, + 0x8e, 0x24, 0xfb, 0x0c, 0xd0, 0x3a, 0x14, 0xb9, + 0xb4, 0x3b, 0x69, 0xd9, 0xf2, 0x42, 0x6e, 0x7f, + 0x6f, 0x5e, 0xb1, 0x52, 0x5b, 0xaa, 0xef, 0xae, + 0x1e, 0x34, 0xca, 0xed, 0x0a, 0x8d, 0x56, 0xd6, + 0xdd, 0xd4, 0x2c, 0x54, 0x7a, 0x57, 0xca, 0x7e, + 0x4a, 0x11, 0xde, 0x48, 0xdf, 0x2b, 0x09, 0x97, + 0x39, 0x24, 0xce, 0x45, 0xe0, 0x75, 0xb1, 0x19, + 0x42, 0xdb, 0x63, 0x40, 0x9b, 0xb9, 0x95, 0x96, + 0x78, 0x91, 0xd5, 0x19, 0x12, 0xab, 0xef, 0x55, + 0x6f, 0x0d, 0x65, 0xc0, 0x8f, 0x62, 0x99, 0x78, + 0xc0, 0xe0, 0xe1, 0x33, 0xc7, 0x68, 0xff, 0x29, + 0x66, 0x22, 0x3a, 0x6f, 0xa0, 0xf8, 0x5c, 0x68, + 0x9b, 0xa9, 0x05, 0xad, 0x6b, 0x1d, 0xae, 0xc1, + 0x30, 0xbb, 0xfe, 0xb7, 0x31, 0x85, 0x0d, 0xd1, + 0xd5, 0xfc, 0x43, 0x1e, 0xb3, 0x61, 0x6f, 0xc4, + 0x75, 0xed, 0x76, 0x9d, 0x13, 0xb3, 0x61, 0x57, + 0xc8, 0x33, 0x0d, 0x77, 0x84, 0xf0, 0xc7, 0x62, + 0xb9, 0x9e, 0xd5, 0x01, 0xfa, 0x87, 0x4a, 0xf5, + 0xd7, 0x4f, 0x5d, 0xae, 0xe7, 0x08, 0xd2, 0x5a, + 0x65, 0x30, 0xc9, 0xf0, 0x0a, 0x11, 0xf1, 0x2a, + 0xd3, 0x43, 0x43, 0xca, 0x05, 0x90, 0x85, 0xf4, + 0xbc, 0x37, 0x49, 0x40, 0x45, 0x35, 0xd3, 0x56, + 0x06, 0x4c, 0x63, 0x93, 0x07, 0x14, 0x8b, 0xd3, + 0x12, 0xd0, 0xe5, 0x00, 0x48, 0x76, 0xd2, 0xdf, + 0x7c, 0xea, 0xc7, 0xff, 0xf0, 0x88, 0xd5, 0xa4, + 0x61, 0x7d, 0x79, 0xc2, 0xda, 0x53, 0x24, 0xdc, + 0x20, 0xae, 0xe6, 0x08, 0x65, 0xef, 0xc9, 0x0d, + 0x7d, 0x66, 0x6d, 0x1b, 0x1c, 0x5d, 0x46, 0xe1, + 0x26, 0x8a, 0x29, 0x77, 0x76, 0x19, 0xe5, 0x19, + 0x2a, 0x75, 0x21, 0xf1, 0x92, 0x8a, 0x9c, 0x7b, + 0xe8, 0x0b, 0x38, 0xc1, 0xbf, 0x76, 0x22, 0x45, + 0x4a, 0xd3, 0x43, 0xc3, 0x8c, 0x74, 0xd8, 0xd8, + 0xec, 0x3e, 0x14, 0xdf, 0x02, 0x03, 0x01, 0x00, + 0x01, 0x02, 0x82, 0x02, 0x01, 0x00, 0x9e, 0x13, + 0x64, 0xa5, 0x6e, 0xff, 0xf3, 0x80, 0x60, 0xc2, + 0x9b, 0x17, 0xbb, 0xa9, 0x60, 0x4a, 0x2b, 0x53, + 0x41, 0x48, 0xe1, 0xc0, 0x32, 0x56, 0x85, 0xcb, + 0x27, 0x86, 0x9b, 0x91, 0xdd, 0x7a, 0xf7, 0x4f, + 0x1b, 0xec, 0x92, 0xb3, 0x35, 0x30, 0x4a, 0xd0, + 0xbc, 0x71, 0x77, 0x5b, 0x4b, 0x5b, 0x9f, 0x39, + 0xcd, 0xf0, 0xea, 0xa9, 0x03, 0x3a, 0x0b, 0x10, + 0x42, 0xa5, 0x88, 0xb0, 0x01, 0xaa, 0xfc, 0x23, + 0xec, 0x08, 0x37, 0x86, 0x82, 0xec, 0x55, 0x6c, + 0x6a, 0x9b, 0x43, 0xc2, 0x05, 0x64, 0xd4, 0x7b, + 0x0e, 0x56, 0xc0, 0x9d, 0x23, 0x8d, 0xc8, 0x2d, + 0xa2, 0x7d, 0x0b, 0x48, 0x56, 0x4b, 0x39, 0x5c, + 0x21, 0xf3, 0x0b, 0x2c, 0x9c, 0x9d, 0xff, 0xfb, + 0xab, 0x75, 0x9d, 0x6b, 0x48, 0xf3, 0x8f, 0xad, + 0x0c, 0x74, 0x01, 0xfb, 0xdc, 0x83, 0xe5, 0x97, + 0x79, 0x84, 0x4a, 0x79, 0xa6, 0xfe, 0xbf, 0xae, + 0xea, 0xbc, 0xfa, 0x74, 0x60, 0x0a, 0x4b, 0x84, + 0x77, 0xa7, 0xda, 0xfb, 0xaf, 0xd2, 0x73, 0x2b, + 0xd2, 0xec, 0x1e, 0x79, 0x91, 0xc9, 0x18, 0x30, + 0xe5, 0x6f, 0x27, 0x36, 0x83, 0x2a, 0x66, 0xc3, + 0xcb, 0x88, 0x94, 0xe4, 0x5f, 0x3f, 0xbd, 0xe2, + 0x11, 0x43, 0x61, 0x31, 0x84, 0x91, 0x49, 0x40, + 0x29, 0x1b, 0x58, 0x18, 0x47, 0x8e, 0xb1, 0x22, + 0xd6, 0xc4, 0xaa, 0x6a, 0x3d, 0x22, 0x7c, 0xa5, + 0xa0, 0x4c, 0x0a, 0xfc, 0x46, 0x66, 0xbb, 0xbe, + 0x04, 0x71, 0xe8, 0x9b, 0x76, 0xf1, 0x47, 0x39, + 0x6a, 0x2f, 0x23, 0xad, 0x78, 0x80, 0x1c, 0x22, + 0xcd, 0x41, 0x5e, 0x09, 0x16, 0x6c, 0x91, 0x48, + 0x91, 0x91, 0x3d, 0x8c, 0xe6, 0xba, 0x81, 0x8d, + 0xbb, 0xf2, 0xd0, 0xaa, 0xc7, 0x8f, 0xc6, 0x01, + 0x60, 0xa7, 0xef, 0x1e, 0x8e, 0x91, 0x6d, 0xcc, + 0x30, 0x9e, 0xea, 0x7c, 0x56, 0x9d, 0x42, 0xcf, + 0x44, 0x85, 0x52, 0xa8, 0xf2, 0x36, 0x9c, 0x46, + 0xfa, 0x9d, 0xd3, 0x4e, 0x13, 0x46, 0x81, 0xce, + 0x99, 0xc9, 0x58, 0x47, 0xe4, 0xeb, 0x27, 0x56, + 0x29, 0x61, 0x0f, 0xb5, 0xcb, 0xf3, 0x48, 0x58, + 0x8f, 0xbc, 0xaf, 0x0a, 0xbf, 0x40, 0xd1, 0xf6, + 0x4f, 0xd2, 0x89, 0x4a, 0xff, 0x6f, 0x54, 0x70, + 0x49, 0x42, 0xf6, 0xf8, 0x0e, 0x4f, 0xa5, 0xf6, + 0x8b, 0x49, 0x80, 0xd4, 0xf5, 0x03, 0xf8, 0x65, + 0xe7, 0x1f, 0x0a, 0xc0, 0x8f, 0xd3, 0x7a, 0x70, + 0xca, 0x67, 0xaf, 0x71, 0xfd, 0x4b, 0xe1, 0x17, + 0x76, 0x74, 0x2e, 0x12, 0x7b, 0xad, 0x4b, 0xbb, + 0xd2, 0x64, 0xd0, 0xa9, 0xf9, 0x79, 0xa9, 0xa6, + 0x03, 0xd2, 0xc2, 0x8f, 0x47, 0x59, 0x1b, 0x7c, + 0xe3, 0xce, 0x92, 0xb2, 0xac, 0x3e, 0xee, 0x12, + 0x43, 0x5f, 0x23, 0xec, 0xf1, 0xd3, 0xf2, 0x21, + 0x22, 0xe8, 0x7e, 0x7f, 0xa4, 0x93, 0x8e, 0x78, + 0x69, 0x69, 0xa0, 0xc9, 0xce, 0x86, 0x36, 0x13, + 0x10, 0x21, 0xc4, 0x7a, 0x52, 0xcf, 0x53, 0xd9, + 0x9b, 0x58, 0xe6, 0x2d, 0xeb, 0x60, 0xe3, 0x75, + 0x1a, 0x22, 0xf6, 0x3c, 0x54, 0x6b, 0xfa, 0xa1, + 0x5d, 0xf6, 0x38, 0xf0, 0xd4, 0x26, 0x2d, 0x7d, + 0x74, 0x99, 0x6a, 0x13, 0x8a, 0x07, 0x9f, 0x07, + 0xc5, 0xf4, 0xa8, 0x20, 0x11, 0xa9, 0x76, 0x11, + 0xe4, 0x48, 0xae, 0xa4, 0x8a, 0xa1, 0xbf, 0x1f, + 0xba, 0x37, 0x50, 0x53, 0x43, 0x91, 0x45, 0x88, + 0x03, 0x52, 0xba, 0xac, 0xc8, 0xe3, 0xe1, 0xba, + 0x63, 0x24, 0x72, 0xbe, 0x1d, 0x01, 0x1f, 0x6c, + 0x34, 0x10, 0xb8, 0x56, 0x4a, 0x67, 0x28, 0x4b, + 0x7a, 0x2b, 0x31, 0x29, 0x47, 0xda, 0xdf, 0x53, + 0x88, 0x79, 0x22, 0x31, 0x15, 0x56, 0xe3, 0xa0, + 0x79, 0x75, 0x94, 0x90, 0xb2, 0xe8, 0x4b, 0xca, + 0x82, 0x6d, 0x3c, 0x69, 0x43, 0x01, 0x02, 0x82, + 0x01, 0x01, 0x00, 0xe7, 0x8b, 0xd6, 0x1a, 0xe8, + 0x00, 0xed, 0x9d, 0x7c, 0x5a, 0x32, 0x10, 0xc1, + 0x53, 0x50, 0xbe, 0x27, 0x1d, 0xef, 0x69, 0x73, + 0xa2, 0x8f, 0x95, 0x96, 0x86, 0xfe, 0xfb, 0x82, + 0xdb, 0xea, 0x7d, 0x73, 0x5a, 0x2b, 0xe7, 0x4b, + 0xd5, 0x8f, 0x4f, 0xaf, 0x85, 0x1d, 0x15, 0x1a, + 0x58, 0x5f, 0x41, 0x79, 0x70, 0x5c, 0x8f, 0xa9, + 0x8e, 0x23, 0x31, 0xa7, 0x6d, 0x99, 0x0c, 0xf0, + 0x51, 0xbf, 0xbb, 0xd3, 0xe3, 0xa3, 0x34, 0xf0, + 0x1d, 0x7f, 0x4a, 0xb7, 0x8f, 0xf6, 0x0a, 0x49, + 0x65, 0xaf, 0x35, 0x7b, 0x02, 0x2e, 0x69, 0x49, + 0x95, 0xb5, 0x20, 0x70, 0xb2, 0x98, 0x54, 0x9b, + 0x8e, 0x4f, 0x48, 0xa8, 0xfa, 0x7e, 0xc7, 0x0a, + 0xae, 0x84, 0xe1, 0xba, 0x85, 0x98, 0x96, 0x8a, + 0x7c, 0xdd, 0xcc, 0xcd, 0xd8, 0x5b, 0x50, 0x60, + 0x88, 0x2d, 0xb6, 0x3e, 0xb8, 0xc2, 0xae, 0xa5, + 0x62, 0x10, 0xcd, 0xdc, 0xae, 0x86, 0xfe, 0x31, + 0x8b, 0xf7, 0xee, 0x1a, 0x35, 0x46, 0x83, 0xee, + 0x5f, 0x55, 0x9a, 0xc2, 0xca, 0x53, 0xb7, 0x2c, + 0xbf, 0x03, 0x8a, 0x78, 0xcc, 0x1d, 0x96, 0x7b, + 0xac, 0x00, 0x62, 0x1e, 0xbd, 0x6f, 0x0b, 0xa5, + 0xec, 0xf3, 0x02, 0x47, 0x47, 0x1e, 0x3d, 0xf6, + 0x78, 0x42, 0xe4, 0xcd, 0xf8, 0x14, 0xa3, 0x7d, + 0xd5, 0x2f, 0x6e, 0xcc, 0x1a, 0x9e, 0xe7, 0xcf, + 0x48, 0xb9, 0x80, 0xb8, 0xba, 0xaa, 0x7b, 0xae, + 0x65, 0x74, 0x09, 0x7b, 0x43, 0x26, 0x31, 0xa2, + 0x95, 0x43, 0x69, 0xd0, 0xb7, 0x95, 0xe4, 0x76, + 0x2c, 0x42, 0x19, 0x47, 0x4f, 0x63, 0x35, 0x9c, + 0xa2, 0x1a, 0xce, 0x28, 0xdf, 0x76, 0x98, 0x1d, + 0xd4, 0x2e, 0xf6, 0x3a, 0xc8, 0x3e, 0xc7, 0xaf, + 0xf7, 0x38, 0x3f, 0x83, 0x3a, 0xcb, 0xae, 0x41, + 0x75, 0x46, 0x63, 0xaa, 0x45, 0xb1, 0x2c, 0xd9, + 0x9f, 0x17, 0x37, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xe1, 0xc1, 0x57, 0x4d, 0x0f, 0xa5, 0xea, 0x1d, + 0x39, 0x9c, 0xe0, 0xf0, 0x6d, 0x13, 0x7f, 0x79, + 0xdc, 0x72, 0x61, 0xc0, 0x7f, 0x88, 0xf6, 0x38, + 0x4f, 0x49, 0x06, 0x1e, 0xb8, 0x6c, 0x21, 0x04, + 0x60, 0x76, 0x5a, 0x6d, 0x04, 0xd1, 0x6d, 0xac, + 0x7c, 0x25, 0x4f, 0x32, 0xcb, 0xbc, 0xf8, 0x4a, + 0x22, 0x8f, 0xf5, 0x41, 0xfd, 0x1c, 0x76, 0x30, + 0xc2, 0x5f, 0x99, 0x13, 0x5c, 0x57, 0x0f, 0xfd, + 0xac, 0x0b, 0x10, 0x9a, 0x4f, 0x78, 0x0a, 0x86, + 0xe8, 0x07, 0x40, 0x40, 0x13, 0xba, 0x96, 0x07, + 0xd5, 0x39, 0x91, 0x51, 0x3e, 0x80, 0xd8, 0xa0, + 0x1f, 0xff, 0xdc, 0x9e, 0x09, 0x3b, 0xae, 0x38, + 0xa9, 0xc2, 0x14, 0x7b, 0xee, 0xd2, 0x69, 0x3d, + 0xd6, 0x26, 0x74, 0x72, 0x7b, 0x86, 0xd4, 0x13, + 0x5b, 0xb8, 0x76, 0x4b, 0x08, 0xfb, 0x93, 0xfa, + 0x44, 0xaf, 0x98, 0x3b, 0xfa, 0xd0, 0x2a, 0x04, + 0x8b, 0xb3, 0x3c, 0x6d, 0x32, 0xf7, 0x18, 0x6a, + 0x51, 0x0e, 0x40, 0x90, 0xce, 0x8e, 0xdf, 0xe8, + 0x07, 0x4c, 0x0f, 0xc7, 0xc8, 0xc2, 0x18, 0x58, + 0x6a, 0x01, 0xc8, 0x27, 0xd6, 0x43, 0x2a, 0xfb, + 0xa5, 0x34, 0x01, 0x3c, 0x72, 0xb1, 0x48, 0xce, + 0x2b, 0x9b, 0xb4, 0x69, 0xd9, 0x82, 0xf8, 0xbe, + 0x29, 0x88, 0x75, 0x96, 0xd8, 0xef, 0x78, 0x2a, + 0x07, 0x90, 0xa0, 0x56, 0x33, 0x42, 0x05, 0x19, + 0xb0, 0x69, 0x34, 0xf9, 0x03, 0xc5, 0xa8, 0x0d, + 0x72, 0xa2, 0x27, 0xb4, 0x45, 0x6d, 0xd2, 0x01, + 0x6c, 0xf1, 0x74, 0x51, 0x0a, 0x9a, 0xe2, 0xc1, + 0x96, 0x80, 0x30, 0x0e, 0xc6, 0xa9, 0x79, 0xf7, + 0x6f, 0xaf, 0xf6, 0xe8, 0x2a, 0xcc, 0xbd, 0xad, + 0x8f, 0xe0, 0x32, 0x87, 0x85, 0x49, 0x68, 0x88, + 0x15, 0x5c, 0xdb, 0x48, 0x40, 0xa2, 0xfa, 0x42, + 0xe8, 0x4e, 0x3e, 0xe2, 0x3f, 0xe0, 0xf3, 0x99, + 0x02, 0x82, 0x01, 0x00, 0x08, 0x39, 0x97, 0x69, + 0x6d, 0x44, 0x5b, 0x2c, 0x74, 0xf6, 0x5f, 0x40, + 0xe9, 0x1d, 0x24, 0x89, 0x1c, 0xaa, 0x9b, 0x8e, + 0x8b, 0x65, 0x02, 0xe4, 0xb5, 0x6c, 0x26, 0x32, + 0x98, 0xfb, 0x66, 0xe0, 0xfd, 0xef, 0xfe, 0x0f, + 0x41, 0x4a, 0x5c, 0xc4, 0xdf, 0xdf, 0x42, 0xa1, + 0x35, 0x46, 0x5e, 0x5b, 0xdd, 0x0c, 0x78, 0xbd, + 0x41, 0xb0, 0xa2, 0xdf, 0x68, 0xab, 0x23, 0xfc, + 0xa9, 0xac, 0xbd, 0xba, 0xd6, 0x54, 0x07, 0xc0, + 0x21, 0xa7, 0x6a, 0x96, 0x24, 0xdf, 0x20, 0x46, + 0x4d, 0x45, 0x27, 0x6c, 0x26, 0xea, 0x74, 0xeb, + 0x98, 0x89, 0x90, 0xdd, 0x8e, 0x23, 0x49, 0xf5, + 0xf7, 0x70, 0x9e, 0xb0, 0x5e, 0x10, 0x47, 0xe0, + 0x9a, 0x28, 0x88, 0xdf, 0xdb, 0xd8, 0x53, 0x0b, + 0x45, 0xf0, 0x19, 0x90, 0xe4, 0xdf, 0x02, 0x9f, + 0x60, 0x4e, 0x76, 0x11, 0x3b, 0x39, 0x24, 0xf1, + 0x3f, 0x3e, 0xb4, 0x8a, 0x1b, 0x84, 0xb7, 0x96, + 0xdf, 0xfb, 0xb0, 0xda, 0xec, 0x63, 0x68, 0x15, + 0xd7, 0xa9, 0xdb, 0x48, 0x9c, 0x12, 0xc3, 0xd6, + 0x85, 0xe8, 0x63, 0x1f, 0xd0, 0x1a, 0xb0, 0x12, + 0x60, 0x62, 0x43, 0xc1, 0x38, 0x86, 0x52, 0x23, + 0x7f, 0xc9, 0x62, 0xf8, 0x79, 0xbf, 0xb4, 0xfb, + 0x4e, 0x7e, 0x07, 0x22, 0x49, 0x8e, 0xbe, 0x6c, + 0xf0, 0x53, 0x5a, 0x53, 0xfd, 0x3c, 0x14, 0xd8, + 0xf7, 0x2c, 0x06, 0x2a, 0xe4, 0x64, 0xfd, 0x19, + 0x57, 0xa0, 0x92, 0xf6, 0xa3, 0x42, 0x47, 0x61, + 0x0b, 0xfd, 0x71, 0x5f, 0x98, 0xe2, 0x6c, 0x98, + 0xa8, 0xf9, 0xf9, 0x7f, 0x1c, 0x61, 0x5d, 0x8c, + 0xd1, 0xfb, 0x90, 0x28, 0x32, 0x9b, 0x7d, 0x82, + 0xf9, 0xcc, 0x47, 0xbe, 0xc7, 0x67, 0xc5, 0x93, + 0x22, 0x55, 0x0d, 0xd2, 0x73, 0xbe, 0xea, 0xed, + 0x4d, 0xb5, 0xf4, 0xc2, 0x25, 0x92, 0x44, 0x30, + 0xeb, 0xaa, 0x13, 0x11, 0x02, 0x82, 0x01, 0x01, + 0x00, 0x82, 0x42, 0x02, 0x53, 0x4e, 0x72, 0x16, + 0xf1, 0x21, 0xea, 0xe8, 0xc7, 0x10, 0xc8, 0xad, + 0x46, 0xec, 0xf1, 0x7a, 0x81, 0x8d, 0x94, 0xc3, + 0x2c, 0x9e, 0x62, 0xae, 0x0b, 0x4f, 0xb1, 0xe4, + 0x23, 0x18, 0x5d, 0x71, 0xb3, 0x71, 0x92, 0x3d, + 0x4b, 0xc6, 0x9d, 0xe8, 0x62, 0x90, 0xb7, 0xca, + 0x33, 0x4c, 0x59, 0xef, 0xd3, 0x51, 0x6d, 0xf8, + 0xac, 0x0d, 0x9b, 0x07, 0x41, 0xea, 0x87, 0xb9, + 0x8c, 0x4e, 0x96, 0x5b, 0xd0, 0x0d, 0x86, 0x5f, + 0xdc, 0x93, 0x48, 0x8b, 0xc3, 0xed, 0x1e, 0x3d, + 0xae, 0xeb, 0x52, 0xba, 0x0c, 0x3c, 0x9a, 0x2f, + 0x63, 0xc4, 0xd2, 0xe6, 0xc2, 0xb0, 0xe5, 0x24, + 0x93, 0x41, 0x2f, 0xe0, 0x8d, 0xd9, 0xb0, 0xc2, + 0x54, 0x91, 0x99, 0xc2, 0x9a, 0xc3, 0xb7, 0x79, + 0xea, 0x69, 0x83, 0xb7, 0x8d, 0x77, 0xf3, 0x60, + 0xe0, 0x88, 0x7d, 0x20, 0xc3, 0x8a, 0xe6, 0x4d, + 0x38, 0x2e, 0x3b, 0x0e, 0xe4, 0x9b, 0x01, 0x83, + 0xae, 0xe4, 0x71, 0xea, 0xc3, 0x22, 0xcb, 0xc1, + 0x59, 0xa9, 0xcc, 0x33, 0x56, 0xbc, 0xf9, 0x70, + 0xfe, 0xa2, 0xbb, 0xc0, 0x77, 0x6b, 0xe3, 0x79, + 0x8b, 0x95, 0x38, 0xba, 0x75, 0xdc, 0x5f, 0x7a, + 0x78, 0xab, 0x24, 0xbe, 0x26, 0x4d, 0x00, 0x8a, + 0xf1, 0x7e, 0x19, 0x64, 0x6f, 0xd3, 0x5f, 0xe8, + 0xdf, 0xa7, 0x59, 0xc5, 0x89, 0xb7, 0x2d, 0xa2, + 0xaf, 0xbd, 0xe0, 0x16, 0x56, 0x8f, 0xdc, 0x9e, + 0x28, 0x94, 0x3a, 0x07, 0xda, 0xb6, 0x2c, 0xb5, + 0x7d, 0x69, 0x14, 0xb0, 0x5e, 0x8a, 0x55, 0xef, + 0xfc, 0x6f, 0x10, 0x2b, 0xaa, 0x7a, 0xea, 0x12, + 0x9b, 0xb8, 0x6f, 0xb9, 0x71, 0x20, 0x30, 0xde, + 0x48, 0xa4, 0xb9, 0x61, 0xae, 0x5c, 0x33, 0x8d, + 0x02, 0xe8, 0x00, 0x99, 0xed, 0xc8, 0x8d, 0xc1, + 0x04, 0x95, 0xf1, 0x7f, 0xcb, 0x1f, 0xbc, 0x76, + 0x11, 0x02, 0x82, 0x01, 0x00, 0x2d, 0x0c, 0xa9, + 0x8f, 0x11, 0xc2, 0xf3, 0x02, 0xc8, 0xf2, 0x55, + 0xc5, 0x6d, 0x25, 0x88, 0xba, 0x59, 0xf6, 0xd1, + 0xdb, 0x94, 0x2f, 0x0b, 0x65, 0x2c, 0xad, 0x54, + 0xe0, 0x2b, 0xe6, 0xa3, 0x49, 0xa2, 0xb3, 0xca, + 0xd7, 0xec, 0x27, 0x32, 0xbb, 0xa4, 0x16, 0x90, + 0xbb, 0x67, 0xad, 0x1b, 0xb9, 0x0f, 0x78, 0xcb, + 0xad, 0x5c, 0xc3, 0x66, 0xd6, 0xbb, 0x97, 0x28, + 0x01, 0x31, 0xf9, 0x0f, 0x71, 0x2a, 0xb9, 0x5b, + 0xea, 0x34, 0x49, 0x9c, 0x6b, 0x13, 0x40, 0x65, + 0xbd, 0x18, 0x0a, 0x14, 0xf9, 0x33, 0x47, 0xe8, + 0x9f, 0x64, 0x0e, 0x24, 0xf6, 0xbb, 0x90, 0x23, + 0x66, 0x01, 0xa6, 0xa4, 0xa9, 0x7f, 0x64, 0x51, + 0xa3, 0x8a, 0x73, 0xc1, 0x80, 0xaf, 0x7a, 0x49, + 0x75, 0x5d, 0x56, 0x1c, 0xaa, 0x3f, 0x64, 0xa9, + 0x96, 0xfd, 0xb0, 0x90, 0xc5, 0xe0, 0x3d, 0x36, + 0x05, 0xad, 0xad, 0x84, 0x93, 0x84, 0xab, 0x1b, + 0x34, 0x57, 0x39, 0xae, 0x0e, 0x80, 0x0f, 0x4a, + 0x9b, 0x32, 0x56, 0xbd, 0x30, 0xeb, 0xd1, 0xc8, + 0xc4, 0x9f, 0x9c, 0x07, 0xb6, 0x05, 0xb1, 0x21, + 0x7f, 0x69, 0x92, 0x9f, 0xb7, 0x68, 0xe7, 0xde, + 0xb7, 0xbc, 0xb4, 0x89, 0x5b, 0x1c, 0x1b, 0x48, + 0xd1, 0x44, 0x6e, 0xd7, 0x6b, 0xe2, 0xa1, 0xf4, + 0xbf, 0x17, 0xb4, 0x43, 0x70, 0x26, 0xd4, 0xb9, + 0xf5, 0x19, 0x09, 0x08, 0xe9, 0xa3, 0x49, 0x7d, + 0x2f, 0xdc, 0xe8, 0x75, 0x79, 0xa1, 0xc1, 0x70, + 0x1b, 0x60, 0x97, 0xaf, 0x0c, 0x56, 0x68, 0xac, + 0x0e, 0x53, 0xbe, 0x56, 0xf4, 0xc3, 0xb1, 0xfb, + 0xfb, 0xff, 0x73, 0x5b, 0xa7, 0xf6, 0x99, 0x0e, + 0x14, 0x5a, 0x5f, 0x9d, 0xbd, 0x8e, 0x94, 0xec, + 0x8b, 0x38, 0x72, 0xbc, 0x8b, 0xca, 0x32, 0xa8, + 0x39, 0x43, 0xb1, 0x1d, 0x43, 0x29, 0xbe, 0x60, + 0xdb, 0x91, 0x6c, 0x9c, 0x06, +}; diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 5a7993e56c..287b367ec3 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -77,6 +77,7 @@ if have_block 'test-crypto-hash': [crypto], 'test-crypto-hmac': [crypto], 'test-crypto-cipher': [crypto], + 'test-crypto-akcipher': [crypto], 'test-crypto-secret': [crypto, keyutils], 'test-crypto-der': [crypto], 'test-authz-simple': [authz], diff --git a/tests/unit/test-crypto-akcipher.c b/tests/unit/test-crypto-akcipher.c new file mode 100644 index 0000000000..b5be563884 --- /dev/null +++ b/tests/unit/test-crypto-akcipher.c @@ -0,0 +1,711 @@ +/* + * QEMU Crypto cipher algorithms + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#include "qemu/osdep.h" + +#include "crypto/init.h" +#include "crypto/akcipher.h" +#include "qapi/error.h" + +static const uint8_t rsa1024_private_key[] = { + 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, + 0x81, 0x81, 0x00, 0xe6, 0x4d, 0x76, 0x4f, 0xb2, + 0x97, 0x09, 0xad, 0x9d, 0x17, 0x33, 0xf2, 0x30, + 0x42, 0x83, 0xa9, 0xcb, 0x49, 0xa4, 0x2e, 0x59, + 0x5e, 0x75, 0x51, 0xd1, 0xac, 0xc8, 0x86, 0x3e, + 0xdb, 0x72, 0x2e, 0xb2, 0xf7, 0xc3, 0x5b, 0xc7, + 0xea, 0xed, 0x30, 0xd1, 0xf7, 0x37, 0xee, 0x9d, + 0x36, 0x59, 0x6f, 0xf8, 0xce, 0xc0, 0x5c, 0x82, + 0x80, 0x37, 0x83, 0xd7, 0x45, 0x6a, 0xe9, 0xea, + 0xc5, 0x3a, 0x59, 0x6b, 0x34, 0x31, 0x44, 0x00, + 0x74, 0xa7, 0x29, 0xab, 0x79, 0x4a, 0xbd, 0xe8, + 0x25, 0x35, 0x01, 0x11, 0x40, 0xbf, 0x31, 0xbd, + 0xd3, 0xe0, 0x68, 0x1e, 0xd5, 0x5b, 0x2f, 0xe9, + 0x20, 0xf2, 0x9f, 0x46, 0x35, 0x30, 0xa8, 0xf1, + 0xfe, 0xef, 0xd8, 0x76, 0x23, 0x46, 0x34, 0x70, + 0xa1, 0xce, 0xc6, 0x65, 0x6d, 0xb0, 0x94, 0x7e, + 0xe5, 0x92, 0x45, 0x7b, 0xaa, 0xbb, 0x95, 0x97, + 0x77, 0xcd, 0xd3, 0x02, 0x03, 0x01, 0x00, 0x01, + 0x02, 0x81, 0x80, 0x30, 0x6a, 0xc4, 0x9e, 0xc8, + 0xba, 0xfc, 0x2b, 0xe5, 0xc4, 0xc5, 0x04, 0xfb, + 0xa4, 0x60, 0x2d, 0xc8, 0x31, 0x39, 0x35, 0x0d, + 0x50, 0xd0, 0x75, 0x5d, 0x11, 0x68, 0x2e, 0xe0, + 0xf4, 0x1d, 0xb3, 0x37, 0xa8, 0xe3, 0x07, 0x5e, + 0xa6, 0x43, 0x2b, 0x6a, 0x59, 0x01, 0x07, 0x47, + 0x41, 0xef, 0xd7, 0x9c, 0x85, 0x4a, 0xe7, 0xa7, + 0xff, 0xf0, 0xab, 0xe5, 0x0c, 0x11, 0x08, 0x10, + 0x75, 0x5a, 0x68, 0xa0, 0x08, 0x03, 0xc9, 0x40, + 0x79, 0x67, 0x1d, 0x65, 0x89, 0x2d, 0x08, 0xf9, + 0xb5, 0x1b, 0x7d, 0xd2, 0x41, 0x3b, 0x33, 0xf2, + 0x47, 0x2f, 0x9c, 0x0b, 0xd5, 0xaf, 0xcb, 0xdb, + 0xbb, 0x37, 0x63, 0x03, 0xf8, 0xe7, 0x2e, 0xc7, + 0x3c, 0x86, 0x9f, 0xc2, 0x9b, 0xb4, 0x70, 0x6a, + 0x4d, 0x7c, 0xe4, 0x1b, 0x3a, 0xa9, 0xae, 0xd7, + 0xce, 0x7f, 0x56, 0xc2, 0x73, 0x5e, 0x58, 0x63, + 0xd5, 0x86, 0x41, 0x02, 0x41, 0x00, 0xf6, 0x56, + 0x69, 0xec, 0xef, 0x65, 0x95, 0xdc, 0x25, 0x47, + 0xe0, 0x6f, 0xb0, 0x4f, 0x79, 0x77, 0x0a, 0x5e, + 0x46, 0xcb, 0xbd, 0x0b, 0x71, 0x51, 0x2a, 0xa4, + 0x65, 0x29, 0x18, 0xc6, 0x30, 0xa0, 0x95, 0x4c, + 0x4b, 0xbe, 0x8c, 0x40, 0xe3, 0x9c, 0x23, 0x02, + 0x14, 0x43, 0xe9, 0x64, 0xea, 0xe3, 0xa8, 0xe2, + 0x1a, 0xd5, 0xf9, 0x5c, 0xe0, 0x36, 0x2c, 0x97, + 0xda, 0xd5, 0xc7, 0x46, 0xce, 0x11, 0x02, 0x41, + 0x00, 0xef, 0x56, 0x08, 0xb8, 0x29, 0xa5, 0xa6, + 0x7c, 0xf7, 0x5f, 0xb4, 0xf5, 0x63, 0xe7, 0xeb, + 0x45, 0xfd, 0x89, 0xaa, 0x94, 0xa6, 0x3d, 0x0b, + 0xd9, 0x04, 0x6f, 0x78, 0xe0, 0xbb, 0xa2, 0xd4, + 0x29, 0x83, 0x17, 0x95, 0x6f, 0x50, 0x3d, 0x40, + 0x5d, 0xe5, 0x24, 0xda, 0xc2, 0x23, 0x50, 0x86, + 0xa8, 0x34, 0xc8, 0x6f, 0xec, 0x7f, 0xb6, 0x45, + 0x3a, 0xdd, 0x78, 0x9b, 0xee, 0xa1, 0xe4, 0x09, + 0xa3, 0x02, 0x40, 0x5c, 0xd6, 0x66, 0x67, 0x58, + 0x35, 0xc5, 0xcb, 0xc8, 0xf5, 0x14, 0xbd, 0xa3, + 0x09, 0xe0, 0xb2, 0x1f, 0x63, 0x36, 0x75, 0x34, + 0x52, 0xea, 0xaa, 0xf7, 0x52, 0x2b, 0x99, 0xd8, + 0x6f, 0x61, 0x06, 0x34, 0x1e, 0x23, 0xf1, 0xb5, + 0x34, 0x03, 0x53, 0xe5, 0xd1, 0xb3, 0xc7, 0x80, + 0x5f, 0x7b, 0x32, 0xbf, 0x84, 0x2f, 0x2e, 0xf3, + 0x22, 0xb0, 0x91, 0x5a, 0x2f, 0x04, 0xd7, 0x4a, + 0x9a, 0x01, 0xb1, 0x02, 0x40, 0x34, 0x0b, 0x26, + 0x4c, 0x3d, 0xaa, 0x2a, 0xc0, 0xe3, 0xdd, 0xe8, + 0xf0, 0xaf, 0x6f, 0xe0, 0x06, 0x51, 0x32, 0x9d, + 0x68, 0x43, 0x99, 0xe4, 0xb8, 0xa5, 0x31, 0x44, + 0x3c, 0xc2, 0x30, 0x8f, 0x28, 0x13, 0xbc, 0x8e, + 0x1f, 0x2d, 0x78, 0x94, 0x45, 0x96, 0xad, 0x63, + 0xf0, 0x71, 0x53, 0x72, 0x64, 0xa3, 0x4d, 0xae, + 0xa0, 0xe3, 0xc8, 0x93, 0xd7, 0x50, 0x0f, 0x89, + 0x00, 0xe4, 0x2d, 0x3d, 0x37, 0x02, 0x41, 0x00, + 0xbe, 0xa6, 0x08, 0xe0, 0xc8, 0x15, 0x2a, 0x47, + 0xcb, 0xd5, 0xec, 0x93, 0xd3, 0xaa, 0x12, 0x82, + 0xaf, 0xac, 0x51, 0x5a, 0x5b, 0xa7, 0x93, 0x4b, + 0xb9, 0xab, 0x00, 0xfa, 0x5a, 0xea, 0x34, 0xe4, + 0x80, 0xf1, 0x44, 0x6a, 0x65, 0xe4, 0x33, 0x99, + 0xfb, 0x54, 0xd7, 0x89, 0x5a, 0x1b, 0xd6, 0x2b, + 0xcc, 0x6e, 0x4b, 0x19, 0xa0, 0x6d, 0x93, 0x9f, + 0xc3, 0x91, 0x7a, 0xa5, 0xd8, 0x59, 0x0e, 0x9e, +}; + +static const uint8_t rsa1024_public_key[] = { + 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xe6, + 0x4d, 0x76, 0x4f, 0xb2, 0x97, 0x09, 0xad, 0x9d, + 0x17, 0x33, 0xf2, 0x30, 0x42, 0x83, 0xa9, 0xcb, + 0x49, 0xa4, 0x2e, 0x59, 0x5e, 0x75, 0x51, 0xd1, + 0xac, 0xc8, 0x86, 0x3e, 0xdb, 0x72, 0x2e, 0xb2, + 0xf7, 0xc3, 0x5b, 0xc7, 0xea, 0xed, 0x30, 0xd1, + 0xf7, 0x37, 0xee, 0x9d, 0x36, 0x59, 0x6f, 0xf8, + 0xce, 0xc0, 0x5c, 0x82, 0x80, 0x37, 0x83, 0xd7, + 0x45, 0x6a, 0xe9, 0xea, 0xc5, 0x3a, 0x59, 0x6b, + 0x34, 0x31, 0x44, 0x00, 0x74, 0xa7, 0x29, 0xab, + 0x79, 0x4a, 0xbd, 0xe8, 0x25, 0x35, 0x01, 0x11, + 0x40, 0xbf, 0x31, 0xbd, 0xd3, 0xe0, 0x68, 0x1e, + 0xd5, 0x5b, 0x2f, 0xe9, 0x20, 0xf2, 0x9f, 0x46, + 0x35, 0x30, 0xa8, 0xf1, 0xfe, 0xef, 0xd8, 0x76, + 0x23, 0x46, 0x34, 0x70, 0xa1, 0xce, 0xc6, 0x65, + 0x6d, 0xb0, 0x94, 0x7e, 0xe5, 0x92, 0x45, 0x7b, + 0xaa, 0xbb, 0x95, 0x97, 0x77, 0xcd, 0xd3, 0x02, + 0x03, 0x01, 0x00, 0x01, +}; + +static const uint8_t rsa2048_private_key[] = { + 0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, + 0x82, 0x01, 0x01, 0x00, 0xbd, 0x9c, 0x83, 0x6b, + 0x0e, 0x8e, 0xcf, 0xfa, 0xaa, 0x4f, 0x6a, 0xf4, + 0xe3, 0x52, 0x0f, 0xa5, 0xd0, 0xbe, 0x5e, 0x7f, + 0x08, 0x24, 0xba, 0x87, 0x46, 0xfb, 0x28, 0x93, + 0xe5, 0xe5, 0x81, 0x42, 0xc0, 0xf9, 0x17, 0xc7, + 0x81, 0x01, 0xf4, 0x18, 0x6a, 0x17, 0xf5, 0x57, + 0x20, 0x37, 0xcf, 0xf9, 0x74, 0x5e, 0xe1, 0x48, + 0x6a, 0x71, 0x0a, 0x0f, 0x79, 0x72, 0x2b, 0x46, + 0x10, 0x53, 0xdc, 0x14, 0x43, 0xbd, 0xbc, 0x6d, + 0x15, 0x6f, 0x15, 0x4e, 0xf0, 0x0d, 0x89, 0x39, + 0x02, 0xc3, 0x68, 0x5c, 0xa8, 0xfc, 0xed, 0x64, + 0x9d, 0x98, 0xb7, 0xcd, 0x83, 0x66, 0x93, 0xc3, + 0xd9, 0x57, 0xa0, 0x21, 0x93, 0xad, 0x5c, 0x75, + 0x69, 0x88, 0x9e, 0x81, 0xdc, 0x7f, 0x1d, 0xd5, + 0xbd, 0x1c, 0xc1, 0x30, 0x56, 0xa5, 0xda, 0x99, + 0x46, 0xa6, 0x6d, 0x0e, 0x6f, 0x5e, 0x51, 0x34, + 0x49, 0x73, 0xc3, 0x67, 0x49, 0x7e, 0x21, 0x2a, + 0x20, 0xa7, 0x2b, 0x92, 0x73, 0x1d, 0xa5, 0x25, + 0x2a, 0xd0, 0x3a, 0x89, 0x75, 0xb2, 0xbb, 0x19, + 0x37, 0x78, 0x48, 0xd2, 0xf2, 0x2a, 0x6d, 0x9e, + 0xc6, 0x26, 0xca, 0x46, 0x8c, 0xf1, 0x42, 0x2a, + 0x31, 0xb2, 0xfc, 0xe7, 0x55, 0x51, 0xff, 0x07, + 0x13, 0x5b, 0x36, 0x59, 0x2b, 0x43, 0x30, 0x4b, + 0x05, 0x5c, 0xd2, 0x45, 0xa0, 0xa0, 0x7c, 0x17, + 0x5b, 0x07, 0xbb, 0x5d, 0x83, 0x80, 0x92, 0x6d, + 0x87, 0x1a, 0x43, 0xac, 0xc7, 0x6b, 0x8d, 0x11, + 0x60, 0x27, 0xd2, 0xdf, 0xdb, 0x71, 0x02, 0x55, + 0x6e, 0xb5, 0xca, 0x4d, 0xda, 0x59, 0x0d, 0xb8, + 0x8c, 0xcd, 0xd3, 0x0e, 0x55, 0xa0, 0xa4, 0x8d, + 0xa0, 0x14, 0x10, 0x48, 0x42, 0x35, 0x56, 0x08, + 0xf7, 0x29, 0x5f, 0xa2, 0xea, 0xa4, 0x5e, 0x8e, + 0x99, 0x56, 0xaa, 0x5a, 0x8c, 0x23, 0x8f, 0x35, + 0x22, 0x8a, 0xff, 0xed, 0x02, 0x03, 0x01, 0x00, + 0x01, 0x02, 0x82, 0x01, 0x00, 0x4e, 0x4a, 0xf3, + 0x44, 0xe0, 0x64, 0xfd, 0xe1, 0xde, 0x33, 0x1e, + 0xd1, 0xf1, 0x8f, 0x6f, 0xe0, 0xa2, 0xfa, 0x08, + 0x60, 0xe1, 0xc6, 0xf0, 0xb2, 0x6d, 0x0f, 0xc6, + 0x28, 0x93, 0xb4, 0x19, 0x94, 0xab, 0xc3, 0xef, + 0x1a, 0xb4, 0xdd, 0x4e, 0xa2, 0x4a, 0x24, 0x8c, + 0x6c, 0xa6, 0x64, 0x05, 0x5f, 0x56, 0xba, 0xda, + 0xc1, 0x21, 0x1a, 0x7d, 0xf1, 0xf7, 0xce, 0xb9, + 0xa9, 0x9b, 0x92, 0x54, 0xfc, 0x95, 0x20, 0x22, + 0x4e, 0xd4, 0x9b, 0xe2, 0xab, 0x8e, 0x99, 0xb8, + 0x40, 0xaf, 0x30, 0x6a, 0xc6, 0x60, 0x0c, 0xd8, + 0x25, 0x44, 0xa1, 0xcb, 0xbb, 0x73, 0x77, 0x86, + 0xaa, 0x46, 0xf3, 0x54, 0xae, 0xa8, 0xa0, 0xdb, + 0xdd, 0xab, 0x6e, 0xfb, 0x2c, 0x5a, 0x14, 0xaf, + 0x08, 0x13, 0xa7, 0x6c, 0xe9, 0xfd, 0xcd, 0x4c, + 0x1f, 0x20, 0x3a, 0x16, 0x2b, 0xf0, 0xb6, 0x7c, + 0x47, 0x5f, 0xd1, 0x0a, 0x2c, 0xc4, 0xa5, 0x68, + 0xd0, 0x43, 0x75, 0x6b, 0x65, 0xaa, 0x32, 0xc6, + 0x99, 0x06, 0xcb, 0x8f, 0xe6, 0x8d, 0xce, 0xbf, + 0x4d, 0x0d, 0x7b, 0x22, 0x2a, 0x8a, 0xcb, 0x7d, + 0x7f, 0x16, 0x48, 0x85, 0xf1, 0x86, 0xcb, 0x54, + 0xb9, 0x39, 0xd4, 0xbc, 0xe3, 0x2d, 0x27, 0x59, + 0xf6, 0x81, 0x5e, 0x94, 0x45, 0xdf, 0xb9, 0x22, + 0xaf, 0x64, 0x0d, 0x14, 0xec, 0x8c, 0xeb, 0x71, + 0xac, 0xee, 0x09, 0x4c, 0xbf, 0x34, 0xf9, 0xf4, + 0x66, 0x77, 0x36, 0x3b, 0x41, 0x74, 0x01, 0x4f, + 0xfc, 0x56, 0x83, 0xba, 0x14, 0xb0, 0x2f, 0xdd, + 0x4d, 0xb9, 0x3f, 0xdf, 0x71, 0xbe, 0x7b, 0xba, + 0x66, 0xc8, 0xc5, 0x42, 0xc9, 0xba, 0x18, 0x63, + 0x45, 0x07, 0x2f, 0x84, 0x3e, 0xc3, 0xfb, 0x47, + 0xda, 0xd4, 0x1d, 0x0e, 0x9d, 0x96, 0xc0, 0xea, + 0xee, 0x45, 0x2f, 0xe1, 0x62, 0x23, 0xee, 0xef, + 0x3d, 0x5e, 0x55, 0xa1, 0x0d, 0x02, 0x81, 0x81, + 0x00, 0xeb, 0x76, 0x88, 0xd3, 0xae, 0x3f, 0x1d, + 0xf2, 0x49, 0xe0, 0x37, 0x49, 0x83, 0x82, 0x6c, + 0xf7, 0xf1, 0x17, 0x30, 0x75, 0x2e, 0x89, 0x06, + 0x88, 0x56, 0x32, 0xf6, 0xfa, 0x58, 0xcb, 0x3c, + 0x98, 0x67, 0xc3, 0xde, 0x10, 0x82, 0xe5, 0xfa, + 0xfa, 0x52, 0x47, 0x8d, 0xd7, 0x00, 0xc6, 0xcb, + 0xf7, 0xf6, 0x57, 0x9b, 0x6e, 0x0c, 0xac, 0xe8, + 0x3b, 0xd1, 0xde, 0xb5, 0x34, 0xaf, 0x8b, 0x2a, + 0xb0, 0x2d, 0x01, 0xeb, 0x7c, 0xa0, 0x42, 0x26, + 0xbb, 0x2b, 0x43, 0x0e, 0x1d, 0xe2, 0x4e, 0xc9, + 0xc1, 0x0a, 0x67, 0x1d, 0xfc, 0x83, 0x25, 0xce, + 0xb2, 0x18, 0xd9, 0x0d, 0x70, 0xf5, 0xa3, 0x5a, + 0x9c, 0x99, 0xdd, 0x47, 0xa1, 0x57, 0xe7, 0x20, + 0xde, 0xa1, 0x29, 0x8d, 0x96, 0x62, 0xf9, 0x26, + 0x95, 0x51, 0xa6, 0xe7, 0x09, 0x8b, 0xba, 0x16, + 0x8b, 0x19, 0x5b, 0xf9, 0x27, 0x0d, 0xc5, 0xd6, + 0x5f, 0x02, 0x81, 0x81, 0x00, 0xce, 0x26, 0x31, + 0xb5, 0x43, 0x53, 0x95, 0x39, 0xdd, 0x01, 0x98, + 0x8b, 0x3d, 0x27, 0xeb, 0x0b, 0x87, 0x1c, 0x95, + 0xfc, 0x3e, 0x36, 0x51, 0x31, 0xb5, 0xea, 0x59, + 0x56, 0xc0, 0x97, 0x62, 0xf0, 0x63, 0x2b, 0xb6, + 0x30, 0x9b, 0xdf, 0x19, 0x10, 0xe9, 0xa0, 0x3d, + 0xea, 0x54, 0x5a, 0xe6, 0xc6, 0x9e, 0x7e, 0xb5, + 0xf0, 0xb0, 0x54, 0xef, 0xc3, 0xe1, 0x47, 0xa6, + 0x95, 0xc7, 0xe4, 0xa3, 0x4a, 0x30, 0x68, 0x24, + 0x98, 0x7d, 0xc1, 0x34, 0xa9, 0xcb, 0xbc, 0x3c, + 0x08, 0x9c, 0x7d, 0x0c, 0xa2, 0xb7, 0x60, 0xaa, + 0x38, 0x08, 0x16, 0xa6, 0x7f, 0xdb, 0xd2, 0xb1, + 0x67, 0xe7, 0x93, 0x8e, 0xbb, 0x7e, 0xb9, 0xb5, + 0xd0, 0xd0, 0x9f, 0x7b, 0xcc, 0x46, 0xe6, 0x74, + 0x78, 0x1a, 0x96, 0xd6, 0xd7, 0x74, 0x34, 0x54, + 0x3b, 0x54, 0x55, 0x7f, 0x89, 0x81, 0xbc, 0x40, + 0x55, 0x87, 0x24, 0x95, 0x33, 0x02, 0x81, 0x81, + 0x00, 0xb0, 0x18, 0x5d, 0x2a, 0x1a, 0x95, 0x9f, + 0x9a, 0xd5, 0x3f, 0x37, 0x79, 0xe6, 0x3d, 0x83, + 0xab, 0x46, 0x86, 0x36, 0x3a, 0x5d, 0x0c, 0x23, + 0x73, 0x91, 0x2b, 0xda, 0x63, 0xce, 0x46, 0x68, + 0xd1, 0xfe, 0x40, 0x90, 0xf2, 0x3e, 0x43, 0x2b, + 0x19, 0x4c, 0xb1, 0xb0, 0xd5, 0x8c, 0x02, 0x21, + 0x07, 0x18, 0x17, 0xda, 0xe9, 0x49, 0xd7, 0x82, + 0x73, 0x42, 0x78, 0xd1, 0x82, 0x4e, 0x8a, 0xc0, + 0xe9, 0x33, 0x2f, 0xcd, 0x62, 0xce, 0x23, 0xca, + 0xfd, 0x8d, 0xd4, 0x3f, 0x59, 0x80, 0x27, 0xb6, + 0x61, 0x85, 0x9b, 0x2a, 0xe4, 0xef, 0x5c, 0x36, + 0x22, 0x21, 0xcd, 0x2a, 0x6d, 0x41, 0x77, 0xe2, + 0xcb, 0x5d, 0x93, 0x0d, 0x00, 0x10, 0x52, 0x8d, + 0xd5, 0x92, 0x28, 0x16, 0x78, 0xd3, 0x1a, 0x4c, + 0x8d, 0xbd, 0x9c, 0x1a, 0x0b, 0x9c, 0x91, 0x16, + 0x4c, 0xff, 0x31, 0x36, 0xbb, 0xcb, 0x64, 0x1a, + 0xf7, 0x02, 0x81, 0x80, 0x32, 0x65, 0x09, 0xdf, + 0xca, 0xee, 0xa2, 0xdb, 0x3b, 0x58, 0xc9, 0x86, + 0xb8, 0x53, 0x8a, 0xd5, 0x0d, 0x99, 0x82, 0x5c, + 0xe0, 0x84, 0x7c, 0xc2, 0xcf, 0x3a, 0xd3, 0xce, + 0x2e, 0x54, 0x93, 0xbe, 0x3a, 0x30, 0x14, 0x60, + 0xbb, 0xaa, 0x05, 0x41, 0xaa, 0x2b, 0x1f, 0x17, + 0xaa, 0xb9, 0x72, 0x12, 0xf9, 0xe9, 0xf5, 0xe6, + 0x39, 0xe4, 0xf9, 0x9c, 0x03, 0xf5, 0x75, 0x16, + 0xc6, 0x7f, 0xf1, 0x1f, 0x10, 0xc8, 0x54, 0xb1, + 0xe6, 0x84, 0x15, 0xb0, 0xb0, 0x7a, 0x7a, 0x9e, + 0x8c, 0x4a, 0xd1, 0x8c, 0xf1, 0x91, 0x32, 0xeb, + 0x71, 0xa6, 0xbf, 0xdb, 0x1f, 0xcc, 0xd8, 0xcb, + 0x92, 0xc3, 0xf2, 0xaf, 0x89, 0x22, 0x32, 0xfd, + 0x32, 0x12, 0xda, 0xbb, 0xac, 0x55, 0x68, 0x01, + 0x78, 0x56, 0x89, 0x7c, 0xb0, 0x0e, 0x9e, 0xcc, + 0xc6, 0x28, 0x04, 0x7e, 0x83, 0xf5, 0x96, 0x30, + 0x92, 0x51, 0xf2, 0x1b, 0x02, 0x81, 0x81, 0x00, + 0x83, 0x6d, 0xd1, 0x98, 0x90, 0x41, 0x8c, 0xa7, + 0x92, 0x83, 0xac, 0x89, 0x05, 0x0c, 0x79, 0x67, + 0x90, 0xb6, 0xa1, 0xf3, 0x2f, 0xca, 0xf0, 0x15, + 0xe0, 0x30, 0x58, 0xe9, 0x4f, 0xcb, 0x4c, 0x56, + 0x56, 0x56, 0x14, 0x3f, 0x1b, 0x79, 0xb6, 0xef, + 0x57, 0x4b, 0x28, 0xbd, 0xb0, 0xe6, 0x0c, 0x49, + 0x4b, 0xbe, 0xe1, 0x57, 0x28, 0x2a, 0x23, 0x5e, + 0xc4, 0xa2, 0x19, 0x4b, 0x00, 0x67, 0x78, 0xd9, + 0x26, 0x6e, 0x17, 0x25, 0xce, 0xe4, 0xfd, 0xde, + 0x86, 0xa8, 0x5a, 0x67, 0x47, 0x6b, 0x15, 0x09, + 0xe1, 0xec, 0x8e, 0x62, 0x98, 0x91, 0x6f, 0xc0, + 0x98, 0x0c, 0x70, 0x0e, 0x7d, 0xbe, 0x63, 0xbd, + 0x12, 0x5a, 0x98, 0x1c, 0xe3, 0x0c, 0xfb, 0xc7, + 0xfb, 0x1b, 0xbd, 0x02, 0x87, 0xcc, 0x0c, 0xbb, + 0xc2, 0xd4, 0xb6, 0xc1, 0xa1, 0x23, 0xd3, 0x1e, + 0x21, 0x6f, 0x48, 0xba, 0x0e, 0x2e, 0xc7, 0x42 +}; + +static const uint8_t rsa2048_public_key[] = { + 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, + 0x00, 0xbd, 0x9c, 0x83, 0x6b, 0x0e, 0x8e, 0xcf, + 0xfa, 0xaa, 0x4f, 0x6a, 0xf4, 0xe3, 0x52, 0x0f, + 0xa5, 0xd0, 0xbe, 0x5e, 0x7f, 0x08, 0x24, 0xba, + 0x87, 0x46, 0xfb, 0x28, 0x93, 0xe5, 0xe5, 0x81, + 0x42, 0xc0, 0xf9, 0x17, 0xc7, 0x81, 0x01, 0xf4, + 0x18, 0x6a, 0x17, 0xf5, 0x57, 0x20, 0x37, 0xcf, + 0xf9, 0x74, 0x5e, 0xe1, 0x48, 0x6a, 0x71, 0x0a, + 0x0f, 0x79, 0x72, 0x2b, 0x46, 0x10, 0x53, 0xdc, + 0x14, 0x43, 0xbd, 0xbc, 0x6d, 0x15, 0x6f, 0x15, + 0x4e, 0xf0, 0x0d, 0x89, 0x39, 0x02, 0xc3, 0x68, + 0x5c, 0xa8, 0xfc, 0xed, 0x64, 0x9d, 0x98, 0xb7, + 0xcd, 0x83, 0x66, 0x93, 0xc3, 0xd9, 0x57, 0xa0, + 0x21, 0x93, 0xad, 0x5c, 0x75, 0x69, 0x88, 0x9e, + 0x81, 0xdc, 0x7f, 0x1d, 0xd5, 0xbd, 0x1c, 0xc1, + 0x30, 0x56, 0xa5, 0xda, 0x99, 0x46, 0xa6, 0x6d, + 0x0e, 0x6f, 0x5e, 0x51, 0x34, 0x49, 0x73, 0xc3, + 0x67, 0x49, 0x7e, 0x21, 0x2a, 0x20, 0xa7, 0x2b, + 0x92, 0x73, 0x1d, 0xa5, 0x25, 0x2a, 0xd0, 0x3a, + 0x89, 0x75, 0xb2, 0xbb, 0x19, 0x37, 0x78, 0x48, + 0xd2, 0xf2, 0x2a, 0x6d, 0x9e, 0xc6, 0x26, 0xca, + 0x46, 0x8c, 0xf1, 0x42, 0x2a, 0x31, 0xb2, 0xfc, + 0xe7, 0x55, 0x51, 0xff, 0x07, 0x13, 0x5b, 0x36, + 0x59, 0x2b, 0x43, 0x30, 0x4b, 0x05, 0x5c, 0xd2, + 0x45, 0xa0, 0xa0, 0x7c, 0x17, 0x5b, 0x07, 0xbb, + 0x5d, 0x83, 0x80, 0x92, 0x6d, 0x87, 0x1a, 0x43, + 0xac, 0xc7, 0x6b, 0x8d, 0x11, 0x60, 0x27, 0xd2, + 0xdf, 0xdb, 0x71, 0x02, 0x55, 0x6e, 0xb5, 0xca, + 0x4d, 0xda, 0x59, 0x0d, 0xb8, 0x8c, 0xcd, 0xd3, + 0x0e, 0x55, 0xa0, 0xa4, 0x8d, 0xa0, 0x14, 0x10, + 0x48, 0x42, 0x35, 0x56, 0x08, 0xf7, 0x29, 0x5f, + 0xa2, 0xea, 0xa4, 0x5e, 0x8e, 0x99, 0x56, 0xaa, + 0x5a, 0x8c, 0x23, 0x8f, 0x35, 0x22, 0x8a, 0xff, + 0xed, 0x02, 0x03, 0x01, 0x00, 0x01 +}; + +static const uint8_t test_sha1_dgst[] = { + 0x3c, 0x05, 0x19, 0x34, 0x29, 0x19, 0xc7, 0xe0, + 0x87, 0xb6, 0x24, 0xf9, 0x58, 0xac, 0xa4, 0xd4, + 0xb2, 0xd9, 0x03, 0x9e, +}; + +static const uint8_t exp_signature_rsa2048_pkcs1[] = { + 0x4e, 0x82, 0x56, 0x4c, 0x84, 0x66, 0xca, 0x1e, + 0xc6, 0x92, 0x46, 0x20, 0x02, 0x6b, 0x64, 0x46, + 0x15, 0x6b, 0x24, 0xf2, 0xbb, 0xfa, 0x44, 0x3c, + 0xaf, 0x42, 0xc8, 0x41, 0xfd, 0xce, 0xed, 0x95, + 0x34, 0xaf, 0x25, 0x09, 0xd1, 0x06, 0x94, 0xaa, + 0x52, 0xd4, 0x29, 0xc8, 0x52, 0x34, 0x67, 0x59, + 0x4f, 0x5a, 0xfd, 0x23, 0x30, 0x5e, 0xc7, 0x1e, + 0xa6, 0xe0, 0x1b, 0x23, 0xca, 0x82, 0x47, 0x9a, + 0x2e, 0x2c, 0x66, 0x45, 0x5a, 0x12, 0xa9, 0x15, + 0xbf, 0xd6, 0xd6, 0xfa, 0x8d, 0x60, 0x99, 0x89, + 0x91, 0x39, 0x06, 0xb7, 0xd3, 0x9a, 0xef, 0x15, + 0x7b, 0x95, 0x87, 0x77, 0x2c, 0x41, 0xd4, 0x71, + 0xd5, 0xdf, 0x22, 0x7b, 0x01, 0xe2, 0xc1, 0xfb, + 0xb9, 0x4e, 0x0c, 0x9b, 0xd5, 0x04, 0xed, 0x2b, + 0x7e, 0x73, 0x53, 0xaa, 0x33, 0x89, 0x9d, 0x95, + 0x28, 0x8f, 0x8b, 0x80, 0x34, 0x7a, 0xea, 0xe3, + 0x66, 0x8a, 0xa8, 0xad, 0xed, 0x91, 0x43, 0xdd, + 0x77, 0xe5, 0xd7, 0x16, 0xda, 0xa8, 0x00, 0x29, + 0x3f, 0x9f, 0xe0, 0x1d, 0x42, 0x9d, 0x35, 0x5d, + 0x0f, 0xf3, 0x90, 0x27, 0x3a, 0x8c, 0x46, 0x13, + 0x53, 0x3e, 0x3b, 0x38, 0x77, 0xf8, 0x57, 0x61, + 0xbc, 0xc4, 0x54, 0x68, 0x48, 0xae, 0x58, 0x03, + 0x33, 0x94, 0x3f, 0x18, 0x1e, 0xb3, 0x3f, 0x79, + 0xa7, 0x26, 0x92, 0x5d, 0x32, 0x2a, 0xdb, 0xe6, + 0x3a, 0xe8, 0xd7, 0xaa, 0x91, 0xfe, 0x9f, 0x06, + 0x26, 0x68, 0x8c, 0x27, 0x31, 0xb0, 0x04, 0x9e, + 0x94, 0x79, 0x63, 0xa1, 0xc7, 0xe8, 0x5b, 0x8c, + 0xd3, 0xf1, 0x88, 0x58, 0x31, 0x2f, 0x4e, 0x11, + 0x00, 0xfe, 0x29, 0xad, 0x2c, 0xa9, 0x8e, 0x63, + 0xd8, 0x7d, 0xc5, 0xa1, 0x71, 0xfa, 0x08, 0x29, + 0xea, 0xd6, 0x6c, 0x53, 0x00, 0x52, 0xa0, 0xed, + 0x6b, 0x7c, 0x67, 0x50, 0x71, 0x2d, 0x96, 0x7a, +}; + +static const uint8_t exp_signature_rsa1024_pkcs1[] = { + 0x6b, 0x5b, 0xbb, 0x3b, 0x1f, 0x08, 0xd8, 0xc0, + 0x4a, 0xf1, 0x5a, 0x12, 0xc2, 0x39, 0x14, 0x65, + 0x4f, 0xda, 0x79, 0x67, 0xf2, 0x89, 0x25, 0xad, + 0x9e, 0x7e, 0xba, 0xa8, 0x34, 0x15, 0x03, 0xdd, + 0x80, 0x6b, 0x01, 0xd7, 0x4a, 0xf3, 0xd6, 0xef, + 0x1e, 0x48, 0xf3, 0xbc, 0x75, 0x1a, 0xc4, 0x2c, + 0x90, 0x15, 0x9f, 0x21, 0x24, 0x98, 0x21, 0xef, + 0x6d, 0x3b, 0xf3, 0x82, 0x8f, 0x8d, 0xd8, 0x48, + 0x37, 0x16, 0x19, 0x8e, 0x3c, 0x64, 0xa0, 0x9e, + 0xf7, 0x0c, 0xd9, 0x5c, 0xc6, 0x13, 0xc4, 0x5f, + 0xf8, 0xf3, 0x59, 0x5b, 0xd0, 0x33, 0x95, 0x98, + 0xde, 0x67, 0x25, 0x58, 0x46, 0xba, 0xee, 0x0f, + 0x47, 0x7a, 0x7f, 0xd0, 0xe4, 0x77, 0x09, 0x17, + 0xe9, 0x81, 0x6e, 0x2d, 0x33, 0x9b, 0x13, 0x0b, + 0xc9, 0xb2, 0x0c, 0x2c, 0xb5, 0xdf, 0x52, 0x8f, + 0xab, 0x0d, 0xc6, 0x59, 0x1d, 0xc7, 0x33, 0x7b, +}; + +static const uint8_t test_plaintext[] = { + 0x00, 0x44, 0xbc, 0x6f, 0x77, 0xfb, 0xe2, 0xa4, + 0x98, 0x9e, 0xf5, 0x33, 0xa0, 0xbd, 0x81, 0xb9, + 0xf1, 0x44, 0x7f, 0x79, 0x89, 0x23, 0xe5, 0x46, + 0x66, 0x9f, 0x98, 0x95, 0x6f, 0x56, 0x78, 0xf6, + 0xf5, 0xac, 0x9c, 0xda, 0xc2, 0x79, 0x59, 0xf0, + 0x1b, 0x03, 0xfa, 0x46, 0x1c, 0x1f, 0x18, 0x07, + 0xce, 0xad, 0xed, 0x3d, 0x11, 0xf9, 0x1b, 0x26, + 0x4a, 0x97, 0x28, 0x71, 0x5f, 0x2c, 0x5e, 0x58, + 0xf0, 0xd6, 0xbf, 0xa4, 0x12, 0xd0, 0x1d, 0x07, + 0xcb, 0x73, 0x66, 0xb6, 0xa4, 0x09, 0xaf, 0x5d, + 0xe9, 0x14, 0x14, 0xaf, 0x69, 0xd6, 0xee, 0x0a, + 0xfc, 0xca, 0xac, 0x94, 0x47, 0xd5, 0x9d, 0x5b, + 0x2b, 0xfb, 0xce, 0x9d, 0x04, 0xc1, 0xaf, 0xa5, + 0xa1, 0x8d, 0xa9, 0x48, 0xa8, 0x65, 0xe6, 0x9f, + 0x74, 0x78, 0x16, 0x32, 0x93, 0xb5, 0x21, 0xb9, + 0x9f, 0x3f, 0xc1, 0xe5, 0xa2, 0x50, 0x8b, 0x12, + 0xfb, 0x3e, 0xb0, 0x8a, 0x00, 0xc7, 0x20, 0x56, + 0xb3, 0xb1, 0x29, 0x95, 0x89, 0xd6, 0x50, 0xf5, + 0x37, 0x38, 0x8e, 0x12, 0xf1, 0xba, 0x82, 0x37, + 0x34, 0x68, 0x4b, 0xe8, 0xe3, 0x11, 0x1c, 0x46, + 0xf9, 0x63, 0x3a, 0xd6, 0xf3, 0x3f, 0x55, 0xa6, + 0xbd, 0x89, 0xf1, 0x2d, 0x38, 0x91, 0x7c, 0xc2, + 0x4d, 0xf1, 0x69, 0x82, 0x6d, 0x71, 0x77, 0xf4, + 0xfc, 0x43, 0x20, 0x6f, 0x43, 0xb9, 0x43, 0xd1, + 0x65, 0xbd, 0xca, 0xb1, 0x43, 0x87, 0xf8, 0xc8, + 0x76, 0x21, 0xa9, 0xeb, 0x3e, 0x9a, 0xef, 0xc9, + 0x0e, 0x79, 0xbc, 0xf0, 0xf8, 0xc8, 0xe2, 0xbc, + 0x33, 0x35, 0x3e, 0xfc, 0xf9, 0x44, 0x69, 0x06, + 0x7c, 0x7f, 0x5d, 0xa2, 0x9e, 0xab, 0xc2, 0x82, + 0xa0, 0xfb, 0xc5, 0x79, 0x57, 0x8c, 0xf1, 0x1c, + 0x51, 0x64, 0x4c, 0x56, 0x08, 0x80, 0x32, 0xf4, + 0x97, 0x8f, 0x6f, 0xb2, 0x16, 0xa6, 0x9d, 0x71, +}; + +static const uint8_t exp_ciphertext_rsa1024_raw[] = { + 0x01, 0xa0, 0xc2, 0x94, 0x9f, 0xd6, 0xbe, 0x8d, + 0xe9, 0x24, 0xaa, 0x9c, 0x67, 0xd7, 0xe3, 0x04, + 0x34, 0xbf, 0xd3, 0x27, 0xa1, 0x43, 0xeb, 0x60, + 0x6b, 0x5b, 0x64, 0x15, 0x55, 0x16, 0x98, 0x35, + 0xc2, 0x59, 0xa7, 0xf7, 0x24, 0xf7, 0x05, 0xb9, + 0xe8, 0x56, 0x6f, 0xf2, 0x7d, 0x8b, 0x3c, 0xcb, + 0xa6, 0xc2, 0xac, 0x0c, 0x37, 0x8c, 0x70, 0x70, + 0x55, 0x05, 0x07, 0x0d, 0x63, 0x6b, 0x7d, 0x5f, + 0xae, 0x03, 0x1e, 0x55, 0x05, 0xbb, 0xa8, 0xe7, + 0xff, 0xa0, 0x8c, 0x5b, 0x6b, 0x01, 0x48, 0x2e, + 0x4f, 0x7f, 0xe2, 0x74, 0xc6, 0x32, 0xa7, 0x2d, + 0xdb, 0x91, 0x9b, 0x67, 0x4d, 0x71, 0xf9, 0x8c, + 0x42, 0x43, 0x75, 0x4e, 0xd0, 0x0e, 0x7c, 0xa0, + 0x97, 0x1a, 0x5f, 0x8e, 0x6f, 0xe4, 0xfa, 0x16, + 0x1d, 0x59, 0x0e, 0x0b, 0x11, 0x12, 0xa3, 0x0c, + 0xa6, 0x55, 0xe6, 0xdb, 0xa7, 0x71, 0xa6, 0xff, +}; + +static const uint8_t exp_ciphertext_rsa1024_pkcs1[] = { + 0x93, 0x78, 0x6a, 0x76, 0xb8, 0x94, 0xea, 0xe4, + 0x32, 0x79, 0x01, 0x8b, 0xc1, 0xcb, 0x2e, 0x2d, + 0xfe, 0xdc, 0x9b, 0xe3, 0xe9, 0x23, 0xe4, 0x0a, + 0xb0, 0x6b, 0x9f, 0x6b, 0x62, 0xf5, 0x3d, 0xf0, + 0x78, 0x84, 0x77, 0x21, 0xad, 0x0b, 0x30, 0x30, + 0x94, 0xe2, 0x18, 0xc4, 0x9b, 0x12, 0x06, 0xc8, + 0xaa, 0xf7, 0x30, 0xe4, 0xc8, 0x64, 0xe7, 0x51, + 0xf1, 0x6a, 0xe1, 0xa2, 0x58, 0x7a, 0x02, 0x9c, + 0x8e, 0xf0, 0x2d, 0x25, 0x6b, 0xb7, 0x25, 0x5e, + 0x05, 0xaf, 0x38, 0xb2, 0x69, 0x5e, 0x6c, 0x75, + 0x6e, 0x27, 0xba, 0x5d, 0x7d, 0x35, 0x72, 0xb7, + 0x25, 0xd4, 0xaa, 0xb2, 0x4b, 0x9e, 0x6b, 0x82, + 0xb2, 0x32, 0xe2, 0x13, 0x1d, 0x00, 0x21, 0x08, + 0xae, 0x14, 0xbb, 0xc0, 0x40, 0xb7, 0x0d, 0xd5, + 0x0e, 0x4d, 0x6d, 0x9a, 0x70, 0x86, 0xe9, 0xfc, + 0x67, 0x2b, 0xa4, 0x11, 0x45, 0xb6, 0xc4, 0x2f, +}; + +static const uint8_t exp_ciphertext_rsa2048_raw[] = { + 0x09, 0x7b, 0x9e, 0x7c, 0x10, 0x1f, 0x73, 0xb4, + 0x5f, 0xdb, 0x4f, 0x05, 0xe7, 0xfc, 0x9e, 0x35, + 0x48, 0xd8, 0xc8, 0xf5, 0xac, 0x6d, 0xb4, 0xb0, + 0xd4, 0xf7, 0x69, 0x0f, 0x30, 0x78, 0xbb, 0x55, + 0x67, 0x66, 0x66, 0x05, 0xf4, 0x77, 0xe2, 0x30, + 0xa5, 0x94, 0x10, 0xa3, 0xcb, 0xee, 0x13, 0x9f, + 0x47, 0x1b, 0x2e, 0xf9, 0xfd, 0x94, 0x09, 0xbd, + 0x26, 0x6e, 0x84, 0xc7, 0x5c, 0x42, 0x20, 0x76, + 0x72, 0x83, 0x75, 0x68, 0xa4, 0x18, 0x2d, 0x76, + 0x62, 0xc3, 0xab, 0xc0, 0xc9, 0x36, 0x59, 0xe0, + 0xa9, 0x70, 0x1f, 0xff, 0x97, 0x07, 0x0d, 0x88, + 0xc2, 0xd8, 0x51, 0x35, 0xf7, 0xb0, 0x50, 0xe4, + 0x9f, 0x3d, 0xd4, 0x71, 0x8b, 0x40, 0x89, 0x71, + 0x6c, 0xd8, 0xc2, 0x63, 0xb6, 0x3a, 0xce, 0xb1, + 0x32, 0xf1, 0xc6, 0x11, 0x31, 0x25, 0x48, 0xcf, + 0xeb, 0xbc, 0xd3, 0x9b, 0xc5, 0xbd, 0xd2, 0x57, + 0x73, 0x9b, 0x20, 0xb8, 0xdf, 0xbe, 0xb8, 0x40, + 0xb6, 0xac, 0x24, 0xdb, 0x94, 0x6a, 0x93, 0x43, + 0x4a, 0xa8, 0xa3, 0xcf, 0xd5, 0x61, 0x1b, 0x46, + 0x1d, 0x6f, 0x57, 0xec, 0xa6, 0xd0, 0x44, 0x05, + 0x48, 0xb8, 0x90, 0x80, 0x23, 0x8e, 0x5f, 0xb0, + 0x4b, 0x6f, 0xe3, 0xf9, 0xb0, 0x04, 0x60, 0xae, + 0x80, 0xcf, 0xa5, 0x5c, 0x11, 0xe4, 0xce, 0x57, + 0x5b, 0xbb, 0xde, 0x92, 0xfc, 0xe7, 0x3f, 0xe0, + 0xfc, 0x06, 0xc8, 0xf3, 0x8c, 0xac, 0x86, 0x09, + 0x31, 0xe5, 0x7e, 0xfb, 0x5d, 0xa7, 0x57, 0xf8, + 0x1d, 0x23, 0x9d, 0xa3, 0xeb, 0x53, 0x28, 0xde, + 0xbf, 0x53, 0xef, 0x35, 0x3c, 0x7e, 0x3c, 0x1b, + 0x76, 0x9d, 0x09, 0x25, 0x43, 0xd4, 0x8b, 0xca, + 0xda, 0x45, 0x5b, 0xdc, 0x9f, 0x57, 0x5a, 0x30, + 0x2e, 0xe9, 0x73, 0x68, 0x28, 0xfa, 0x40, 0xb0, + 0x7c, 0x31, 0xd7, 0x8b, 0x4e, 0x99, 0x94, 0xf1, +}; + +static const uint8_t exp_ciphertext_rsa2048_pkcs1[] = { + 0xa5, 0x19, 0x19, 0x34, 0xad, 0xf6, 0xd2, 0xbe, + 0xed, 0x8f, 0xe5, 0xfe, 0xa2, 0xa5, 0x20, 0x08, + 0x15, 0x53, 0x7c, 0x68, 0x28, 0xae, 0x07, 0xb2, + 0x4c, 0x5d, 0xee, 0xc1, 0xc6, 0xdc, 0xd6, 0x8b, + 0xc6, 0xba, 0x46, 0xe1, 0x16, 0xa9, 0x04, 0x72, + 0xdf, 0x8f, 0x1e, 0x97, 0x2a, 0x55, 0xe7, 0xac, + 0x08, 0x0d, 0x61, 0xe8, 0x64, 0x8b, 0x6f, 0x96, + 0x0e, 0xbb, 0x8a, 0x30, 0xb3, 0x73, 0x28, 0x61, + 0x16, 0x89, 0x90, 0x88, 0x8e, 0xda, 0x22, 0xe6, + 0x42, 0x16, 0xc7, 0xe8, 0x30, 0x0d, 0x7f, 0x44, + 0x1e, 0xef, 0xe6, 0xdb, 0x78, 0x54, 0x89, 0xa5, + 0x60, 0x67, 0xb3, 0x35, 0x2d, 0x79, 0x49, 0xcf, + 0xe6, 0x8f, 0xf3, 0x64, 0x52, 0x1c, 0x6c, 0x43, + 0x7e, 0xb0, 0xde, 0x55, 0xdf, 0xbe, 0xb7, 0xb1, + 0xdb, 0x02, 0xee, 0x76, 0x96, 0xcc, 0x0b, 0x97, + 0x8c, 0x23, 0xaa, 0x7d, 0x4c, 0x47, 0x28, 0x41, + 0x7a, 0x20, 0x39, 0x1f, 0x64, 0x0b, 0xf1, 0x74, + 0xf1, 0x29, 0xda, 0xe9, 0x3a, 0x36, 0xa6, 0x88, + 0xb8, 0xc0, 0x21, 0xb8, 0x9b, 0x5d, 0x90, 0x85, + 0xa3, 0x30, 0x61, 0x17, 0x8c, 0x74, 0x63, 0xd5, + 0x0f, 0x95, 0xdc, 0xc8, 0x4f, 0xa7, 0x24, 0x55, + 0x40, 0xe2, 0x84, 0x57, 0x65, 0x06, 0x11, 0x30, + 0x2b, 0x9e, 0x32, 0x95, 0x39, 0xf2, 0x1a, 0x3f, + 0xab, 0xcd, 0x7b, 0x7f, 0x9c, 0xf0, 0x00, 0x50, + 0x7c, 0xf4, 0xbe, 0xcb, 0x80, 0xea, 0x66, 0xba, + 0x0e, 0x7b, 0x46, 0x0b, 0x25, 0xe0, 0xc1, 0x03, + 0x29, 0x11, 0x2d, 0x69, 0x4f, 0x21, 0xa2, 0x58, + 0x37, 0x4b, 0x84, 0x15, 0xb3, 0x65, 0x3a, 0xac, + 0xd4, 0xd0, 0xf6, 0xdf, 0x4b, 0x82, 0xca, 0x9e, + 0xbb, 0xbe, 0x3c, 0x4d, 0xd5, 0xbf, 0x00, 0xd6, + 0x12, 0x48, 0x72, 0x0b, 0xc7, 0xf8, 0xe1, 0xcd, + 0xd0, 0x28, 0x03, 0x19, 0xa6, 0x06, 0x13, 0x45, +}; + +typedef struct QCryptoAkCipherTestData QCryptoAkCipherTestData; +struct QCryptoAkCipherTestData { + const char *path; + QCryptoAkCipherOptions opt; + + const uint8_t *priv_key; + size_t priv_key_len; + const uint8_t *pub_key; + size_t pub_key_len; + + const uint8_t *plaintext; + size_t plen; + const uint8_t *ciphertext; + size_t clen; + const uint8_t *dgst; + size_t dlen; + const uint8_t *signature; + size_t slen; +}; + +static QCryptoAkCipherTestData test_data[] = { + /* rsa1024 with raw padding */ + { + .path = "/crypto/akcipher/rsa1024-raw", + .opt = { + .alg = QCRYPTO_AKCIPHER_ALG_RSA, + .u.rsa = { + .padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW, + }, + }, + .pub_key = rsa1024_public_key, + .pub_key_len = sizeof(rsa1024_public_key), + .priv_key = rsa1024_private_key, + .priv_key_len = sizeof(rsa1024_private_key), + + .plaintext = test_plaintext, + .plen = 128, + .ciphertext = exp_ciphertext_rsa1024_raw, + .clen = sizeof(exp_ciphertext_rsa1024_raw), + }, + + /* rsa1024 with pkcs1 padding */ + { + .path = "/crypto/akcipher/rsa1024-pkcs1", + .opt = { + .alg = QCRYPTO_AKCIPHER_ALG_RSA, + .u.rsa = { + .padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1, + .hash_alg = QCRYPTO_HASH_ALG_SHA1, + }, + }, + .pub_key = rsa1024_public_key, + .pub_key_len = sizeof(rsa1024_public_key), + .priv_key = rsa1024_private_key, + .priv_key_len = sizeof(rsa1024_private_key), + + .plaintext = test_plaintext, + .plen = 64, + .ciphertext = exp_ciphertext_rsa1024_pkcs1, + .clen = sizeof(exp_ciphertext_rsa1024_pkcs1), + .dgst = test_sha1_dgst, + .dlen = sizeof(test_sha1_dgst), + .signature = exp_signature_rsa1024_pkcs1, + .slen = sizeof(exp_signature_rsa1024_pkcs1), + }, + + /* rsa2048 with raw padding */ + { + .path = "/crypto/akcipher/rsa2048-raw", + .opt = { + .alg = QCRYPTO_AKCIPHER_ALG_RSA, + .u.rsa = { + .padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW, + }, + }, + .pub_key = rsa2048_public_key, + .pub_key_len = sizeof(rsa2048_public_key), + .priv_key = rsa2048_private_key, + .priv_key_len = sizeof(rsa2048_private_key), + + .plaintext = test_plaintext, + .plen = 256, + .ciphertext = exp_ciphertext_rsa2048_raw, + .clen = sizeof(exp_ciphertext_rsa2048_raw), + }, + + /* rsa2048 with pkcs1 padding */ + { + .path = "/crypto/akcipher/rsa2048-pkcs1", + .opt = { + .alg = QCRYPTO_AKCIPHER_ALG_RSA, + .u.rsa = { + .padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1, + .hash_alg = QCRYPTO_HASH_ALG_SHA1, + }, + }, + .pub_key = rsa2048_public_key, + .pub_key_len = sizeof(rsa2048_public_key), + .priv_key = rsa2048_private_key, + .priv_key_len = sizeof(rsa2048_private_key), + + .plaintext = test_plaintext, + .plen = 128, + .ciphertext = exp_ciphertext_rsa2048_pkcs1, + .clen = sizeof(exp_ciphertext_rsa2048_pkcs1), + .dgst = test_sha1_dgst, + .dlen = sizeof(test_sha1_dgst), + .signature = exp_signature_rsa2048_pkcs1, + .slen = sizeof(exp_signature_rsa2048_pkcs1), + }, + +}; + +static void test_akcipher(const void *opaque) +{ + const QCryptoAkCipherTestData *data = opaque; + g_autofree uint8_t *plaintext = NULL; + g_autofree uint8_t *ciphertext = NULL; + g_autofree uint8_t *signature = NULL; + QCryptoAkCipher *pub_key, *priv_key; + + if (!qcrypto_akcipher_supports((QCryptoAkCipherOptions *)&data->opt)) { + return; + } + pub_key = qcrypto_akcipher_new(&data->opt, + QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, + data->pub_key, data->pub_key_len, + &error_abort); + g_assert(pub_key != NULL); + priv_key = qcrypto_akcipher_new(&data->opt, + QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, + data->priv_key, data->priv_key_len, + &error_abort); + g_assert(priv_key != NULL); + + if (data->plaintext != NULL) { + + ciphertext = g_new0(uint8_t, data->clen); + g_assert(qcrypto_akcipher_encrypt(pub_key, data->plaintext, data->plen, + ciphertext, data->clen, + &error_abort) > 0); + + /** + * In the asymmetric encryption algorithms, the ciphertext generated + * each time may be different, here only compare the decrypted + * plaintext + */ + plaintext = g_new0(uint8_t, data->clen); + g_assert(qcrypto_akcipher_decrypt(priv_key, ciphertext, + data->clen, plaintext, + data->plen, + &error_abort) == data->plen); + g_assert(!memcmp(plaintext, data->plaintext, data->plen)); + } + + if (data->signature != NULL) { + signature = g_new(uint8_t, data->slen); + g_assert(qcrypto_akcipher_sign(priv_key, data->dgst, data->dlen, + signature, data->slen, + &error_abort) > 0); + /** + * The signature generated each time may be different, here only check + * the verification. + */ + g_assert(qcrypto_akcipher_verify(pub_key, data->signature, data->slen, + data->dgst, data->dlen, + &error_abort) == 0); + g_assert(qcrypto_akcipher_verify(pub_key, signature, data->slen, + data->dgst, data->dlen, + &error_abort) == 0); + ++signature[0]; + /* Here error should be ignored */ + g_assert(qcrypto_akcipher_verify(pub_key, signature, data->slen, + data->dgst, data->dlen, NULL) != 0); + } + + qcrypto_akcipher_free(pub_key); + qcrypto_akcipher_free(priv_key); +} + +int main(int argc, char **argv) +{ + size_t i; + g_test_init(&argc, &argv, NULL); + g_assert(qcrypto_init(NULL) == 0); + + for (i = 0; i < G_N_ELEMENTS(test_data); i++) { + g_test_add_data_func(test_data[i].path, &test_data[i], test_akcipher); + } + + return g_test_run(); +} From f0cfb761bc6e590d648b759e6bdb8c946062b5f5 Mon Sep 17 00:00:00 2001 From: Lei He Date: Wed, 25 May 2022 17:01:17 +0800 Subject: [PATCH 528/935] tests/crypto: Add test suite for RSA keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As Daniel suggested, Add tests suite for rsakey, as a way to prove that we can handle DER errors correctly. Signed-off-by: lei he Signed-off-by: Daniel P. Berrangé --- tests/unit/test-crypto-akcipher.c | 285 +++++++++++++++++++++++++++++- 1 file changed, 282 insertions(+), 3 deletions(-) diff --git a/tests/unit/test-crypto-akcipher.c b/tests/unit/test-crypto-akcipher.c index b5be563884..4f1f4214dd 100644 --- a/tests/unit/test-crypto-akcipher.c +++ b/tests/unit/test-crypto-akcipher.c @@ -517,6 +517,158 @@ static const uint8_t exp_ciphertext_rsa2048_pkcs1[] = { 0xd0, 0x28, 0x03, 0x19, 0xa6, 0x06, 0x13, 0x45, }; +static const uint8_t rsa_private_key_lack_element[] = { + /* RSAPrivateKey, offset: 0, length: 176 */ + 0x30, 0x81, 0xb0, + /* version, offset: 4, length: 1 */ + 0x02, 0x01, 0x00, + /* n, offset: 7, length: 65 */ + 0x02, 0x41, + 0x00, 0xb9, 0xe1, 0x22, 0xdb, 0x56, 0x2f, 0xb6, + 0xf7, 0xf0, 0x0a, 0x87, 0x43, 0x07, 0x12, 0xdb, + 0x6d, 0xb6, 0x2b, 0x41, 0x8d, 0x2c, 0x3c, 0xa5, + 0xdd, 0x78, 0x9a, 0x8f, 0xab, 0x8e, 0xf2, 0x4a, + 0xc8, 0x34, 0x0c, 0x12, 0x4f, 0x11, 0x90, 0xc6, + 0xc2, 0xa5, 0xd0, 0xcd, 0xfb, 0xfc, 0x2c, 0x95, + 0x56, 0x82, 0xdf, 0x39, 0xf3, 0x3b, 0x1d, 0x62, + 0x26, 0x97, 0xb7, 0x93, 0x25, 0xc7, 0xec, 0x7e, + 0xf7, + /* e, offset: 74, length: 3 */ + 0x02, 0x03, 0x01, 0x00, 0x01, + /* d, offset: 79, length: 64 */ + 0x02, 0x40, + 0x1e, 0x80, 0xfe, 0xda, 0x65, 0xdb, 0x70, 0xb8, + 0x61, 0x91, 0x28, 0xbf, 0x6c, 0x32, 0xc1, 0x05, + 0xd1, 0x26, 0x6a, 0x1c, 0x83, 0xcc, 0xf4, 0x1f, + 0x53, 0x42, 0x72, 0x1f, 0x62, 0x57, 0x0a, 0xc4, + 0x66, 0x76, 0x30, 0x87, 0xb9, 0xb1, 0xb9, 0x6a, + 0x63, 0xfd, 0x8f, 0x3e, 0xfc, 0x35, 0x3f, 0xd6, + 0x2e, 0x6c, 0xc8, 0x70, 0x8a, 0x17, 0xc1, 0x28, + 0x6a, 0xfe, 0x51, 0x56, 0xb3, 0x92, 0x6f, 0x09, + /* p, offset: 145, length: 33 */ + 0x02, 0x21, + 0x00, 0xe3, 0x2e, 0x2d, 0x8d, 0xba, 0x1c, 0x34, + 0x4c, 0x49, 0x9f, 0xc1, 0xa6, 0xdd, 0xd7, 0x13, + 0x8d, 0x05, 0x48, 0xdd, 0xff, 0x5c, 0x30, 0xbc, + 0x6b, 0xc4, 0x18, 0x9d, 0xfc, 0xa2, 0xd0, 0x9b, + 0x4d, + /* q, offset: 180, length: 33 */ + 0x02, 0x21, + 0x00, 0xd1, 0x75, 0xaf, 0x4b, 0xc6, 0x1a, 0xb0, + 0x98, 0x14, 0x42, 0xae, 0x33, 0xf3, 0x44, 0xde, + 0x21, 0xcb, 0x04, 0xda, 0xfb, 0x1e, 0x35, 0x92, + 0xcd, 0x69, 0xc0, 0x83, 0x06, 0x83, 0x8e, 0x39, + 0x53, + /* lack element: dp, dq, u */ +}; + +static const uint8_t rsa_public_key_lack_element[] = { + /* RSAPublicKey, offset: 0, length: 67 */ + 0x30, 0x81, 0x43, + /* n, offset: 7, length: 65 */ + 0x02, 0x41, + 0x00, 0xb9, 0xe1, 0x22, 0xdb, 0x56, 0x2f, 0xb6, + 0xf7, 0xf0, 0x0a, 0x87, 0x43, 0x07, 0x12, 0xdb, + 0x6d, 0xb6, 0x2b, 0x41, 0x8d, 0x2c, 0x3c, 0xa5, + 0xdd, 0x78, 0x9a, 0x8f, 0xab, 0x8e, 0xf2, 0x4a, + 0xc8, 0x34, 0x0c, 0x12, 0x4f, 0x11, 0x90, 0xc6, + 0xc2, 0xa5, 0xd0, 0xcd, 0xfb, 0xfc, 0x2c, 0x95, + 0x56, 0x82, 0xdf, 0x39, 0xf3, 0x3b, 0x1d, 0x62, + 0x26, 0x97, 0xb7, 0x93, 0x25, 0xc7, 0xec, 0x7e, + 0xf7, + /* lack element: e */ +}; + +static const uint8_t rsa_public_key_empty_element[] = { + /* RSAPublicKey, offset: 0, length: 69 */ + 0x30, 0x81, 0x45, + /* n, offset: 7, length: 65 */ + 0x02, 0x41, + 0x00, 0xb9, 0xe1, 0x22, 0xdb, 0x56, 0x2f, 0xb6, + 0xf7, 0xf0, 0x0a, 0x87, 0x43, 0x07, 0x12, 0xdb, + 0x6d, 0xb6, 0x2b, 0x41, 0x8d, 0x2c, 0x3c, 0xa5, + 0xdd, 0x78, 0x9a, 0x8f, 0xab, 0x8e, 0xf2, 0x4a, + 0xc8, 0x34, 0x0c, 0x12, 0x4f, 0x11, 0x90, 0xc6, + 0xc2, 0xa5, 0xd0, 0xcd, 0xfb, 0xfc, 0x2c, 0x95, + 0x56, 0x82, 0xdf, 0x39, 0xf3, 0x3b, 0x1d, 0x62, + 0x26, 0x97, 0xb7, 0x93, 0x25, 0xc7, 0xec, 0x7e, + 0xf7, + /* e: empty element */ + 0x02, 0x00, +}; + +static const uint8_t rsa_private_key_empty_element[] = { + /* RSAPrivateKey, offset: 0, length: 19 */ + 0x30, 0x81, 0x13, + /* version, offset: 4, length: 1 */ + 0x02, 0x01, 0x00, + /* n: empty element */ + 0x02, 0x00, + /* e: empty element */ + 0x02, 0x00, + /* d: empty element */ + 0x02, 0x00, + /* p: empty element */ + 0x02, 0x00, + /* q: empty element */ + 0x02, 0x00, + /* dp: empty element */ + 0x02, 0x00, + /* dq: empty element */ + 0x02, 0x00, + /* u: empty element */ + 0x02, 0x00, +}; + +static const uint8_t rsa_public_key_invalid_length_val[] = { + /* RSAPublicKey, INVALID length: 313 */ + 0x30, 0x82, 0x01, 0x39, + /* n, offset: 7, length: 65 */ + 0x02, 0x41, + 0x00, 0xb9, 0xe1, 0x22, 0xdb, 0x56, 0x2f, 0xb6, + 0xf7, 0xf0, 0x0a, 0x87, 0x43, 0x07, 0x12, 0xdb, + 0x6d, 0xb6, 0x2b, 0x41, 0x8d, 0x2c, 0x3c, 0xa5, + 0xdd, 0x78, 0x9a, 0x8f, 0xab, 0x8e, 0xf2, 0x4a, + 0xc8, 0x34, 0x0c, 0x12, 0x4f, 0x11, 0x90, 0xc6, + 0xc2, 0xa5, 0xd0, 0xcd, 0xfb, 0xfc, 0x2c, 0x95, + 0x56, 0x82, 0xdf, 0x39, 0xf3, 0x3b, 0x1d, 0x62, + 0x26, 0x97, 0xb7, 0x93, 0x25, 0xc7, 0xec, 0x7e, + 0xf7, + /* e, */ + 0x02, 0x03, 0x01, 0x00, 0x01, /* INTEGER, offset: 74, length: 3 */ +}; + +static const uint8_t rsa_public_key_extra_elem[] = { + /* RSAPublicKey, length: 80 */ + 0x30, 0x81, 0x50, + /* n, offset: 7, length: 65 */ + 0x02, 0x41, + 0x00, 0xb9, 0xe1, 0x22, 0xdb, 0x56, 0x2f, 0xb6, + 0xf7, 0xf0, 0x0a, 0x87, 0x43, 0x07, 0x12, 0xdb, + 0x6d, 0xb6, 0x2b, 0x41, 0x8d, 0x2c, 0x3c, 0xa5, + 0xdd, 0x78, 0x9a, 0x8f, 0xab, 0x8e, 0xf2, 0x4a, + 0xc8, 0x34, 0x0c, 0x12, 0x4f, 0x11, 0x90, 0xc6, + 0xc2, 0xa5, 0xd0, 0xcd, 0xfb, 0xfc, 0x2c, 0x95, + 0x56, 0x82, 0xdf, 0x39, 0xf3, 0x3b, 0x1d, 0x62, + 0x26, 0x97, 0xb7, 0x93, 0x25, 0xc7, 0xec, 0x7e, + 0xf7, + /* e, offset: 74, length: 3 */ + 0x02, 0x03, 0x01, 0x00, 0x01, + /* Additional integer field, length 3 */ + 0x02, 0x06, 0xe1, 0x22, 0xdb, 0xe1, 0x22, 0xdb, +}; + +typedef struct QCryptoRSAKeyTestData QCryptoRSAKeyTestData; +struct QCryptoRSAKeyTestData { + const char *path; + QCryptoAkCipherKeyType key_type; + QCryptoAkCipherOptions opt; + const uint8_t *key; + size_t keylen; + bool is_valid_key; + size_t exp_key_len; +}; + typedef struct QCryptoAkCipherTestData QCryptoAkCipherTestData; struct QCryptoAkCipherTestData { const char *path; @@ -537,7 +689,98 @@ struct QCryptoAkCipherTestData { size_t slen; }; -static QCryptoAkCipherTestData test_data[] = { +static QCryptoRSAKeyTestData rsakey_test_data[] = { + { + .path = "/crypto/akcipher/rsakey-1024-public", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, + .key = rsa1024_public_key, + .keylen = sizeof(rsa1024_public_key), + .is_valid_key = true, + .exp_key_len = 128, + }, + { + .path = "/crypto/akcipher/rsakey-1024-private", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, + .key = rsa1024_private_key, + .keylen = sizeof(rsa1024_private_key), + .is_valid_key = true, + .exp_key_len = 128, + }, + { + .path = "/crypto/akcipher/rsakey-2048-public", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, + .key = rsa2048_public_key, + .keylen = sizeof(rsa2048_public_key), + .is_valid_key = true, + .exp_key_len = 256, + }, + { + .path = "/crypto/akcipher/rsakey-2048-private", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, + .key = rsa2048_private_key, + .keylen = sizeof(rsa2048_private_key), + .is_valid_key = true, + .exp_key_len = 256, + }, + { + .path = "/crypto/akcipher/rsakey-public-lack-elem", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, + .key = rsa_public_key_lack_element, + .keylen = sizeof(rsa_public_key_lack_element), + .is_valid_key = false, + }, + { + .path = "/crypto/akcipher/rsakey-private-lack-elem", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, + .key = rsa_private_key_lack_element, + .keylen = sizeof(rsa_private_key_lack_element), + .is_valid_key = false, + }, + { + .path = "/crypto/akcipher/rsakey-public-empty-elem", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, + .key = rsa_public_key_empty_element, + .keylen = sizeof(rsa_public_key_empty_element), + .is_valid_key = false, + }, + { + .path = "/crypto/akcipher/rsakey-private-empty-elem", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, + .key = rsa_private_key_empty_element, + .keylen = sizeof(rsa_private_key_empty_element), + .is_valid_key = false, + }, + { + .path = "/crypto/akcipher/rsakey-public-empty-key", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, + .key = NULL, + .keylen = 0, + .is_valid_key = false, + }, + { + .path = "/crypto/akcipher/rsakey-private-empty-key", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, + .key = NULL, + .keylen = 0, + .is_valid_key = false, + }, + { + .path = "/crypto/akcipher/rsakey-public-invalid-length-val", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, + .key = rsa_public_key_invalid_length_val, + .keylen = sizeof(rsa_public_key_invalid_length_val), + .is_valid_key = false, + }, + { + .path = "/crypto/akcipher/rsakey-public-extra-elem", + .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, + .key = rsa_public_key_extra_elem, + .keylen = sizeof(rsa_public_key_extra_elem), + .is_valid_key = false, + }, +}; + +static QCryptoAkCipherTestData akcipher_test_data[] = { /* rsa1024 with raw padding */ { .path = "/crypto/akcipher/rsa1024-raw", @@ -697,14 +940,50 @@ static void test_akcipher(const void *opaque) qcrypto_akcipher_free(priv_key); } +static void test_rsakey(const void *opaque) +{ + const QCryptoRSAKeyTestData *data = (const QCryptoRSAKeyTestData *)opaque; + QCryptoAkCipherOptions opt = { + .alg = QCRYPTO_AKCIPHER_ALG_RSA, + .u.rsa = { + .padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1, + .hash_alg = QCRYPTO_HASH_ALG_SHA1, + } + }; + g_autoptr(QCryptoAkCipher) key = qcrypto_akcipher_new( + &opt, data->key_type, data->key, data->keylen, NULL); + + if (!qcrypto_akcipher_supports(&opt)) { + return; + } + + if (!data->is_valid_key) { + g_assert(key == NULL); + return; + } + + g_assert(key != NULL); + g_assert(qcrypto_akcipher_max_ciphertext_len(key) == data->exp_key_len); + g_assert(qcrypto_akcipher_max_plaintext_len(key) == data->exp_key_len); + g_assert(qcrypto_akcipher_max_signature_len(key) == data->exp_key_len); + g_assert(qcrypto_akcipher_max_dgst_len(key) == data->exp_key_len); +} + int main(int argc, char **argv) { size_t i; g_test_init(&argc, &argv, NULL); g_assert(qcrypto_init(NULL) == 0); - for (i = 0; i < G_N_ELEMENTS(test_data); i++) { - g_test_add_data_func(test_data[i].path, &test_data[i], test_akcipher); + for (i = 0; i < G_N_ELEMENTS(akcipher_test_data); i++) { + g_test_add_data_func(akcipher_test_data[i].path, + &akcipher_test_data[i], + test_akcipher); + } + for (i = 0; i < G_N_ELEMENTS(rsakey_test_data); i++) { + g_test_add_data_func(rsakey_test_data[i].path, + &rsakey_test_data[i], + test_rsakey); } return g_test_run(); From 64ee6989c9476857ecaec5496cdc188b324af5de Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 26 May 2022 12:54:29 +0200 Subject: [PATCH 529/935] New SeaBIOS-hppa version 6 Staring with SEABIOS_HPPA_VERSION 6 the serial ports are now emulated as on physical hardware, with LASI UART being serial port #0 and DINO UART as serial port #1. On older versions those ports were swapped. This SeaBIOS-hppa fix is needed to allow fixing the qemu serial pass-through from host to guest. Signed-off-by: Helge Deller --- pc-bios/hppa-firmware.img | Bin 719040 -> 719368 bytes roms/seabios-hppa | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/hppa-firmware.img b/pc-bios/hppa-firmware.img index 392bce072bad607b1baaff0136f35844fa5d439e..b2cbb71ee0f91623d038db04d6900a5ed17472a6 100644 GIT binary patch delta 316773 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

vm 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 z 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%0Dw!)TtvKI>`$pBaV6*9o~1?(yd;{xyZbd1J4= zVR*PH=#At(pwESKjJ@LfWUk>eegrf1FsZ!>J&A0|^%*~*gG6u-e?S-{J9}XVm8(Rm zmF13HDyH*HBKaFVP4MMA_=jf$oJm1RSA52ODF{X#UP@SGm;Sp``c{D1=z`A|!H@o; z3#`kgMX5mQ=qmijyDc$B*K5jUV7l7l)PMM>Rj;XETaYR)63$cF=vq!`mS&OC&`h!w z^*NJ3{fo|mnPn(@D??o74u=^_hi^y(q{Dv@ev@2L>nU)U*XV; zxFc0;y$lAE2#xoMUM7xS9_^Rxk9>&3LZdp-%SVz3q8=3=WiN#u9zB)kHl(tBtBy1z z$Y-}pF%diR3gLf(GRIQYC3nyZF1In=(bZ=}xsTq!tFxa%=}AjptMUTOv4OWW&=jRU z`kLNYJX!)T_%CY)5>?;I^T-TD&u%{FNbdY{Ohrb6Sav3v$Mk%3B69)f1+tlwMD=gS zL!uEbbCR0B`HUr6R|uEa%XS|CEf{(Wj|d8bEr`GeC4(a$nVejc-1BmLM!?BkDw@G0 z13yq+t3`26h~OhQn|{2VseP<7;z52n-DgbJk}I*XoqWa&9AEW~)|7^P1W#mBw)w_A z@aZcwl85^tveY`N8JGr0ybo*oL!^D7B9ImTmJH z14~LCB0}_Vt*zo8o&AiE%LPCD*Jq3seKG_xU(iaRpKU!NfYyTxMeq2GXt;*&wjz4GhowXZRMrs zwP9&D!)LSwM|9`oqQO#$h{|NY*@|qh80b z9uinkD!81#OuU{#_>AJHc-i1`m2ulSOXN=>%9Q^vNcv97wlTyxuU5qOoA|J0dh3f^ zeZRqo$TPvZkN*$?zu~#bNZ((Y4R-4q)bfjHjHoXqtUTyjsY}SC?_k7AI?A3t__A~^ zN_hKu-&)Nq+1v81D@Q~8fD85Wt=C=2^XD^t8y@XeYgRELE}hPThquGJE1z}gJjnij zqkNY&|Ad776MVea$4Dv(2@pG*nMA2|;T<}4QNGzeX@p?C@w4w!jWyN6`jqKFsdah^ z;2W)l1}>KEPw8LI^o`ZR&ND`RyyiR4h~5OI1jVWqd6O8NoWPu*EDA=PeuVT}Tv>Z3 z%s0(KwD6`qGR1EA2efqQ>KmwO`4L(eP6Nez5mt}s6PQ*;&v6WEb}*ux%nm9)?Q7=@ z-Ev_T{q3r1`o%%?aW{-i2wr1lBFxtk9oy;}1=bQ*qTC!k8Su5NW=#f;3`XsxRhP+t zucc_pEaKw`)?~ofO8U&d4!|73tcvozA75)N3dAvGN0wlobom(Da&l<{oM>eavm?7f z*d_0`w=T{*`SPA5*PY5tW#1RRRNVxUkXikeVpsXe7ICT3HgPA&exy1!9_mt&MNJ(O z?;|&;hpv4}OB8QxV|tDn7IAv2@(ppu_)#w~9Jc3df{)e!Rt)dh`LHd$yXf2S7K>dWmN!^fLJeriB{v9;Tcs zI98kxS(4?$cy6LRUt1PAORNYrZm?Al|1EAw{NEtJ>SOXzwi4We?~>QmkJ01Dk|Ywv z1Kn|qvpcQ?{H6;ZC(DpZ{C0SK`4*fc6GSq>AM@VRTkAtm_(fO83)ka8t3#Ev6l$GZ#4GI?cO zpqqeX6P8M3uTm#4Ehh|#knuz+K{_tsG7min{`NxLFPy8oRWVOp;yf6YejI8{ET&vB zFVnlX80IIwCVVO6e9TFuTTc>$z!Nhh@*EG#2<#o3w_5SQEa1dmiL~Y64&kOms4F*^ zzzop5#Uc93qXg<_u;#+N+)5G~%>!lU){zKJ%|*0xUw(`To^i=Z%2ioTP2Hm1xwJdC z51TT#mQ&R0$|QYZ{Gnn(?^Tk<5#v{%Blkh+y=;o8yzmtX7U6OaSE@#U?;FrJnNr+6eyn&NKO($_}PDaQmzuZR2 z&4#XM){*3PPYu(n$G{fo5%QH`H1BQ>vywJgZeR2sNg62&&*lhzyE$2}DS1iD6|Hxs zEeCyw&UvMfyrTto!UG2@u_1&K$Y0iOxkgB2_}=F0HkXlk>sQr|XFI`Fc?6ue-2jR) zswc~EocVS$CRg(R71x9xktg$Zds3Z7WHR5$Pc`4Ss=IHc#Do^4 z4Av=^$CDzI#8e_l{EU{`55J6FNj?sk+g+S>6Uve%WlBmQx^i$ae|ny}I!6zHZK1|D zEEiSfZ6fpDcv@eNP)h`58$7v()jrvV@Tx>Id0@z%?9YDgy;XVYTBa`ITJW?;<*LGK zUgkaA+mj5KlQSf;lZV9wd7+@>H7Vg7v9*Ze$<=h!ebn)_OVUyDt11P*43(F0KIkJPlwQ$>!@(2fAn18S~=+$<_gysJ^Fp4>kySfA2?iqZ~85X zdpGm^>goj{Jt`!43RqPeOEn=>ah7mWNdJq6UkE=#dQ=Fc-$$ZO1ruBj<*0FL;}^>R zCzPMHDL+*jv?!bMQ#jM7VjiLV8uqhY0qIg&H089`rSVH?tvt|FQwm@rb_&1XRDwj3 zc|d|sJt?J$^umX0eIMn60ES7c14XLP%eG8bZJ*BsgNu!LGb>%>;VPynfAqZk5jDfY z#4Dnzl~@1b8ig8fh;+#Lkyr;x5w zQy4TCM@eOr)JR$B+|NkmZ3y!qne|hT1cC<)ERSq>ip_8gzmR9tJqBR6LwVK$Thi!x{#ZdTBm8C61 zE$;kC&p7=KmE!Ng8)M&MN?oIQlMrf*gWEND!N}ORkwReKseQtmgz`XkyC&Q~Q5pM= z0lrQ6NuU=gU4Q^igL=9MpIJCOj50U)MWlY*KsEK_=2C9;v6OrGTW~59Se-BqV?9n| zC{H(_q{DMRjKbxn1YAr^? z&p*UDZVi{f7>7HOP9K~eERolE_?Yma)Z0h;4fg-!$g-tvSqnFQ_yh0;&74+o*}|Lm zBzrVj#}mGg2tNI3)YR$862S#L{T*R0tnf#*lH%hnQ8Erc4tynHxzu&RZlohKFiUF( zasGb#L)X|gZU;hFLky}oey6t(HlkrrRycklO+STMmaN7mktXZ4MtyB#^bEi;!w z@EpIRki!;&H1kraN5);t7F3H%a+!l1m*5&K?h$Hyg-a6aq24R_>ZdOfq-&#kpogxM zCH4>Dp+u@Hb*3aCQX=SwGZGRcg68m_X-4cBi9OFlI|3^_=9O1@7)0nVkq$h3LHHbR z$k`<;p-UROXcrNtsQU35oKK_?2{VK%zcOFp9#OnvEb)UJ^gEgs?~=Yk62l z;8j~*VnF$yk>qWX1Pjj~&}R-v1UKsp9?Ka~w(^qrnJa`#62ZWnLAji{V>=*M^kNvl z{K-q=u9`87vy@p}9~?y}AuPRuF0ft_xB39z4mIHCjc{#V(}dwJj6T%%v}QoC{^N}NWv47FNO@mZc$Hqq2K!w#_ZB3f zMJVoSaXZuHf)q3$HC}BYid!B~YSshe!FouS2W`YJHdU_LUpslbi7U+C(>S(oY2RKi zhQ|IYes3E@`fL?KC3{)%Jcb-3epOhgu>>)UmCu_-r4r+qITBgQ(WLc3o z^xM$wlSd*#bZgBMIry^`-&pqm*tXBgDpx|>@BL4;dJ&z!V7fXdEU{p zPJPv3@sxOTX`Z#pivFyzx(qvh`BLTZGqSbbJjJiDiiOBlJe` z`V*^*1rilpTg$U6@hOt9CTBm^1XAcqO&?l8g@hXMln^)Cp-&_%L+D%M(D#JhFpML{ zO#kY93^7-n$hdA7W8v%~@?9tmAM=m13GZ_BT{o_{9|KEbgG;_>dwp>jAzQMv!36U{ zIiv(Jh%cG%fm)v81x%-Sckyz&flRxl9;Bo8*MTB&?B;(((wqNb--kjcLKCkIUOrc) zlB0H6AKPWY`wRE~lUa-GIpkc-X#675_`-^`1Su9P8ZRC^OTjqm+Kh&c=q41MuOY)R zuq-aP9v(-7JWwz?E=EHN*X(>aoDz%>p zHT35Wvyj@f2BF42{jy@Hv4%2KD!^@E`~W6r#FFBJ%hjOVmkmjin*Ib!3V*q#6b@F> zuu$Xm%G@yga$rDwa5cZ|KJD3!OAWns#9O09K4kJs*}`NxyX zf%lKyq*Pt46xx1%sNu;k^fTZgErF0Vd3d0CLU1WRFZRVk`KHj@pr!mqTNAH@Xf*EA z1}m&%m#!-G4lPYd*Ds)l-qls1n+YQ?;tSL&XO;ewE?v&{)OooTSC&={J;)yW(W`7zj-oSOm(`A1L((*N4pK<% zJ;uAlj(!}7OAM~;zsiuoYMfo8S}OJJflzq?hAkmiEx8qkwr{Ou)vJ>K3f)Ryl142X zx`nRRh|~gtb+S0AqE*Xk_+Zxp-`D8FDMt5-ypR@NwrO_4gP63}_mCvw;G!324V2WTWty)WilG;%f)Xk@I*2$$obpCv_1QmBD zM#T$~gbhYFecwlgP`M>Pc{qh+P)M9EWG^-xF_|QV_^Ig}op!DQxj#7*I>`rG7ftry zq|nK%`zAs1xhDyAKvlJ94+KnQApIY@&I7!vV(a^RpPiGFMj#M6XcCBo7FrZRAfXpQ zipNMtq=hC(6Qvvk6ciDu2N18QsDLOznlwd3MFGXm_4TC*UIdg-qzm8gKYJ(S`aU1e zv%<`*HEY(aS+l0>nK^YQlNbb;P|yr@CsV(-{*0cj9#`j*tH#-;`Dk~_n@j$>C8Y09 zo``HHsKneC)7}qV~=6aT~0q#&X?itP33ez%m9|5`XbaY5!Pmb5g$mkGOWZrtD zbBFF#w}ED8YILZX$@3tq^ZTR6c`Y_?I*I1Hc-1kV+hq4m~Q&WxQ^&g z?Jy0P1R=biKtnoKdFVCZW&F*&4UCV+!mrc`ly80{dN_?V^cT1%Nx${#l8I(f57%zk zp^tzqZi&MinVMOLSoR(IiOtxd7mX{uUMEntb*bn9h^odKx)Wv<46}JIvjN7q$aEF> zi!@q#pm+Z1aB<5z94BT64YM9~IRF=m?&^mLCS7l>tGKRI3az515&s+A+S6*iV=l6F zl8}U{ZR=X9Z32T@Z2#y7i&@$vUY!(OH(!q#@a-hwG8Q5TO;XonMhJKxu9mK*=@ebp zv<(SNLkPod|Y?CP`in=v)q zydK*x!z?HA64wUiP2@UDeF-)@Haf}E+9M45u|}}WuU)Mr$$QcSM=+=()kve!lQ2`6 z?vWY5P}0z3GFz12|Hrb9CIAi}2+AbqS&w|L$#K-#=(~zp&b@aq`j^p<93AZj=zL6> zECS3bkFpu&l&MGHJK&2FTsq=Aj#H+)WgVj$M{g)Hh)5!!No*Oq+A%EZ*d2;IO#tzZ z)m7vb0&RiT73f0;j0_BZNW$sGs`juDGR?is zx%|3Xk#PjR0=`s)p7-ltz*$9J;_y7)=6F1jP}!FWJpi<0dGO9=YC6-@bV5}-oju-r z)-fe|=X3Cn0*|nU+(3F{3LUe+(F=32fQ@c~-y0sFqppJ#3^pWs%_c1mFox zIr?_eaDe)_zp7{1m~n)BG@Vdun4o+Hiia${2}BU;zI7VRzr>PdS}I30zTRmt~z`EI+|904L^a0`&mRi(~MpC)oWt!Ghn3!6ZW``V;Hv zbq!>Y@Hf;oVr<=tx>qlPsArtO@=i=8MLpxh9ALJ3Mr@-zYe1Tje1D9+0MQ$ANy>@s z0l_k0u_74PiS>Yf{Ve(@JYv!H34F+j&(!;3#}cA8C)me!Vy9ZxZ;1elVJDVyeyb1E zQv?nC2CLuNDS~c(8vyiGgv$Rm5g4xsmH%x%FozEXv0p3YAhFfJTZ$Yf!0`Lq4n@wQ zf7W@{e|(MTk71my{STP#nsr07*%@ViIe5TgFRhix zCmSmqkn5%KKu8mo0#+J#mXa-su zN&k{E$|B_q;AyHEdzXi`z#bH~3YZnZa&gOvGTc6D5Gd0F#_BKk6;;7*f1yFCY))k) zrGwn3R~vnZK@Z94B%m1mh6Cnh4gS~1$? zdTpfH1ZerI2{2os)_-;?Qi{M?;13KgCW#G_>y3&14e0C0^>*C+Ee>eE<@&<}l7I?| z&>2qF1!^lYg+LR!$jL@t_n>@N3X~RWe~wlfX$VvIIN26xO^UjQwt-J}(T31<29BIP zM(U=q_P%14)8umrcnE^NKrclYI8NeWPL7eZ-Bt2wVwnEPS&D?{rYAAqldltF;ImHt z8~8yHRU!{KqsSeW^?Lwt6sb-?3FQ>Im%!Zs-vNC$S`wfa{odwDBJ>{Ljlsm80=O9F zyMZzOz8+ZXb%?+7i-UMvOSfj!3p8>n&0^Z%3XAQ1wh`0*;5}$k;w?QlK zqLtsj1r8`e9e+Oz{4d5cnDeT`<{6vlDd!x8qVxIOtL=f9x!fE_=Z#-d){q#T0d!`| zFk))|`(I+zD4&rmU2p4ai<1lEuy}>+@2EnHE$bA^wo^WBjO(i4kO*y{=r5Nn?bSH- z#z*0-L$;?X0_AB%9kM-D4M?-@Ge;~9vhhnhZ!>VCT>Zu*THbv0%sr|rS9RVsz-!;Ed>Q6W~Wl9@% zsaTZ%keo}Y&D+L}vy$I;YyLKp51f+xrhBy9e$cX3UQc#^hbGUuZw2Ko*E+C8-*g@6 zN`5ZhRMa~4GX?#a{^;1zq^VJ`u2biL(=GTh4MxircUGp5uvQR`M*iid(eKXHg3lH4O`#V#`(hgij$J zb`wjxD?^`49uWbzfq7QLi~O&jfOA^j=jvjFT#G6P?P=aAwmMEs9)V!klXbcm@Njy+ zz9X&V5tL-o@XM#iRUT|5KknL)b(+!O^t?NDYAQK2N{M2(9$1U(x-UspL*z^HDr4}g zgKcvF>ON+3Emr|CE<%3pKIUsC&D?n~#NJl!eT#)DVBs50i(?GCpG+QvF|^d4OY|qn zgYHE2)*&M0en=j~c%67eZ5mjf+((w$a#i^L7J>WiZ^Pjhfr@eeNoLk7X`PnW!#kC7 zJ~>M%j7qI4hkqv}x@7V_k>qTZ9WL53P&NA9( zgGitCI{Q>k>n~i)>$fpUvz7>P%tb6IKy>_a7H-mMeceUOD?mIKF>4x#Hi<5R@0Ez6 zLPp=3HBks&4^u5B79eK)HjBmzIc-|G7(S3I3l$&w$}G99Hhu6;jlP&=MhWwL-Hd~? zf`vPiURnALQOW|<;A*yAUZ{^e9_1Nh(Ke{EOSA3bLjCNaiW^fDYHiPK zw(UXv<)NYtDkSyPX_<@)l z;UYdPK=fFjtsdEKhl|)$fLJjzn`7)wyCZJtVd`D%m$?2`_RFXU0b5&Em227ZFd7Zp z{T(+l)NinrJ+=UQ*Np7p9`^onE)#8{x>+|rliepD+0jMzaZ4CAV33vlDAJfo$wTY2 zbBZz$7Lf{fFU)=rk?v;=s0QZVIZ8H3mYs@r~@JRaFhwMaa#NPX+FJAUi|354ySaJ5a7VySK}(F2p$(QQaW=Da+dD zvo#55U)sgoX)L~w?^*l2VZ1b(=NFy!ja{m;|D@WrR6QXgBgN(gP^bOz-mdfV9}3sG zKX6B=af*G7{*cuz#k+IQk?QsfVjmr4rPzAt$X`nrcH6%V&69to*qmfiBPr>7k{+&* zVr%rZml4@LJH=e4PuNLhOM?_UPfmKEdBsY3FQE*L4v6#MxfI>icG`z-8M`NDI-I&h zxz;K6``|iM@lfyovr6S!i$^daMYpz{4&yw!=M4)_LAY-yBvqdjTTaVdQW!Ne#hwQ_ zzr3mU=u_-)_x6F<2b-qwoR)+WyG7<^1}TZ6vsh83m_gwl;;&Sdb6#XgHGsO`+PRt(7@!Y?|_y$YvXJNcqc9nJxRBDc2cmA?fv8 z$`O%hE=Orc3<<`&BJ^a6Tro{1s!1syiHdV0qWY+S>d6#2bZcOtqI*qJj*;)AEGI`t zo#`jX@_!0A@*NfOWQyk1ZW$wIr_51~MsAMKod1)>3~2 ztMMWtF;%jBV~mD~V3X522CCE;mgRd?rQ&Kk{Tw@*&%ar|{*o)xdV;E7$?`qqp*xod z|JX55BmP{Lj~98J&RP=o?inuDDNr-?3LLA#D#A!hq{d<*7^-mv63H)~i>O)W*`RBE zo#jg?>ekGQR>T~ssQPkdgDm?Hy6miv=_{rYaff&K_3M;nA5`f_Jk-G|7=Ea*<@f8P z9+Lh^mc3tu`qVBS`$cF5;FJeh-j@gP}O?;{w(`0vFl%~U(P7LkltmMDe#_DHQb;JAIn3r z{YDG}QQk06p6q&Ac8u~YjU6@O2~cq^>J1FHVM3PeFGBZP`DxZw(d>vb*)`L3{lSzK zS?7f~7H=}2XYgNW zW|u(4niI0NDc0F#yzQ>rjJKudGkzgC>m3n|3%7YNP`TV3_`-5|Qa--Z{aMco|6%yq z2LtI%e|33HO1sT#Qf)&!o64>}k~OA?0={Zl!%SfG+gSru`_R9$I>6?k#^Jvn4BVTT zkk!U?H!$O-W>pbpLbz!#P&IU4R&uQ2=RCC7Tzbl?gzho9*0k=IS>^MQ8(m~Y7x@xp z#=MkO%3u}QH76^JHehq|J1`&SPRVT%Wk&AW;*2#Rc1D} zynn#RXYQgck{@3XnfkT-_`|vrHfm<-53b*+4i;B!Urp6&@ZrI(2zm{<@L*0um#&)nx+r8~)a~_u>bG=NjY2E> zq-xsy@CKJEY^abi1@$g*g@mf=c{rME!fHObY}=IlWA#Pz9PY0Ye9ergj>sa;=ovo-mrQvLJE29Fl5R3j{_{`S-w z?81C`1EoyV_D46p_lBD4iX@~Bi!Xpr_@v(Le+(TQir=4FFP?)(7thQJz=I-ZI*l zFWxIPl%ZlcUT2CqgGgrrUNL8w^_|gsb1LRc5^#r#>Gj{mRPc(4NSKoMh+9DJdWvsk z3K*Q)&<}&pdF3E?AFOhB!Uh{WqqozF5B6Ifo!o;&8w2;5E$zMcTDK3tcckiA-&g%p z*~G-wXv6MR(LB~y3e9`J^_p6W6_96q;fq}Zm7^C#`ZR0l-X)yejcpGKY`_7od6D)W znRoX?R5P+CF{YqqGMqan(srkE^uF2OMtZmZi98mL^re(dGZKwAw{wUt ztwpqnXzW2{jY{mt1!Bo+s%*p{bENTxW_{M-lImR-{y< zzW$oD??~HE+Sdt@C%v>ku%$(1;5*1KDHP7hWd<4C|@{-}w$ z_8vk&RE@Xs3hntCXpnAY{*pcNF_>gCA+<=aqHY}y8D9bqZH;O56?;Ww4VOmh z@m!~uESRbuG-Sf;Ssr=7V46qaQb8SXQTVhW+ao_$o}O-=&kGP+--^`UL$9$e;==-F zTbD+1-3g5AQX}21JQb6@B$DqdU{<+#a&I$h7s<55>GiW${u>5^AL{#65lcSlFwCsR?F9&gq> z3S+zN$Y*9-^t(s%X+Av>KGKUj(AglNPnJlchsK?<5dQQ;WaWH%%DO8*Oj%m!8~Wk* zMVgh98JFj@j4Yul^m#09ycMagLmz6!VZ>fRM|;A3p6Q*xm7(Oe3xgrw38jAz>56GV zpKhNP>Q(rPXDbGMZoiPLdT~zBmnU~KP_cE#g1!sM_~+%Mz^~KwpznXh?uN(ie+@g& zz*&?-p;^$%YC+!)=pHfaN0qw+3qC3LpyGDWYz1rOFH4KQrw;7~eR_pDDktdM&kCye za*3eWXOtol;Jl<;(6>^YU+^SY`Ok58NwMCzVdDG^36Ar z6Hx*4p`-x#*L^kU8!ozEJi6hCX9O4B@S6E_<<|#&+Vt!Dl?yj(pB=ju@)#XWO_K5aSom0uC}pfObg z^gW0<8aYc4l>uXT#fNC)g$J%v+ zKF#YN&GW=aD$Fpcpyg_A585}O>vz9PXV<-1h|s?IPkC$Vmxf+_Jm`yr-i+Nt%Y~C4 zHFE(KTPA30_qyK{kKLKV+%$hGFa%jy?J|Iz2f(vC&b>u?DiIB zx4$sEuRM040)Ep=8GbQACQR^q-Q%~dFu!eu`Rypo@56tJH$6t|>J|^$`iRy4OOM^U z!irs|SAAWFQ0rXKUM<4&9^vZ3gmN)1T}JJot&wv;Igjp*!gOyG(AD`mXzL@_fQ}yB zlEQRL3R+a}-l$3Id@XU)S_f?w&dz}8Uar}Nb7|k_zw98bwKApN9kicNrfXiNCkkhJ z;-8sP?~d)4Gn%vWQ<*JRvP*<>`vVrC93i#SH8J7_|FApZ`_C=!)G& z_$6fqZ8^_@Cp~_8DmULX+rfVdk(8-SRUQx89mq6DI|eumyMvnv_kr`YJNz?OmB*E< z%r`+>%Zou>yj-mc7uD*YnK(&IrsRi%b_r$r$;(utaHbL_lh+cZiZfBIR3iNNz(DnW zGlO=y!p1D?NPgHGwC%d?azkt6- zVseEBa%?wU9HHCBL&0t8J!~Vg6iX~Z4o%~YF-IjdbZOQtB16g-3(T_3* zhbCG4fVDP*diDrnt~4}49Dp0@mc^pTQ3L4tZQQJD2D4HgYP&+#HEx!0X5C=j{7G^< zf3R)?bFhJ0EngheSUa?do1sdYSF4hL1glUhb7Y7NRoW;6(wFEE)VjxQvvPy|w z32x@HW;RDS++qm#eLQk+D-{Q54P3mmhCHD)aL&?7c93QHtPERU08(b;S>G_pH^1lX z4BM2(siOBmAs`Og`r{$s{;|?&hF#Gp)tNi9n0bIM!%lYF$@*g&R1>N)4Sp}fzAK8r zPi458h>G5OGsDh|RWVS!2E58ik#D-Xht-BvSu`|IiWA1ZV+|~4n4U`$a~&r6<^zjg zyeF}9;l%GP=VjKu!yeOFlDW}r$>`o|#}y{W4KD{vqyjeIa+Y`bHgdcfo-mZwVdrJB zUM14O6rHZAxgg^il%N+a_fNOjUD4`z#HK1n3D00>Mh6>^d-YJG1KxeXkxEKT`_;!Y zp3B$3acGX1m2t)#FYQlO|>i|a&N4{d)Ay+YaVer6iXgKOQ{F~(A>~&<=vHW^cx=K0<9M(2h_-nMX z5;7}sWX5x_c&r&K`tV`!?4SLq{j>0C0#^a;pCyj;lXBUz&N9%P_3_K5i#hqUf47B( z6KDGC6mdc%;mOZp7-xA&!dXnmIa?XP+Bh%e^QY%oUwv<}SHWM)YLl@Yj*ngAgsr~~ zRP3RgO;_YT0!@HMoWS&Bp=a9yt;buw=s!(XHW&;8tGK^)4A%4&PqYRe^;p)`9J~139J|;SA<8&WI)mpSzDj zy8#a?vNJy-MT8MsyK-k~&9nV2m9n2BXF8}lq8Bz_GW3<@8vTe-g{<|f+O7$Y;H9zx z6aFgb8vTeBB>tDtBji^L+=lhql{SxfKVyhix+4zbGU&;p&5Drqmprxis@ix<_t;9^ zk&9(KM9OBzRB+!r(S|W&dvwsVsTSGBr)Dg{1=JKw8@(* zHqz{9FhR?Dqp#nWWvZTM&z{K6(-f67d4yY1RP?2@^JK$ZmH7AeAvtMi@+bBNP z?|YbDGVucTF!^cDRO1!%MsRF=ZG${JoMyIj*ZF-J(2Tx_8L!1^^Du-wy@gTya~>#I z8+7KLw=n9pkC6Nez)b_++F=C#1azu>?f4L(tH5Q&rd!sz7=X7jd~07KkPMXNA)B@D zP-Z7n=CL}Tu;(^N~K`P*|yuJ7Z%eT6un2n|B@jm>}fxVcwIn7@N z`8u!i0c|ut({A1pI3HnI=Y5qdUx>#9L?@vV$$9%R0mUN=Qu7}Z@ThPJdQ9LvlN!ED z@=qe9sZtW*2{EF@f(TiGQuP*s6LabjlX%?HFaA2C%@N8;w7;^VIa77iOue1aJH_*< zJbMoQg5NcFM*k!hZ`eab9ljS9Mw^9>$lF=uz&!VN$g^KEKl@%H+3!omJjbl2()($W z^GQG%TDpW@-`GEtSPRNO--L$-e&B~K=eEaL>o05QBECk-I*qJ9^n|7t(1Tn*9{3?RFad*2*rX+)%J z;`iy6*f_2&`u4pB#}|R;C3gpGao@W#N($V!mE^a9*A)4jz$d^*ihNH1kA40}MKICx zCjhQy`S#KCE>Ph4E8=wBH#eldwm*tg#-j@<+=kd+GS8mZNvV9pyU-8lg?U{5xaEv}9T5*6g61iJS7Uq!za=mOcm@NQSHoz*8Ea1XW0*AFybR0tZzelB z@y|^qel~P}V^Z4?!3f5Fkwiih(Y04zLxOEK`J*yRaHqsmM73wEBe)XuTbOdv@?4W5b2e ze*Sy`&4(ok90Lw1l1$(lpyvLNM|PN&!$K4Stc<)M|**_k`tr1U~L$~f4vw3UC6 z`$4`B$L84!ayS9LiQ!>>u6zoAS@_l+fySR$$q2D2G!x=VfPUy@6GP3#u0W8kFn@#P zZ2n$1cRpl_S7I3TZmSaT?-z#vIf|f_i`d6SJ$LirN&@)ni<3Rqw;;>7z6o{N|8m9` zLuqn-7Z(8YQ2l}yxW10Y_sOJar3H)-^gd_2IlPTGQd$`=jYb=yE1$|qYr8h4hEnrx zaBXaSPPpk4fl>|mU03<4@e|#470LX4t_6%=LYjY!73H3hAFUgG_WXk$a!Yvb6WHi+ zFZ%EBI-*?l!g$CQF~(|>D%%-di*j*VTMi*ij_Ld}{Jz@Q#)LeoxrN?(aRu-%*~ZK0 zW(#BG#ht*1M7H_~U_KW$=4?$Ma0<}dKwB%i&A7FyW&K4F7q5sSbT_doz@3UUCGaqC zzasY&SPV>6M5%uOr)jgTv`UHhk>?3v(C;Nij=wGmLlc$QZ8=Z>pMz$l^CPwrS2$lA!ed} z_LQ#j7Sgh5rG?`?WG2X{F;?`&%F#EBJ}E(&r+avg+8g{C7vE^GZ;DH>0D{hN=dE%* zYiKep_tK18cKrl3#7Y)oz#IMHr=R42#loJhMLhKhtm)|nj}lC?`l4PEKkQ8duo<*> zs?RUpNlIM3d06j+1Zpbly)+Vd4DO3}djq#k>qvM8Oxf-PDrD?bX*ImG2OB7n-laqw zpdsv_G+IV!zj$fpH968$z(r3yyJ^03P%dBuk~f{OC_Lh+Kq;o7M&A=wi-z7Il9gWC zZWZ8OZgY!SK+$TQ34FjDtfJMI&UnT6qMGHG!@JeK4HpoL6^r?6+4uT=b=8A6I@F(v zTzX2TeKds8Zj5)0c4Ik`p9h}Bur}UB;1xjDzp*ZXRlwVdG$9}>TCYeu0=U3SU$E3$ zx+>3Jgx7`fpVf7JdZO<0ETyMhIszP0WETN!{F2svOZ5={C3@DS%T#0$%WC(XDs#=& zyS93-QOP39)!M|Lr4o1cp+O?Y&XNwo%(pi7%hy(pnZBui+ea5MufAv`y5{$_rhiXL z<|VYFc)H7RfG;$Rxz2J@HZok;$NwO$mI^ zQN)@9O%+KbK)1TAAAUWNL|_omPmvk~o&=uY$+k0NV0}e&Qy*7{5*h^2bi+_JjD3% zkGesZ%OzT?On1M13%V(s7V&*Fj%2Dt^2j0)JP+YaDWRta%dp4b`)E39V)l0V(+ZZe zHrG(HxkM}AoSp*3(eR4NflBeas)Aq*d9JoadiaOQoMJR->fKfz z1LLX+QgRGVPbU3i5ZV@|suTS_=A+JxIlV~kWs>8l>cm7wD6F*1M9l9;X4{vq0~oLU zBMzp_YiPk>V0eYW>q-&B_Pspo{7R#$+)$$LJ$&X2Jtz1h#&m_z>`JOQ=8EGN#P9)E z8Y=Q5fd_%kiu_985um3cc?6hbUtx}J|48q-@(d6n@>2|f*MOI)&SBnEyD-s|`$M8{ z8QpE_>-?soeRvH7`0Fd16=8_Fasbd8x6BXlIJ||}3E(I?y?{F3J!Lshx0BN8Yut9_ zaaQ-;iVNG-2|zODXvOFHS>64GP?--{&YB+J&G>^P_TZYXr?)Q9e+)`XCSLLqPXC!~ z%qa}+)9`Ck0wtm|yi!htcT8c%K?AAKske*E&v-HDp~@FXQh>^_?B92g%lxd5Ydprw zc`s#LL^^}-uBsHmb7z#ATwLs-Lw4vNc=oCWxpOb;BL4079sgv|$RjW&_7eweF1o$x zuSDOgn8Gu4Xoa5|qVFrfCAGp|YRT4?b(Pk<>Qf|0pc;_IbK3UdGD+lL>A#Ywu3{?aEC?Pm~WT6eKw!f_RQ zx;l-fzL-bCkN9ur-9>rUUs_X#^qR%B& ztv4B*vG6IzB-Ia04?ur^6_fs8{1-Uc*K{T$IiAh^wZKcmWO7_P`)h?|pTfAOb66_J zZX-AK*9WdqDXQ)lvM!Qhm@;d&f9ebMO-Vc2m1vI+7h+b$l{VQ;V}F9v;m$L6DQ$}B z#D6h#XB5#&&OXzQu9_rc;4e$oMBhuibodOrN%omRsBbIqfg(K!d=|~0-Ieq(LAcH{ zEK(URu6_sT-4Z=QaPWn+zGmg$%bg^Rd%sM|-uo zrm|{zwYi2A*X}cwft>k}`wLFaK6;Wx0L^V=<(C)1s0|5hWq z4<+#0Ye=YluGP*c2Fh+BhjsplYqT@;F~y1T8Jjgr3G4g~%UlDV!BT@4C>j};o9J52 z3@tCbNuY`_^F5640yREsR*bBjEUPiY&MXRHZ02=+oXd~&{%dsnYs{RCdZuh+%$z9J z{KcmHJ|6jSW_*a5P1&PAKTx-GOxT(5b<&otyr zKDHhp_JS3O{|Ghp`~1*8ujdZSGGFv<{a@tx5ZI~}-S4D!vz(cFNo4Dvq<#w=;OmKR zTZKI9QW@if2Gl)@`+Gi?N&L2|;Ew`_#cu$)w%tvPdG)o^iZmr~9nj|Pwhq+)dNIqo z9w&ZGs4jKVj}4TaQ1<}*o_kaLCV|GJuQNIJZF`&mF8cc2iqLbe!{K^cl{A6X!nWsF zEx>8V7{e(*^4z+th@IzfXTBZlpzQpi5@7yuJ;b|9z8y;ljRVFgGMfO_be*x@ zw?lz>!1J`?rJj~IX?35gonTt{DHQ$=6Tc%Rp;%6&LR}oybI-GgJ(8h6P4%Y=Gr}Ve zQ0XJs|Md@mTye~0FJ;>z8O^wm%!zF%Iju|6Asnn^QGr*GTr+QrXab_(LyH`PDC^z~lGM@m0(v2q+nL%JW{qM$9mGl$#v-us@ zezq(ytYklb)Z0t#W<5!UE#Ht~4lrAhPYJvNEKy_&0j%qW_B6JS><2zY z*O!z2+kDg-IpIFf2cl_&e>V5&4Cx*f9dVm`)_b>`8;cX>qTAfFcHM67%Z#TQy=EO# z+W7y|+?Sc`n0*QTiUIFXsex(i(B_KpJD?J!RtAC_wBU`?Zfoa0Mr*TN$DiVd0_bB- z9aKid^5ssjtiSOifBR_d+?k{{!5F#=LpS=Hf#&ZrvY6ZtsXtYLpj~xaFH+1&L_fLv zAgE3w{9Q#HdGWxP`)`t(0ZkP7jQ}0y?}rq*Kwv5`5r*p+Zm-lZLOogC<_w_o;=f?H zE(!c{V5uVT{2Nd9_XlGBBrMj|Bz6qYF8I2Jmc>%ax*5;Z-?y$cp*BDhYO*d!2KG8$ zWJK|;dx+GLz+-G6=*Ob39Mtg0U#4-@?T45z&7Mzj?@WOPcXe|@B_b>yprD-$-R*BE zisPrfRQDT7sCj+@%GF1do6iGiQ}1^9);*eMT~(wq0!iuX=ma;zzBd{4*k92wk z{pvDJMfl4&P~GMjhco*!(yhW2Z(@o!_hO1ymy>W*Hu5xNF$}_2nYFoJYQ~Zxu@6AP z#P!9BkU5i%1T~soVeH$`671D9*U(-xTj&^p(mG*WY@xmQfEZ74(?)t}gGjSEWo`E0 zCBb$fyu=ZtCZTZ(fX9ZG;IGV70b=C(rO`;GLN1?V^u10Y>)^$dPLf(~7kTkhk&khu zPjoxSi+ZXrKP_M88{uze2g-%mBv{9-m;B|5>aEU@`!c1_flXh?U5>{72l$DEUNq|^ zhHVCWg#F#`i`H6}faP05%FXk@pIFbDVx*#}Igbld(z0&RLvBT=AFOGWXI+a@KPVrH ztz+|1*qOJJ)>(tW-6{>R31F3H568ErFR^r>nj$pvEe!OQ2Iw`Y`_>b{$hJl(KhP`;i-q(Ysm2w%0(pv=hoU!$^Z&4%SOu)JOyu@ht&|1~IIxBicpKAR=h zRQojq;S;3!i&v;)Cs4z=@pPSt~v+H?pfs~z7c z+$P9p-BVrqT2Bgtbt$pFme2ZY^6$@Q{WFn+iiq=Xz;SWz?{W6WHNz0|c{il%T#IwN z&b$(;t-HCIr9O3yS%&5k^QyQAla}H3`FX9wcg|%aK{E%s`@BaWvDt-2e0T%WW&&|{}yaL(W17^(SCakM`rfCO5{EE1Y_STk4vsh>_CTb=Da`$dsuk(yg8kuoaWy{X{F zKw6UZ)0=*-brIe~?uUx$ttb+hDp`xDSLAdeRMHw4&YT}eNb2lWrcp|viZ`mS%0T`0 z$?(Yefz+y@8-BZSbMfSE`ylvbg0ysZZPE*VJBxkBg`J5!H#Pj>{6Jaznef5+9Q{RU zI;3pqs($0QpGu$#N1zMz^4rgth~Bae+|{1(YrNmQ^s?}Aax8nF2m+yeP|M!&o0nb| z>dJ;t#ZkPAdMLwh>yXdFk3E!aP_d8p?`!!(Hdp6;i|0{bo7#TcT%9*Jj;22D|4X?R z`Jywk-uxrBRY z8*})Qa`xOsjWgpO8`dveYGI&b=VdhFBE9ie>ubNRim@@Q`=G?mx-qFBsv=xd|Lq?k zvBC*1*AbP(6hcd&6BF?4J16Sgg>>c!aA<>RNMb#t|CZ7)svzw$o$S2a12h z;#{0O(P;P%;8xRx2w5Fu=w$In#YV%+PLypI>!%>rfcOt`VQhEAB}0cy6-YF94ws~i z;pey?iMT|&!(mAJ=uzall&t&|*$!xyZUnr95^e1y^CFyWkFDI_inx+5-8NFztBi*) zM;xb&gx+~pO(vi2)AdUhq(gk15_s&}w$A}a(-HGH-Ge8=ZC_iUv0KXVG)kcm-%Ma4 z4z(uU_ogO1`YK}AV#D|irck!`5^^1mXqJ!olA161IG#ejWD=9mJ09j=-YMqcR~PdG z21v7aJknHFD=ba#)1Tj#d^=v0_K-fK6)}?7gIyWkuIkCK2N`y%qWlPmX$IdlQqEU~ z{Z22%sfoC$DA<~JJmO^}ca}baH8k%V@p6I+AUrT?SH#Qo9;9iq1Zh^0R_nJ2PSoOz z2!Av!VrE5;_JKALGt<2EevKn$-luHwM*lP08mTC0&)|s3kyLr<|HO|RGs=pXT*_2> zT;E}Ysfn@2=cYzXu4Z!3Eal&d;OYe84>fthC?b4nNuYc+Mr^06 zUJrZsT7-J(%RO9K2O5X%$~q9mCiD*1S{g_xEAgqy!-cByu&GLT$kIUhM&lydQL2vd z7SS+h4DRKh(xvfs#zHA>3@|KxbX}6@$1*zSZQ#}L$4hmnu$rN61hp*1VXEMKYp5GR zt)z$|fIpoc)Tox*Y!S^!X=vTcz2B`7=|%u`8AQ$cJA&gXXgyvcq?ZqTidzAUavWQA>wb|Y%Lg%r{NSDh#kS;5kTG>M?kF+AH z(Eh4U#N)tlWlX*h!7+TAC(r7PbXJ-&zS6djaS9cU-Zjqg2A8}S6Qe2_<-N!uA}am~atS(*c=@XV%0?c~|n%<0s;`*58$=TsyuLR1r zKVprvtOtfUzS_)DA3p;F(MskFY?5d3rW)(L z@HejnQk!hZ=ke;J9*;DShaczdui^1X%jfX`iS6Lg=YZjn@vlJYJ9?9D8EKY z>84cX9>pJVe5I(-s~>qaDn%!tMsxl}S2-fJP8#C);zV)Lqlm*F6euc=vJ2S8G3%r< zWO_Ww@kNknxo+l4Q4tIe1)2D5&fA&jSIUGe+mAVXU?x*%H&e*IVbn_uRoOS_j4t;T zOC9@y2#0y73)nWO2Dqi^j{U198Ovw7OzdC5@d^$?Wo>k9y<4|@TQODw_E#)ON31QT z&Ot=OmtF=KHPf-#bR}Yig3O-wIC@tMSDj~V8AGzUIPltPs{PzlQ1nQRE&icE-)aMg zvv9QE$C8l7_AdeEF1C|L<5C@4dw?2v{T~6FF)+=#63(0X!^*0bHMf~#Z%5da2UsW) zf4=9Zj=e)pqPuTyq8Ys%`{R5j{{xeMvy|AvvOynKUt?;Ozm(Xr6BFf2(`)*g#Fxu0 zEGFDyw4T_Cg{`O`etLPJa%d0Sr^{!&-mRJ|<*PUiBjqUy(9o%BzKV8K&B$25@v8Z% zYeaS=+pUq+7TaDG^g~DmRiFlM{-Xw~yc$HZq>YVii$J+aMxa`+1*(VE4c0>vj;%}b zDM|K_ZvD{QJnSX$l&!mRQqlr8_Fi8{p{#==&2w$(T}b6ex?g8js9DDY`V&KU9R8|f zPoz7pxj{wEQSvv+dE!r`E2)(t@o$lRjQG!g8glHAC$D~;^4&B^h7zT{_w!JrnKJM> zV{T7N-F^5n#~uj(K8*_azu@s7SlZ)14gQln{*FB+pFPv&H-^Uc8!OWoQjy3DG)~Cs zlT)}zopdf-B=t)8^gQV>cDzFRJ1FAK8$$`HtULE@py#9)sx@x*E1B z9ihFe>wH%nTv5MLzOrv&Xe$<1NNj}Roghitr z)daY!GTr6m;cMs+_Bx3jRuE?BhFc4spOxZVap8m=rdZ zoRypMtX|7lv0G8g9lJW)r*G{Q(bo{rr((DPtk@W4UV1{wc9x&96O+@f z75SaON#M9F>i}9=MH8Y+J0`^0QD+rx70b?DY`QA&3klTkZL{|~)@6%zB;vMM`v zJJ_r&PR&-ortH{jEOX*mPWd>ivA|e7QtTvzT#W&e6JdneOe)qGtM}=9pCrN4CU`2= z(`%WP=G#9NQ<{!Os<~F0-ES{3&r1syYK)qu2`zN<1JpS##-wfcsHfhho?x`rYtL;F zv>6tqo<2d#PY1dp&UOU@)-?q**HCC7~! zJ~CuEU&;4qmx77I*RCHTSI=F}c2mMrZV6^w_e$8FN{&sWQ^Izv)XFqmw>MBwUUT+8Q!S$MJjhr;mD&WoZaeZqd@LCDXR%+}{V0*d*Tx;Ye`aN)97_4SW zm*J0Aa+-Cf%j*^9gDFYi&jSB}7pz{x;ePZ=j4A?uBM4w!*m#RXBBYglY#@v+HH5^y3#>x@ z5A}2=VQnewsKo68c7{_{Gmp9mE3;^OXP3*WACqLMH%_(RCszF=fLO6uiu;vC*gL!O zct1xUYNJ{>%+E-{^T*u)t}%&cooqjJPH7sXMl&gg5%%V{OWy)5fk$Yt9&`ErHJRDs80OcblP* z(j(KFOMc9>NCMy|?YXIG&Fgq+tx3Dj+^J1#LAz>CrwC(1k;fUA-fafEROA4ssQBF}VF>_I}W086m5&U}k;&x^SS1IADgDu0*0(D{nYH83r$wbs4w zD*t-mT}4>f7WoF)OI^F5|6%jO71nUHy|<9V&?XhhLWidNQh}_yO$BJ#FNdZzHgy-} zBA2o;6Rv#9#9N)X!&4iv@N9@a@+ljdb+0IEbxEslDA^)oj_;DzH+m#Y z@%3H(q58%x)9M&f>bC-3#%;XU#Z_}1jM%82QLV`DuA1w5YL2gD+3|PM^qq4p^OHsI zWyukbw$$96caz4tg4@J81FQ@3d+fAyQ;;yO6zOS(J;*M@)2inqUvQDtP0f^Z%gOj5ks#dCNzzMiCB z?zO!;aUN`ES<>bw^_yvGXl+87Ypa?ep;AnG4)s^itFM1@A0Dr zxwXTW`9JhonMCciXoi#fK)k+;lu49&7K!zTuarqBzz%b<2~x7bKC`q;Q~~yR7aQeb z^&aTn*|jG~dyD1~DfLTjE)@F~hs|%ZY%E_}OAc$1Qv?OYjji2+6Ae!8iSRpX1GQVt zBfQSRrXR_vT@P7e+pE3fuDu*%8Uy4V@#CzQV=!yFeTrqZAJkC0IP03D))mtlwyR?H zBa(C3=IrSvwSbBhJ%5{YY}i<|?#pfs8zrf+DdeVTQ8S`Q}mS#FR6@#;O+u)5k~ z-3Av^osCZOu*SqH4Xcx#5g757Ke_CnXO8O*#E%|fEjw7BYU9rsr2Bp0vq!0l>#j21 zcfBk8RW858`@Zf(M}Ok8dr-*{YhyK_`fN$engKoTKku`%T{UqAP;dT-I2%j>vDwO6 zB;s9v`|Qp}KNR!+6py%bVd5?%(y2*W^`g&iKUmaoA^q(jB>^74A z{U1HTHpx z-)U}kc>{g`$Bt(m65ozQu}Ou^|1wU*KLLy&QS4G(c6R*xB)-LUNvjKU%#DnQ=E#Mr zwk5-77ncq;6!oMlPNNk_SG<)XMpIY4>_z#KQ#6L`G5h|R z{ZZ>r(^bJ$$j`npq(PPZf6^c-z9>_aqRGn7lIwQy^nq!UeZQ*q8}-3y=mFoaVxkXD zXb39is&6&*?We_}Hz<;$0e|CiV+Zub+h*6gBGn3KT_yq;O7872+A&}zZ2ab1d2xR#- z)eT2(Mn?FgC~52~PYdxW>Y@b$K!b z_LyO}G(7XHdzV3zC{1sknhsIRQZ9G9=s1)*iUIImW@#T}g?nuZ+-biOp0o)Ow}_o~ zxDm0nWxbwaH!|#W{Zyz%E)Pmtve0f|B!th*{E|MX%tX;{Afiq7kV>#;Sq++V9)_rx z-B6RM5B@-c1;9&5M6Q})_vP>Hd-Q&jsn!QsD(oIt4hs8pPq_BxK%)IixaDRx|6m&Z zk|xAfoLwyr7P1;U{{_KOm9sZ{%C^7tdez1Nx zZi|=NJzR@mNCcBKyTfHNb05u*eR9AipIwnOm)+Lo|3z{mp9I4y(nchpy_uDtl}RSc z0ev|g#NylXeZ=|e5{s#KgsJy$bD1W5^n*P_|A#(0W)GHf^dn>U=0arNc;3c40{THQ zn{Uf@u^x)tL0~2@g;qAic@SF>yF9lg^n1X{{ERG{ihY5)8bm;lz#L!(BAA?4#3tfAKZBKz-T+!V zNhaeDM80XRn0T@_N;t{lz13FAykhxye5*(@ry88?3qdh47|r+!Op3Y@>X!cWfko%VXqc>?+PNIH%>G1gZeZNZL}w?Io$d z0zc}Nk8TNC(_NFXFOgoJY|u)!I>{Z8Z3j2qT-k7Q#m6YJ*Rm6fKTV9g18^SZ3c2H7 z;pF{D#^};;3Pb!1+B-1X;&)pr8bc@!?FBy#+Qe0?#Y*DSs$WHG2kuKMVKW!9L9*evYmM#hS^%M;f*|th8*5$}WE6ej>t;*RoiDEq@+oWGx}?Z zjz9-RUMGNIm*~dwUi}+V_b*!^Q97jg(F(mFB|lJN6d;?IhbS=>m||7(a-nJRs%;{o z%BvKUfqqe9c7BFeiM#>s9cQj+jdD*D6yyI*L`p&O6XqNH0t^ zK4OXx&MF?wMi;N`nWv|k-~dqA2gRe~i;4FKALm(3n1)#6#rxyp4oP^W66*lYJK7)M z6-xXY_=fTCLp)3qwvf$VgfC^^6OH>fJlyWFyObTOElDos=ezIEZtN=j(azm4yiH6k6(}|lVP?Tn3rFt#imZO6V^&yOr4bNdnNdPDP^~( zN*_InVcF9N}f}J44G*dGT%YU-m933|HpY#})On|6p zsFKSWA~+k;h;oaIdR$9lJSAnRhAVxkq}EN6cEC$eYxppV+BKPx&mQo)J%lzJuy&s! zBG8c0)BZB9o{*F~U@a_Yx{`D_`rGkkj8>Ua|9v~*l@>Hmb&cd=wY zKy(ZRE>JyoC(-sJ7#~Vr0sd6vtYw$NN=v28L^UIBSg2_vhGQC)jI@ydVmbQ)uJn^V zp6*L^gua7XEWcSxv79K?%hDm~5h`$vdbIvpp`PXJKX7SoLBk-+@kA)~43QAUjktmS zM@AES19(;P-|)_dF~1p7DH1lc>&Vi1R?{fL#(V7k1vVqAl3^>bL6Lh190a~q6`CW8 za)g>zmMr>fC6%)eNfbkgRhG*0c$7}G?9%a)qB((dpoTPXi+uOW%|troY>d;{t!X58 z7VXl=Q~F*-IH^>cFLKn z*qkLOZ}2#uG11N6_-xKx*esbN5>8He1OYT_xSofK_-D4YKWE+Hw2HOtGK>V+JCV`^ z$^)e}YY=fUQAbYa*Gg4>>HG|Jp-Fe8tt}#nyCj)C2IsT)jkF@%3lY2GWm;;M(87oV z{)nWm7#e+?QG?{#xX6|ybJ%x?Gn!7%_I8UbEewsx4%(b&wd%@YebeZlvt@1%`U0L^ zflgTIpda<;S4Lt(xyOk6NqM^hlMR=0I+PRXX_2}~KIlhctANlOiv3FHGhpXMY-!M+ zY^hhnf#tBC3fyBkpT7uAP8|6E1^&kpin(q8aX&vK)SV=s2TmbFP7P|)dW_Tt`g65| zS)zCc;9JiW=633kCy*4o%V|ii7YK9w-OkCh?6NdLS;STCeesR*tTxjLn_Y=LVVqk0 z1K?4A*=o44cn)#s5>Y&!tL#HS#~ws_ltPp?%U#d5=b><|&jTgd-0;OuwVXW@!W}*j zRP^srHw%yWJW#6Vjk-{up%CNkzfjlUBA#7VJUP^1-{@@$v2Wn3%f1RM=|N&=n?l-J z)D=&&=MU9vZd6m1ZnsiLZrj506(1Bn`Z=eQA5O@#+O?+yvsn5FKbYCw=6x=KeuC-!&{V#p@i-V)C8(3!uVK@7Ae;l;ksSX)12*? z+Zsv!G{R9Tjci1`=t}*iPx82F_tT~HfX|nqQc4`{lUnY_-rY-k=5~Z;F0^w*vplQ) zFkG8yg1tY|&JjUM?gX?^q%VQ-z$itS4V4Q6a}}9M-~%8RbBI{znnMKcs2mk6_cOK; z@m`1!v-NVCH%Ck$a1*$}dHPai^Q;byG@$aA-TUJHS8>{3UVyF?#$LWCfI0X|RVRQp z%9o=C9ol#!i*GJp_M`yKu<$DR3=teE9JLs7i_{72)jcD_kO@rD{+>pm8Vt?YG3$4^?F44b1!x3?s@=uG7q#C>~f z5%>Y%5dt5-%Vd|Q?aQC-!4;{!DQU>mnH_}N?+VjLHdbeUxdI%`T5`Wxcra*Jhyt`& z+=w@*kP4KqA+O!tqUgMUZ8R-?~FN4UUleJ*!SPiUD z1Z%Ib2iVol8t!H_d;)X$b?tooZ{Ux3IV(mGxv2;|E8^BG{y*y8Kd!1Od;C7<-UHkN zq*o;YMMMQbMFl}6Lq$bJqr$|*qNJokBgc};in=snQNuJkksFKBl8PEDYAC7fGg!{# zlrv*xlQqs{Gfr7qF^yABp*`=l&p8*I&wQWP_w{=IdeD9E{<-$rYpuQZ+H3D~ZqiT^ zI2kTDB8yy9`-p57x!;eGD(_J|nUE7+nlI=Pv?;$(_V1~oOc_7C6A#TK?V)KFI?GC2 z(QPbd#yh6i@Ban7xroj%4548&Bykgws|hP4!Qh77Lug<&&21rqVLR+G)Y9AyBJhhF ziM>s?A}*YJinL&`&InP|4x$&5%?bP}_XpoapacoClilPJ3ncXN@`r;6VdvREW|17W zPZF5w$*fDmzL&&e61jx2Y#{aikETMBUkx@d(fcHUmH{*)>dnFWW&aEQ@QT-PISugv zIUwOm@{N+9v*e!>?%`!iW@iO0(O70D+AjGi!lP`4mK2cjnQHt!?vP@`eDN~LL!LT! zJ5ytoCa2oY!TtfdE*GiTKL^rDX(Cp&ZiNS2V(sDvs0uR;#PtE^w1AN zyufsbr|+3I=^H%DPjE;q>xn-)zzqRm-F>@h!0KWY=)T^ALHGThe!eA$EA+k(43nQM zHiwI~bRW_+oM8^1j76ne7SPfN9OmgJx8d-m6fgD~qTGkeR#!LNK;m|cfxux#T@fk^ zV|l{EvO%E1$`>GhH3>6Cka~Ln)O|s^eT2{~30OJ&0O1WuETLW`2{ET$K((bX`BEl8 z`WKizDOVCI29pq&T?T*AuMRe!-~ku^TP-f&lsl*-+h75l@*rW02e^Yoy9XE>Fy(bd z5dA8X>4hILjOruqDA2r5xx=_=hrxE+@SVG++qkAqq$>KY!R8C_=&jwTv~zC-%3)qF zkn$H1_v#M0NVH0Q2o9@ozTvA z-tAOqgLc~C`}RqCJdfFy0z*?il|-{)jyMZ<(uiyxIX$mcK6pcw?>q)KVhv$6uPo3& zP8j?}f0CSnli=+=E}RifRJq54(@tWCBwC5EP>p~gfFsgPI3}d}gdOjBa(!bpHnS_1 zqriHg$mK1vf-s`hMX;>hnL0k~0@5SG#V8mznX zZg)w2dE{01T2=R2{zv8b4j|`YCC5Yow2bpd1!UZ=e)o1%`YgtYfM99pak2~6;~e!K@ZNIAnTjGA^}QZvii}e} zjzdbG&GWx~QcZq`h4=)?SitE0{JSG)SsXCTRBV&fG;l0VAu@+BT@sl@E+Ujkf@zWp zAyZdK0)3c@mQKBq)xJ1Rgz(x_Vim9;{5E6BWY#`?0hyo6sA~9$b;(>KoHhLK@;YRc z&TMxc+>$S={?{@G4yFLXdwKU$s#sD>SF}l zG5(>yAtD(sIB$zKu0ws&zF5>)V9agYuY4CJFK;?9Q}+?x7)9czQbTS^^J(;XTePI{ zZ@RhO+oIhxy}eKf1Q?O}F3se+uEw=o5;2KmZeTwAaRAHY(5L0Scrl47f~ zNw-l`1QboH_jWPT_tCAXAEQQ6S?+!B-)xv^2zM&Wz3+Y0S=vZ~yqDzthlpUArR8_x zDt-Uww;FT!dJ%Z*fQR+;-ZZHNZPOMI=DYN*X%zbM33<;L3whteO3>s@E2Y{6qa5EipIpV^X)OPH zPcjwWUo9V;Hao)%VVb4MYqxO=iqv@=AN<#^yb+L1h zS8?2e2GpO1yclsl6g((sih!p5j_~Fvhl13DfP5k%{iY5ah4it7B@F@H+%N&1v`4^0 zK>0xAUp6a(ZLPKmTGO zj~&ijHE&(iZTwhdp-z<52P|Xet*o?ZCy>9iuO)>vj*chDT74_RI69Y*B?*L)$F0rL zMXboT!lcnO99dA+YHW*W8N83gunRxyFmR3Hf^JCA>6pop%zsl zsPgxI6?vE-P%0#?aB+~86^r5Je_@U!TpEquNZWgaM04n`lP>lXXR3a{3th}xakP$p zfUw1NT2l%ybRBERIdLFy2(2Ve>(MBp(ePQjmq$NK;u%92xCX2A$A^W}d@@yrl*krS zm^^wH;U%eq7NSr9OO-xMCJmF_+%S`!v^Rj)f%0pb8Fc5c0ZE~e$V+g@>{uLjniZoD zP;tK`grc7kKFJ|*vwZMsT8HxAlKrm~5)X=rdTS??`iCT6L>zvMZRqMPxfvsKAEh%Oy@h4ZUW)Dee&@>W>zf(p{nrlIsCwlIS3kMi?cDHX@S>A8knCB!wZ+!-Mf|&dyaNYhJz|bFkJzHM2 z;De}ONboBZy2z)2i}|)#L8wa*Wi?1g{?Zp}6j8NuJV8AU5p->9hhz^l z=B+-O)#)sd=~pnpwD)&?rEr>0=JXKrUiMChWJ~$W&=6`}M_3~%OpEk7!foMZ=oXr- zp;=&v{NTL*&@`zitz?XtQ%);Xb$W|#B`9*{r9XA6Ez(NBi!`P`P1xa~_&-d-^j-Mc zxtK-+)=&MZo3#X`39~N!w*-FZ!vEaX$m)BoYwoqc2G-Ut>^3%J64xusUlu{J+KZ{m zUL*ZIC{}x=d|Zdwb1P?C)P%FKGl%>L#{RhgCf&+XnLfFPkMAUfO_3f>WEv)y(#(t~ zDFIAIA|W1TZYUySk%~FQu2TAkpw1`W?3J-D3fx6CGe$|`N+L)|hS>DAkU3)>q0pVP zG=@w9!mx&1&vQM0e$J&*#v-bn?@}p)ZCHkW^hVgfVV$_~W6v9MO95@e?yZHmrv>JPFV7nWSR;iGwvj8kOb_{xRJR z9@%z$wTI7T1o0bymrOuU_~Y>uj6qb!%%Hb;CdU}e$T8Qr3+!EJ1OQ~n*v6R8%ixZ9 zgF~s0+2ZP6YM^^{y*^_j&4};HkoB{ViQ-iA28Yrg(@F)Ik{a7Q5!Ac*G=gKyr&(}TYKZLa3RS;fi%@;fp9Muc$T~+YE_x?U|#gy!5>oy(;(#HYe z|3_yc^&Kw(kSRIl&yskZ$Ug{QFsC}+PI6n+3T_YZX%r0hEk*?&{#ME{OldJpYU1dF zOApjbmlVGy+BAfoFYFTTJWgrgqWI-f@QP~RLJWlo(k>Xdq|nfGI>=>KVGaMe!6qqjGX=lkh>JjVL6;s0wtk6sI# z;3C@?+00M}1fM=8bzGbmLL1@Zcc;3IXGG2J5kCHH44r)+q@#L5Ee!d7tZ!2a{QQ0@ z8Eu3|VAc19Xy5OLnJlHcy^zlcrVWgex1szk!M{>UsrxH}_@gvLw(etpi`ojN2?Sot z<-j~d_5tar5L$DD|4hDM$uOT`7x#J(Lz1l>W!_1L6mf@e;8k?R+f_b_8Wq~nXJF?P zgA1d529fL0XBC@L9Es&^2km>1hz=R)X8{qpwenFXA3tF%9a7_j9!u_E-|9%i|LG|~ zI9CL7t$))-Qv|!tFvl4n{f*@Q1jGi1hI`7^CKvkOURJ~%hEXX__zk>{`^@$x}FEtR!IFBf(S(TC6w#j zP41wf5J)nG;T&>F8TR_aPf~W4iuqeqQglZ^d`qO4sqDXTOQ-`Dcdn7+wdWyMa6Ki$ zu;SZd6cM1+(}nCr%%s94_&KBB_4@NwhP?kYE^I~ zYS=lYKo%JK$#sY=5O6EHuQh&_)%P4u7ysVwbPHil1({tSLC>3pP-_%gVG0c8NZ$Re0jI=T)r3x!N&*tHXv|E&lZ7uT-Yc- z_ohYaMkJ_<@IQ0Nt*3=3B_`O%$EDf^dJkNMZt8vFcS=snRDh8WB1X=LT#aq;IL}wo%J7ciVkM;4%-DuEr5!P{E5I&d0 zej@)Sd@G4PhMCC%of*TP&-ETf2fB^t9rw{WA4g5#o$K1k^U1@Yq!q6GG>q|Fg~NzX zUL{*b466RJ*S65&$n2l2WM0>Xa7wf!TZk`@qpj_web@NWikOP-U-Y*TXLCGE+ zZAPjSA9H-pPAj|!;=R(|(}ldW_Lq&C3oi`j$M?_}6^w~jh?tq92*V{Yfe7@^oGJXl z!|Gdz-p#y%u$(>RLQYqnXAV&I+u^*C(*NoC(r5+6w-IV3aSM^qJ$y7u3Wss#{e)(L z_gjI7S(o`ZVLR}|q5HgkcVY0O;dhE${DVf~&&^~fnYmMD;x8f0Lq9Oe=NXjvbw8D5 zgCARwk#m-$FX((aLGsoj*jl_p$Q~7t$mfer^Xv*kipxYa*FhAi@XL(?mDX}AOA|QN z;nb(dwWm(Z1z|q@63!R1Ab-kS()`5*C@jDv5gXuB(KOlyC@#<}=5CD?yOaLYw<&f6 zRerfqCYqG;9F2zgsRy%6qgE%`URD+8L5}urW@4Kd1M~jO@MIYJ9P;xzC^zp*sKy)& zWpakomY1KEtCg&)%Ek>2UlTx?Yy9;qN}*sb~$DKY@z7rQ$3qF$>54 zQ3m{cn=EPs{rq)}uuXHOj&*b1cis;XJb%#9-k%RrAATA&%0A&HXG${u%x&^yykk+k zkmVL#siuC0Ml6w}P+BCSN`u}e>#A?}2i?Yd!suhNt{z(mVRoYd#~&m7RTBR)%n1;O z$0`ipt620CN(l2Lf#YPtj|uDWmc1%|z*iTLY9~C2hxgSnGOqWkaOO4|x&F_;rgyW* zxS2dU5?}5yG$Q^;|6}f8L;989?;UsK=2(FWd>)m~1tj0ASBkB(5nKNIUA*fl>b;8J#${Kj~0(@R@Z*cujb;0)USB;%S9T|!2+*G zMs6g9;;l!qeR{rPPA0*005gi;6ZTT^L5wUaN(bM@TO4HgzbKK4-%|0RSSo!^_ym>w zP$GgXT^AU7#ri^=utMweYEAXV*AcNQcr41|RLXoP9Uv@{?mHhh1w^_}qI@4pmkCQ+ zqqzMhfYnRS!y@7>Io|o=AM`vdg0XME^AbMZ&=r_cRPbeUl3{K~rY4*u$Qk7Jzk3Nm zt5Z`X8}-yYYo^|$4jOt+~bhzivwWAL64xZHc!y%*)JtBlGxA>KcHm!Il{w2 zHX&l`qupkpU3Tol2E<#aGyhk61j7N)rj`B5#4`y|ES#-f^Hk5*@Z6UT?F$Y(u~nBv9d6!ZiYM0RqM=`pk*z3Ab}-vLK7x%YnFAO0vnl zhtS9`Wj1BcF?+(FPXVvCSsS+zOhni8o)40mPR%WUQ5L)_@%zKXc+X zLd$d#4|bc;WinhTd4${-2+xt8!#Lgn_+H``13yCs2K6WYj__N#mvs`-Z6Csq9!8^d zMHzmDDG<^kv9tlIo6$9H{z6w$mgZ~1i;6U(8#$rAmPV@_%tbrq%#t%~?&?T6(_aIv z7nW(AA^RgrV$dYI<)hN_2AT5c1-EHPC=!z(HKcT%F1^t!Wh}6DGlF-rM|0%1c#GFW z`A>+uZ1YbT8B#j&u#oCD#=E(h6o&D{ZzS=kVP*vhv5;o-bKS-%k>gnQ#-pWlCnYd2 zlr>T;DU}F_7b%-XnL@*4!Go-9T{M%T*A4%_gygD#Y~W>ax@0PLTv^C{7C${{sxl&1 z6RwiP6-1b|S%Q_ijtJ6_b+;toX4ZDX!;)ykla+;FW<4c1Y@wrn8vcLEbx_5soOOV( zPZBK1*$^T-QW70Renz;9d8c+u4!R+m@nmzk$y9$L@+zT=2F+33rZ0nG8_B8h{!W}l z|F{~;HIJtJ4}>>y$C%A{sj~k@klzVNP6b9YgU?3QX8#lR`D(d?fWG<%H+5F}Zq^J6 z{2*-eHF%PZ!$^(}O?4CqS%&}X*@DTZhB?Us$|*^FLjt-^8X_R~((rpg?$EzMgGmD9 zTK%(+zC&)2J{)mNVnvLsI=AGo2$)+E)FsVs$#;E96gA!N(DjA#Y{_omshmq;n0L=vwM z;izWPl|oefIcCdWNwGprs+Gi7L>?qut{_`W4|OhtY%fvtAnITeJf8HN%;^XFgU|{3 z&7hbAS@Xd-igpuzCBulwcL%6{Q~>A@lAqF$l2X_PgZ_D@`urbJiB;G{Lh^r36iS3E z%5a(W^DuaOb7g9y&IF3@IM~tkKP#jH%8EQc7(5`5Yx?9NBr^N|*{Z6)j!L(gt^EHN}%0TA0iNhl~ORt@emGcqoB{V78ePj$}x7VhlZQ#+{RM5rIQ$bMt#dstA=y zPz0@g3iC~W(owws4wmYFAzzwUIknWg*^r}+&3^^pebWAK(bu;ld;82)eBTbU2mQ2r+2bxB-B1UoF}s3br) zmyK2~-c|F#bBRnKjFkimGIuUvmaybmdV277Qso30-h;CB$i1HMBS}3#gdJn9T-ANB zjmR^EM&;Cnu&1XCOu6Y7sC&o&NTVvaTWR(-Zo)4)8w1o!me;d438fUdeg+q z6#Rfzrtk-lCwSVR{eUJn{vq&o<&}#BydWsr96gen=iwWhSe2Yk>@k6CE zwr}t4TOw$4;w$Cr+?G#;%f}<4x`@?Yw8yu<3m0jzu3|Nid0_04a<%)LsKkh3Ce5?z z!*8PULZ>X5=rj>Kb4ja1oQ;nlzeQpfs;Fh9-lI@jWV(i z3GYGD%`}86zWbfX*FEd!_AkH8cK+d7(VuanoQ^K{!N&=5WSZ{8{uu7`-} zyu*F!u&9G>#J6`}XS3cc8|r}t8WBT7is>SDX!!?s##NA3`+Ixrl0Z2bo4oHa7phUdgvzeXT?E)Z!F zXX&FX9#j57_yYCv=m2stRKFLC@lk|wD&JH6GUFee4jgcOB2t2oN>MH|^9f2GloHf1CFra5 z{N|_)cfNnx9gkEkXC?yZ`@OwY(MnQMCD)%R5x0f5y9N9#mJ{b!Ce3J@xgeH#Pf&gI z9j;t4<%Pgajydl2%rb+{xTTL#KAoYYQn6W7kc^9&H+42)hNF{u^dtlDO1jp%ph%n} zJ#~ipk2EIcNy8a=&s|a`8PPHT5#W z5=opQvYBuX`lctr(KkK(0Gc`VC31PD!t9ALlUzV7ae(8~C>R)t=JlVt5*R%()O?$; z-vjs;65QT!y84_17ZHIDcK~hXp){tR!m-Nl(wOngApOZn;=rg#*85YbY;i;UFpZf9 z;5-{Ci08SWCq80~{^+RvTA&6WbB;<*%@uhJTnCxWY`i?Y6(CzY-)4NkA7L7>XZ+5AglTlO51L_wiqo#!>kIx!^Rrb^s zmrcFwth2^fuDq`1rty=qCQZtkJZbXs>?yfZvZjt-lbw}i>;l5(WfCNI{hys+7$b}b zlLaLBx@nkapXfGQgL_H718d&71A30HqjtE`pQx1oZnybZMZHt$-2YbVD{4)DxZ7Oa zzJ~?vzk?d!r_zkGyUn&WCvb*1mDIDRm|<6Tn`?}=kzS^Ug!!q1>40%)%y&K>#!=`V zB6oC~w~HZ;S}pju89?zr`=)J0tXz#ouq5>^ZwZI7TTNCh))g}V<_B07fU@#?)1>oN zmQxd@Na~W6Cruw!f0|_aXuq7>&&E3+*7X-WB>I=zc^MJ@F`%rkm)zMB{qY9L9c@|y z{pTj9n8ty-oxWZ%xo=?{cp{p{@2c%TM4e;atiJjoDru;LxY^Plz2*xJ1i(fFE1fXv zzR`gx13&jIUw)(EivzUT4_qdGe&6aqYVw1o&N8?e58P%iWf?#?@W_4bfia(t7VmO~xOp$=$y)RCw|oxEJ) z9(g3{lE-q$V>#q;`g+B3$P=f@v(XHk6S~=Fo`7V=7x6Oi1QAs;g0~$Q#shF$4+pJb zSd;p%HfUyGBIlJ7iuzX?!`<{Y(k*x_tVuKx9c)ZI#kMs%hAgSuMR-9H#YC_m@{UTP zkoTwLV*j5dFXEoarrfYDk&i0*SPKT$Z4}b>tR0fL%P^<0z)j<&{D##;gtcqhQb}wj z@(JNJNj%BaT1mJ<63-KnMBXQa-j&q5#J(gPm97uR^6@z%>0%)H zoRx4tQ&c-b%!|s6th345PAh)L*vz*HOfMs%ACWPHQIZ%!=%v5k&+#;l zUJR|$(4N6$vYUilC$7I7GG|0bX%jEG}sicy4NlE9joK8p}Ki&UgV47*_ZrINsO zo6eqM`n4MJN+4GN`Ce(Yn(XZad;$h{J4TuZoG5-$)5{fv)0jUfF_q^ElFBeTeQnjmbCJex=-;RS{nIgct$uwl5AK;RjB z3Bu3Fr9}Qk_(BpZ409$kd*)C{ASN?WSTiq>#4SYbCWxkuypzZ{$Ul>dBt|4$nR$Tl zhDK%^J#`A%k3npME6B!yp3M<~SI&Rk8iFQ3AE3S>mii3i-2`j2&XM?_KJk8i;&yNR zz_)$kU#r;2z%YQ~nDT(W<^Vm10UH|}puO>aR&U(yjRQ2Cf8cBN@EL&wwJ|afadCoG z(g(TTc)vdRc5fUw;W`JtcH{o#%dauqxC}dTqG0v9>W&O#Oi!>{`XJgH@7E{a?v2wy zxDJTk)-RBxu8j%|L(y6fYCwh!t((1+Wr%itMD2(QOgv4~-iaJU95u|sC;oq{X*Vx3 zBSf2trges+HSIE%C|A=K3}vN_;WbvSrY%5S7Tl6}qhUq_P@$rX3nbi!2DO#}WgD4B z)*sA>Xsvv2p^Pa~&_(4CW|27yomC*eC}Uks;zGg*eQwci7>XpUz3Q8BJw^#R+-2_ zM4)KlXObAsd&;nd3xANrI1-Yf6&4%4xw(W1x}%M7E}Kc`*CW1<{KW*_?ZZSaAzTcI zh^L6GBJhhcMg+*r4H0gU#IK29-Ot@92{<$tX3iDe8u4c$Qu-^c@-8%t>=d#^m(Kl| z@K;H&EQIF%o7BH#Rl0^cS@3M06kTVS^RV3K@rD>9lC^r?2!b90Ds~>~c^-GBj7a*P zS4ZHn4I}aqBIx#ct&)()LBiXTc!|h2gfBHRuhY>o$Q{MLRn$U~C}1@v_CGc7ZK8_) zKWpHG(v1S=G&TI0139c#(e1tQ|7$fo3FtQmjfC$8@2?`IgVn1kpsCZ@rRaXK);;(yF|Ge*)8XT?bRS7xp;e~^<# z9gy-mi(4>gW+IN1-CiDuFBp_WH?Q`#8Ik0}&V7xZVn)hE6ABLKlMaR+tGFy2?U4?|^sV7f8_%N7iRo9yF_KRL{eaG2{d^U!HE zdC#ahnvVa%_H+c3kC_J|7uP!U2)W6 zykJm%qA>e!y?oI5IOFr##2itJk^_kY{;oOEOUsYdEy;nQgFZQpog&sp)f35q`_eJ=w$Wq;@fyG=2F=Fbv&E_5mmfLM^K{Fc#e6QhqU$=R`ESB6JxWCXa?96U+ zyX2GJzK(C)Bim`Ozw7ueBE6Sy>W2St&+rEN_r-t|r%!8;HLxgL$~1E-;AM9zJXS#k zC*jnRa?9YMPp5o!yTOX*6zNZ=yvQqW13|wa=lwb5*LdZE|9}jyP=4*psqk~J!tGfU zmWM02<-Sn3ype?lu?_#}_V(>w`JGKWn??s#FWDJg8%V#-x?)ZBO*p3x?yWG6eX*!_0SmP&N5g-lZr3zON)$IocEhEmXwBqtz@|y#L`6hR8rTa4q zPouVZMv;)z5+K30Ix}*cVWwANb~&Je`>p9lf%NpMvI@$m8L4aTFVlHkzHsZoi3DGx zVI>sn!G*JxFV-Ft8epZ;zaBGD7jdW0by;4QB93OTF2hSZ<#ib%j^Q|B>&3l#F>X5t zOYBhxjEkU1=2-KLZKny6c}A;&Jc>y7{vq5K7O4ZV_Vgh*GxN++tFYBFOT(39```D$Qt7gW8_vVFbXjOa;V!VD=asc z3RZ$vS)t7Bl~(G-Hqc+NBC|cXWrY_DJztQD3|d-27`IiKWfXXz3+6kZsZ%yz<|=<- zB5Ms|Ub05SlNokCS6Z!(m_0EN!P*mZEEbK@6yF}tS9|=Tw)y^ z(ma%8)2Oads165EMUn?|d2E6&pPB67y*w5YTHFJJfC+pDw;F!Ihgzg!g#+FnT~)-Y z`}^DH`VU2SsL%S_lKr#!AR!dS>qM2~As0SUvWEXea6cuteDl6gZMX z-IUBTsQS_xby3hB5^CwOTBCcMCbF!`pHwclj4Zmy+T{T5wi=_4IJLTE5c22N6l8?z z3^04Em5||^wAISk;q&Ee)yVMe5Thb4Hqzg1zK|lTh3@3C8Y^U^N@hERI3Bex;Km__ z{DH@1>wxanh)pqnWOYaF4VXXbTb^RBaB@WzI)7eEjTbDYoK>UR+7+O&tRo)q7~X3V zQy8Zh-FR8Enmo|X7<74tWdzMjgcfJ;bts`BQLPzh$6c-q1TCSG zeD4cvv=Q!&cAG89Hv4Ea$+nnXXYeKM!qN&xSGEb*GT37Bd8mH_36EBY2Q{v$QXdbr zX9sI6qtGn3$~hw{w>AcMsk}j~XfiE3_tIpTtlZzQHmscPlC5+eiQmIVMdSR!;|95#wpYjrC4uINQr;4?P0C&Pl>y5r5`Hws>=0F?+c5^6Z(gdi%}c|% z39NMF*2lEOkn3}FLnS=Ow4#GdiLU5<(K@EfLIOw%g@D_qIK^&UOP`e23wG63d-Seo zp;aG{nm|n&rW4h(j5aGfG_5#4fmU+30Dh9)W$`NNC04V^$u=T46+) zmBmjvl!Y_v&=pDM#a3oLKd_;3bSl?jY?(`~%o09Imiuc?fP@2QC7jA*0M(+VH5~Ut z%B7=KL81ReR)UCERvv03uZURDI`Yxhq^1g%!*4YnggtE^zJr~ygf zBw0qjlWA4gx{)?tk5-*eb$}1!yt+Krx@}7+EcUAyrRBR>OX$r=sHi+(U0o&F>vi^e zvfW8^HIqQgvwCN+JTQcda=s-!nq?1bU?Q4=8%qXP=Z2Ft=qPm^O{@#aLV^I|nF(VpoW6sxNF zCb=Wgo;b2c*3fEeO^sk6*6hH;dPCrM8L@1iI+8*x#r#VehcS?jPcoPNp!l@8Xz zuZt4Y*+c9Mvr$zJu`gyP&^5%Kl(G@aXpjG>-{wibZr>h~GD`g?ZSvK?p?1NgQfr5` z-x_kGF)8&%V`MHLI+B!=O0(CbnJdc|w`?C)t;qSvv;|vu)GNQbUvNaTg;mNpPyiWTrWq z51fnl$XuzidJ-FkKnNGDb6Z3=ms$-8tqHv*)44D_6Nc9(Y)e3@^mG$iox4pvoD3`X zsolwTvbkR!PPRv1eLyN#Te<8otip?-thOw4eO<)XFduXZtF@YiQDt3)^rh`3qQ060 z>4E?Ba9)AfgQZqd6(7xJm+2zq6c(y$hucHULe)6jPMBC7#m_i+?P?r}55{TE(#d(p z;>-&Xey>8IdS|#j!fE6V{(QsYZRn*|9(v6&7d;-!H`ttSsZl9N9^aKIcG{$)8=Z=P zKmS;x*}H6-ntE0ZmT zCtW2Qoh2X@trpJfTTiQ_WeM~pROC++9DJ80sIn3EsKrtgUeZdsgfyjApwQW#yYi*8 zp*{J!YsOTvr@&)T$>CJL{X!i`pz-jkrC?z91#jw^o`3 zx{D>@G5CUvRK2~FDiu64A@q}YCEbY3dU4^0#G5TxBidLK{(|GGeWX3iJg$B}l1=*w z)jiTqs6dL?Iaq4|QHpRle~fG~1qCwTf+ALvqDqNMr4_n{RDib?$bWUMH-yr?nx(=T zk3FUPRMjYZWN5!IR_|F#cO>bKz>g?UfhY0y1SsXyu!_SqtYWF*WS7XMD?(Q;$?0ua zD|14Rx3r104r{lvI0ye3zu!3CQTmROWQGYDk41De6hS zLJ6tfaF&*r(4qV>+NBkik%JiI7x&c;k_!i|xJ+M7oRqoDTzY5?O&z=%bzzTsX0$zcUXP1ns<*Pcr7~@+tU;39 zi{L_P58}$2&KCTfZWkWZuqGb-@36@JZ?F!kl5`aM5p{LCoyOOubUQxrh|mPFxtUc!ezVZZ)}+1)&}KER0p%>Gqj37P8z^jQwx!6D_DG)WReofzLv& zc)>D_oahdTdVkPveuJ8mVW%ZFSjJ++W$_{FG>TAsdj<&V;;Y=^UJ}gTrJl{O2hZ9k z_Qn$HxQWIQKZ2&_d~y$o!K1TXgJ(g#vs^hSxHXH4RbY&rF>s$DjCR&i7;BUrRkO#~ zsb-tHY7A5Jta4d)S6P|NBWq19h~j#cKdPS9XmNUcp_PlSCI>_9tTxO_UF=pFS1mUB zDoZ>iR%Nxn#@uREyUSajDpMiDR4nNWtp>BjlVHq$KCZ1udr3gnRdr;E zxywGvk{ww}rgq$9V%}M0s7VK>ak~U3nOMfSgO<5em5#OlgqfH%&Q6+Gks-S;$9Ogt zRmdv265j-us)kE8Z5CBzxVp|*RI6?oXSXIUz#g;a#9?0TC~7kCnFX@M*4nW^-CEhj~vj&3#MGO z?kF6jiLM!u2G?WhGFIl0`YzK>xw0Y{IpC14uD#f^xtD<31N+sOEiUteeTs0IdqwpW z9qm)ppo=1;Rg)1p;D}SC#RdM~S*Ys9+e0ywTE^RnMWq=Y$?t3y{lm&w(9Wt!ZiVL$Kmq>n!J&t0uE2^I9%el>pV*Q zmttwlA7TQU_3f5{zPI9QkinWhBCKgw->&K=U~IOlZ4>Nai#7zT$PIn`p!IuY>!Ar( zf86pniqB1`Sbu`wgV646V}qrIUUD}C_<;`TS^o)%x>Uc3_BggG(z zC^l!MRp;C2!&|FGgsP#5_F$@Rp2$}1V5v9$I}fh&#vkj!Z78yg6?pYz`+1E+lsgZu z=~GR_{Z1~PT}2C`4dqtETBBZm3DZsLq3Cfn)P?bHsMidqahcJu(E_w=!i|O|$#%rE zI?Uxe+J|~vzM~y3!%l}^?Z~3bs9kL63@jYe^!YR|s?^pjJ7rd#P$kB@hF|%6MH8TI#Dphzk5JBmTc5c(+m17P)S21#gxtdxH}09Y^(NFn6A8riM=jxm zjvh1QBmy*?f3RhJkGe72o&+d3j;FGz$RVckZAS}ea5EAMO@C&L|^ddOoZRWsy8Ru zDL%fx;CptGsJo?BLX*6f#sT-6_C0cHrUmjhv6k;HH~;nAp2*0h_gZDVp3QTd7<=p0 z`8oCkvtHen!wlM}9?G%vGn(sskxTBiE~KXXG0->iWSv-Im9t*;<|$t;`^`KxI@eyE zN{vytk*OimhjG18BsP#^N4r2&XRckioSH$erWUt1nv#4|Txt*(?r8u`Nr4Rs&?>~i zn3Gcz=Up zc-rc_K4wGH21AdwE_Z4&zU`0vEDh%p1hs^nqu=n=MI&Y2cRA5{5*6*p1LK^ zPLJO&+6iycaz|%5Bx}uAFXpkOt5+Z7L8UHrDojpl@~rv+USWXTK;r*L>NvFdfMMPszosr_f! zxopKFrr8ritTW@7Xye-a%*?QbYdmIIywx7%dfeF`>0Td8l`|Sg60Fi)|0xuY6*|~( zp6i}{7?0(}YJW2$AnG_Y5nXw>>alK-)ljvSfFa?ina7UAV!3D$AZis9q-s%@5zX1< zS{;Rs0+FG**+I|`O15B+4@a_L9vdNx?d<8*$&aOatj?GEG8t%4RH;H|v$x@U(b;Hh zog8c?NUnU5d8Us|vQ)}noGas8WyR&423)c=aLER?mQXT%chiTXD<7^auwb2MYQkvnLf@<^<(GLj;_$#1WnPpUP^G?0hMZTaWBx*UL-pFU4 zcSL=fkA;w+BBt9T%_NmE-AMoUQ(_0%w+CYt1q3egaTZSjcQJTy?V$I%NUA?3{B}35k1H!D%6_=c9Kjx z7LihGzweMwwh|B-Bpzo@Fj1`?K7N0h)zissLz7jZY+HP7Vb-?=5=3LjQr=dtPiq50 z-?pkGYtvq1D{}3n4xN@d?4(L`)yQpzxvNAbfm^v?Av4Zl2(TTtv~{wki9oKYkNU%x_IEp`M%t@jKPtSy1Gl`g)cC+0rD$xzK9i1_o+EFX&sWb-rBTs^Not zTToj0h)%w&N`3Oyz=<{MG?^Lb7OZ0)8W+y%M%$RS{!KxSG1J*RreBmH3Bxb;!j^5g z-Flz&Zrv2cV%gpPeD!-=fCPwUf@K2XWSBqG^O4(!>4aX-m!1v(m%;2XymD ze4_kO>!nmxKi5u6sKPZZTf8>&fUPyRQ(C2V&&4smPJK4lzC5?f*+2s4$60&9`UpHE+J1&DXm5c0s5# z!Eb-%s-0I#6U=3hkDgxXYr2up>!@2m9nG(o_E{nl!n&9Cdq%SHa)m_&o%?cS*hYT2 zlYSm{`ys*lruzxK+}X!QBoXe2xVH$taw6!rkGZBa2?nbtz$+&L+P?G>($?PIWM*jnjd0=TIz)&%#MxfuSNDW^RODWz)s8EFFO*{#Wr(?oPO!C-rge~ z1wE=C^MyeZ{sVMfoVsCwJ(a6MPcN{~J`(_9zThtsDc8)ZYgMNfaMh&MGVqNou@0HX zypuISEmr)~i>(4I4QF259*ds$p=t2-F%(~gvu zD%weOiE)NuhnI`n4y$bo5t75|jfHlqFBDYW3+=(vu!tbg5{`#XI2h76bSType~=9Y zE#7g(A>(m5YTcr#OtE@nBaRtt;mNoVGX z;jzLxAd3bYd?Dzqg=$kV>+v4-R52ENp88#}J@S&u;}#^ZdJH6S88LES2+YiGk^`$oU-{z7FgwMQrr12AX`@;BrNf3hKl%JFT!fPUAwoN9s@uTDT-?ueH1uGE>Y)+Pux5xjiM% zzm~fN^2Z3ar>M&=vd_GFd&+R%T4x`ia}n{#yNnIS2yS(W?^4r#dx4movh11L%Yu%j z;>0z@9gs#zK(?M-mEhooL$6+SCmm9%KDx+G9GKN#yRoE=&Obj>#a@gu$yB))V}xg_ zB^NUrGgXMpAuX;!C=OwL7VI_Jp}H=%<0F83PNn+G#r9xzQkqq&^m10SR<*p`PUP#R zayu!Q$z?g+o9=H?vwE}~p7Z_tayy6bo&HOh_`XR;RQ9FzXmicZvPQy}X5U}NuBK2WUv3YLpMsGZ;96KNOV%afI>oBwa`q~v>PMF|-ct4W z<@T^)m{nqhSV1{Ts5AG=9PxTTTGPFho`8(u#(h6jKn@?XC)gZX_@X-o8 zE|EGn;#AsU;@i0b#U_9BuxyX&SE=>Sq)K~YNlGxVDJ61J>L{+LYJ={gl#;+EV=ccI z&rZlC+eMa;biL22ZZP=*3$*@4?HQ3jb@qg^GHB!ZqIUIcrJZsC>xSG{#DMydqYb3z zi^z4xBpQ!0CanIWEL)Fgl~r*SOW#!o`Zz5#(%E~|s4KY9!S}o??BSVG{VGnpr)gEHgxs~fMhQ$szBo0Af`*y3Ng zOD+!A`D5_{hcldh&TQrCiAxak%udG!jc0q|toP=b2dBy&>`m4|td8*|qJCEB%?_On(99EEOMb~l3 zG1sQoJ9dZ$o8N93XH(;B{osN=>!V8k@oK~*%9h#zePAg4IEcKRsRplPl4PoBE4e6) zj>^Hb$l);FT2n8=sn1qv`E~^x1!q3I-Jq{y$kdRix59$-uMfJeJAF2r`yVTUlqMnd zNfQz1iBcN&`M7P>J1gz@5$vd0hXnkuoz1l-fb&7cJ$qElDwwcG6*^zHuCk|)>R4ru z$wE-l(P$Y*#deTQtU%6VQVXM>>Ofbbn)&rfx1>a!akZU1w?gJ?BiCGllxdsp*A+p} z0sQMK%Xe+K_xs8$epsT~YVo&mTM$u`KRUUuMyHPnYPs`DB)A<8r?<}s8!XNA(iUhYWrL)|BtHeaq;^)9lKgX_V}cZt5MhBb2_5V zyT(o!d<1~-c}<<1PPnX8`&BJv+_<{$8ny?y>iKI}$8yz&*VyS});Xe+Ag5>@=C1Ie z#!k+7`p9{Ev6{FV?@qBg*ZI17wLR3X;{p`iXm3+LTg}S3SM8F*z3KzLR_zs*S6L|) zK(45EB*rh2`NGjGE|)Mp#DtR+k^;G8Z}P%X2#zEKvY7IkgkG-2sI30L>!0OFPoGkC z*^lhR0Xx~T%888p38-=hn{o%6^8X_?wWndjGc~=~)c#j&$o+r8rdF^S5^OpRnWlVo z(Hdx9rEXqhr?SP^x(4pSS%)%Ce({@eNiLDGOlSR(J+=T z#;G;e+3`NUg${#W%w z2vd#IS!d&abarotdj2}({D^x0I{WU68Xb8I!cXql{>Qw}rZfd^r=-K&bSag29}yw! zld>e(os`b11slj|b4+kOrUjkqm9=*KvQB)g?hgQ1Lz~RV?fysO(*fda{}vn&23A`E zbe}gH790}5)mBoD|L%I3A%I>eha@65-mF?srpDLchh%mnAii9W6)%xHpB9jtgkhEB zs9Py@cKHrwhzA=4D@LUYVI~Fx zzUh79-m;sRfSK`u*CIjgcetQZ0d=4^AqCp%NGzY=QI^ppR*J>PZt{$-e!>kwJ*9dg zD}uuoGo?YDxSlyysS<9mXC$-Y$+1{m5^kR6Guj4)y=lN2VW^rLn0X!Q{u}K1ED?XD zg>RIhM&4*=#3wjQMY?9Xj95sYvR_?xqdmB^c$-gFjEg#4ghxomHtePbmohp-YV2}p zI-*$bHuYxCjccI#zKbAJs@}ZO9+QvJUclI`fM_a@>r%xXsiW<^(Gw}$ zgm;*6Ol7UZ|8qhWud|1w46)({t~YYiICY+uyxy28PZ4Tk0a!y~W6x2;ZnDo-yVu$A zbE;6_$TbC{YCTV=IjT;32SvCNkLe>v9p!2SWS1zfgmEV&Q8n}?mZ$`^@+LbuzDth3 zs;&J4-W%vlC?VaDgX*E1*oCF2&YSEpIVqTILc$#jwpx36drxn?F;d5Gl5rcDOH4Uw zpVp${ZpKZMs|s$mlS*<+z(Z3rE%*HYa$Sd^I<7i1ZI^acmRiRm>LO_*YQ!APO&lhd zJDJVV1!~95c5YDJ@@+V^;zvnFDIRr(~Izs6KYH?{?mh&fwjdWBty5MF1=|w^q?xQ z#U47YZmPA@W(>1Lnc|5}JT#J_MG1?N4mrzdztiW2U@hC#XZU zkS$d}TxeyKYqzp=B!!uBhRBn9aa@K-=?J)0#waF~6F=PH zb6{ym#}Ff=!rB$l9x00=|L9;GL=j=n9K9`4d+l_$Ad7i-)U&$TB{#ED7?G@ea_%?OwRy!?pu#h<@ zXGZ4uwyc;9K^`4Qh#Wb}V)E!rPK0E?EagWt`$SKx>XdUdTAI*So+}frG_C?Tr~!$FPh$8frC49c(~czkjR99xX69NR4~gohQS=Zq@pL;rR+FfI zeS%k?tAijQW6dO5=|&F+oTtMi`*6To-(|?KHGjuz1}?RNN6b3s*%K!_U$uu&!TD-m z$R2I8ArmKkT#}kmXOC5Bb#~CKRa5G?mBbHQtluy2L`jV29MbWrn-em^WSLMDaNWSB zL|up5gp#0~bLvHZYzl*uK?}Xcrpn%pcO(&IZ*yZ@q)36^P1D?IQUf>QjF8i0ov_1{ z4gDDOdYLD3V+-J%Z=HS^Y#l)44~7oQb!OO(ksC8)$0+m~mXe_#2ntWq3G2jZbRjny zBHX#7+fJx+U3c=FR#vCF=61WEc-3X<#KtidQaU2^qypx|j27XO*3)iW^JZcmvjsXy zzY`1VERQ-9OOE@sLXiA2jvX%VJLR$xWOv1i8cgB|o}^U&O+2-jy2EEKo9}?i>co@m zKJ`1%yPBfqC99sBO^&2zb&6M9cb#=~oR&s+)@B`3vwqA?j^jaONY9Ea9o3Z2I&S#a zbFI)z2n-S9>;%`g>ozAG86=k?bcYj;6iSC86B8rvhbF_hw;@_6lW{H*B;b=C&@W>uv zh-QKt*Q3ww?u^jBJ*jhI4LJ5uZ<8vhFSHKCp{L`L{Oh1~QZCFf{rV}f98|a=Ple#u zX!eV3lc}NR2DWh!CyHK7)=Bl20Z*2*6@^dBd$ZLa*0bqoR7climA6f<$kSiW z8L2cqATEw;tV-ZD0A$AheQ! z*hXIOs3R?*IqhXy${mU5R9|dh`gB-Uqg+?fw9e^t{7}NZT>+~gKh;BuRHNuk2gSXy z^25Bfy-BNapD0y|1x;kZin_rlO3O|K3GKWTl(V@}racc@xO0MXvxB!lIc-v0os{5P zFO$z1Z=8%bVRS+-{ZsXdqzRA;(fW)!Q+;@c9lt6!AV=>GpL2t_tvTx!G0M#^moq{g zjdkgz6G5%M1!8VWtOt?bmtr8f1#+s6+bY+`D_Qf)L}`o0kU{1asfs(HUy^Nz_F|sJ5T&9glNq%1c6?Omz~6 z0{*n#B2uFA^sM67I|Q=z_tD)Th*Go>|s2qBAXICgdW`|?^oOIVmp(iUb>6x zpLy!DyX+DL#|RY`LXVyH(Op z>@2ROp8FH~4z8;m_z9bxjLnTWiZWDMqg~C{&l~NVL;Kyw*E81WlQ%~Urs-S;K(5$C zvN*}0ryYcl3_5=)A7xcYj@~m(JCP*S!g2RaA?Dd)EIX2Oc0jxFwd6=#R}r8BcFKOW z>8ExIPQK@UYNwUgxBFy|BsYtB_bdru%iRYOyas@TElb+j^}I@0kaM<1XP>|!L3Tdx zBhtANufZuJ735D&R`d6&oO^JRv0bZ<>3b4JH=Xu6o_M`@E#6FX-qz3_&4!}ZQMqJ(A0Gx zq}Tfnt2y|%_gK0n{^Wee66o+I;8d~5eb?*f%CGlk@5~)?h2=^;`y}p4h(xiqg^4q} z55j9B49;mHVC6YHn~m>-DHmnwRLErph(1`px%*#f;LAE#6Bv3 zNY33Wv!KAhZD$K21#OL{>`~;FqE2`Yk%A+rM+c)>xfp=1pJY~tBTdv!?$YNInrP)_ zGW?f^n@-F=wqn69eIgm|n_>M+2N1<#qP3IVGQ9_JYZxuNP@SMQ5D7{b7 z?3k0F5`PZoYt)RN+gD@kKlyWe3m3f$@3rs2_y5klWHzdqP4+MO`e&1UdkCdejs|Qr z_sQ|BD-?6kN5g&B^IB+S@}>Wv-<&qCX#1{DvBu${$1KvL@p4D%T;3pYT5hT}j&`R^OOWlUK#SA1z21wU)8FtWj{YWb)ipt9@ zkmZ6w$KHr&d6`A(FPpiAR%033qfujBzngbuwE8-HI!31;K05`|I^YPgjz=06KSfG@ zs%RXIx|<&n+neu>V|IzG7fY5US(oCjR8HZ(RDW;T zKK+U+Rxy``vpZ!T-k|5<4a`H`WL}%lkUzSI7Q;)_9~8&__3CS7=Ug`5VxGs;7)5ec z|I|UwP7BVDxvNj|{IZyuP`DH@jAwq*)X3_4t!wnt8j?_z$M%aA zLr-W2B#Mr2u}7FCI|tuy&$rB=y7VCqpn|Hw`Fc*iYSf{J?6hI9l}T?I?Q%iwsLAaf zcDBe7U?$Y4uRcaeK7ys{*xXJF9b< zx_vuXRjH@8+wm*n^0a>rkAHUx4meE^qdT8vQp>yXRl98aMD%r3eEx3Kz4#^-Fz38n z=d4Y16 zRg#PuFOr5v{RCNHQup;ffc0e;n-^T0GKUNjjH_gevDe9@32Q^VR}AE#0W&e$cscdDYGBl>oqemLbBIj=6^H zP4InIAi_5`^cm_z9Jujv2$pvw%$m=7!s7UOAdJ}OsbO*atT`->5_QEXIj-wL}R? z4vKt0l6*EW+NbS8tx*?0VJ9ZC9?2uwMHgdQd4IHeyIuYC32qd=W2v1_U;q`Wzdym% zsX~?VB##>vsU=TxK3}5lc@kGyrF!y7`~T_ddjR4puD$Qw9m4KqlPn2=O<0mmAjuk0 zi9tn0gOMm&G-yzXqCv$<6e}9ERH?frL@}ZviWyQ-v8FArq9uxkT3WHvKB{PGr4=o$ zsOX25*IpGZRjS|boSD09^nD*~+&S~-%$YN1&YU^(=axVkzW6E3ya}20xOc?@o6HdW zY5UF?&Xr}4V_L12-+$a2IzC_NE--(%)Uj8MVVuo_%TSTQ1vN#iPmSSn`P$>&Do8_q zr}uQIf@miW)sD*6PH#rI0L^zjnfB9h9GU zddu*$`3Z0CRoTkGF2fLKg3 zyEGN4RZ!HFN|qv5fV5K&LK3RwB?rC79icFD_kFkA@4f|eIsmtiz=Wy%H&x4Xp2Efk#vtFJAH)11##|Hnsu)*sQ#D$J2VixH zRx&Jh=L%6k8iC~LrZzZDX*OfRZ-R|_@(5^HT=b|>9 z*}ficO6j=T7b_^{CIRu_WFCec3l#j#5{%yFV~1fI&4ACC*y-Y-c}J9^mwaV|Dn=HO66le_nrcge*5Q` z47=o4KZmto%VVDNZdH*B1I*w@MldUcNLkSzl^l`JJ?C9==?K|O9L5s5k6;fqRo?QD2Tz_wsZNKm?&BK5W;OQa} z$iy*eg}W6?i@5xpqc)#%kX$gG?L%Dp%%N|V9^$1>EFVpLwSA0VOVy*{uhIT!Sem^! z%S7?B^&6c9ZIyJ-X!Ka2snQW+x738t;aD9*tw!}vJ!}aKWcj?~M@Mk(*yISjiY#Y**( zFhXFU%dbWxHKaH8V8_F7h{PtbhkNDvUwM}v&Bc{Z0D0q!LuEO|W9d{TFqf-S6z!>( zUB7~nS19XkWO^>@WF1y`MsFx&>?D;XJ+halDRKHqYcT6 zU+^wDX($&SD_YbW%`c z7eV#pma%t?p4no>x_1EAhzw@7iY4x%ulIm(pDU2}h^VY{VbMjCy!zurdGD{inTsh8 z6li4~5JMg_$TmD+afw1GoP zO>f77XHeoAIJEUQ-gcK6-8X<~GAh@opHlU68~t?1jseJQw|sK|GTSW||IWJ!>yvH2 zgSP9Jcl-{r+Ak0O4q0a8yT9`u>$=Ay(_ZqPlUAzN-XXnD!ku_eo4oZUY_qn7aRq>B zxYy@wtQiQZ-9YM?d-1JDr(+Q2l>?)=H-J8zZ!Mhk?AvYR933{y)P*o3$QaSX@?Jmg zG`ZZ{YaW4jZIT1JuJCthRxmyDfgjrqB=uBPqs)5Q`#W^|KVC+Q8)aY+!>Ci9I_OP3 zCq&J-k~Ryt(u6*hRg>H8*jo2~)-`Ka+jJ|uI*oxwSUTzj{o9NPa^Hpr_ zth;k*-G%Qtpgp_MEJsEVrZG>=yt}@hY)Tz;*VbYJVxXZGH1OcKyNQ~m5H{;xBn#|r z^x{HStxqgeS9U?96YZIEli{^-y`P*%LVh^pT@V42`8f@J{93bUGosajZLDQ*dY5$> zB3-*ZY63-g{$0k}tlgeDnJF!<6`9}?YigZI<0*xtGx{3G1H(N)(P12H3)d`;!;jb) z{?dT_@(v z9Tw^g^jo(PWH<*copD6m&8XjMk&}PqkJ zZ6T*$^A_V(hKpskP5%hU;pG?axqq8>V!xKTnem7UD)jc3GbEB@uQ1HIc{%WjF~eo5{?B# z(mEwBvWz3Kq;VqUd4Kk%URa?PJ~$9~1zxV9!$PdM-kXfAP~K-}DK8=3>*IYW(roXg z9Ek~=2he*3Bo1&$vmO9x|L1`G<)3lf{eXP?&v3HzO4sYO%@yS{EmU}d!rB$|0WL6* zHlXNn+TBwGOpN2zNoF`99HR}YGEoQ*c+3}~B60H(k-(*v{1ad*s~)(wHPWy`dKA|X zR#>UB(vaKZJS{a*O7Y5$Lw#e-@(-_jgPF~EiINagm%j~uSHJ^MhYhuuP5*Y2^pAKK z(VM^E7Zx(GJ#y(ZDl_q&ie+e8EEsFfJ3V|Ce=}~{LvDx<>d!^@I^LOsbrtLZ4|ZiNjVDpC|CY+6mN&;%KxaJQ~t`(_x}nDx<>xuuW)16NZ;SQcj0H> z-(X@4%fJ22doq5OyoD^ovg|Eyb_B9YC!L29dJ{2hSl?IropuvfDg#>(qssbao6e3!QbFuU$0rTwgA$l6-GEoeB zD|V&#a{_2Fc53yEpKD;s+Ett z?Ok^?*ZFNRM#BO&68Um2Z#3w73b*`<$&fNliCb45*!K>O;mpV-?_ds@kte+4JvMI! z79tKiiorS9oabp$5q?#OA9lR}+;7E6N6|57h7LSxEBb0%KKc&Caa!{qo-ctnl4G4v zl_mf14mJ&Hhy{UL-)ELLB8Di2skN_I!AOy%o>ZW(W z@_c#CyI^^#-2bk3#Tk{t=x~F}UGAoYSvFtQB#fvV6K10uHtAMkDWhnHB|xs=2KShH z+e1ZnN^>0bf_cO6v4~L@R$$Jiyz%WydCWL^yh@ggW0l@1?-}==wWLzSnELHe>?Al< zT-_?|aqkjWl_7oadDB-_fkpW2hDeH;D^+a==q?2dng>RnZB(_%bKdi=ico@LIYsvI zW%mnUR^#pkaTDOkp#U{&Zt4kdzuWE}iyy`$4!>a~_ z(LgUuG`Ty4d5R*6>Q?a=srXnA=;#Yov@_!{3#&%uG4Feij!a>;fu|G@kIE~+LrDv$ z8tJYz9x$&?T)XKuBZ%{aFhKDK#MgpDIG@>tL%&#^;wExHYzIKIp_2^Lhra=#B;i`R zKL+YqEUpd8sYkQ#dO3@smdf9vE4S}C)R$oEl@ zog610phH9I4}_hB9_3w7xL-ucH+HHh8L}l(ieT;(aq_mgR2BVkacO=4tyv>8KJYF{ zLx+>am5tpE_UCb)muBR-A9&L$XZT7)#f$hU9=2Ux?g--@0e)!Z{$z7C zj=`As)XTE}@jmIg*N~onc+WajhT+q8W;s*lYiqa|Dvs(gWnm4pBgv{Miw0eDZqaWB zazwG*^A9{CDNE$qe|lGJQ=`L_&--XZO;NG5Uw2IKE;z~8r8&-{G zzf0`>7#xX}jjcSX!%l~@DOHHVtRe52kuGYdFR_7GNRT?_GPNtyQ3ZEJonG}Ri zO_{%nb7u39{Lw$XnU$~xsxYpqwqt)))M80RDi{U!786e9$KGQ27;<==BYL5`HisPH zl&6B0Qo1pFG2xAnavYgYp_1 z)9awzWy808pCO;Iy=x=)K^gNR$q)ZfZXvuwOyGTCzxyVPNCzORpNP7zZIE;`ANaek zt(&VN4%~Mj1eXZ+2NQo^M}s*BJMPp$nt=O2B6&*|!U}h$I5SM=VR~sY=!Mo7+kZ(a z7s74cPbZwNL#0go{Wv!95s2@S9Upmf&*_3$g0_;~r#heo9&Ba&nJpnWeVsa6Fb1)x zp`+B)Kfv2k;A1m8mZM4@@v%4kNcwQ)Y_S@6Rp#8x2aY52fsnlG6Yp`62g>l408)VLfvOTV z6Ll~~zynnz@!LdVi5|RWYoDf@vf4e43;^vuOfA&LWw;ur$Jjm}_L6iJ`~0oWx{@*n zMJb)1$`gs$=ElsA_X;Vx1so;qg1LZX4wdYq2}mDxB7oOOI)U}G(>4^pcS`P^!a<(S z1~PD2IQCE&RUsEL?CIn~O!*=cvD8s27Q=(>n+j$ZDs2vv%XrgU ze^f4`pL!QX3e~bAaQKxW<74PyY{QD85i;7ehv}0x%|1M{LlzC|;ZMRe6Kmu4lM>pT z0)zcsboq;C^-oH=5@@>)e`qnP{yQh`!j>{B!!x(>++O~z?(neg;8HQ@txZq%nK^mwf^`+S;(4>s~k z7LXj{(|moqgdGTk!j>Vi>_(iFA$PW7?OnR0^j`2x0 zNs1FBL{69yQH~sTq;uvRbz6fyzn|nPS!RTAAT!^%UZ_G8L8TG?j0b1nBk79X0uO(p zlA{aa%Ry8?t}jL|u6QVNi-=reId$$hiQ7#qZa2k=TdVStOn5r+g+e2l$o*(dQ|#&> z!Jh@7+I3IrFmMvm&q6Xfja?^5mm0q0)YcV#hDaRH6D8k>gP}(n=&*cP&()%iMDkF4 zR+2-*$q55xEQk@Ub5LfY0^%@7P#HP-9~>b0?0`Jw-`=Gce&(a*esgpUs^(66>GOc_ zvQcw;*-U$)g*CMC*(h{`(^?g#TBx<-^5DO*%1n{J`!{a6rI70zH)QhNH(}Ob>H8Nx z#7hkWRtoC&{40eY{{^`umREm)2OF#8LtkKW%9gKu;awdb z$#?G^g`7|aPLBu%*s7ZzAft!2Iv5|KRBDBl=0_P^eHG!_va8o z8X2W^#5-Ld$CXmt*Ye>#%{maAKx{ki^FbaO3?Pj1u^@J@DGSBYmjw8aP?2tl)sa*}5uGd<hU;d~rY>)JgKr*==5XEp=sR>|8$9mj8bWS_?yl=lcL#dV2K zJ|?U_oRX|eu<~IxKAK=H$Gw*q6Rc|NvggdP?!wP=bF6b0j6*1RBScw6M!82WNwki@ zdF8@HtFo%gprXnJ$e4$MfLbFAP_AVE;LbD^!6)ODWoukE za%j2NT4x?LMbdZ;eJVQEJt%iEqWO({igtD|FP@UOTUH9r#q6`J%)?@+bHy$ydYQpH9pFgFh9)I5+=^Bf79jl$|KM|Mq=A(7f^2GU8 zC@?|PV0*fBHY12UaYEiO-%43M&F|GI;!Xk`%-p!D7~@I#vU5JjEtW6Mx6;dtb!XFS zSQv}!(>ke`5XFMZy@h&CYS%cadOdJ;bPlM>Ih?AKy5wnoD>c%kYbcDbp=-7V1Y$IMuxB7@m(&PDckWw_3f>F=B-Ns$U(vD+J>NqC7L;EI-Q#yRE z3XD*fpc~)-$*x2=RY-^PW8#- zldV-Q{9cx9tpr;elA#}q<&TmrJTM~%lC3q1%7_JL@s`&1i5cFlfL>r`~LT38zEJ+WNtVc#dW%;s7T*Qz$^*B6%P z!AJz4{`IZ2gN`qMh<-^HV|~}uGhFx>@;Z4*=fdk|BTah zY8H@Y@#Bz`>Wn!u*iOrmH7V$rEO~E=g|~iYor$OA@#_k#R1uz&JjhflxU~>=lzUqZ zgoDhM4FND$*@g&mQiYNmRI!1n#;0P+W|^X+J)p}&(V8R}*_2x%P z6?EK7$H-I&BbP_~H=`LVMQf~-+yB1|{6ZWCQ)7{Mg@RJkdk8s9HC3C!Hx|L8`SV?Mz<^DMJ|PaVE%_b+S4YnypFh zO@$V3ke#U*Fg^13sn$~5ZvRKBbwtKl7`IrL;*&I}yO{Q8)E_82yIAI?VSX5pWoZ!B z0l7QP3T92K{6RXQ%$ng_K^h&-AIcS1%a_uu)uC$IT-YXxu14dop41l|6nQFFasb1) zS{@s)Rz{#C%VDU~7jwy8XUylcDc=e@ySRGNHRp3^nOk92QtzLW?{{yfW7iJAXRsN- zM^ZT`Y#vQrhrcy#K`U37! z965>U8R`tQhEnNRM&RU1*h7_+%r>TzJT5DiU}y}>+m=}AtD#4EXjCAZGo773?#zqS zM4;SUjqhed^s421OCWRA(vuDhILMT4h4~Y+>DE#78_~Z{rdw-p$?lDGE1fo5AyGn* zqMjX17lfrR2q_NB)j?}59hD_VTz0P0Eo!c)$dNY$F-PP`8MHDoa_C4HzWx&CCW&xC z?AZXLqCoy3Xr%@UG|#oorEONEeiekG#?mqavfn7rRXVlznO5|w4ArhqE`dgEVGv3=WO+J%`!BlQ{K7E+Jc|A z@#DH)$o!DCjD9Z-S)q&TVGJj2kGq4Mlb5u8_71Yht350=YBrmPMKt5BgZKj68Z_ei z7WsO}TAGcqRB~8>iuS`0=+>h|O;j#lZqXf%^Oj@PV9Q&VTdN{B_^88i@Z<1l4*74$ zQW^=TxN)YUo|XXQ@VcS6SSw1(Q?A4%4f2ngD7o41NDj&CjXtzH7LaXCn&-yi*rl2qOVpWVY8DXG;$fE+7yw1`HuclC z0+UP~m1Jsaqof@eNo`XMNo{lNjBRZjT)uckQDtd^SMvL?z|8a!vBdOe-yd%-7>EkILr={f>?@^$ZEB+A(w_c22Z| zWe3{Ai*h}Hn3x?fVYM~31JA->znJ=X#}H1RtM1-09HVx}nDfe#u>*RkIzl|4Lx($T zI{9#=Nb;%P<&EYYHbKxc3YszW<0!OWxszPB^jk>C*)P4*hZEsZec+XW=2<{kH^Fpu z^0CJPJdPMUi$X*_k-W1I24tL>xsyGvtjc#*;^TOyWNF0?$jQid@y;5&owOdQ4irme zv~@6+#%4{tolzDYPD*P;n*LbqY!~h-mRnX@!AN#odv;}q=J<@H8@hBO04rM@gzu^g za}TgQ@2b)|+V5^MwN+0U=t)D$TZu+SALegbGF-)-LswXL)#3BBs{Op>A3+3)F#~qB z@TCwZ?BwGH?`n;2KA^)=8%GioKR4X-zQ_zH_9G%mN6g8Lk`6}QjbrLs6$OX#U{0U_ zp3LQknHwQAn4d}T8zD51s##Xu<&mwcFmK`a*Q=~-I5PgZ3MLD7OJFTfiMz6y+W;VC zcjXapZ~()Rvf1b)JX6EMN8&~lJy=vrzQMvCVmNd5!6HaM4OBllygAe3r9`Xi=x5^w z;FC4tT4jIJHi>BZn)MGdkOQC1-bNn|hmvYk8D^)`CtGMNY!gZ4vs#kknDX+t=?JKP zCghi^t<2*>TG8U*5L*(8yq}fQwMI~n_8?5?^w9w-S}rdP!-fpYTf){6!K!qObNDYY zS@R!dR1^2X9{GIOIv11byd$h57fm=%KvOnlr94$D&ppBloG>1a9hm7JcRp%p7zM~j zB+SNr^+g}Bt0R?9H_3;Nu$E;)6=mtO8zSl+cRS}es21+Mr(5J-kFe58p7B>u&lHzo zz)=?i=Di;sR!pPrekLFch?U4J1JhL2Dmo4_`$w7TWZ@dv5q0wBHJH=tWcwQHNc;@0 zv2t)L*{79H4 z)iRuIWfY;qwt}=Fb2JrQHjp-*rU?T{GsV=Ko9S@Rb?R8lOhcU-?XxwJd1!ii9TG8+zf^~o`fM;>`J3@t3`ijRgh zmnZK%+N#41xx{0v)#r|=RRM?-ScN+a1k;7a_;KD4pJZ~5-|4t56sMm=a@F7nJrlz< zi3VAJ4E(`k_%5}zY~vvH??t#nG|CsU70GUnyx24vC{XC^eZo37fB;!FY_A!`ajUXfsi4L+5j+TTFiKU=W8ogf~mo;6L5 zEmg6~2r^yeYI#N&2Gp5A6^tY`@d=*XRqLJ8Gsxg~B2OV7aPARm&Z44;NHOWdA*_?W z9A%5j#R6x1mEx?&hTS;Gz?1%$gNAE|9%^6BRGOEoIfR1DUOI4Kd^IBjYpsk(3E7SG zt^mbl3uDNf({8vw^B7_PhXZx^f61^YF2f?&BVWhx=@+vZ5I#Hu&gT+#5Pafc1u+UZ zJ~j%zf>GLM;$X}W9Z96e#A#w7QuF2itc6KdEUjbtXZ5jGE}-&b;g2qr&Bt0R*NpfR zFTP*w4eKX{jIX+ioy!1U4P`^9_0fQ@@GRo7)}m~*-p>?_(U;Un`b7D{!&E}j-?ib~F`=S|#sS(oRxWgyBb3tR+)U#gc+7PTHwr{Cc>mjdAb8Y-adFVV_P_=C)K8lEnG0o zcWCEv)(f7MqXtgD+9Y|xLby?MCOP5$qzN59wCz-D^&ImrhxQg)$GZzUpl*e)z(}x- z>}n4CIow2HkB`G67$^t}e+q+Bvq?vVWw6NlfF9|l+#)+iltf+dO%1y!>+z6_0T-RD zRbV+4IfCy!Au_94YD#|LpmP8)lrr_4cQF8W4f zh-0YV;|tG z@Ue>QDvCK}nhN^3BTg-b{||4&Q2eQ76t5U?DtWX~eSi|+mqw;gn8F3MR1-cG?c+{8 zEsu#{TpKD5OWL6N+e4)`bRO2<Xi)pN=j;z8Vhq$}i8h zQco{5m@u$5SLEf3{6b2cjRe1$SsP2J**@;gjjdFBh{Icz=jYRd#__Jy_ONz)YAUb%XSfnro=S>r#J{Iuv z`{nXtD@2bUXaSP@i*l$MA9vqHXbn0P4P~0k@;Hfkv?XvD zaa$%S3BIBRT$d5kxWwF7Y|UBLNU@%6zi{TYrRKm}aQaK}x#stxv&^rfrH<}Vf zOJZvx6|J0+r=5$L6zm*#<4VP-z%|{01WLLJap>%CM3-|jxQZ$;(=RHATw=u4D@4DT zNe~TlqKx?)X}t+};XgjZ08NjuIvU(U{`*{O9z<;NTq`{cTESqhU|W#GG#ZJdZ8;43 zIXoavvRaS|b8c|y(>Z8o->!x+4>|DZgeLcKwaH)wX zY)g({PFLWxdLQ1Prqa)hGg*gX(|F;-l2B+K<_K7+U?_i-K z(!is9N+p*Ku&|hslLg|y{Mw096fb-{+;)P?P=_ROq~y6Z5u>4qs#KFs17sRu6mZ0H zSN35jc2!dbr5JZ{tfA%lC^k!|wL^Wd=oZ7>xfIha2OUHEKp z)UA>!eo{kw2WUbFF!H^ctCXu{nsSBuO)=w+3W|9EZ2(bOSeeamJr9g>L_J>M?4nt{ z(~VKz$>UQN2*dJYHlTw0%4FnxYZaF4KR(}D7U`u@;XKi5wsXVf5HU)L4}IYr-4@1T zkxK4|Rs{$d=FY<$QNhjL50(g#!ZNiV%@nvRa)6Q12h6!dm=p+?acpshNFv%iid(2OuV(4Q< z^5AA`MFbdq0=Fib-M~kA%Bb65O|)s={y2|DYC$u%;m0+UTH9=bMdKXvlUh|B*&sPn zrs!~Ya#tP}&kgRVA|fGNN-1^pV7pAn^GmH@8CqN+I?YZ~Ot`^6knuQLfv3e;3qOG< z=CiV(p6C}wJ!DgH^+}X<+V`_u3WxGU0ZVh&wES(UwHkW}|0uNrv;y>rb}`2I58?;i z6o&F`rx`)%?x(_ppfRC?CFQAnVT_u1)M1Fhr$I)Rh`QU{;(&XS8~HSbuLn!c3743F z(Bfj;5XV0QCPE{z#&~X&!b6ECHhDygXT(FT!{a1lizkT}StmvIc!+|c64CCT zULc|in-)@PTx_pj^u{O2Vk&?OJh*!>Kx5TxH7Eu(rqr^JkK@n)p$tj0l}W&U03|dJ zVWlIg@!&KAu%A&n7NIU|;JOBD80)x~`=KVHT3`Jf}Aj|{QnNOqJ zY^f5s`9a0pqTAErb>dLjVbKxF3p6F74DOH4#3t%q^8qjg8m6C#R6tp|z|_cz$c_a- z54U}vpF5p88t3_my_J=s0}l;Q1fAbUg{t9uMyOaQ2MNZ@<4iczwER_>wRDREmg3rt zUYxue#Zn4rY z1$m61UWwH(23vt>cTck<4wn=0&;iq~z64l8YRHUaF%=b}ZVW>k7k;UVH)}N_P*L!LhXQVyg;2PvQrk-ot)AWn4LH(06+9m1ZljvH*MNqPmun->oMl zQBcLZci2!^dp6>w9LoMbh|0!N9+p(^Veu2hk3P)FaMq1+ zb^qk*a0D+Nv&|z+^)&Q&MI|AnNJFo>Z0>;kdKm0@=?Tx}3^6jhPg!)7{iA$2?@}wv zpU;$IK44Y$QK8&`Shzs0z7%`2#qv(|^Ar5gN*V&mll4a!cR6Cp)8G|N-X=@5SX~xl zMLdZRhnXq9EYav~v_!Mjsd8{^AWQUlqu+>yFndS5V$5sPc*F^I>f}bN)e`Mi+et}I z9NrpZb@dV2gSAdrv{|hxv7f3>$r3}>lqIIECLJpymtj-hmOr@6I&Q8_e9|P^a`ZCm zXrv@<#m|&HX{%L`nL-`bKfhstXj;(0>&K4~MeWk9|2RcHwABi1L@bXNn6bltn@Rc@ zq9#N%xhYvRB@ZTxvE-R#BHM{?r1%5LqBFUd;?4ba^7F0Ml2ht5Dq4>5pb-bmZt67i z2ZdBO#$C8b6p^&yYxl9t40g%$D&U=dI6(LAaqE7<#G4FCKax4YB=Q2>d_;{6pGdLY zqDdT}iPC(ug(~PYd$>A+FiZECO1J&6nuZH|SIi$OB55u%e+aoGBb}DcwKU6^NB(d| z&?HWp*7%}1|V)38JmC2V|-%Za|>ZO|})EShh6jeN7{bx`$8iK~n`e;l~KgmEdzGcVRh6$oaVu*_W%t-$g)=BeGyAUJzA4PtdEw@~O zeT{6n>k2C;Jxqia(g-qLsILH@UzlXJxCiCX6;|5nMxGK$D=U96dxIH5O18-5_I}wW z=Ur(9E&vN)evP|8LcbfRhTV9lW1NZklGAda2L4}ZZF*JpRW{Ky;2L9YeOV-Lz0wM9 zDS{tTkQb60(L(J!;2-jf5&sa+$eszFK8WA&43Y@9o0=)yZ#-m7Pdyd%Ws5dA5-F>1 zRN7Z!OKViFue3@c?bLuKS1YH@^-$(Evf8?|G|pvS=CFk@x0Esu&lye>!-*rbwl!7M z=wVT1l&gKt5Ut3~xeRq^XhAPYSEvLNq7wE9#jwC;Wl?tcW{e_Io-CV-&_pDbP)ceZ z37~3JYB6gj?xV+|6i)^YbKo~tbDh$7|@ z4522jHqgy5DM&Lg%Hx6CADEDRS6OS;GF5Eyn{+T2P9W0%_#mmO+6hy$IGiohzs<)i zPQ;IL<=DyN3&i9CWm_#~k?vg(7Zqw22Hm*jMT@z-LNm#ihl3r2bNM)t=*eUJgYZqz zWISn#riJ}19E%Z`G7C*I7vPsE6%n#qSo{}HQ*1WVzC=)%O-+1ilW-T;5bh;vNajGV zO$EeEpd%wLHi*~>(wF8EuC6z&nI;P}E2R7x2~idS0^yw`4+ml*oMQ@etXuSmu0+wD zIKZN`64k;1av-rsfsh0!B4`xu{*{muV3>s8gex4Qr~Acpu#pK$2fMH;97`Vxijm-0 zkg}xr2?K+#3m=6P9l*v$ z;c}iyxvR=r76i9EEgDKMLN@>p5}f*nP=W`O%o zPp0OY5eC^rJd(wl7vlKbAa?=_O*R@xVomt@Q-JuAW0VmeT{N3QVPs;iuUT8k02j#s z&vQiIipEUQoH?E)CbQbOF%+*ohh|2W+_R0(uKg50b8{4pRAEMm{KGaYIJbl{vjJdc zl*-Sy!9pmLORj;vP%hVBV=byKr!ttoM%GNP;er)9Vko=gD2iC8TFy;c3%-I_KgH*I zgi$N%n|ZuZg45QFR&wtYbDw9RFzjj`hZ(l)y9Sp!3gl7OS~r^qt~)09pqTcyGkwR; zMl_QhVIJQhkG&3C;T`hI>u|#W-(9=TT0R$|8&bBVd1AF3yv|y+w3;xDCQc@bQO~$X zOk#NGYn{Mc?V|XA+iz4w_=Cl~Oy+N5#Wz7@AAF zrMTWIoT~(phsM%TdBOFtiAH4ue()kY{(jYh?5#4lvp);E`)3Tu@S*x90PBCiEp!dXb#DFzoiN-)1 zbNL+50i(W96jxK_=NiPJzC|;O7(y4oVS{}h?3+})G@ zCht|5=U34BrLbDmHZa=rA#?en2<}@oFK*7Eb`_Gj4{7h9`MO)%Z=1mq<0LUjCR3YB zP5GNq+z;e~jEpX}qPkYv_JYTv58ntAP57!AHSU6-{QV79`mxX?*sS82W($}Ew+)B4 zPU5W{_}$>iHW2cMoCeAwdOIeL`$U> z$sny=%x!)0^&72~Y2%4vGI7i!COkHbP0tLg*lm;2yWLuP5}1o62%GVhjm%-3vLbcH zO68hhTsWV??JhMzT+<;h-)^PmLOxJcbsiB-YfR=efewoAgorGf3Gvxt+wexaUXpFw zt&Iis(X>Q3TV`_c-~BlS^xv966F)!5_t1X}I~U;Ru^Iv%s}uC!dj4;;h{6Mhme*Rl z%|rinleK2f;yYX$8pP>46E^Ik4P(Pdq5ohb7B|-Fu^2Cv;d*O@D|7|GsrJeded>`&RmKL8R84zOVv$ zH#98RuyY|`UFX^+g!4{k>^libi2j352;p^z?}LbATld|DOLXh{Wbig?&C=XSq}Dm8 z5;yGh0M1iIj;oZFx524(!U4eJ_~%pcd5!p`>NMebZ3LgD2q)4|U0xS{>I<2SUB-q6 zbHh&BYmb#VF&p6=T_!{c*y%0DPrah$PUG}D%w4Y28{9kRV+`R>BgWk>PsCcbA|Fwe z8ySCtv0*12LNNmLAG&dcpVEzT@9owi*GW^dB4TB(r8cxHw%lQy*5EpQr+XI_(rvGhiQ{~Y7oi6Ai{?jC$ z+5o6pr8gL-De^V0Q*ESC^8lw3E$g!>GyZAh>sw__6y`*&Y>rx~YfhssD^{%F9@ltI zE5*SB3Tw&OP$7q+R@&lDL}kY{Nt3i;WZ&&LXr3d3_*vYGOoeecHI70{2gdik1PkY zxEKZM6_MN~-So3@g_d$v$}TDc69UlM5o8`O*aaRg~jZLUUq zvBG`W0MrfH+=KL-xN@4%&D20=VCstTeD4q{zN!&P<#FWdBBkSq|5}e49 z0pL%gyMRa=Rbw$Wc8Par8_T1WA!c8=E#-P#T4Yqe}0MqIh#V{9br{1rJ! zE6|-zVN_jFV;D(3K7Q+HTLoYjZ;pw6TVUOS37ry|{<*UliWNfCQkhlUUj#MO8- z{7#5Phb+1iGe)PZz0*2jk&QG5xkhw@Pxjr3G1M-{?zGYtO(MtFs=Co9eT~S`D6<=Z zu~C*Zsxgnqjs0=?b+6Qt02If`l8(QL+8oc{EWjWYU(Ok9#O}+moNB~bwU7+o1!zc? z++}4hA48Tl#h=r5C2eT%oxYRb!3`lEWpAmMEy#vu_RvqZ9Hp{jQtamKob26*Y?dW} z7SoW6Djh~;o!;H)lg+!Ww6od~HE`I7G#aW9R}|L}EwK$F5j*MK-Z$f&3@KJTM0wjGhydND*9@Xfbw z+1_Mjo=A0JswNxe4r9YElP6TfX{NOFAY2f~NZs=-({ctxWi%tXR?P=R>O;;@I*3CJ z`*HvA9&6oEltmjRXYABZS@=|z2dU-sFQj3=Y`+IYjRVwrWf$i7n9ZSyYU@LKR@|@- z0Y;5&<8lVY@vW55y^#7+SwKG(vf^GucFKl(!OTI~Pf)F#xEDMvmHs{G!zLNtgUCu* zyvJI09F5O-Vb`+rL>{^p1{oP^r!~w!eWxG!^iX`VMz-&i)u3z`9y%L@7#kWu={mF>+|=H=9@?Hd-hM+o_@4I3Ix->|cA7Jtw1|3Cfb zwMg$$gRSt6IlB@YJUhLJG6*j?^IVq9+H0MFhbYSTTASec@7#;=+AqiUTA7PRD4#Z0 zwdnoUCj<9c>yIE-Xz7TzNM5c(JV}B=PtW#6@3T(GXhW3dTx@iKYed1zBXamYc$XTa z|9(`Ri%+$JPV7PTOMSk||obdKzy$gmu1 zLFrs69>7n53_oCf3qOcVmwO(tJYan518DAy9D2Y?U9z7fvLJ5YDIvx}Vc$M$)q)>T zqe%*b_-D|PLFVnVmYr3jqm{5?@c>xhp99xxI0e6G;TP0jkdN4Mz=^My?fW2Py|QN? zXv&f{K^4*?t<1$VIEv%S5Tzgi{^>%AW*5sk915n#i40>fZWL-tQ-&atovPb6?wa4= z-H!VsnnznM`wFB?6fvCK#Y=N9i5gXb6e4fMp@m8 zL#yM+K2<2s+k;~W=Gi1i@uN~#cJ|EI;&o-;3L(BxHA-3XyG%AP0*D6>zSV)BLPvY) zl|fjiP2v%fF-7Qx#)J)bB+8uq7;uBKc)ztSxydjVfRX|XrVV$lx?}YQd@a>V6T8AY z*WjheMY3-{nA$KwxM0x`a}C?o+NxpJQGls_N~b3jDZNL-xRuWEfQCI9ruI{Q9(c&_ z;I~xz{!*O|cB1@d*ZxW!p#;jcKdND#CT-VK(;DWlYT2%*38V_<(=TAI7_eW#&l-pN ze_;LHG(SAl)rMz2Xa+X%KPuw7$To05#t>Opy&=j~X}fN%kW&v^o7Q%txIi3a$MqO) z@l!h;xD#+!9DE3HudIE!{8gOZVVhljfD1Kz$Tpur`A7`GZxBIj zf$xJ0{1Gq^7#C2wp}~MklzpN5ZgIF0z3@Z zr{Q0~BSF2KqVxav*WlLxx5cHu1vt`$h(_>T@(Q@piyq zsi9e#xDP|C0I(jBi9bYoA7CxiiQPzVk4t|QN6~$NHOCW2?TC9@eO!h~WM}|fttWKob08BDL@E)9qC)lZ=l}^Y5&er801x#I7rs2rbI18VH zh$bEJYbcT-z%C$!V)6VQ>Aippb^4f%Bk}kv((p%sivUk5*z2=hFYX3RiU|aHGXUQ; z3wu7Xjg7g0wG2hP7-k!Zg?$>qMtWNW_4_n@u6iDXSqOr>TWnX`81mz)6cOmHw2dN+ z8eDo~8S&l>n7Xh^!w&(T1YE7*=WOFF;&27S5ySi6s9+Eg)JKHyHDu@ktozXWEkN9b1Np~w`Zn88P8)(T{;ltkw+0!s z5LqpF!-IrGv)Fo!-t++6su4U7cmi;VhX3k#W;Fah;0mN?Yj_GWLglp(TK_?M6W{>S z@kJ>k30Dqd5d^1w4PN;*cja1ZMNrb!LUG% z3ab%OqaqlFCOp3%aE&g|fR{N)X!10CKfTlexLCtofT_!JH2fRD#32WM!!}BZ00-X$ z;6}jZF7TfSm`21nBD4_sz!Bx#Q3!oOz*M2`BHuCO#DS11Au@bI{*C2@TTa=N@4jTl0~guhZATMx*?CRLzBqD36m)KO2)*8_oYG02^krxnRkTA{01Z z!{sQ@4On-{+-m_311{GHzHhs3ZvnhO=id#t6R}jcaBd6I8v&D^ApFpL6_Bx{5?%f& z+ZDz9V;GBchUZbh6NhjR8EWI;H*8mA8nBc9eWd&2(!sH7`v3=31@l~hM*-^w%<}`D z0ow#5 z2l-uvx`ONRD2a`9hoCwgUe~2clWC2t z83=*y!}%MLPI^HTG#_)ba?7a-=WmAFEeGlO8or#|a3Dy}1@o`5jhi7urf%T;Tk*(6 zT?hrbbb%&(?Ry9r{2Km&ZG3MG>1`VBB;Op;vo-uI2y8;SL*TFJO%uQkI(A^!=uQ(bx&X$Aau{lOKj1E; zI|Td~Z)2bVF&L_N7jd9W=LbiWhfu?VfXk6ytKf(qn&=L&+==i*H{V$phY%*%oqe-i zlAMSZP`c(&@l8|YkOg;(DLJ#0-Rblc5q)z}Q&FIGXPu@h{M1*}h z!)3@YiVT`X$xu8^QFM`Jaq=xlr#{qDoqQ)?YLP-{BxCyC0~vAkXnc>MKue;42p zz}x_g|KwlV#(lYn(3&avWxx%93p9dp!2N)24Sxy*)W>?*F2Jz5zZ-C)N?+iI&=G-p zGFq?#2F`$nF;^_W%B9vtK&q)ir^T<>Mk`6Z z7NP|(O7{!MNRuYuACQspxbl#pA5i`}mA=r6CrmtmJ$n9MxEK+BL=5W;N5Eu?0@egA z#7gEtLO80^FNQ<44{(--Zy*ONVBO~nArlQ$0hPz(v#=RoqHY6$PWmHsuLm;Xi)aK- z+Qy?5$WW}|7j5H*ohTd9FeabxH3Fel91Edpe>8~v9XcH{@jaAx#(fH8;wL23V=8^c z1R6vf&<#qN2bl0hNNQnFq(JpP4vL&%l#&Oy3Gj$Qkb?R8mI}anx=p#zHaaT-x9aq( zk&X(TE}EN-^cleUI(<9r0UIz8fG$tD%{Its95M5BhDLh(1sSv=O4)~3SOnmHo&Fr) z0l-?drhr3T#enN{`X2%J1An)M#~?#lNY@-onFLH->@)x--!pYI|BtHzi=arJB_Y&` zV$o56sX_-n!!{1(g5`$JUuGLUfSuLsB4|$Kiq`4(&|}I-*K^CFeV8pf0DF~8EP`48 zTo&q22 zpwFuSYnG>B`fVT%YXZ~01H1nA(%Aw_&__>1bp{NRv|E9&2e7vB(lAOs1ObjeAPuTC zQh;==8Pk4b8-E9fV(Da{5J#PKOvjVR@76+`7Wp$W2xOpz2Q*dMJGSe#DZmbe|FDgJ zqCgDcS4ba2x<(jCqI)KoEH#G$X}0URI%rlB2W(cAzxAk0&0;$DpbN0pBTF6zL4|-F0v`uK)TK14s6iN(QQ~MS@t-Jq5fL4TNYd~Sh7A$4 zLc_#T;(%u9k`EztWq>tHmyqsH0i34trzfBRGk`S#>EK}97~sV^eI?)lz!9gwafqN6 zI0ZJ^uAAy1WG%V?hGAVB()GAczZ?z*;y@PC(W3OLkxm@a989l;P?rEE0x3NTo3RRT zordp4{sz?Vn9b>6*-wj*p+skR2D%*xoDGR|2w7WY9KzRufcj9Y*7W}am@3d+lKwB- z^?_gKM;8YZ!LjN%I28@(p!q*XRT#`d1hL$K*P=j0T!B*nQ-zx4!LtC@#KCZ2)KQBy z2ZLAG=CdKdG^{aDf;XZ8Hef9S!CSE-LiOX;g35ql$W9`sz&^kQ5K{b)5wwFNImk~f zq!wWz@lXgbjdQR#2nWVP)ItY-6^bhWm>L8b3&JA0eIgG22n0nc5TW}h!-W==Y8Vw{ zkS?bd=@w@k0R%mOHNuP&Y}bSBfT;l>AY+5=+7Fn!jNo&?kvybpj$~l=dycxu!FP@A zk}Gcfa56kT0Jua~@=vI1LP}gfB}*acoz%*ZhGEq_UNoD3 zDSQZz6VXn7EN&iejmwYaUgW276)e388R9Fz>gA{L2rwV~G#Y_;v`h(oySR1}CqxU3X#9KvN_V@Eu~+X2VplYm=i30U@o z?fOYP{(cxC9q|=F*>uELV52}>1tAQjpTt!V$^aZ!K?uITAIDV?IveS6_(RaPKZ(O1 zirkC>@fF+yIKBcbp?@4-!Ov~ikK!wUw)}B?1#r#%IKF}z>tHd zuzbDkIuKXE@(Yn3SHW@^9Y2bzVEGQ@kFQ`q;J6Bw{|s!CVi~4XnqagpSON9@SjV9Q&sz~QLh*SENO2e|9<>dV@RFfGFtq9u ztpLsCJbG5Z$$4-j4#sGEq8YHj(8K6j@eW28;d5ZyHvcOM*vQ~fz5>F0uxBs5a z(&fK{^j^T4z|7n2hH^X>%P~DG#`oX0KJB8*W1qSPxs$^>{SAz!E@G+XzLQpO``k9G+cx7G%d{2`GctN`ykk-E4;%t z52PSncUdIs9-I@(2kg-ZTG6NNvl+5}2w^3Jy3ew}Z&86c%GLxwZJT$tpg|K0Sje(| zX`4Uoj4O{WxE)w$S^ge=h zH9N?ppg%AYCdbOX5Va9%GKj=zUil#Mk0IHkVKDmfC}5|)UW{HoX%hkhD)3tvQ3dcG zI}LvglQZRa;1N0z2A4**>gko3DGrVzSrfbpE(lL6;5^l{s}_J!1Aq%v{#8NS{BZ?n z6>9LT%EVmQIgAXtg{#)0#R0&6)xuS$*yfpyC{V5u!00+Sfpn)rOf3iBjDu?+I@N%6 z3m4bf1mI5-bPG(DD8ayo2G2boqqmmwoDUX3R95Xo3m|KTPZzi!6;KNtf_{JsNS1X4 zs}7*&KL>cRV(}_y{)4{(>=4*vy9xk0U9<|vUeqBl-Jr1n5-oXH-D2?y}Vw z{p$FbZomh0IST0o#6cM3t4WHx5#bOp1GsAzVK@mauK}#}TX>0WZb6s0`cxN$S3y4! z!g8gb!dRYmQUf%;Fzn_h_7grO)Zx>?p?<*B09p`+&q0d{bOgZ{*)*IDSE(O`0AFRB z-vL2pq3YvsHOBE!T>hJ(!9#!>H9_}4U(qlm0`UJZ>46#zL+Zmn#%gl{Fh+$%QXhuY zc1<5@_?>lO!lB7mtsk2H%WvGa{mQM|uex#D<<(oSzp3_6(~$Muh31J8A6f13Dbt_={h+|WpR|y^)$|v ze@0;s!nh$oVJJSVNM-3~IAmKQ>+zG&ZJ1|{%Z|@*(6&_$Qp`KJJN;8Rjr^|pxbpZf zeE(@>o-D-goYkQGPp`TYtyV;hx g)5!OODOpaxFAd8E{HA_#4|@MR(C_>~Dh%WQ0<2iV{{R30 delta 315404 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%0DK~8dP;bez%D^@NzZ3KDrVmnY0#Ny} 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�$w7w!zc+N|LKz@s3&c+h&z}nE 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�pec{seF zno&pH4q#_QssE#D86K#J^aV!A*GHk$@6W>Rc3fWtr!P190OD>NICGIG8%>`1r&oCs*;}!_P!maxODVG8)ZNiY$UihgKUT7}&C|=b+IfNH7EvD^n@vne*yF2z=lHpIROvD@I1)-HGxC%#FkT52N`xT#f^ z9yw(;mIoHq54>m^^-p5)RsRIG%}dTh;y~YO&VfRHRI)KLxmT|BtTo0FSEp z0{y+aSqLUT$|j2mB|uClA+(SL2!s|0y$Yd8hlCnxD1oJfUc?Zx^j-x75kcui1OyQT zQ7i}wR@B)3qM*LtnYkOl_g=nlHh0dl4b{A8NST$&O*lD(+USJBq`psYiUD?1ytK`M3 zlE-8aI)ur#UG5mD`bbL7ugtdDN>cKH!OXVpN+J@ah#6B6PfHcUZpHH{kr2d@rq>@T zzoQUZ!@q%HKj`oEbEN4YA{c|ph?y$yqY3lZViE<|ZrqOEf*K-#!NJPm=3jE!eh_Ud z<|OX8co6fLi?|Eof%`ExaMwlfWSwMCBYgL8pM!zcSj8P~ek9zN>6$@p$gTQ*Ac@rJ zm2vo_5I5->l_&S0=ih;jQgxmSHwy>AgR%nDB!T%(Wf2as(9KJl=(=2_wj$h|E5`8P z=R9o&Ii8JEvox!36F0s}xVfMrA$3HRt-OsQNDT`&7b+&`v7os~NsVXaAWlvH8*VNQ z5JDyTnhnV36Q@Wb0<9GLF>YjtjmgsWxF9b@5+3};-z^z`ish&1Eq8{Sle|SAoM{zf z60&X;V~Q>Yt$X>W;hoJ9H18_Zx;DcHzuaAydjwOLYSs4nqP*S-5gf645?tHl4l$!9I7BM zCfwxMEZitC#PTpIiP#P4Tt(B=3H}Nfs+Gls3BpA)!_BsZ2*+9o+frEeYzdvm28ElY zy>zBOYeguHsKE`jUC1m8?*i_q8s@Ykd54hY8M10{G~A5Glm4vK&DsdrJ~ZS870P}g zQ|46lj-ny|^BXaU!IGJ*Dv9tW>5Dy`#@ce^MWMPLcIBj3R+U&x?i+l$ zS@>6UI_d37DAZq30_#Hc@UNm3UK)=lFZ@F}E|xysmu@62{6l89D#&HQRpP@x^wddr z1kl~ft2k5dgrDV@vwt?FQvzcbT^V`c0QFEAd~0CA#Jm8=IC581UU8yzx=23wfB6o`^}*h}D^ z57Qlyab5eUDqX88f}QiUuXSD_!ypDkHcFP5n78c z4{wS182Kj97dD4iPnF;^!Qn0Bzs()qyvS0bP3Q1`4;a?G+iQ_UCbND}eOv6nU&o6u|!^!&n zh-dg%hg+krSm@R`It)Tkf#wJoRJI!u9fqN&zUMFS93Re|^qeh*)U5f$+r0lJyD!?b z=;trl{)b=nnj`wiYa9R|ZbToykz@IOSeoyFT7Tg~@<(K--J2Dzfb4DA&>NIT$(uJ0 zvrU4vBR0{di+99>YCDyO=js|fmGQXq{Kj!8-!`R`L=#$0e#gbr#sMO9Rx}hC&pklG zeT0c4XH_zch$w=Di-RfXF5LDiV+M@|M`w1|kDLYI98R_nzxiR9tqXlUb!Jri0e25z zs2d>Mmn$D*<+x$29|WE16=r*$j$-iY@`|1wnjRw-xrwb=K4Z)PGLZY=rM6;6;RejY ze2aQSmM@4&MePb8nxVbgzRhsvB@4t^b5Fi5|Y-25yk9p3?3&GRULR~ z`jrW4-IC4fYFpBKWSpOBD1rUkRT=eF)AQyil>53c^RkuI?E7S;2HKf- z6erAULWAand7W?J#7kzF`2mPj?cAbRpEADS`b}d_q*&Sf!j3TWL)u8@0)`ZFNm=Z- zxUa=?gOA^Fzsjjm_*dVUqi%cf9~EYP^fUtrFXSKRRgLO)#lJ@IPcB8BTHKSHiPaMr zX1-w+;JHiWttPrgchb^pzCk}F(pw#sQN4s*{xbod-ezxz`ZavR%wrBA>?Ohx)#}fQ zCx;INqdIm$OT(DZKFr){WznP!_*9QRrZYD(>@Urr2bkS3ij)j9d3e?wy;U$UQ&qho zE{WDtq$I-xxv-*oI~)jvVWmkoP#DH9!-g<(FZSx_PrPZn6BD~lC(FPyq%aj?PbxH& zq}u0Z%rGXvW8rwY?%2f2GW?O-V`qqX|WJlmTN}#*Eff& z(Mc1Gi78^G$a=a+g-R#UEa95gL_071oOIoSFo45}F(hyBf z#3}Kseiz^uQa~zoE+iv)JHpINL~pDrpj7Hl>=UT|gA`Zz@d)>qtgC0wCkbboNOB;| z9K-&{v8$!A9>=gNibE*O?EO!Aw&8&VH3H)ZS%q~qH&3_XbhD8(-bOMxV$4l4%!zp- zHhr6fnHYE&Ff`*iNBI~hJQz1r7nd7uRUv9bfU~q!+!w6k)}Ys~kqA&)TOV)C6o5@F z+UHzSw66&>+4^pd>+7Yx8*${`GDW-gh$a%^2jcom&?-JA;KoTI(7vLIIFB-2&dc~t zSH%FmRg6jP!pvk<#RWzVot>`9@uR3oQ9tq$Mc`SG&BnQ_Xf>3q)DQrwx5iqxRwm7) zyc8*ZW0)z=n}`CbaRzsUb0uSuo915N7XWWt9BJX@2%T?@0$Pq-lazB?+5o?*4YXpp zYJ7ES_*HaNjlXenFUzZU=#J^6Yx=sS>8NC~0m#S^jY`vL!^xQOgREpVLx{<4BAqM( zPg$wW9A<8GZ9ca=%nY*FFn2c-6#-J2Sw~@msMMg!qEbmFuCm33Af%j97By=22Ku~b z%6Lb(8$Q)^Q@E@DgqiBe8Q4&hzN+R1fWF9#oV79X0lbOZW3eIJVnfaQ0KWrRwnCU$ z+G1GEKLGw-US>_gOs+>&tgYo|7`2Kry5&h79;}z)#-tcFt=V=Qq1NA0(sPpNaA5*F z<7_)F62C02v^5(t_mXHy`89k>^i8a&XG8GALkn6s8>0QNPi8}E(cWvJ0JWl{Y0gU( zO!CW(q+w=FCSWEMNQ)V)*5D&kBH3n@GIpjobAES zY>x#kET8s!%Qq2Jv>)BxPl|-lkmj*-X5AoECfl_*SgEGNC&j1^#IHw~Y4ayOiok!4 zut8~piFuxNSxCez(9NJqm;MoE7W3BL5`c>=)iwu7Lr+Z$GyPC)6B~M2w~{y>FY9RG zwYGRQ+ngP$eiww9{+v;nxIlW&Jcnfanj1l}1|Y zOWYl+wYh8kitlF`ujb4Xlw#wJB@vk(*&cS)%5>HuK<6dX$@l4~=^U<>1~S+%q?Ofr z6e*p^4U2uXLjgM@`wam0p+#HmionW84mZL+l2{BnYA51i+!UeA!?2s)q(cA>u!=AX zVharUr3jyJb;_hStRmD#ZfZ}qicotlp4r^jqk5uQoLQy1{KGy+&?kLs)mCk^ZtbO3 zZPk7k&l!Ei92P{5%mc`;$n0I}cyd`QRUCa$9DR{$9&y2V0=;*|<;Z;_2ERhvSI{<@ z1s%oSIGS->X^XbF%6Ou^wB^JR-S96T_6@zpBJbtg*M)Rg9w&eR?wlrs=1 z1A{oarMUjU7^s}7Zo#l_;zmY}<4jZ7d33mnHx1b2$bsX5UGTyXx44rcC?^hv9h59+ zVNF)>UkwDOykgZz6ZZ#-Y(i7e#t(`N;R;$D zwpFGcr+kAX9qSgh70T6|)s&mm4rK2rp-7ac87SCZ?UTt>j?>893WHBnBzblbUP~Ba zguSE%jo@rsScW26LhE~OO>u;W`G=|5!h@2$NsX`ph2ir(!P$;VQ4hlg)Fu1DkaFf| z*nlSTEpd1JFYJZFxEDSBvYB6a81@1s@Wz!FwRPM#ri69(#+_OmOf;tMv;q~gQTMR! zRro##e8|JF?$Wxf+`6MfHHHgchczk0FspsoRUL1k)cR#$YvBm|)5d6Lq$5>M??2J0+O1XJ1bQ zPL*SQPk{6|xiE&z>rIJF_zLz;YYxsP;}gCTb7g@4gwaNVyjXp5xc`JqBjGz2pYD4| zpS(Yp^pPZku!I{41&Wkj^6+qiY4^`C68=)k!++eUaeNC8)I7_i*aX?Kg~yz>lhyCh(^Oi4_e@x%;8qdc z%>|v#K%PA^lBa{2GOm#dfumDV57tb>$OlgBh4r8sXCOaqo_lflt`!^!R+-YVsAN{P@_EGAN!9TVkGb=usMAQ;P-y; z+;BVUC#UHW#^@4Cc?VufNG+}yD>K7K7m^@L71d_6F^ui*cvBu#n|@u1r>DboWc3bq z#q?K|^u?R5LV=wA*3%#@kcBZsAbTx|e;aHwo`+{m#>c-+Cl)Ag7A4$>Kku!^hCAcm z370rlb@l5k>68@4n+}-ZHsWt8E|Bol=J=1L3UBc}XH@(r-tR+i$A9Ym9(_6fA3wDa zR}zNR?MUA~J6=!vkj(_)c6{f`!fgYM;(U~A?q)K4W^@1&%XhReJV2xxPeUrU-W|UI z{UqoWMKXn6vMW~&VP{6;NvWJ`?hBN)3Ow-}bIn(Ukb`)-7Wb@~;fN|RH`nB*by_)m zoayphnSmWNKuv6&7>SlSF(%hcbf_vZXRgy!BqDJq<&oBkGYAwFm5gV=)LgSJl+Rq} zCmX18&H92i-;ef{Yc_e$8uH@!i7|?ax#l*%31f&bDVUU-)m+$cIrV#F55-?Q zKGzJD;(w+y4pkWkD2$<${^W3}Rw-7vNX7ACy&>oN^kn7^X0%C#{6=byj&PRo0T+GEzaeh`UkeP=?*?-W8{N9v;4I09a;wLhYV+TH=vq8Az3SQEBw$WkX4D zr1 zh(DLLgS)f;0eQu-%i2pufBI*5_Re;Mm1<0(>_?Z?qEK^E6}nmqo#)PMN2puM4{fr3 zdE_TLux0V+I1ai)N5%AI6)igEWUGX74DRG`or%0ndgM>Oi(OkLr&s9PXb8iLP3(#K znscxO9G=({tvqvc32Au~dy=WVmSyaoF|j8V(*J#Oo9G@2grsD5<+rRWR(5k`nm_D= ztSgm7Nsvd?AzAN7@??v2T=N%X$>gSfr)p!?HQ1)Ux3jRWq-~fx;J$6W5JIq02#u!;G=~6(jrY1j!D^Y;UNm;A0%jX`00&-p5QgY=RjBD7R zq%Z~y&sv9ijU5a2Yi8E^@)FVkij_A- z9_r1TA`jC=9y*U_{V<8<-4QH>8Qf7BgsBX!l0o{YtVA-HKTv0oND6NTb(>fjv>TFD z-$@VS(gjWOW=8EbP_?J5k*tQ^ns*J&N>+vT6rb<#7b515lbpm*S>G|MpO={V;}kJ2 zA!hzSnnK?bSur$)`EQXC6-n!g1<|IDH(V^PQ}eURnb3cX zZB+CBpm2z6Ih40kG%o@Z!9KLP@rZd=1>Ha}7dAb}Gyf&gg16};YNX}axPhKU;uj2M zTe_PAefO_Co6N4?rP@Qs%Ql%eUhhIo-JN^#V3J@fr1%F=eqIx3B6?*uJ^#@p|aMtNKC7DE-o+2 zLe-)^7J)^d12{V0b98~DqPf;{dx66hab|g4%Bx-_Y}R0T61-eAkXH%E8_Sbw$hXI} zkjH~F{QEODTiynvZBYhDY9=l3=B>x{8&!+Z%&qeP1(ZYkd}wh0ySG*Wk-jImkwP)JoT zJUzy?ScSn;$zQTn?IKvpHKZ9oLsP`U$v90DdH$=+c{Gv5(-GawLMDz}pSciGSS&qr zi#?f(Fq{|94)h;nWaeUwE}pFv>E=NoNeu-_qfwbt1j(C3C+Spg(he0eSrPy)$lbbK zkS1_|%p%X)p4ng4<(C9`au+-5yDv$k!HkhvIju^|*qPajSZX9IXJ)Tx0hEwK zT$#OU2_mVu1D7*pyj#=F_qrwW&GkooPwM%^_fYGb^oG&&{mcZFwJ3(J#WU+dny1YY zM|^`dne~_@Tk@7tDeMbba$T{`U;4Y;ikVeWZA-o{G0w=W%GAc<=`twrvo$bnl;g!B zo)b$r;uZtWg;5QD_6lc{lMQ}GQ3Tu(i{qK!8eE1`FLHf`apgpV%OW9SS2SwY;Bu^d zlX%!i4Xz5W4oapkcWJOjkk2GwO=^RkG?5o)`j6$I#s)8|Z>iKxTZnn!XahEgm^EMA zt)u2X5p|i4I*N&glMRwN3Aq`0k{1yTuKDuJe-YI_6Qw)BXpo|EE)+~8ZmICH=I;%< zMM&0S5iX4YvSnd|{%90eZ)FkU8;`I17M8?Vc>BoZBlpEF?T$dUk9GOHDXF?+QOKa$ z8t~5(%GamVMaMLB`Scks^D0ZfBYR0O9Cf<1yPv2LmyaHn3W|@x_r^k(&saMD^=0tX zO2UI-tUNheTt3r8=iMUY^bMDf+v~a7+Ou#eDvE9v}uQN2sMGY#}3?wcxOprTiM31??U0PdOcBLTf2bqu~b)NCEO!lmjEN`my~ z9R`qsYuXGc-D8+9WfB_e?&R|6t5uOvrz64b4GBL?f|-ODJLB@{r${DefJ zo$WjeeZ>36;*k>Wsk+7tgzVY{bbX@xXt`A@6H^r*JaMmG>JT|KQxR z{d+H)U*CacsE67vpJpJ;y#|iG30N9bVZ0nJ-%A6Ge-6im8s^?|e6++Ri-#QI-@qN< zBS=oV?rnNW&DkSG$EVRCjN-FKo2e_-mbY;4Hs(67k{DcCeBQnV_SKoz{Rl-C{$Q7POWE%@8tKUeBh*9K3U~qf+ z=_g<;Rj9-_o`BuA;(cc!L_nW|Rjcn>e%T+nj|Oe?hd$XTn_nkD7uZ&h0=q?XZoBC6 zDX9wOrwbFH=_YBq;j(9YlX~P@HngTa8wR2^#W-@=XNYpT0~(({UG^=KQZ`rS&(M`( zpGgzaCQ<$eTF=_&aKMA)lGwdS^iZVHlxO||mpxZPMBk$N z>?<*_MfFKO-~8YCJbW4y=!bH*Gr>uwgrwGS*{MqHv0b0*xt;HLHom#b{;HI7FfkT3 zaM|~JJxiv!><0>oq*m<*y`(UeQQbrPBl_(p3ID!)eF3Q>%!R3uuej_(P@U_lKwwwmX3(26!9&XOOD4GNDc+L%lq*t1IzVSGs%~(&s3f?6e<#5@%OM&v$O5x73E;}bm;Aeqx>QnY&sTV+3 z{-m3Qy=rCQ6gxkw@iG?N{5#?3nwcIQf)C&0B_+D z#>L3efLnZ0*D>`aJ|3y-m=y8QY=mX8R?n8W2TWV5>E3+)I5mBrMx5-!F1uWp7J%KE zNRN%kkw81UhbQGOUx1@aJkFgn1GcVMH@j} z;$Ju}aJTP;Y~E2a>iW@j1TGhql!OmSuN$h`=jj@Tea~woRVQ71<&rPsbSlfS=Yh#Z z!QAnQKG#dKY0_<+o~MsSx}Uyg0z04w*78d(`?FXG73uShM`9tYZkEB^>hFLXiwZJ_ zRv9-6CWk2>WRR|I1u+inrKSA|t+23eQ`pjc89*vS*i-j;TziYJWrRI$+D%bYp_ejOziyS6?HM9AMm<_|y^>-?+5RQ?`hSDV5?tEb57~?8WS*U?SrHqe zNO3S~6;iBRi(0wXt3tv`aJu{(&{oMX*EF+G`+9Sx&DX0VoL-H?r3H#P+jSpP=`8uVDy%STJAIm~CRwXeK1)(0*d*M}PBS}*dqAtB&SfKmsxx79EMme0B8vYkVfzjqwZdjs%bgspuYPyXw! zqPBA=miLZ(eAYUuhF5gi^!W=iM@85!Atb5?81m55YON#8-0m5))={bG+AoQ)t-L31 zt)l|#tcE>8n#`tWwa&7=fYmOVs9q{gZjWyh>$1IoFbAFmfb7>BTE73l!G_D$S42W$ zuEXWQ`d%NqZ0cf9lw-ZOai=ZyqYrORl15XKY3+?RBA*=YvW<7Ej)It<;%)$~b>3y0 z>IMD{@OOa2`nhZiEMWcehEYFU5HV4;zAvGhQ(ZQ7Kx8l>n3?tKmzN22m+d9d2Lc?0 z8zD(Llcc&NY38!!g%HX_wo!jFZXzmZ%Qx7KhluiwbpI2Ss@h7E6uWGFS%J~EQAS%E z2~7M`K_LmR3;&4J)JiCkuo`uwDcE@#w&}{+Q??ih;Cjju61XSn6k_MrQ>aQ=`K^(F zNs?4)?o6>2vvh8eBpyU!>ztsZO;u@=th91iP*OF=icYtU*Qwa_C`R%6pC9L#%FAel z;b|J{2CMLbwWY#3U1QxK$D;&mi$uc2{F0KhiAJz)X#N;$OUcv<-e4i^^EkMbN_Rk~ zb8ndTM2IBx{a1ybM9N|Nh7}S#R&j8m%5m#JE5}3sNvKV~t#lMpUmLjBT2otEsMS2! zy2c9p-W%xdr7Bbz--2(l%1LU8&Tj9j0)x8^7$%hrcG)nk&5d!QLk}S@vvIS;gTAf* z67EGIdvk!!U}Fy}gXUMr{c#0qG8op|+2n6-9H(BU(_;=Rh$>V;ON5%ILS#^b$ZXsp zA$stnXF%Y_$}s@9RuA*(8EyHspv9XG(}b zvlL^1N>8yd-DTrZMjBUvvHA-CKNStKxlR?W7wW_TLIu>{fLld#dwzsVpYs&p3EUB@ zg{HWD1q+Z5aqpqZ*YpAqLvuPqx_VPwwzl4O|0^+mhT1hE0Eqvly+W5}(O8>MyCz4t z4^$YQlBf#5nz9MoHho$cn_b(2#zz9sA)9`G98yd65Uz<7G!mteVQ*JPq=83swy27T&++vK5s% zmd$$ul(lFp3Nz^zWHyZ;v@NT9R6*Pjm(3K`B-8!vMq2fQrd!H&SK|tsSx1t2)@^n~ z)T#dutb5eku6Ao_X12$}Xra{XD;Jc2qS(J>|Br zCbeIe&fM=U-If=1QOpB{o!*vBPlK$|d1FZFRy}l?JEU}5?G{32$27aP+_qBhdW`T_ zFQ}%5c`;g11Y_iKmzk?D*42HqnX3zaZwt>}{_QfS6v03oFwkX2V<2vQ!!XPpBCFds zX=B`s#yVos&qxwJlvT&oiHmU!n~kJ2To(kf`vsR-*+qS#){-)D!vV(caGBmQY7+V& zX@>6YjGu?A7N6Qnx}1TAxot7AnKm+GOImo*|4AFr0(<%t7~3Mn*yEQfBnops+bU5p zd$Ngxrb%LI#=b}LJdHbv*lnYE3~%STz187t$v}5oN}>F!R;p%Gklt;yhC^!!?=In5 zRcu3D%QVEc5uy}*A4#j(wok;}(_kBi3tq4YZR{oVee%34g!&QjiXv3nJA^hCLLUfi z!nwP+FT_)tkDqWq2xiRK;q4@MrLOFa8d1pM!261+4~g4-4O?6E&Gr!WMnJ7v(lECN zXu7wnBk8DOfkkM#w>MC9E2X_1RSDh2w__&WHf(K5gJ(RM3GY+oe7v#sfuY{b*e;!j z0#_=0#X`TEVQlj!vm!Exc)yOzj6g=3?x1|lL`HVRSTYh((~^;YDcD0xMk11QUCQ%g z?gl}iBMwkK$Y^>=6Tc%wSfSOcZ-g9FZ+aI6a$6Ot5o$%4UZQd+aUDGMINi?Wz(OImX zMP~}Y#*n$QF{z;qGW)tre<5>cJ0UYsh#}LHLZ;SszD)h3n{|bmO}kj7_~MCRq1tCG zCrQhzC<8Tyo#qo!rt5+UhKU-(PIlWCX0ViC$JpsMFd#8a7ioqR24l%c{%Tv_#YERb z;mXdQB@|a4Mk}Utga4UbT))GV)DA$DHM{foSjCgyYgsJmP3gPGDlPhZ1B)ZbR)b7- zP0Cy=Nl}YMySpAZdICu>u8`B-s?(=a9ek8yJEEFZZLp9;bAu)7Jc-dXfO;&FI$Vn8 zd3mR!jN8Xc!^=xG4L@Pai;8Km3Aawu@DpVc4b$LF-0Kz%+(Qcuz5%XZo~9w^zckPU z8;Eu98}OKh?y8CKtVf0^wNiw~E|%s@gcbt^P5j994gBdGfmfYE-4(8B`^GCWUxV^X zP1`qKiJ{wQ@K>bbwaoZSm)?+E8wOIDoskxq6y0T)%Cv-9GIraanNA#H&^tB{Qo`K? zxB?p$ST%da^)Wrnu10F#nd@U!Lu$3i^|7uQ2(EY5bqIntwn1U5(>r@6#j5`BkW%kt zP##xC6MU$VW@bZ}+R$CcUs3#~qL@>&uEX+0$Jy|CT-(TuF{6R0t`q-w+}Iey$o$oH z#Fu-E3T!X=vI$l0U)Xq?bVi8>u1j=3yJY{nT)oh62F@*>PxyEdw^;V-ssshZA7+&F zalK25-OS4C6sw7}(wkx@p6v$HT6-oH7)S(L+W9q%My~fI(JGqbo;fghQz_kAc8e+L zZH|qknQf}1o7wKkp4ipCd+lwvo1+ZAN{I_@>` zEaKx7j>|P|ZKw0`0q$A^o-OjTkCwP8-LSv^w&(TTj@V*v==}E7_1xd>C{+w~mV%zx z)5BAIkHb}YDfWj;Lv*mq$2Z;Du*Jy5IU8AxBnd~c-C?_MO5|im|k|T5_=2?}P+!|PluEgcuN@PR0)XCaZ zS*ws=!&hEO>t()D->R47DI}X@)l2exJafG@xi*dXMv0BCjWF;P7H?EVCNC$>GH-&- zcs5FXtfeUkLtc5w)94jPX~%TcFZFwcRmR4yp^8Rq#oZuON8R=o(d8a$l{@)W5bcT0 z%wRfdC?!;-JkP(ksD?F1pI~mv8pYB1AGp$F=3s9J-Gb7p3Ij{1iGwt(MYU9kxsleu zjpr5&VU94Zg#`GI8q92N58o?*NbaOPiHmFs#4K}}lt4$3_Rn(CAgw7zs zRHrXoYm0nY639NFOGhI2F%n>lZu*!^BU0}hl=a@ywIYvuChc`N2k!lVCf@v~$m8^s z+_MshFY&`jx#mf3U6JB$j)?TA68%fUfL@WCgur|W={+Wr)0T$0FIlzfNWDBQ_!nJ? zoKc);2l?Ky-}Ccc>^&5vaZ>ukS0}}a5{PVvNh@kA`Agg<(X_VSk-Qiyr8gQub|VK; z(`9yKmk>(zGfh7-v)>3KQno?JY)2zP8$}*44P%~9q{X$8h9Q7me?<0(REPi|ppon; z@GRZuDB{i_O+Q95DR&9>h4lYL$_)jPYRypcU4)xwT;&z(gN!y(ats??@uA3$4rD1s z+8R?3uU35A>c=Y+DCLS3f(hi+2NP6CbEno6uXdA=Al-A52p!y9>xSr8Svrn@oPole z{q;0+nD150Y4kD#ZPCn0@-pW#u+x#UPdrlZ@WKBGCzE_dc7Y@`QeH5LY^LhKFdCP_ zg_dKi*DEq5fN9A>UsaqTFm1E zlwdOie9f*Q2|+-(*GMAY2P1vjYh`pRNR*(TWPN;{Ftr-ZcX(r|rvhW%cD&88` zve0az6*Ay)h?a$B=d~=nHuZ6cPUCL&krhN!^P(dWN+yMNq23-68~F@Z9Wi6^(=YOo z?kA9z3S8Qd<&uEep|%zN!WQb~Km|rb>Si#_f-_1K_L z+hXzL%aBm=bVJ=*07gD&|Z*0a8()MuB+$${dv^wA@U9)Pa4a3ARUoS=S zo##Sr>I|Mt+U9Q!wUrah$#}v(2(?8&!>Dhf$8*3@+4S|CI^YO?_CTnuF826Z%r^{< z8efK*OecY?r{{+Qj%arkDUtb?vqL`!#tnr9XLq%Acx)I97>`#EW@IRMbEV#k7rlAA|MgZ1<3dYOlP=Wf#IfpVyM z3Onm{#1j>@=4XClM?!GxI-w>Ox?vtn1s`QJ*{%X>@K9mq&I&>}o)dHMc&DMMJacEF zgjm_`QrTA1+3KfCCgn+KE4|w~)LbnjbF|{%>VUBv^8yeqeS}5-Y9u{&tf$^VN7+gY zM&)e7yR9Ydi7KJyVsFwrR?@`~6ga>${h%Y!od#Mp*K}wVJP=+?iV|Ej#jkOnR~a~V z9Jx&*1F^1~1mcPjb5w1BT74Kz_}`@VvzmKTRWSez#`UEc9@5h`p(a~Ygm<*V=dT0) z7MG>=Eugqi+q7l#%`$v&v5NUd46Udu3lMKu%}&jwv}_y7;6>81rZ^a~(o3t7OgV&+ zK)L&M_N+PNC|@GR3ht?R9^Ou*w0GT5xy+qZ+pJXbqA6_c^9Ef*8CX=;9cprJy2}+(sxjJ|y{iaUN`<(AHu3!Z^^leFZF6Q`p;g)3-2TdiW+ph|FZ@`O@uTe+XRG z4>Vj)*WA|dBeHIw;5OeFDc<%1D?m&cDAd<_ zrUrFflB6&pk0tknHUzxKZLk!>UlNKC0rjEQtpiSmxSqD0`O`*b1M%+#p@{YHT{5TqpkC5k0WD5SLJ5qB~Kl`1^? zr&Wb56GbWRTp>!4oL`R6sE?IVIkT(}f=Q}oU+yA}g~%_fRs(}xej(4|kmPO{9QSU^ zKz1kgiuz?N5qi{N4Pu)$rId}WL2R@3c-mTn*k)8=vwlwvVs|2f3}VxcIjR<~%`S>> zLnn!HIQE-osRbGqAKG0&$GdvYA9FOS@KNYc(HIB)+on!7LNnF3K~mp>(7Gz#22Yja zjyU(4&?LPBRW6{qk`-EAb=dZ~_+GpcT1EMqFzfyx#KugUdHhCzSj%{@_vo4AN}(6d zhnNqrR~Eb$V(!MTEUFW-M9{E#i1~`k>f<{^gqVAk$8S)k5n}EuhkY32<2SAbo>!42 zm1N>Co}Z4hnWjvL`5HtAo&`;Z3V4vJz_Zo7)`7IPNjt5}_BLf#vJ2gWGR>96sm;&I<&BYcQCQ<0@M z!iSi%l;K5|&Fvxjsu9`YbmC7S^B07e3upwWcR(loEzm*@5;7&mV(k^{ua=We>Gg>$`K#^ZHf}+Ub!Ap}v%sAz-IH;fVn{-lc;wupsVj>bGDlj6BlJRbH zjoUC!HO>HgAYqjRi+Y7T`v~56i3*`paO2^r@HPT^R5^L?s7QVg5bnStUzAqy-Ht@;gITtZ`*r{`cnjb0P70DZ;8 z!%(o~XN9~dSnBib7#FgX@6&UTh|_)i8AXFp(D;hx;F~X|*)3~}~qXmCm6gwZp-39SM z$-U(Ikm{2At2%9Ur=*qmHBrT9Ue$CYs_1;TSP&w+>DBRNXlkP3XqvcsM6e07^4uV< zxH#llLHvtG{4DKAA?7i|Qc%(vY+#6dvQ&Y8NHQ_#N7PC(hv?>OzExSR&;h6{6HI>n z`;Rq}%wfzGyj7VYQlG)jd=A4CwqqC48X!;WB#d4)Ro`z3g>87xt2-0Gc%rv4?Jz3oLO`;}h z=L)s;)>puXegq_v@O&c^xq$L0*}e~h47Gj#Z1D`)iw_uE_M2R;`b=ie;=99m(9$r^ z4)-6?Kf@T-n2`kEe6>|s`HvVi&=}T^x;Z=AGI_gB5R-RQwP771P&H>K;5l$%SVyEi z@T|XFY$m#j>5Vo9(d>?h^&#P;g=Y9D0_sO4+Q1ySG@1$q*=ewV?B8?f7KfjJdLfY~d zJ_B?)WJO)cml0)7MZQmKg94Q_?7TZaudL-sxR9S$Nxl^e@+EtP$o@%wKC?yVivj3l=A%XQ zcjMvtE4)aTp4U5BszE8`QUSPH&%+u&t6Oy?FH5jw z*E1x4mp56HxAS+a`Xkl3L;}~f$v;5zP#b&CRR(Zqvgh*Kj#4$B&p(4Xkh7fH1A6uO z{C8w}Ro07; z;T}~j(N-IQR$d|PKh=yPEnH=f_UyajH$IDiRK?5 zz96cr_!oF+adUt5%j`FaMXg5&@P)d5W0|o`H2~O z!KZw&35hmSH5Y<5evxRiDG%JcPzlKMy%KHDIPs)-emu_}h@L{ngZm~@bU}twQ{PE6 zcL_Pi{iKUdH21Ls?80$UzU-H1o)8g`d9M?nB$_9^9-;aa?3nwj)u1n2lj63>OEk|) z<}w8ZkIeImM}E?x6U}R?Qt59XV9pW5LGE_Aa7~m8x8&8~`wZG-(C);)MVq`+%5Omb z5hSyd&zx;&)`DJPv9 zm3%xd@s3-S0ne0?iC?I1(P7(rCT>@`p7I~iKixGWjhHYHvMMlP=@LTEmT zhZG&)fR00o48A8^O?->Gd*>A2xw(lK<@@bGe-gf_r~`a`ZsK8eN=PfVIdaf)_7u@+ zM&dH^x?PSmziA4VD+>4?Y$UEIC2--}Y`Mz1_D6}#CR6!_d9hOoMQ;uwbh})Mas7~* zoN6%UAg0A|BXJH5w!$J!>0DLX{ELpz;BC|u{oU@wkyfr3H+m{xI?}g#OdQ7H~_yX$Zv&sH)b|A5jW-QXRYoNy_ zm(W~lMYUaXcx;s@mzwn3SIc8l=OvQW9vY90lj3fAGvxMCG?8OFd2I5|tKM^Tsov8d z-MR{6$PLk{-+RnbLaJESmonr|QvleTBl;K}+0+>ovrdH)cm+)`Av%{EGnu&YQ zFxrw&!x-VJY-n0hU~no_jK%j_#VTYYBdEUVn7*mFCeaG%$jZb-w(0$dKuR0v|s(gI`UgJE)MUCj8>sP1UChDM5I88bnm3y#gW^$36*ebX<>O}fO` z;_3lKjSX|ZZ%igl|K0cPK$%`)X5L7VV^deJqS#W-;yWci`M8Pu0L!sNUk2${ztzL| ztG@&N9``L{-j&Sl*HSwZ)#HIov8Z{0tHA^T9U$Ivp}=H;(QD0j9sM^iU%R1psw z*@?jzUd4Oj$~OF5*=9ituWZwPwxu6LKAIyC&0B+BW+PUPGq`#m;$*hLY^Fd=P^=q- zd~h(DX*lSqo*g{t8GnBG@GbrFl0Vv6-M2AtZjJLK*p0vHwNANVg^yB z71?;zZEshe)1o)%IW2n4dq7fGEqa4wUL3J$J_$D>a*SIg+{=-^3jf&n!O9;m(LBi;qumA4+9*l*(LfRi>b%Q8fRN0<1XsRAq|n zxMi_#1v7Dl6HU#!P-6RLGefnl_uq_3v)a}wDd0qDTUUd10n^G`1^k-~{?r9btD+0o zg3h5ufNnZHN_(4*YH2;K;B}Ss^WL0Qp z-efUPkWyQd0u|GoF=f3}yq`!a-;Ob5BT%ig_(q$m>G^z}afHGk>=^xaOi4-Q7M=e7 zNS%zW_c|GByJRDQ>tumC8Rf2j5v}1jy1vg!l_f)%0FbC*`!!ehOoM>(f&>3_2O#j`e-Ggu}e%!gFz4eV_I8zP4+nJqzD=JUdLxulx_{`)pPPD;&l_Hl>C~@9DcfY`RcM=WnV(u>vDOM6gh|`4zE8H7G1u+{2yxkpI8VuI z%!C~vBcX6A60D}LYCXb(L?}Z@h@J5yu`?m|T4}!l13>fQ|4pNqb+MgDqiGbfuUep) zn$AED`Hv>?9A+D?-Qlncgx2WwB<^=&Jl^@GyNz;M^Mt%Zl`kmBBg`ZiUA`RWzW z`nE0DydSWRZeEx9JUC=qS7>^CAoF=ofVAmR7{lPiyiw5yHSs}da@~HFr{^WtER}1z zDXK@T8n^jD7lnw&ryk=T@-#@}E{q{|%j|>c*OYu1<_$l&Ff090Dpwy_?Pbw@m%ctnakFhT5#u(P`T%=JSoAs?bi` z4y(}SjTWkaPTS6og@wM+!wb_OU1*|cudMS;?%}kl4Kp{sR8t-JXrZd^;!>QpiB#8( zFFoCFaKqzpr)`>_H578)blT)>d-U;Y+62-Eb|y!N6i3$w@e)Yp8E3=%P}a(;UB;&x z78D8M-U_i?C+)PopvrEvWNO>xG-Zq|Hr-(~iKCSCJGZV^B9S|Vuo^-RYJNLzJ^4e2 zxm(cz;9cB>@|h#Y7*2DK;H1NCaTj;HG83bJIn7s?g1>d${?a@j080)!&Ar5`@d90D z`2iyal4_roN-m3QA+H*~a|B=sh01NDW@3VlEHAeX0cB=EGDw|*n^b<>V1bcB!R7(W zkz1gh`eL+X{F`yB)r_svJmSpmD_14N)*R z*|T6RLg@v`W7*osyLr+w^4j*5K>&d&xp0EQt*2gSCsl`T~q#)LD$lUa$ zVSeoLCZ4CjnHD(K3qBwwxFAG6$o7MkVSZ<*z-Fk@P|%Y)yW z<&id$CBG`m4h(sUZ z7l}6Sp!`1VBQlIYx1wTN$;BHY(5>hMTD7+Xn&=3$O7w(4x9UZd9$tZ_Ewvir6=;S9 zt;SOKM;JP-+9H*~P5@Pto-&_0io3TUYAm4AxSdY(Yns)kUwes|PSR;!A{OIW*a{rd zs_x3rE->P8i{kA@qgB3_fUS5odkK&d?3EVvjhBFl76GyjThq4@e^s zh|s7GTIi)(Q=JJs%yz(UClOrDV}9mv1vFAS^$#zypj`x7)}5yZSf336hdzgRc!z~{ z?tjqAFpzAI&}vn-O#eKUEjMwfaBLBk@45d^IM$*$YtvsR}ZY}go zzU7E0PC<^HH*Agn2K2J0&n-u&gB_dqY!dn$JNC?5cWF09^-8j_Y}1QQQ}zqp_>yk$ z^J?gPdOmY%6M^`R8<9!xz;cjybni2r7{IlhXP=V8AAxJV|{`2!(B1os$g`nu;p6Z{ogZjpo8mHC6Ob(E9AukSenu)Z;8QEm2 z&cNT1Cp9E(qDqT2y^T9uMR%xjBZ2g7a<5^lKg-K{pVO?TCgZRpoMBc`zE*v8KLk zR7FKJ7ur_qrZHiT9eInCo`i3$!DUX~! zi+)<`RM*)baE#0`~mz1;^yiDHnyV$5fXF~GSmddFQlGbuBxMa`V)VwKTYvWa0kAocL= zB$y6^)4?SJkGB8f9_ornucs@bor_I{!N6)%ai+JhU^RhN1I8#L1OBpvV6MKumaDlJ-nm{bd@wcQ9@A7Urma1O(=SFjDh)&Ogm=9C=*3U&b4{-Uz7;+cNW z5#nxl1;Ba9=CX5`v|vG2fV&S2jV^~zqmOf$5Y^H?P>aV1fgv94iPFAI6v{32eccX7Dt=}Ha&>l7_ z4V=xsHqq~2{reyNZ8j3!n|)F%=&#jj?I+Z~6-?JJ`uppq|4D80O%(mDc4}tdreCS| z5wX%lOIub+_9LC~*AxGnbfO|`s?$Qf&eP^==KRnALg&}V{~LXRj-F{nzxDqKhpQ_6 zKmVU_1X;qr`ENlj)5|?|pU&W$hW|yNZL_IxN+EdRzu{JSELMFp?f(-_N2=1V`){~! z1T`_(m}XcJj{jc~)Yi~xr7Z%#`oF`e3!m`@$3dymX&8w+*HTh7@vmxVTB1(+Z8^`o z-@xlsozu7Mq{XWAO+^ChkCN^f_csMZ6{#yb0P0x@C( z!dF^!$9EodBdxDrEopt`&{%0ZZfCzFBG5qFqcz)4jFl5J&VDHtY#Fc@`zW>0ubsfm zAv8lzq;r6!BiipK#x`{G_v=(%=w{nt=KuuiyQ*m5?~f4tDNY9I-=lcje~r6GySE)i z1Al)m74QFWXa`p3zrU`KfZKM#IS?gme*Y&ur+#arTA}-zN*P@Sy`m?{H5%@Sy{} zM~4F8!y3g0-gGp9JXCDBUqs;$Htce~AommAuSf(+-cd?^9|hl$l6O=k=Uumm6{5!Y z70u&pO#=01QOD858G$B}r{Fp+!7ZW$X!_Sbb*cjm`&9?OZ`hM{f{y-`QF9 z1}JnY`gvW#+H9;D1KACu^zM4D$8UoXHA#*AhzgCv!9B{jQ{V?+0fxn*~dthJF=eT7# zRu7#fr(*H#I!Ypx#}CtxpK8^k)Kan_`3Lt1jj`(_o6Zjr0rPsO*J|^TmcHxBr6ZZh zV(*51eN_UsfYT>x4~f>s0pjL2`}#!eB|_Z=#%^SgMTml^!;JBN_zu}vPyKX)(oRLi zgSO~IpW4Yq9=j{a><>B1Xtd>9UWJmX)c&pwnzSF82P-5^DWTm-hW&EALMSF91BP0S ziO$IYsvGvc<{Om<8Ad*tbm0FAVee0gn!R~6aA9w!7+j=gZ(c01;7ljfPN!Cyz3PTm zfepqnl2eP_`s~i+US4+Wrai-smDJwLac(KC<_G6#gAXQ{s$iXYQ7KNeQD_^}cqmVvDEQO)2CjU}!S3zhfw4^eJ73;)cY?v=C9$(M+(~YMfdgk97E^RNcZAV@Qycy-) zVO3C0XEw5?%1mx6h#IBl>eX5Js8MxD!xI~%>UA}0phaTAWE$uEo>2px6gpp1CC?rx zstUSm8rX4Z?fxhj_7udT$_h6qefYH~Ss0em7u*4LyK_<8Ukz%$w-rRWWo_7-5AVKO z`JB{Pdp^$R{ih&SK32G#zUlKIDulW^Q3;)_Eb(8@Bdl+ojw)5kFn>MIxQ+&$eK;zN zrX)A-bz(BF)2roB$lJELgs1wMPO_%b(QtL#;dgCPks{?G&m8gaikJi|w39b>a z#FkNwy|A{xT1QSG|K^}Z#Ts4Ga9t(;xrX^mZ{pWFAH_W9O2t94p2oTt{nBMDZnSvN(_Jv$x@6Pq?WIq0cbSiGuGnHH zCmQO`#$VLzN;XSPz&N5IcQ*cVMcS!vq*vi(ssw7@lE4B9oT1WreD0_vvcth&qk8k_Hk}z8R zsXTLNA5|~%4EgVm%#6qkBUouUVc#{}g~)zJu&lm{v~(>3Res-L)p*=OPCH z5}hTHPzzmOh#Uw6k`yEl$fC$WKrB_$6;0dq)yTm>M14xCA8}trs_H3gW!KG#FqMeR z7>FR2^TIjaa z=jrUPZ{lMiZa(?iCZcg(Ka6iXZnJpa=HnaO7qT->BV-MSs5!w+*fj75um389X%st+ z*JRxaV_E}z^#x;&g)yxakmeS~G(;$En2ZuM#`CfuV_O>BvbY!9ULx$V$V)qd=S@Mj z)Qjvqkhi?ZKF9MJOglms+RXF%AC7W8D^o9R)&}`r5hlr&+uWK#zE_cjsjFoTA^m?r zzDtR%=6D~-iz6GB1^MRs0+G9uGi`W6El;hCAYbW+jlr_ezjuSD`U6K~i77$8`&E~O z8S>zDPrnC_XWQOWn`Vmi3i3T5wVI5piymngr|ScqIVT) zzs$i#P|c*eE?+lKm{D}Oq|f~y4;eaVaFFIi+cd(ZRtpN{guHLVmI zpGZ;jFCJC@I;d#>!W7u?D&zh-G)T> z6_~`M$%U^ADl!H0@o%}x{?$yvQ*q73GmwuixK0K=^vHPy<|^jP)GyjUs7Ou;mcMac`u5yi{}I%rEy{6xx@$j=@BKKn|#FMYE8oPmAr0&<#OS7^5@8{Hi~3s@|gm2 zZKU)-p4)%38baaM$}miRRpD3HAw^fK>^(+;aJVeYN!i!#P!V_Nh-)OG+bVyLNkq(& z^4oqS;v1^`9|jeX*S7u*lp>>Ndd$Ji6b~4BY{ac>Aq@CX$j5T&@eb~-2s}|z2A-O* z+3N%P758-+JbF8_&Hg-FT-xK>QkZqj%8l6WIsT7qki3l_8&dr;j~rBFLx@$w>+UKr zf+aP)g?Wm9J6eV8*#lH*-U?p#o1*>updwo(5`$1x!952NiQ6YA;DiEmy}yd|7no3; z|9(p(+j4rXo@0n5GGUv?$9&vuDd1m}#6}m@a|@11CYz1Ut0%SB^SpSD@bM+?4yCr8 zr%W3#E-(D9R|3`U2$9i^kx~MFRSEtNS!V)QWzjwU=XvhsifnQpQ2|kwiwdX+iaUb1 zrG;B&X>O>Xpr|N_=62o1UED63m9|=GTA5l|YU-Pnnw44o>MeWIUfXFmbNPSIJkLe@ zzkELD;h8gM&di)SbLPzQ%zdUA=)6as`fE0OxNCIlCtro zL^Rx+19`T}piZ^^Xq+lV2h+8u9#n4$&z2D60u11W5zh;b%<#dAFExA=|A!*=FkLUT zA;piv_hks^TfCOcpc6kLZ=9FId8Vr=6zaRAY<<2r)||%z%R`#;R4omr|=Kdn9Z5dBG{KlK-A-W`KM{q(ttNT`%FWAy$Mz zAm}>+ttBf0>$;^9>MF#9nl3N{!E72gfNr>+^mkr2cAtu^8Ys7Y0}U8mXd zUHrI9Wn43eT+c7Oymfpv@?D0IbC&=FA3f5=gfe1LMIMMSh`O za93>9d`7I5);hO3EA`r>{ zEtRP{Z8{GKeam34a!{OyR02(Ob;skTlO;{kBjNQ^Oy^t`5c07$`vteNe@uFP>My2q zPz~Kmo6b5)ZHb$$Dd;*^n$EU0bO(af_aCOSy<(_5L1$*1@&u{Z!4T6KtLk-uDo}Z6 zJVKv6hEEl7Z=Fpbj5sI$`siV%Q?8{lYSl?*4w-8@BhZR^z15^jj7rR_rn8>pv0qO7 z9EvlYwU|xz$7RdcdW+{(Ya8}QsA@$hDsA}JShNcu`@^kP3OQZkE+8k!8}agSq3Nt` z@zX{y;~x>jBzOSZ@!NXCOU|jVo*=6(1CoTduTL#kQ?JZsVtXpn2K>G(@3z>H@Ej>w4PmZ$2t=0`F_kNAR%MruEUpd#f6AW!~G z$1g!twm&OPH`r|oR4YPi0*5rq!% zqgCGsFE<@0{C#7?e@%yVT^E`c6oTOBWsV0?2X%Kw!`-GM@}XqbS7%zYE5{xj4F7!W zwc4&`ohFgyy+x*DHoaXL2PTY;*(e)7312p?5LwToHD{c*)33fQed8ck)6PL>)Rk1G zW26{C8D7IkGm;YUv(Rb|=*Wwu04}<~v6iNzfWY*<1eg$dgIv+x^`@hTzc&WgBf?2( zdc{FC!%jcoR-UF~AUW{koyuf5WFrUl>BD^kXl)0@rdqpe04p@|*^3bpoTBuOAG7A2 zTU($Q@hhq;x@Y~UwHNH2Kvs-qgr<;q9ZsJ-`AEfdWU>kpqGS0(dqcAjkb`ldnY?TR zHsj2M4o02j{}`h(MgDV@(Mb*OCUg!IF9Qcqio2@S8k7;tDM&mVwoHlwI7a3Ptb@X` z*hh9M~h*Y&&lm4bBN##N#tjg7IWmoPbdA(s* zu0F1jbgYp-1OKJBg}#L<(8lGbS-ssZ{VJ=T(E)|PgXc}9U7EzBn znWW#o!S_R$t68$Rm8@hL!^OIacwhR_G)7XvnWx*4`*N3QOb8*(4qul#RCA+43oa`u zrK0?(tP$Q+$!m&~N0wOjY&VUPKmxKP)^(g|O!Ws?A2X)nR%2PL+OJbe1=;q_rctRX zWVgx&#Z6Yu){HTY8REF8+akyRZ5rk*86U?1CS@w51nqo()N#f4>0HD_EyFZAD)Xnl zaw`fXhy&<8p%=xM78FzF9Q<*2X9jFaGCEKllQoTQ7za5PHaZK)^yP)S>TwWA8{M0p z6W`c0dZDT+ehJ7$Af;IH*@PUK9K8Wp3sS0nmq?hxji#ALKNc^l)L-h%@H+Z+;NS?x zjg2fL50P1wF`g6+F)2|`5ce@~uC8D)AKs|v3H}INCb{&L2hwQ8Hm{jReZNY(9}@}f zH;qVSyrCWjdp!9?(R197*^-R$x6836rjejzOd947hBcXBf+*YcZ+)N~l`6?+<_z+A zq2(x3zwXb-^pJAmRxngk4HLT_Cy;ChrmgdBce^4w%T)zvuzsVhMA*gAQ2d!`WGZTF zc`SC>gxoUU`5*dzawGG}N$6=)Q~wMph!n>l%`r}pZ@&*x1{J#1m<%8lWFw0B@A`^| zHfAu${vb!62iX)PEig4aLm*%#L}@EXoNGDCKssASo(nrLiQ`hjird}P$QJIF82UE4%)PH8&kRCkdA)peXj4w@Ho$cK3 zs63}xy;J|)s;M^S9jM;IWG3gUT@9nIx;@bEyVQ|wjjm!Zljp0>>#j?G%Qy9tsv+30 zIE8j}73*K`LuLK-lS!8KA9DfD@@*Cln0~UIIAHvA1|4i{U698Ifb4-#_JimNbOG69 zpsBwlT^_43wiFmoUFtLXwd){bAWvEN(A%A65RB-IlGYcN==E3*+Zu9R@YolCy%M0k z#=Zu;O4-|?PrrWb`?0Po(%XsPM$vTVDpP-#HkvHy}l0WawISdL~G^@rdK z2gp6g63FF+2G5U#wR06MR^Lk~2k0z;RlJM@?w7z8UZ_C+6bU@Z%X(lb0dM^md3zgR z+25#tgqO>}f3N}dPcOs{)~C-oAC$OHIKGc>U7$(eYhI8{L467Q$_oN5NMp4p^4Dsu zeHDVyoO?}udu^g`{AlcsPpQ2 zlFextVm=DIyCt7vl8@ByE#R0?s%4VeUz_?73MAVZw7VL1^&{z`PpE4@53y(ldenq@ zdQX#0FF$Q3i}qlOO)EP0GL5Ast)go$qbcZG6RckB&!#@zpR$2wrJR0y%JN$&ed+aG z@!rlZWp(vA$||dy=uCYMR#e^mQdDT_b5#sv)7F`~S2~vrTMzJy1>SH81eeoypQDu< zsLhq^p{Bkdga{dvo^67Zq?czas!blK&^j@&-^=3#Zy(lj-Zk|YRqATB0axr0J^{i9Y*LdleWaR`IVv|fFc6&NFualTAQzdnRx*S1 zS>P#d=ghQhZ6sqdvYD&=nk-IJJ?i<`6Cd#)2Dh*qn;hQgkc8EvE3e1rJac870O)1v~+6 z(7(;uejG;?wDEF>C4F!q?IteKc**=!BAaQ8nK?v%KzXnhm4#VPiN4QBWkAo)0T28p}IF zg}P^L(T;*58bMtau}v$OKzCN}^I{4nVDZ#@(a?ek$%+>R9v48n^{iDe+NBvWkrwCC zEXg)JkKVv-G|}(A9_Xc^^xfCP#*~o#=sVT^9|J^eKtW%-Y%xJqTkt^zfW-Yi1iRA8NX?-JtUb#0qbI|sOfPGw5kd#weLY+RPJq5U=6$Fa?eJZQakWhQ zI^P)_AvmmkL~8;K?LbsvzB439k`nV|3<0+Ud|ev3GLpLHJANXQ#-k(?jlgYrsC6!X z9$OlzJRHB=mWSh)+wySydRrcjU#&d;kUU<^cbq4W*ho8%^UTQo^>Ca|yH$_78(VpN za(f=1+@8n(-JZw)S$XVf?8@|}hfk&SL!!whM-DiNqQ>S#^3qB+ER5K6v~SUy`Hr?y zl5$1emPVu;rHIqfHbv54#qu52nyB1czUWlGqq)%U3!lo>6$G$?N+4&35}=XaeO)DK z*+Vs3@C0aDs-7pwXB^Boq~dYUgiC7Ud;^uA60~tXP68wg??DU}juv??)>RpnPAk0~ zmv4v=!1axDMRysNZ+xm`B5Zf;%{L~&Hoil6;dIzeO2w6w72hSR39tmB*zUV4-juV&CIW`Why1Ej6p#3;i6**3VWttUbtFfWFH z*hUEyQP8zCl;-;*!BwZuB0XQPROP0@N@INy9(J`l`8s-B@#9yDDb8OB&-$zL^$JXz z=Uux973>VD@+{gx48>KgCAn5~m4K8z>)-i$bGz(`{p^IzkqKp&YuSkHtXlS{$2G(| zCtq)ZlkVB18Htl9i&V539RUQ*a#yc>J<=9$qR-|PiNEXFB&w@NgR%@x+O~W>46!D@ zW>bZw)lh|7RCjQKYi|CVHoGQeSi4oB)AHYJA%q0Rukt;S=qmTF&i@7xj{PiTqL%*+ zy-b;0H1b=l%h>NV4L(nYG4{~(aOadGW5si7gPa*$MAr0!k=80g_MrJXJ10GJ zehe8iP0N{YYK2-r28njQkh2PZL0!tX=XlO)_0EMXWm?X9e?b=Q$XPG`kX%f;4ZPAk z-t*VzSj$1YKQ}q&B|rVBjGRO8QP=d&i}5XJ%5?J%lx@`S)P3L=IZ3MOKdX{7#|{Q$ z$l~b(ALj5qy2ej~gh>&jF~FR1Dbch(AGz5+;?kr-${;@>Xf%5pV<3wo0bi-bkzE{u zd4vP8P~fP?opCz{TXoyn)S(w-%BMdz|90Ft+$F0Z@~x`=*yEa!#CK0z&#y@Z z-dOGSI{Qcs;>bsBDJ5ISNpC71!RT)1?2osi&$QM1F9v^0&|Dv6$MBD zJ6Xg?S`;CHUc4asB7XIgy<50`#&jLUc+l- zqr9XcLBJqFlYwGu&kKfpdMQu-%zzH;dFk~y3Q>zeJo!y&_zYVk`X6U0du5|FE-LT8qGhY zF*x8-zpLiB@VS)kp4*wy)ST+oBQBFTLP{5Bt&^qr7WiCsy@DBHm-iQcL0U+PdL>k7 zEd1)txt$+VS~OzhZq(_`huqHEs1x_xY1%2JPDj-8uiNRC{(#e8v>aGQf9RV{8McGe z;#Rwzbuq2YM`UOYFQ0)>gotpf2+hmvA`JOhq3IWWM?qQvT4ppty3r<;tvqRxA#(eL z9*{>28_nF)Asfrs*+_qN;#h^(~_`Yt=sg~nzhwxTMNTxsScKo0M zvgY3EUALp!%0c?!>E&+6J{G5TCz5Fg5nQU=P7%2gv>5Dh2(1cO4|3R0khrOgqgoOD zu;|4oO`AwoGM$zs*`h1JFLX|?=61a7@0}1y5k9bqCct4rl(gM7&1hLCevzy{vSgpuhC8>7RuBI# z)$_NZyxGST*>M}!?H03-K)w2>+i@oaLYIY^oMDkV-bQu(e^6=RHtOygUTL0xqWrSD zJAmPW6385ld&7*h?u;y2t6XV^m9!9t(T%j-h@osZf%bM__kOn{rLhETnY8fBByEMA zPs>|bKlD$OKWm%9EA3=Hf$Wd1bvqg>Hyhcf$CGLLJ}@oqOpiT6fCUGpg;qnv)nt0Z z&VeOSyCKs3x!9=xFDTWkx7KZN>^{M0okQ~FlibE(vQ*oLJ^Q<3F*Y6a>2Fx{coy8O@b03&J#)@zt$@y#)#lF)r3K>=ZwuXmiLC+7)u{YSVi;(pfX0& ziyM$>q3odXB4)8m5)&7Oi z7|m$Mr`hk9X>GYXjem+Oi;zafDTb?d3(5ImV4DQsH}PrUDY?()eGWIZTj$%B!9knj zq>}q=jJB(7ImoY(C^;O2{smhO_xj~<9^_eD4)^-y@Egb2gMiL018w)?;#BIIU`x%7e5Df>j|YZ<6y0^Bu5?1LR=geTMzB&} zH>xPwSNsuhI(`fj8iPF_44bA+qH7diw`X$J_2#pVBhxtuErI{?$?c^2fEll>v*Gb4 zq$wx0z!%`I@%+Qy4? z9fy1cZ*=-U`cvp*n$bb-yE%2kt$!g?JB-vMJhDkMI6&dnzY-L3oJ1F!v|19pM1r>J z-ZQs;Nrq@iK&wpJB^`|Q7x|e#qXR#eMu+O4a7-i=ZiK?|>&o=HO)Ugz6N!76^ESw{ z8Uhdfms|e@p>!NX)kFWqTMkV#=^XHe1pcFGvZgpW3RzZ-s@8lhRH`rCdKA6A!+E4v zHHUcgfAUlbOyy-YpuWf5bdHbn&$0B>;Wu)Z2|)L2Iht|TS?2PbJlq_qIi71sO*Ut$ zZ*+~04I$%PBd5izC4kFPC!fqizM_n+Z6-YeCAF`s=J5SS^?Wi_k{b;$G9;AGAz6mg zjGlwIxM?#Jb87a3TmO~%bUG;2{DHTgc@z?HPJUbh3^r4o1g_zK^jyU0jtFQ+Nz7tm z(3L5v5?I4aFQ5}MP$iACl2urS`w47C$1iPROhE=yCRxJpYExDaS}Jo^mEw@dFRZ8g zQN-8D^rv_P8u?aG#5V;qHRT0Wai)hoMSGe`wMv}|hiOqb?qUEJD7Y%k#`ROU5NY!& zW@!k;i&V-fqX-#$EN#(gu3wCCx3|SQe_QOc+M?5ABGEt}ET!RQofEFU?Y5`|)dRUG z^*W;QMY7Gb`(^*v$N@p$=I!)7+==;Y9EL=bevsJ%Lr^})tv}NoEB!7N{TMi#QapV! z9pD+}FVX=@43Jk*J4}ZDe2^q#kdDXr>Ce}MC7#kU3QKz;Mm+ z&3l^BS*mJOX2~2vN}PL+8u!|dhN++VJAl8Dd5_S~*NiUY(|N1Vmnv}`*rqvll!80% zJJQ(|k#$jiD^p}C^sGtc3?=Sk#a}hTfqgcQ?{DLA%Hok(M|ebg&soVbIXWma8xh_? zlzT_16{eI@G{!?!SVV)#6Q4PgTeI<*Z)$xo_3yg%?UX-ZRkgOa18Dhpo6@JqIx$gx z0o{!(a#JRao+-#!B_OZHHkwv4Aw_PU2iw-VQ@;eYE~!xBeL}gU1fKz(q^5iGC3k=c zw*T%TWI*@Zi}1PxQG>m!{52?(?#IW_Wm=5&F|<_Uu3}C5f$}!L&+XN%UuCY=Vi;ig zX%{JYrmYcGEi8>FIZD>A%A$DX^KP9JG19a~7x{)V`a=+?g>r)qttHS#Vln!nD3wZ4 zf<;RzEg`@ork-1$@8{t?uI`%#!|DI z$l(j%69klz2hw&Y=uuPYKvQ!h(3qD2K&}MP!l~ncJOVwh@`6#EIu9=L0~}Ky z0UknC_Fu3%U3NX+p)6PQFsqxPAO|!{K`gC4!jW{knCeYpsf8d=`i0#mq~%v{a_cx+ zs^zm+Bi3%yK~O;D4Ig{Nm!8e{9Mp8Us;NkHIW3v%muPR2Dv5SIY)dq^wX_x`eGb@( z@R;lAxt&!O+SF4Z|79DY+&gUKw;(Ut5*>7#M0@2>*Fw$ks((tN_aKX|&xxo;a(;z@ zWE!6$8od_sg6yWrd9YsPywDA&$uY=Y6L>-J)A%IZ=tWPRHVEh|5~VLrn+z0-M9VCR zc3oX#ACzI>+T}vWW4^OlE?1ozDeq?qZbzwaL|0c#0R1XwsBd0ZW-?vBv&GlFiHOfu z^E)iLA?mmyx8B|sbxs3Yx7#cIvuU$xWIT6)TTi8S8owE`@p1mEBYHVQ5z@)$+}8P= zY$@SG@>|mzk5h`_(yW5&eu2FQW*hgr^+c?J%oD{a)Z~6p{1ILwXwSq3mVY>HE+VkJ zBK7?j8b0kIU=vc=IKXlTa$fe8v|#?F^p zcOeQbyQQ_;VSAXD<>sQ|KiwB>-8py!n(b1k?)}wGJ?;y(>P&ls0=$A-OJ}@bYtFRq z@NlPn1(MEq!PcBox2BcWP90mwTF#d(g%M$lOld1j9R2efzcO(%g8RFAoKeXo@;+cN zJATq(UuHm8Pth(}Wbd9Oib8{wjsc_}N_XYcbFH+Sd=@JGwG>aXR8HSXe=V&5788*E zTDk*}rFZGCrH6o5kmJiCmUeY-r26YEP2yCWXwnbeSPjU~j2`xV5^9Or6N$L)D{-Il zi!07At{zWX;yOhWNKY$04V*wS^t4kbnpmmQKY$-o)o6dJw}mT<(X_G%OIoK>Eoqf? z1J?;@c@fu#w~Ol|TU=$xp)3z^NpC!uC*tBM;^Ib5qsJx@1AVb<5-?E$3wc36WlBKw z#j>S<2uS*3*#>}}Ak`Pkb`f~e>WdLt*_(t;Ag+VOmbiM9DRFsgI^IEh{Iks4UNLVB zgyJkrr$BUsgBx!bB187RboXm^m+NsUOqu-Gl#+!hoq4UNNTHU}m7}WiAt=f*tLA;_ zYj3+>)V-oM)!K&b>BU~RoQUL>Onob z`8($}25#v;(rx(y=^y>+;Y;qN(w};63!y))P~9n{h;{8Xw|6J|imr3+kbKR(ok`A! zTx#%syjy_*+-q<@9~=Tw-LqQ%v+i9^uMxWG(SSJ$f3UovCRdIW zB~H@ZGbOM6#Gpyj+i}5NL#@?L_b|ncvh~VQzh34ZR$rL-PWQy}$yHHw)#0d-I(0)2 z9WMTo{GgdT&vJB{vxC^(&HS8H!e)!braxvVVO5xNp8Cg08mpBCB#Lgs7o8r^QsI>@ z59sLUdruAD=)&FZ&NYm$S&Tbd<(u2f)u4gh@||;qr<5s6rS(1Ai!VMzL{!ys?(WF8 znl>J>O4Cli7q~mMv<$JuQw4=91~*Rj#h0G!_>}C6FI?I2L20);#>!P!t={eUD79iY zMGRj1t{s|%FZYc<0r z(jLB;rGL*{SaXJE>Bq>YcQE#;XRj<>zK)V5R9u-X{d}ZUkIDHRmx)fjJ4^qlW~K6u zzyFD{78Zpf&RQ~t`}1qE^kU(@2inKlWa-n`b?d#y_x&As0AH$w(ky+cDi)da9%XZ! zS(8ccY5$8_@=p{$i!)^sWv!s=3||>sGP#7n8cqfDJ`CZZwORV+P^psg$F8*0JZ#)Rj_6#?Iwu0fRqg$^QkJZ9u~Kv2Q@vd&p=n_%hhFiLf$#I)u12*lXJt$4 z^cn1P_HlXI%(5sts3L@Mt(TT1ccQbGggvcyG>a(%#P3;D9?U&_?(f5gyBSvNW~EUS zX2M{7w^9js7rpB?~m_H~l7l9J>-#l3$ErktTL^kaRHgSa$!dUsIVKBKfrl zjGe6*$Tf>Fn2q8o1|*tIsqA0;jh)>JO;INqrnHQm%WCSKqik;WO=VX^K=(K7i@H1+ zJ6Q>+T1)?pA}Hto&R;0a2LZ8@J*Y-03cL(hkeXjwro~QfCHWA30(b5<5-h3*rOdJ(S?i3sf)l?$}c9hGJxDP%eS%j<$0a3Xe?Qgy=g!t!Pl zJi*B)OzOw}Vn_Q)vLWf>EUec09MX*37z(fv^Q%_6C zo}H+=aqJydnFg_2ye>8swyC8Qpa7E=W{cP)RZ1xW6>eEKHYv`o{G3-~lRBxEp$#%q zV)+)F>Y)97TLhw=kVYriq%VFI8=XoP*{~p4^j$(3BBM`ijMccbQH!uxuF4{LFQ|~F zn{w0aXkxF>#+&56hLNKhuMq+kU-((>#%tWL{G9jYD;lq%`=U3nY4S>AR=DFK`^h33 z5O#}9j?<|m>=5Snb;Wu6o)0O|8gng%zIq9ATztCmh)~6eUk%q9PrD6YZsDbu4r|g_ znUH?5Aw^o_ZmLZceUIDd`I!SLkz5IT?7qh72uB^}?$?D{ZW@LqcYnCym&h{h3C zznWBjnV7F7fJH0+75G^KH1G^^DED$ztG;EXCb#?<{nbKJxvXy(#7fL|O@ICYV$@gJ zIb0)y zK#$%@DBkC$D`UVl7l(Kngg=5o80gZl$pcLr6UTe3JX*-3qda=aLym)O(KO@kA&5dw zcTvl#3$VH*FI}n1%iGlL3(e1X^n@Q#-TFZuL`jOAuyLB_CLXbSth$NRa}!&rX19Zf zGg4xi?jGd(dH}~i7I^f)U^_0j+N0O@2UeGQbalw_O@@qtrK2@%C_iTFqCc?WCa9&L z;M>jDBUYqQFaQ8-nYhRP{5~xngJ$eLW zHq{kS^Cy9-p}IR5RIi^rdVMB!7S-L2K^46Ys-|Ffr-OQDs7G&L72i!zY7^NAEg}^g zgGi)rXOV-pRSA&88+Z5pNoU{4?Ky$YG@x6h)-C&1!F4b&h)~~Eydawyqa-k&m+3&M6s$fP+4pgI@T(en zb?o~ubz2TBlfb9EYz8(;p(Fv^ac<+M zW_OVU?5SD_9)o6wKfxXX-rfEbQBIY`-0Un#aoV5aRft~pr#MOAUz*3tA}XADxy}Rbxi;7f*TJG6I7WdZ{NqLtyC2k>cabj6{YFb47&xs#A z6yx>sTG}8g4X@9?195-8e+R;mwzHXH{W{W&Quk8DKUE)-Zw$RLLepRWLSaP;Pu0_} zs@$Gp2zdQx%Jc*9odmo$cw-S|#vhF|{ctee8Q8-On3^%5&kT_O!{p3{Km!S2$7a&e zX10_-7hYxoWfHiP7azdtw0@+ZT2I)nwDm+i{a1=~Uoh9cADKq{Yk>5t_!Fc$;-w3r zH`>fUsqK*!{dMGl0~D2UJU5sac78;s!$j(yBx}^V_Z8p7dtK3dGpjyp^6NZX8EQ~W zIB9d0(OvnmMS551BncP9-}AkCudAVV9Hsk?`c{Zc##6Axz&tXETWlQ-yDyW}GBn=5 zPx6jqVN;HK-Z#ibFTAMGJ8iVwqOPb9NltMLq&0_b?`MOy$Q5++<}8LU8RQPnuJ-Ej z^4+gIH9fAL{vDs!4`qc`KfIN4JP2%&z*D^J0-lk;K3-^*2VRxHYF^F&EP?5VkMi<= zz{e6e#mkStMG1VOX|o~$EWUpDYwG-$W(?^cpf%SIe+QcNo>^(sE}pF_sojuP{%Xjt z`RVa!gi&87?qrbYR&2_3~ccX@t;^lJi=g~zloHGEdpA2 zQJm}tU__CQgfOM!qO&2t!|+Hb%z6X8gyCm)i9WPS%oK`5cfSyrtuQrLi8M}gnX$N zRHuCNhcaa8Ph zF#*Hi=#NIt8UzfKz>B<00VYY{FfS{C~Pqt#$bf(#^Hlu%-pP>|+)5X0GeyRxq%StNf;U9tx1A64%ESOJ;Q7 z*-JT<5dE>Dp-B=dOy?o|u;Jo>Bw!AW=x>n!>}R2Tic&=H)byjj6JJP{0U@pX4!B3u zEfL43A&!Ia`Wvc)GAbu*F`cgquh)gw7I-y8X=Y=dX1^w^j@Yc^082nf&VcTURa3TT zELQsD&2SE3K=Nt{PnphR2z`Vuyktb2yc0g30v~XhfIj&}(EA0AU7Uli&%R0ZDUJ)* zEb)RW&PmgG7V9$lF+q0*T`gl>!e^%Q`Ebn`HC8x(CZg#J3%uPqExiQpuhx^itil=q@Fg|H=wcdm-2*>YC;|6YqKB)qZV}TJ8 zz&_2H56qKHWlW#6i4Yxb&hj}VEkPuVbC@h)tohcCaMkj5B?9r2;Hv4|LQO{1lGInp z*L}D00SxyjIM7yekdWan=H&?Rx&*MXbKV8slE6}47!~GxOTFAX6<@j<+`*Yf42?GO zHMG+Gil)t_CFjaw%24;4yoCXBy3CEoG&dTElmNWuHU$zT@Fg#8fOIL?-?n7TKu6`{ z;#QmWi0TStqOPQoi*hE9bVU#9Dn^iu-;=sq#mky_vuKEn{Bg$OzGq-LwC67q~V@RwIec98O)|7+!nyv<6SiQ z*lN95q!=!qnm*HX?g^*hF3L1_7%))O0_QJDw8FI#GBtSfWG};Xj;3YuWYX_?2;!wI zl+9g;BwWwXM3k->gM%s^Uy2kNvly26%@Qe%oR!j>VVvGPLD~PZG$2Pa!W!tkRMa{v zVO|s8=}|6Ez)lJJe&^NuA_?hD>WNooItxV4lSLsBn>N@vV0zad!*-0IwwCZXtN9ATT zRBCdTqGwSI7jb%9OZN4o1x2sN>;1%BHM=ZCzVmsm#p!!^0+ z)foL>DOF{-6eyWe)MDq!9_Dqv%uxmQy*1j^U}PqdoCCxBQUFo8VLfPbvHSzM1UCAV zhE?~}_IyCLV*}}%p4xFl#V}S4OeRwd5FlSf(?i`o9`^On0b=nRdjl5+Pl~m~N<=<=*Cm4%@4W zZ8XL3H=HBZ(G%$rY30iY;hsoD*7OpZ!_cQ6iGfBsy4EcvMqh8i+X$_zTc zu_RHJR?VR0gATYgRC!AZFRk1y(r#|tSZQs;$KA^@yJXG5)8F$kn?Lh1(SgPc6<`^B zJS#m55Y*fWj5OD$fIX>1{AO+aZ_ty1MSgGcc6|;)IR+f&jNf(U#h!~4X_v&T0s9f) z{ZK}+>xZc!t6Wh08m#xnkt#lcsl9$0ipzj3FM4Fgb{)rm9z)-}za;QqhVCe!o&w>=FO(8f4z(q7}(8OMb81D!P zq`=SvOHOm51tn)DZV0p8c-sE^SsOj7~OGzpB_MM@G;a=(*lDsT8uC@3L#6#$s{O|}G+tO*N=D2;Ln%>)WGf{N2WsK%%Jl0ZM%lPabrCJl?lQ=y1 z-|<{xR)^B;M&|P$24o#&H?3g>;E=MH)l<%8a;y~-D1&17ZHx|yt|k@+e;x~?d%5)7 z;+1L%`ZBE&$b$M#e;BW9u#>+a5YN`K_oJAL_rBILgzltfAhH9P&xt6#nScbAf zha{k(7J!?7Ljp9^0<>pAZQ4ocL-S0P3r}+Sfm{kZSh;w$1@$3}u(Mf!MlFby)|Kf^ zb5;}8Q(Cv0URn4wtt-=;1ucLS4*{k(kfCfmVIJ0=!Qb%`PBLM9E*o1jyRpLLCbOFb z?QwkKupUX0 z3ERbXJqH0+Wr6(eNTT?^H}GB;pkfQ&l>myj;3wcxcLMLjB8^P*N!(9jF|`Y6=Y>+{ z8>q^{p}=5|=J2M!0Bxao6+HP1epC8=`WfOk0F@GWgBMD>@DWWD?l-FSRMFQ6xUUh0 zH;LN?JVRHw8SFvX8$dz}si!E<2emW6qP6sf)DWmzNC%%G^7o4=HAAvbd?{FO49^Lw z7f4C*&lbL9OKG8$#?Mm=t4?jc@~}q-jR%Y_$?2tu{Z#PGC8eKuR4RluUib;{k=^+geof$_l82-kq6Ui7 z!Fq>CQvBsl!Aj}EpF{^v+sPK`U}ys5{rnrG%Tu}KAxxCi+mSXY=FFqx`E%U05&{H~ z?)fiy!TaaOuthLT1HOM7I<)~jQ*5T*RYgQt%Rj}#l?db;BRwU_l49{JaLhOS)06q~ z6Rvtn4@)$~a(w^|?7OGf70whzIVr_56*l-b5lPNex{&g?#?KWBmawYAbLVgc7$enF zn2#SG1VR)Tn(d4se5inN*VZ6{&7Hy#%(J9q>s|Y4k>`q4}>mih*UCr9htoQub)<*rNXeTqod&W@KLUEAaCJ1Xc@X z6B|!>Xp2;_D8=F?fY-ygA%j+{M5#@aHp#CricZd_ATnqzP6tFqWE8amC~>PKd(isF zD9U)!@ZoAbtwdUgC+EGA`Ao)`e2nxB_mDmt=z`bM@KtLf{=cbI7*lWb( z1L7-r8wT_4FpJlbtC+vVBFcxv{5cx7 zs+JQ8%KS~i-*YrX?-oA;>|{37Fw-`F=^?_DC+2T#^22`n$CNJZ8e}76a+kVJx)Qyn zRiw2zFh$+Hpt@cwY>2EEOi?qSTmw~`Rw(J8L_wNKi?=DrIO zyl4mS^xY)rrEkils$`@zM4-wh?H)#Jj$M_^6x=M;HD{=$-?Tia@!d))CAT!`volN+B&`4nA=B8M>ez}PeE4=e2+in2-ydEIQDL+L?PTI zPQXx1zNMvlD-%!{q_?IRbH#TIxdK5wKt45W!sNz*L!>Qf0W_6>$xCmb8|4TU?Puu& z!ipfh8ReK03yaW9;`0FSNa4Z4sv}gA6ay0^a1Sq-_$B2M5W>a4Ld;g^Y{6hWmuv#W zhJ~)?Wk2u&U$TW_$XjE+9ifkcVPs#zPf|HTKLm>jBCFj&f8);15Z68Q7yOAOSjr_I zNr=&O37926N{Mz0iyNHO33x40(EKzOcLw9?J&?LAy)j?JN9Nn4H81UW$m8 zPJqDgs<$pvtaxh9py#7Bqs%{bTT0(rI-PVfbz6!6moBVHgmEJyOs%APfgV&g8X1U- zv6Sw!ROG5sZ6mN%rD7VU+fg$DTU&CF z!W~!n@Fd-9q?_K_UpU6UrI-AL`<1}YVwl4+NksqCv^32q$J2F$b>Y4e!b@-1)1cO8 z6;Ga&{VmtSrpJfDj>6<)}M(L<0%DsgHAL34=NzDpk;|bf?owb z6NB$nbhk}|2r~_`u{F~mD@=Bx0?S$fEnzR#s%<*nEtFQ~;s0Ns}+D9bv*q=SPlBTcrf7to_7Rhml0lT>d@s#*S2gP_nA`9*&!6n5D{e=3x6+3K29SO#jvlSC}P z8Z)B&iO|<&Tm6Yp%4JWeMEJ*T=Bq?JNhC{>GkQbk6_sCh0N_p_zaCnmLyDy02|atq z#*DfCOwK}n#-9oHW7#KaMMN^GQi*ty=+gk95&qu-U;Fv1$!i!6NSke1E&5-Rb3r%p zh-Qk0)(K>x)&a=AP7_uj9d#lIg##g^uM>xlWb0;|?J6stWHla3Gc(4{u7c*S5KAn& zSs_0LkuYZ=^W*_uglS@IEW@Dym6G_0_ zsbZKv0c~6{foxPCZgWKJ7*9GV-35R3gpGz}FI>XH{UNDt@j} zsz{ZJC#f#^m1;R-OvQ~FrDCiNy9?g9I7sC>->AZV_6Zn<4dL8tLm*0YN*w*Ld_v8D zCS3gD2t!iKsmStlf7Pz2{CJYz#&FG;HPx=#@+`ybm;VZjF%kPEw9%XjtRO=Z@kaeYe4e{|DVRMNa4~Qckww#wm02^q^+s{Z$FzQhzWXErLB=xpP6Gw zpRuOMs?RXPw#Egf-Evuq-(gjeq*ZD!QbJw!d<60f7>-$f#m@|?YM zWR9=*R>Vwi#B-kWo)F*iobA|Mmg78!g_W9_hq4mos>12}{GRj-DIrq|@ubt!WH9E5 zC(YV}xUk|Li6^}RzimZQD{-Ym-h@WAEE*U>bFM(qS1>}#2pe-qV@JvtHJ5Mgj^I@< z7C*9Sea~X*KQE3x)wDjT?#0(!F%%execFqTH`*sXv1vk+PobN8hR(2e6FKiizgJM= z6=jk#fs}i95Mr=fu@EI89aFTE=SlLD2qrBD*56tG{?wU~3B^W>Vje%>bX%laN@}!M zq(n+_1cqaYM5h|f(e%W4d0DJE=B<_&Ozx0;OsSC`PY9ob!lZgGP}Ei5O2ODvFw!w* zD>eX?5@0M@;eD9LHVO6S90L7- z9uhzdD<1&xPmT1=ypYk#)wJ542deeP;i8-J)VOfz1g$pjcVxH6y8@!;fjt^KMCm_K z&<8bR`Fp~H9<=fpa99H9?@BE1$`3h<_a{SbJ2i`GX1X03%$Bp~qhDeA)Sfj9O>4Hy z47`cOT6BS$H(SOI-Ia54hbrl>vqN{~O9ov*{)o4{YAi8*B=k2gp9AL!{1wOt(QsOI zQvz^VT?Yszm%q}<MLCA{XlPQ8t3N!ilZG zQ-ml=k~i86T*|@oMXcQGS0B-|H6DNot$uYqFLa7E@=J(G>}u;*cM*CC*hFdn4uuDM zwZwHaYt825&O#hW{qIF4m9bhu7DwGfj% zeK=s*Ee=)CG0zhYUTy8;gdU9(7D%hpHO+Bd9VJW80rjRVbP4)01}YCB>Vm!&Drn^1 z>4?Y{)?)HS?qZudF}6Lrm_(gfwKhF!8D|8=5c*m;Ux7oYa3Xs<&mNty=l=aVYJIW;5iB4?XCR~I4vE8<=4(7niIl# zX5dexS~8Z_{A(}q*s!&@y82(QY1%q$*gBW+n+J=(-X>HJs0)j$v5G|?H%}$4HEVr{ z`Y!&AWLIg|bqPS61hV`A;jtEty?PghQ~nRJd*Iaq>(G;absDsixTQ$&f;#lHV6m%7 z@4q;Jkr}AfQcpR2RqG?vVo7)D$KP7q{`%9;&FSanhEq?VJKQpdD{en7=98_BB2>RX zuSi>S?xv7$eGnnlx{?g}cGW4jn}Oe8n=9UyvTrB1E1eyc2ROo}U+L|r+%LWE%3yN1 z7wE@%jw_6ENvtGR?3EbCgmqqEh6FI%>z)L*;alrhX7hFyI3rONynG3KDjYVkc+8H& z(zz0|73>Y*ssxy}R#J}2IvBO69Lk7*AWk&{wXx9AmZ`hD?Jb<%U~UqN2m+X zUa4P~Jm$8dXiJBP`tWU$wTFVPbt$uSZE3N@%u+qJ%N$!&EN^Ozt@@Rh;M<7`PL&ev zhc81?gQ&DrJNaEl`;jFB`AE5cWkggs=6xS+AnA8VPo3AH1!p#~2svR8O)%A3Y z+&&$_ODR?4XV&?>W#5YAE1Rh(%phu;9j?^&m1VA^uspeXS8!d$BKoSAxtdNGAcg>$ ziB)w3IWDU-YK#_E(r9F!sYXhumIxBnlh%&2TDw9{afwA6y-w10NxQ9Yj6R~2Aaj?L z-8a92pFi7fr{YxJ1bY{=ojt}^$njcZuHxR#9xW6iZ=P&c0>F zVl;KBaodwJNfstf;GDvAFuB~WVwjmw0;4zMWZzg+vh_=S6PlO8m;lH)-%|y zU!$TM5xq^aA-Y1WrJ8m$&ajHV{1Lm-Bh(f}TU>G$7LDb!iX}w`pmuS%h~G%Ld)yL< z*B}LR2&2g~UX>EDblSjNfT5|lSX*YSh zQyzomFeiqjp|?^028%jDxk zy@0}}+uLXDe&fr{3XohZU@fK;+U?Rl#IB#cZG(P@2-Dv}gyFn9Nu)gKGc3!lKTIyK z%A{`(CpNOHh}V)oc01&J!OHsLi_;g@p99{PUc&mAV^1ETFMxkbfbOuKWv}&@)po>l zzrbXdG8$YbjeBIQWSPscr#2M71HTe@?k2w+$Yf!I<4!Ht!KHwbLhQxGsB~HM*po&a z1>F!Pfu_8~0gWYlmQoyhG6^*Yk|`>R-{^Zy9VA@&tZ(>A?m7yTW(MCl2{C*{0p787 zW4Jm2m$41qpoguL^W;oEg+&JW%XMrkuiK;}LZGG zTD^gIrBT?}2pbpdR#bOoN8mSF}MM6I5}qZZ@ShAbe1oEmSG zGo!w+)vo5=fG^4UilpJG=@(4rbsUhjoM12ln7wUa7~PP^c6Y$FYCY#9YV2ZAuiz}C z5k$#I!xFiq)V7(?^PsDiCtw6qSz^w^2jlDML)>1&$(f#WA&5MbZZWR!s87kV017+=; z=FGPSv$fk*bQ8TE@#1F`%5X%{a<-|Wm8^9oHD?EqQ^_!G%+Vpam3-~5q^kMVfYF~R z6{W{A-W^-(O5}1Cz43OL-K9+P$Pm2gX(_#Ysgb&c@|_375U1j4ZTJfKg26rYMMw^y ztzs%u4}xV5xZ!s(Vw(n6>)pN=`;&6a?O2Vgx1k+YWE1+gk%rmm6z=#Jj!jbtHDaQ( zv7v}-YQ4L1d{TZ1(AoPj*5|@w^9=X(L66(q z=RH0Z-phvrJ&(&ot9ePl_q9c%d*ViITR_Lrk%=I>Ym{UKsxO|{3%TL|mj0#s4C91y zIQpcasUc!9c_MbVV@W6mawC;D`rzMhX%DoOKp$SD5Bew@O5Eurq>2LITmKU^gix`JK2QUtF)NWW%874QdnCRQEfsaC4_!pGRD6s!b zLkeY-{>2QjTc-4{=5ySR<@B$O??{`70IAs))K)EucFR{Z%LDX8v}t1zGXydnHO3>0RXXuh!-o_<#Z0c04_u8n@LOeAs&h4nA zzME(h$EG_V`U?1xw(hm__Doh;nK&k}xTLO_o6rQM65TH-^bw64ph2ti zg7gJ!Zkn(8CRdo3GNt}VjC@XMt!^k^BsSc}KP-6p90MPPzD7NSUiQqUc&qhT+zlkM z!-I)1HYbU6b|9T8t0?j>!1pAHrJa3TZK%hxf+1fSZ~76QMxe^a8+(s+ns0NkLQc0u zw;)fnyVr5Qiro4JUlJ-;qi-)*4iQ(Q`5q6)D~!#b^EqDMpA@#1U>p17bG+slN~15m zb!$DKHg>(A3+x*tILVaS=m+iAJAoe1^>gz=%WP%0$moX>-a)6ao|?09FSKJbyE#Tb z%CHqfymhq{^NvhWZ7ILnkTA+%06MnVMvE?t$)(f^yU+fl)X^_Hkpg>h+egy#UNSGA28b%(m|%tU@V!}FS{X#p8l->qU+ zCL1X}IYH+LV!O-kug<{b6rQ?P9r3r+KYzSK8_Thvxt<;RTDtO-(;iF}n6b$oul(OL z#p@X-d!Bc$_uMI$d{p%d8IwPnTOZhht&)aWFxE4$HYJl^&UðarPOjQ2Wsc!o8D zW)RB-RoSgMa`BAk9_%g`U$_ZP9q$>_PKD$$s^Eb<>V%U|gMl8F@ib%08(g2`X!JH=T&N|O4Hl-wEzA=ZCiNEPfQ3m%2klgES(w(hFrQkOHn%W8SeOjK za96uzcGE(&ts&ZC-SFjUcMIdOXxiVxw6!oDZei}QFdc7UhFX|Tw=nX%2~@SS!gwY7 zEpsgt8?kmhwyd=vi%_61df7xvP1Y6Etw#nAbbh}NZHLMp@t5TP?nH{ zBvb{00#a3)fQkarLQ|xJ=+abBKtN>qQ$r6ODUnW)7FuWlLI>$Z41$V^`u)z_y8++# z{qj7sxpU^s%$YN%OuKVs2>HDDi){?5hv+HQ|8{tWkb{(1@qO# zsi+SI^;O|>1UQ{3kCPyu7cIFye6GMQ5vT353-lhM!slVzX3K{$q6YTur@~YG2(>_{ zktau0=_HMzfoFujTFZk5sNj*stZSdGxu&Wz*|HR~{=v(yn#If%voYI8D3Y5^tdbOn zArzxByGCw`eXen&PR_71w#-fTXJi&9l+5n!Pf4~;bF26u$>WFW+b#8nVBXq*F{8O8 zGTu^gZ%7BE<%HLv1Bw92qrY5|GOiYo1!t42&)E&rsT0-ITSRfQ&e{#La0EPoy_?MNOn{*kWv<8Zb_x)7K&;UufkupDVo~` zP^+jm30`1KMzGD95G$8yPA${ZNc4>V;A3Ga>XpIZShm%`wG z?oPsXQ0Dj5D7bs$^Y9m0J)6T0syUy5*4(26nHkRil!x;KIlg3P@a>%wkk2bv_Xv0V zSWk%jrrmhTX38afOkGR=ca^H@F7 zRnNnX&U-=L$=9@wlc9mJKD=5n4n=KiaJdC<_*fdQkbks)PsD9)v(nEgv~ao*I{;fc9vr+iaV0*b*j z->Q^=;w9aJ>cNm&s6EGoNBL3b*YVv*35YZL`U=hG-#5O7^Vv5V3Y)bDT-XuY9g`Wh z!*)3-qabmZw&!6xq;Bka$_j!w#U(YvcGxZ_g^o)(qFqi{dN>Zy%Sx3=CoSyA-Fg?K zAM*?hlf~ABuh5uAJZ_=*T=~DlF(uW+e#^0TF~bXFS}$3#pr&`>u@G^VVKYz?WC3M-%PY1$O)AyGmL#6$*tD=($ZlcGk8xdG z{nF!jny^|(5O*D0o+hjoo@U`8?Ph4Gce(}Zzo-&}fCJk2K= z2<+0EFrpu5T!|gl1y8fMA5yvWcQPaq>M*g~*i)lmSJdvX>e!LR>`*#3enxUrf}FD5 zIE;t3w0~h6In-$9$ZHp!C#-r=e~!-JboA%wO9Z0;8L1|?*kS&ThIPTXE&c^EQqhTp zDCu-E*;pvg$>2)ELkih#DVY~VU0}!C|Fb@Z&+nWSRyZpY7(}A;+3<1 zy3`C}`)HRYfgIwe@`Y6{LXIK+94Em!?$20?gn7{?1R0a0cIROn;d602O0meW^r~$L@H$J6<5{+R8CDfJQ)z;4;!47*TG}OP zW5VKc(@IHNTyEMYTf-{lroAX>iIqx7IpVH9Nee5No7h$o%UNkFjn_K&QekB@qM7=c zFD5l0##rxrCpDm2U}|;{GlP$OzSMw7Zwp*b$-<#;g=wW#Q6aIxcEN8c_eM1$LZOAlU|4geWgs1A;=k4-^b-9e`O~){AQUPY!L(VhiMx zQnyoRxfVKUtd-QlN{VNRu2<-50dllkC-^!n3nPy4fF>4}T9i<l(avf>Fv` zURq{*^CpG9%51N|CaS0{Hg|bmE6=O`JeSCmO`ZZdIuBF~Ul>|nh*)0Qs_W7++*M_= zReUG(C4aU*$@W`m7984#Vgj|flk4smyQ8{&&{c)j^}~t*E5afYFQ}^m)USVqQFYie zTE4?(At`t^e*eQlE3R4SrI>PrvS3JOR0f+#lm6wLZD^7kF_L#d7FQv}+WiHJ6pNvu zLjN1_5*Lk$ z%;#b#S{IxhZ#bmRmG9DBF`2|5Ctnx4^t`%sN=dpH|DqA#RNRbDY+|2yBT#oQkWsv7`*ux0~ko?h0sp@G5&OfWFn3jES@Q_Tk+X`*fC)KPs3Z+ zhku#@O0iS%Ke`mx!IONOa1&TW$N1}3qt)U^z#i(W&*SB5m7>v${~PfxIPD zy`-c>_V7@NP*EbN`I2gcM22=hvq@r|RA&*iY3|NKJ#>M@7Sya#vs~i>}k~qky zaxg^aQUxP-Ay$Tm&7L43?Y@fNFH*4jS9%-n?=Q#m5=$cX*L@}tvM%M9hz$Ir>K@u> z(CZ(lcv*A<(1*_gLV0kyS5U=A*h4(m{M0ZxUy6h z+NJCJDt-vye0xDbeuu~aayryP?2rob4E*R%J}(=H9VW$O z5WLz?yAWMaBherR34{FwusTn#G*F0LhRx?y}NjhO0G9;gX@V+WT^H1+Lz*I!s zROb43BdNh~34fEoJ4HDDuGF2Q9<%_cBL0Xr^2vdN4eyb5pTJv2=7v^EEv3av9TIt! zhbTfBiM+@Ij9gl+fMiC^H}oP#SxecQHa86BA(_yfgT&^B(L4>})0sBp| z3AJv%DCY<{X`vqU)9=NE@HEz%fv!8~`*dAEL~ypH`|EOibJqowa6ZVfbbozG-=1{= zQNejc+u>Oq-$StTmJyxzxz`62f3-jTCdX9dm(Gg*o93*S;rdJ;^sObxzT(WUc-T(Z zDiJ7LdVsJW>VL{3g!n#KkHSFHO3cZ6Ifo-}<49}x^5<|0zit_>_4))|keo=hdQ)0@ zA44^B5nRkKEq%7f>Tu@KUm^TygEBXkmcpz<7I0luzCr)!BWR|U)eXzBO2v?eBXp+i zsG^UE^|2h4uhfQsQtsubWU*7x-2I4$@HN?h(?gmb_R*wV&}PqvttxmqdcH1LsulAQ zJ)c{i`*sWw^AWumn_%0jXtDl!$EWV8=w(cxOj8f-O%p8gr5t)ko$mI)Z^2Ih;YT@+29yvv?zKN0)P`;_m zECn@48=|G}ZYRn24cpywy8)agq80RwEq7Fl=zcSeiE-{LL-j|9gbk#=B&9|kOS~?o zH0{q2F=UDN{kA#nEWH}rDv={3_9!mx-hUug_xjUioYf+KBCmBR^ZV)|Ihl!k1qQ2Z zmFqpJ3#NpLeG;=Y+mV#SOS+3B^V{%VlDYj-2ZGKmUy7B zQjK?rV2y8@xLiwej=ERIKM>p8Ob^5omxJcj(yt)tVMC`f!O92v}7{PRuP$ra*}zIOinjXB;&^f zmJrO%qj&&i*(8Y!;$ap+j+$-m$pdD1*&>O&%foj#hGlCIg?rP)1c{71zkg5LkfD1G zEJM8Mpq8O}8rH$GXPa(m*jm3_71W7Ymhs&j;oG_?puG3qeakp+j+W1_4KPJ)?>!ZZ zOwCBv|7-l!cn6&yxh9dTG@x}Rk^|G{l;gRXB?xn#jlUA-G=d?vAk3v#_4w-pl{hz2 zo_(D*2ZWb=T?|=bOaGv&Wy{1jbr-^6K3O?&Ghd^y24IPA>+S%KNXo23rHM$s=ZAi@ zD)BvStiY&oI? z0tHahtNDGEwy*+yGV#?aU?qtbj-H*6rE#*gwj^BeYvC5z&yH=Cz);-Q!Y#6&{S0Dh zp+8*|smO+eT~gN8f?5j`kT1U$ChUHugx-Wb{w616>LyF(%3BjSa!Te_n)wN7o?IP{M!ctocmm})SI{=I5 zn6S)hm|ETwSPwlNO28ip*S%^vCUALwOA8a$(y`kjE!MJSYir^5Dzs!Q_$p#^!UD8# z+cY$4dtWko3EUQ7Ztu*)mxOT=d6S2435 zUHeSVHa%Af(pq?zDbm~ws^6=%aGqZaD~cB0-DYXswg)mDD&u9xU1meut>Zf!J<%hO z*7Zai@3OL@wecP!{Qt*nsPTsg!Ol(z9A%<};aVFLCZLVmqb-4$@Jt&MCNzREmNq6# z%+*F;&Fum1ilY;1YDrM$j{c&M2{oT7WI}D-n=l)N?7KanRDMe#6ZBST67Y$Ad~>!3 zM0Bm2&g3ujSiKK(I=5Fy7*%9FJjz%+7Tp?AHaYmmR9sRV=720QX)T1I%)UDTN=#`P3 zg(&G{-WkQ25XKJRIqC3>Qu!EB-QaormorL>kfrgwe)Eh-EpQ?IJ{+KCR76PgbrECC zKqIi6{tnoTD%PPFuxD?XQ4Mv?FXvi5%AE0{CDP6Dj1j0au@ zd+A?1bBkK*vOAC>2`SGK8i>YaFH(+sO-R`HEP(WyceouHS{#8L-Q%mdE5H-c+U=lG%KYI4yNDD$o$w9ag?l8!eB@fm z7fX-sA@YJ9sTNNJvk++p&`m+S!jF4;q5A-@)fs8 zwnkJ=%x17LRzxM^9Y~GI1f1WJiWO_=r&PJWS4w(QmjvV-;RH2KDC>5#g|M=Z*=o%L z)(^eh4$FxvwGtz+;wivmZ@3-22?7rQ)+f|r>Qitb)zu-j>ep_^d*Yi~k}{Og2VjlU zZbwJAGzGwS$l}UXKnoXfJKon`9l#O7uE?&*NPlk|wyKm;s|rUB=mP8mKdce3q{smu z0Q=An>jf+s`X{Bi9bT%b@*WESRB$}M+cC0)@BxI62?GF@&G5P%(}bAmKvD>Eh5kR3 zxp#UbUu1MU#t74C+^SuKossfIP`6_|#z)9sb(nCFLbI3VsH`e7b>SEB00pbNn|C@* z1XHa#LpX)VWpPsSbU_ihpn6&<>UrgamX_qRuRENdkeU6$jAfweeWF5vZpS1bdq1P7 zj0}qTjc`RGTj@9yadk^k)j*Ul;}o%lgn1JAkq1H9$gDi$XZd*w_yAJ2`YhojTiFK+ z^G;tnGb8grSwO!M9!Z2Itbvf#|Db(YEtGkP6SaFpUqupxZ2h%HGw8nP*Qq_^*b2ge z{~(C}JB@SwJ^-B4Bb4K?6q2cN((OV}--G2ZnL*mIo@RIZP#$o86!z$^pQzJoE$_Ow zj4y3ZK(+dNtb?C>{ci-ds4UblvXIJ{q}44Xl|5E`2OE~XZI6qAouS~W*MJT8#qMQE zp&*1|)TBq4=xz8~svL+LfYS%+0t}K3xPnKJm~zV89}l|^FtA@!k`OGB7Ca0l^n&*V zj|k5YyEQ8aOC>Udhn}JGWT_s zOe;yrAv~aEr=skZog!IUwy%NRGUz`=|0Es|`uz*7B2d_4>6@&AR_E;-t@)nYdEMkx z;CziSkjm)2ear}+>t3C-$?CLy={o88PV@I!7JV;$wvX|&zt6H*c99X${=&Z0eF3$+ zurhZtoZDZT)61ExpTz3J!aHt9SH=?i*{L>{W1rUiMfiiZpB$+-r)bN`nuu^Ga0WQpsIEW$TWJE}cV8?=3h2e{3%xfIAG916^{<(^Ss zo{fJ-fqCIM3QYEjEegK*(QV#Bb}Z*g-RAA*>NfA_x@9m$<>n*Xn>3*rF1MMXYtK== zZ&ryB4ipl4fKeu_3Q)mZ2VkPr?^na~{L1mR=b776aa+QT=)C&P+a|M#e6TZ-L z(>zJ0ztz)1T3Jlk zWb~qx1B2b>8bQQsuAN2rAHbu1-R4@|V*pkYmZ&BSm+7AwT8wk}d>C0~ONSh82JaC$ za|RO02l--Qk8%3Q&1&Mr)wj^Qo_b?Muc z_`(uOH3~4Nl!1Z6o(PAqQ1WWrb1N{gQZtA+t=44so^!P)Dnl|baENE zuTNtcwT1n|n=3Q3yYJsa0THiXaGTBintCKSToXnES=&WGOU-bbtzb(9`BeDPpWJ3^ z&0!+n=X0Cw`~uGy%zUf3jOKh@4+oU57GNo;*7Ti?-Ns*b{|w!RaS50H$qcC^ ztuX$IlrrEqa`jymI$}X5fF8Re-Us-0WS{ptgZa0RbP2#XK_9z?BI|c|8~+M8$!qrx z@1g4639`mfW*MCd{!+qXx@;&L4ANyse*QnYMDu*uG|ls!M*_-K=&T!Q{3I>u7_K|t z_zC}*+1cW(@ldze=gQ=3ay@zdL27QIRJFElx%;p9z7LObt2zst8)PtN)U-QXjXbjL-(ruK+XUb~8dZc#!y8y8yhF=5MGi+Ml|IHjFE#%KUo(6`ns;Dhf z>oj2uOVk=y zivb=&lqAM=I!nJLo{hJE2;u?{J(qvvZ*C zgnO1T?sX!dq8EM3D@(4gFLnD*pbWy4SqH05Mj_O6P!|4CGrns z=nQp(D%0w4sB`cMa3y7S?d)D*OV^ohr?Hl?L`owA~S7%SacJl7y*Ge00!B^kZE@K65wN}j z^SR{!q{#8c2?P-@sOVxXngZBFSSP!G0~@+W=BSTr##kfcyw~*5bRhUyU${s3>pBkl zQOwG4R9NA0&IIedV0W^ccp8Zp3FjFE%E7*mi^y=AUv?|pA7KGbb8J{|{%*X@qUFY$ zOk-sC7Yv5e8t=K?U*b$CZD{W4J}YjY?%Vi?+8$E82;1=M*3RzfRiciv^di8=R$rdp zFVZ_y&nPYN@(zD0T?$d>CCL)@k3&F5*iY;63W#+5$CxJj0_pw;gvAyvR^$w43o6(q zZRA(l*omqBnR>KQKAW=fAHq`#7@jW2J*mWC4~T5Cxb*P|F29n0~;~#o) zDUBIgT98ycPW>N?OR^L&NLESxYfI8Xnd&0`XAu8hMqLqE%k2+eNwvpG*enThnZFt? zx-7US48v=W9&BXxM?~|_+_af7oce7gI`fAVP*d|l>yV%XrASS1NNnEZR_^Au%^P?O z5FVA{K0%(5$>x!k{G}noX$3g`AnODJkMU*{{-&P$b$FKDo3_h3LE4LinyeEH%A?l_ zSi2d-nn(6t-%Hs6MUADtH?uL{*>Wt4+4D<#4iKm*L0iWIdo~@a$Tyu5rKR{J8k6K8zf&Wp>T&anrjH@zGBVJAhYT_lk zoT;|XPCO_3n&ZFpZ9mI}1sIMbwu^>Un#1YSf(fbd4zn3hi11aS8}fDHlSM+4Gs0{zi<;T%gN#~f2K6rC888De;l z)abs;d2bu*)&!iW=0v+h8b)MUneX zbxfIRME2`C5I{8%2B`VI72$QpW9znu7}Yfpd+~iTp(}-bFf7D)J(8D*+d8IvX@K?- zG!4@$Bw&0_7>flyKY_xUEAzr@HbzpIEC-M}h43}nex7A5S-HDV-FN(aKoxJ6e`Qh5 zPU%-n73Ex{QR*;Qe^7OqA|Xa{1$MGWm{TfCqAZ0BByl2@xI;pW-qMe0RIq?BQ@(zB zeYq}!6WqF_79mDYIrVyd9|%7ZWNrKURvx?<>hJF{0J?s{G3B9{ql+xN$n5ZfHaa7q zN^BRj8TG{2Tx_o#{kmgpq-*$NsCr`*;;>09N1+7zB}|zYlPUkk9HllDB*?J!##A0^ z5#)WhLJ3rOV;QZ<<0UH`kqR%e_-DT;Wi0{d`p!N1Z+#^o^?HuFP+QSBei?Cw7;kWG z&_%|sCZeV`wI{TZ2L8&!M}*!|U5Hdimd18%dvt9W{QtJ^LcjmiM~-uA?Hs?_t@c|d zYYF2#!zsDC>{20}Jj##)r!e|VHfjk!&%;mOW76fdF_BCSWN4)`8BKlvTnvb4i96Fs z9W~Mw?IzDNuF^=1wfq-iPpK#cYrk>6xt)h$m%dC-Dr1zi;2M>k@O8fwP($9Gx%w;7 zTe?^}OgK=*!nw=_fxg+H#dV7ZIx*EwjIZUC2<-S$aWDlTBxgG*eT~-DLDD@U&bjMylFA@x z)p`mUFR9jG=+KfCib{|)R{Jva`TX?N6?vb+&hnnfPg7|iRXtlpk4{7mwaQj<`% zG7A(bAxr4eN_X)<43};+%29{2#pV@k7P1tR_v7zke!76&l+air?Rj{U&>E9hu$kDP z56vlZ-0|=g%cA^vLs+Fv>~j|HNQiBLOfQ_(Z^YdwMW#i16Q^Uye0ud-JE;H%y`>XD zzD88Aqg3!B)JX*^tqQI+lnV3!`?(4ZANE(E%eUtRhmj|8!Uz=QP5* z+jLDvwC1T9(7DIL;R;~@mg<%mp3-$!McHCJ<1mpk%GomaKa& zg;>XwsPsl7ozps}WMRK3*q_Q=Idfo0ML%^nMrg!}TAi#aD!!sj?~M^wu1Z!espBqL zi_{1ylAAS6XDw3J<`oSqQkSaJtenMib4K@t%ZmoYX6u~FyeVg#29Jo%M*pfF4P@~C zH1-lkx9XUXZv9m3Et>1iS_r)9+p%IN6UOjd<8A5&CYnPP3Nsclc}QHwOSwITLrYkkJ{w-il}Z56va_Y~i4Ch~W* zL5NrsE8i@*wGmytJ&FtrW4FF85!~|Du7vj`(vyb|34JBPxOVGs!cd9OD_cJ!jFCt~ z9wrmy{O#>pQa^*Zt^eZ_B#Ez6<4Tzx^UGf>%ckZnj^;WN-veb0VU=j$9R?8p_l{X( zt@L*od&z4NxAazekUlwd2S+340B`BxX3##r+epD2yrAw}SLTc7poLMDJp|HgdQ@~5 z7tD(g$8Ygg>A*y0t;=FrV*phabKw4}NS-TLGPVlMuPPHWWN9^=PZ+~9vb36Ef__Gp z*7)Jb(i#oduNK9wWkiAmU`o z*sit!Y|8`epWcIds@NX5yM}zHUfz~D`ctev&zGdsHbi7w39J7J-MysNMsW! zPLl#2x8H-nLtNCI zrSz8EM7-@V;h;nuJX|E4Ark*P4^IfcN#veV+fkhDCaj*9O)t;&b$-B??9HGuvRFqqe-F51n3I~DK`@7RbEHivyr%*qLa)S*p+R>C`m3Yy+q?Oz8%JcUzq(mOL`rpo zmJ?Yb)v-L|ukKmdEE-Yt{n)Rh=nQ|+JINz&&IqrzU-I&E&R_OJB0u}f{+GyKERv+) z2NLJ{Sv0?(u!vt_(F|C0ua;f#jsmPO@P?Bvcn3V(QOYiNM-q`bcDXxP=-$y3n&(&6 zopAFm$JzQ=?)_eS(TZn#s=_Ip=)4&?miAO7Z&T>G8xxWuG6=6H@AJ${=W{AuNajSW zwL%Wn^H`EwaE;66>ytpk&lyPzvDYlR*~({q8NP-9lmD=D!k(dZ5(3ce2MakfSe{|idERZAZAF8nmeI)mjRTU zOu6;rxu(4Vvb>7+{7hl7tzw#>t70Q|{7QHzFUIDqC6_+`7P>j+9c2E&2CRP04g47_ z*cl*^vpmpYJM&BA2oI?8&WayMY!^?}33AOq=w@6{4(hP;WkM3SREV-tI2MG$>&RgY zF+4k)6PnsGzw>P(ZEcy~`2mqWw#@IuIqe*Zh;hM`ZFov~h1z6lkzbT4rYFku^9Vo1 zc(9$~!8FC+68YLs@meCQ{RD3(BIm_4tp|zhD{Ir5tO9e3env00ap!qWFJiLuC&De8 z;BBAd3b&q9Ua`YK7>pX+O=nY6;qvQ zuu2Mje^7UxU$V#F=tXrzTc1QnO=}{Z31if^21C=sfyORqP^A_J8gl`NIeJ(Xg=zXW z0J=zTig!Lu1pAS1uQ~+M(cc4&Z!x(zQSb(<@Z&2 z7*ISkjnV`*5HcU8`QCcS!uQs0Y|4)bG~U%!(s>VW+jYKM=(#%I#fwp=oEVz;d7y#k zQ%Md+$1y6qAaJ1sVY~_mxhRxcxm}nO_1Tj4ypPe+h_r>vO1Re>U*8_^v5)hEi71qZ>Vz@AU5_}T#Z|drjqVUwG#9I}g;f+2n=mGHaOXZMu&77cto=q{ zaqTx0BDt@h%aql35y{67!uu(rk&;RG9T7}IzAjn-T;>2yH9vmf8rT)Afe6FPwMZCe zg!tM%=8d#hT;``P8$02#%N(sSm?b>E1X^q>@|RM^$w-y2v*HaLDQRJ3|P?QTcv8?4kRcOuDhf@u`oZ)mIW?oUV_1~C4n z%Y4-joB?opGx(8~qbA>$O;~>McrNobjzxRTKX6LB7ZT=UYyLRK11@g&N{Q^@;RixG z4&#rzJRB#;S8f0Jod*F>l2FrFnNP0jjTD#J&0p~!q(90*ss79hN;gspuy*)o75Ryh zp9q|h*WHcs{;UI|Vcnhx*8l%pl%u9RmbEbVCoVHT^TOY|Ld~DdM)qLB_r$6aEFCdp zozh1J!~7x%F4JI*>G#th$`aF_mk71WT1!k|&}xnM+!7OU_9(qJICqW7irZ^UdtRj& z8mOa{;e!?=_xsqKo$|l`W<9?Wcg_566yF_kn9R-adA$xuz+>i(o!Y2#W-e5G08_TOyr~Z1n z-9A)+_qYG(&)A_#D^M_Zd$}FOQ3Y=A#U}3cNHe~+M-6}I{fOtU0x(9(%waN%#&a`x zn8F4bZ+kOP#R<@mPCUdJJLE;6b#J)LB1Ofo{h2phYkg6a{pDI{ThC^}k`jcL9e ze*}~+HV+Wy#Q3v}wy1(@{8>YAeZT(^P|Af6+&-$+INev~&w#4ldDgj1ml@0&+{yCP zDF$&Ol};|=G9KzW)9peZmX$(fuVGWV%lHAamoNsJ{`#2o!6Sg^c?OX;hY+b}8*ScpGmEBU)aF5@@`E@2E2X~TJK5@W0dB71uB zgtURzT*jS3P1zIlz;rdZk&@R&-vo~rz@{Y^sf^o?&Ey^Rmv&AKI>gZKiwy|efYF5-1p#VK;eRP%D(ypEGMd+e<12}-dE&r zjuHpC*pedmPW`H*%V>@d)%Q;QJ=p)zaW3V+Zduldy`xSyM)U8C!c;3 zju<^2ewB=~>bi_d5is%sk>F&P5kt@THvi2P{qyV&wBBe=E=iq9|czG0{N_?}XraA4m#_C;VC@;+3}@YBXE3p!lbxE({fPGd!a7q1=+|{7e#x{VFGmp7 zcarNGNM#9;5;@I7ETM94RXI8rzvNmSMpZZcRWXRzU&CJ&mSBG?KS$^|IKr=RnE%l;nQy$`dPYb7X%nib)m>;RuZz7$s!NFJx{4 z%b4JA+aOQ}_}ey`$Vl;@1IBXT8NcW-Qe=)C)Rk{2r~w&z0`R)8Y;4s6p}pXedQX1LL~enqCB^OYdC_pYZ}ifXI&q=K|%--=&eIt-C#(* z`#|I{ti$}hW3pFrcPr2Bv?GmP$amF-u5NKwmi<#8b0Ur(neU-hpZF5OB4AXL?38MV zZy>A%Ms+=H`Q9)6d6jKzT^kHGCxL*P$*Fbm#QU+%`|qpbFTpuP9yI7xZCpL`gS*$? zxlciQQa}>y9?pO(86LT@5Qh7vn1KboB03q>2~}vr2SW_STk z2T0@fyizhtSWV+~oiyIz1A)fBW;Z_LEC^?0fm_-RmbAT(>kZoO$h6y@aRZ!d(sn)) zr4=dTZytkksFI0c`sX?Q3YzGGY&K*ykd1m6*^lw;{eKY z;3HT_XC&C2ao{Up}hPI%Be{DxHzHz15W2Tg$42p3u*_G_cK2m{si-h zze6nK4Bd6JT@5HLFDsRrUk9<82OSn7`^3_7g`Vi1OLaBOYxmm0aF9ajwZcq0FTT$2ZYY|Sfa@l8V z5yjgu8=m7dj@WWAfq9{+l`{AoYY`;q7SKd89V}kSD~l08MR${cAVmio>a_@fh?lHI z92`RU5R8~ir;&-Xk+q0}^9gbUq<0KJWXoQQa2i>f6Qt7Z2X|viDsFWeXM&U?_?&+& z!f9k{J|J8N(Yb@a%3=h-SA}gX)8j!7Rb;>cV+{S4<#YfTheI-a+*846y;+3d9$H42 z53ufJfRrf$c_@o;5Ma+_rygmk<&cj{10dP=Z+JfinNCO3vsyUpfr$V?s)hj zK~~gd?s)hP;g;kGzL%pWL+fVU);RY*omJHmQ&2)=Z{EuQTus~ft%NO&$)TxxOp3zJMgjMGCGmF zhL1ENG^Bi)(oW)}dTKVldy>p;yHT6WeYrj_-Jal&Y#@XEuWLRxkADSzio2h%QZKSQ zg7=HJ|Ic)}jFdgGgFRjTy1jB-DyH(of9A`usuK@!MyyQnI!|>Po3;KhDsU!-cN5v% zTvVQ6U5`UVP$K4DvXbRAwu+qi4?e#+TMslF$Q-Kn8{JUM_ngL;6ee?Bhw~A*gGT@n z`+Jm#_st>1>e*JsgTQ?CY_jV#rUp^AHQ99<-xiS)kiqXDL9R)%=ekZ~fmS(NjIFuu zNSWDUevCERbR)h_dHoslVPL;ygrMiT?OQsH*|^DoRo0}3*mJ}5qzABLUv(#UvDz(g zJ+NEQ6ys-4c%4SGXA@qhfj5Ut-xFsb6JDp$PS_*w%3&pq_Rm>K<1N1}6ua`awsNUP zxBg;}M!PiAy9(KfOn03|vcH(t?VZL)6yth8qU(^|Cfo4~NLFkQA8;B2iy~dlM0;xy{WaIF&rP7qfaGP9yZW}O#=BgkZ1LJNS>XLXQunX(?i93J@y zp!8N5>3e1p+Wqk-lCfSAqve21M-jVb*Tl7;^bY`=Kq2B{ZCmh+87chCD? z3kfXk4Y{jltWF~it&|z7BV@nb$SVFBt0Uyxe?k7vvoU1G`f7it!Kp6gaL4HxD>1rE z&sZ0Idut%tDbRQ)#aa}d`P)kN`!}U(!O@u zCqbjRb^0ym8oxq@%JoiQaUeH)>=+ZAp`xL^63=W9hHP%+TARRfx)of=snk1-ot^zW3S;SCc+|O^5FFA!xwCTiunI{Yo z{*f``P{UbQXUkFj2Qr^iq6p!?>oKFVE(9fxRa^TN!;(z>2{ zw!q74#hLHw$+`0tT_5qGgn@c;?yN5`uVluVXO8=?h+x*0tDEQ`kx$%K{|nY6HGH={NtKx^<5cl};a4=Qncw-16oWCK9toTV_Mb$d z=VSu<{W@oLv1nz8){~CR=j$jlF=usZ^Uptw0|AyDMF@|^S$$a3?!%*vfHjnf zrIf;OK3_MhKWf_jakMoEE$sww#W0M3iDAPl6_twmc-<(YuNO zE7GterMR+39V^5@-V3$HKKy}<TF0_+_FP>9Jj0i+UA0EXoA7}{t`P1%GjfM3@17&4^M)&C6e9>8|qS{~z=4LzQRt20cX zdn$O06Mi6$=(yV>(*%!!7od6mX@bW%tvLolN5Y%rObziE+5Vgh08ZEYi5}y;01@fq zrwGSSz_k4fJZ1#%drxSA+z9vha};bzA#mO}WbY;(&jJ6oydLyrK@i%2GEQbA9^*$a zlg=o0qA;N#kzH3j#x>hJoM2$Y3&)tOkfUVz%gXYzKTADQ>*{%g*ONO1IMEDf6HwxB zdW^?X5bQhAp3ufF{da%qy#OYo=U>i%ANm##`N~mGj!Cwr%c-Oz;ldHWv(RuEu-L<`T!|+R$8^ z`;~k_OL0$_o@SglOEL7QQhdNYA|3Q`Ja-Ucc9C+EARpk4klL6Qo%kIy{MBU33>O}S zwPg|_=P9+*<*Rd~rt+F;3n=~8vc(#rJB`H~rXYBmpFfmr-qGEZp#{8Z-(0~5$*))Eotdr&yAsCS6$>UoUSS_;Bt zRzd{ppwcii7${?{R*o2Jnrlx{j>%MK$uW=NqguTH8X@;}h`#$uYHMf}DodXDOey;AKCDmY0FfXZY$4b%`Djk z^K2y0tbS6Y%_cJVk$ z|7MwIqNsq(H}LQ>0Zj7pj66GJW#C0c+1Z(7^xc#=`$$qyB; zt+yd{!(+^&QAO`E9G>i9hX&q~#27+<1lUostwmf?q)i-l;N-^^aY+cLj0R3l7vNOt zp|fB1Q-^ChxeQp{Opl(WOeg+5VIwfiWg|bq$AD!*u&xu5N-7W__+>xA=Rr6tHor|3 zAs7sfSyjURDVvbK}8jrM18Q#tkJsLQ;{2IBf)gM*unm^T^P$cj#uARa*v3$2F- zG5d%i2w7((a*_vnDT~uTj+iSvFpkLji!F?ppK{cdssjC0sZ)5KQ-Q;jBh~~WZ_l5q zN~l7;u@%@by)r@}=7mcH8~gJqN2M!N99s*7CWMAmT(|@tI`&n^lw(Trw+1|tz@aNg zY$v5oGetd}Pf+^G`{x234kVe-ULs%cu%56?BGY)dMYt*vcy-201!sbVxYZnqy2qLG z>v|)s@MposR5qc@hSKTx?txT?@RE@88E2jD{Z0%5&om-(-@(IM1a{8M`?U7VFv0+d zK-(D~;Twq{%V*XQma$8FKQTw$7|8tCy#ErQ!vr~_eZLV8*9aFSLQ}I95l$tU_d8NG z;uU#CQfPNJWoJjQvvdCgifSNh<%L(o94i35_ZN~>jSw#p>d$UUcvT`_@jyx0??}W; z|7W8O+5MzlY@eI=p)Xr-q>=Xz@*qXcm&j=zRufjTJ1wtr-B>C5!7qO?GZ2}`n)IB! z%9V}SWPdNpf1|OI*R>px%|#zZY8|?i;@aycSXB;6X;)7O$SM_%Qk(1X5#k!&>Od2S5ZQdC&9`u=SYd9;32)tDn} z%DqrWIPnJ*?;-ra3Fx2lG9{D$`5aSzM4rr_(3k9^gd^zujf$L%FCjGR+jRv+Q*fOF zdK|%XywC>P^f;j9P@(KPCnVx70)KYa-AK?c!;I9)o9yH%xlPi^_yWm%jLII6c|~rj ziEK&A6+30`vy`D0D@L&Dqba#Sk_<>%UXUC&#*t$xWihbvGmo;QNz)|d8I*Dm2RVeD zqi#(Wt5A4%urZz0q;d%`>kX4KN9JRRB?}}I?MHF=A(~t z)a_}yjN5^8!j&V+DMd^o8TC0Uhe{re=HX3(ys1$5wiGdwSZ4xv%$tw%Qv%M(`c-8D zhe1eLtc3YE4wOEGUJ@zG1C*Z~OxJlIzeM-YwA=S-n%!G^zHvK9x{3M5?XmJ8C{Klx z|3~YE@};!?uuvWm6gW#L|3`>LO3r>p7$uQSJP57Rp*$i;D2LFqYZ!-|UEwDkqfRCK zLi!t!9>u$47U{dd-RUR&2$4gOo=Z7S_8H|A_UIzT)YFCWOJS{D6vn|7^UrEu2~IdD2#6p`!%y zyFeRpz5#|QXD}6Pc;6CX`2u?ow-ZVp6COxpy;A3xHJuB?T*n=M3VNS{KN zvUaXM&AU2KDucGCzBT0ni&RGlRx=_kFITkEjAvybx@BPG^*#FZ5NSs!oLWB!cBQ*PGB&h#^EWzza@Mn;5ig8 zz-0io5;pUdh7&a@G*u)=epT(tiz&B46Use-+MUD7pW7o5VG_>q+zkpk(b=X`>`V!t zQ6aE^cO!K-BIh=#APvOd2ssk@L8&%Z5o9k$soi6Y*(LVZtyjQp-$*EM#mEJx!i zzKv4JsPBAs24yz*fl~)Wb?7jAwVPY3DO%mCeqQ75uJ zR^n!YmKyVB5-H6HO(0QT5Wm?+h7}QGVvYQ;!t)doDiYj z39?}>uZUkjWG@VsNJ}2Z5X5TAE8-V$02esT#w+4H%p>^hVZ}|oFvc%`@`kv>a~VaF zVa0`=gzX|JH_>9=8(rfGEaL4X+=YDw;J7%uR(YgjZmw0_>jJon)e)8w%j@~{-_0z^ zBUl%Z0$gIH)`Io?c;e=5JEiZl6m(GX(8W3rlV4c1=gR&7$` zj`&;6{SPAS8q!A|v>(1&RXM7*^ykGAJ`^U@XKWgwhv#|~G@6$W9n5{yg~Nmlxt~Xl zEnIFa`YpdIB-mJ8L^-1S!CpDGaN!c+LRlgl*aQRp)OgRWClZH#8=AYGXvL{cPAy!x zOSmlrQKM+dWj0TFnSy^TjRYI)L^`5VsZw<10=jnL5j}O8GtJf=dDU1oC0L<$vk%*aKWH?Vy-{MHRl4MxO>!j8GUm8hcF~MM+j%V{^3d zI%5AODUlH4Con|_yqrQcLBU20B~+H-hR}DhDWS2@mwQ<4#oUHn!Rg@2Fe#F+q2%LO zsg)1Gzu1O+S74)Vm)EdnewR0JcgHwTSu*90reh)&)*FvCG;8gFT; zgaDKv=ZV}wr8W4wLMMu(RlaHE5y`)TwERazc-4cyG1AbHOt%XEhrI&6f>6b1SC-3l zsWjaxJLYA(Z2IQPmH%YcB7F%x5C<8POd6kK5h+2+W&9o^gLH@2X~^AAdflsqP+!KdgBj`&l4GJERcnsSlLaA$s|U{>b)nKpe`yZ6I7Qq1zucOrodRV zsttn;{mI2NL~bCF!@Se@&Om0rn;*r*c48Gz!@{Si&8g=p~RxZR2*U9A+_`MY4lm0M^-;6W{ckd>DWAI4%BtLc{w z52gqI1X?0@hdbgH;1fXOGH$R!x^(ZMf`6u^iJ$404TB%*s`N{Z!N2R80(H~>(k+j9 z{^b%zL(%NA^$ot7OGCC*_*IbQ#rh_~$g2z&;_t-1X)Cip1(?^z4k zz#K0QXYaBq*0J#Px8-7~w5JJ&?AH znptg^*3hlaClWPLkG`QRB4n=mFvg{4qMWnoGD7ZnuidBHQJ5X}C? zgM@u#{``9I3=de{HOWJ31Otsik}qc6a*#)uk=KHb`N6q_F9U>}!n*X1Pj> zbYgE91@GFU=Ww7VMBfN*WOFuAmc~hJR7Mhch6Rn{ga!HfvwYY!xHSXu*SKx0VsL`a z0z*JmErhnJEun+V2|6=0Tp^r@m1D6jf)mhiF_D)^yqsU(VI7=M*V;?J+zD7KGE-Y( zgvId7DZu2+9(|e^DS3xeS7SB;Zc$U+>HiBX0U3}!}FwcfS5vKiP4oKyre zr;H3rE4 zA6@4GURAOE?Y+;=$w^2E5CVjr1R|kG4Iqdl^xi`N>Agz?5tMRJQA(5!2M`4m6_KVQ zQWX^uDFPO*dbxrE3Wyqdz52bs+2@2@{?C`^StomDm07c9P2DrIof^v^Qu?=vsquzo z{o(_>8U)2p%CY*BAJj;%Xg@C9xx~SVUk(A4{+EIZyu<@_=a&Z3Rxfhn-y($T|H64u zCw>bLQ-LQH_=JZI0IQyUC;ls*7%2R5NT?rqI1ijw;5W-UO?jR!tiV+sssJejbVU7h zBj6F%bBpsqx_&1Vi%Xtn5Olh;0t|glKM9OgfD$_W3J_3$4*&G0z*YkO;@x<<4qRqh z@yS&B>OqW` zYTy}l2S_7bOBA}zd=PS~{~OG+!sKBNDm`A6u`yK>;?8Hkj=xtf$tPp$^$NRh9vWaAT^I0=l&G#)@UPMd0yZ*aqneRI^q}~3l zB3aD$OAt$~sJ}?q(_m;Weru`O!_cd_qO(*{OkGkgq{dLvRZa5OKd8jrs>BKes9`vV z<|*}c8Kj2{QdfpGP-cW=(!G2Qj_=FW*;EzLk>;>oxoMipc`r?N*m-X6fnuf#E?-z= zCE8)nZ9lpDtq;&kA(cTEFie53c?bZDDV2P9jOX?(LU{FW6sJeChu?MpTEDrYg4+-5 zRUmLP|l!w)|sqXwn&-2?~#HjB4M(^_5ZR!pO z&0*ML)NT}IAHqBhb-B@<<(74h{_vbv0qVs$5XDt0dC zDFUSxLuYcH(cAer1*-EvMLypxSX+kW810|r6gjn}!7db5CvpBUyz=}gwGSKU3WgUn zR2)5@$7bqB!m!GQH=%kOn5Y05K0gC^o{}COZ`q^T8xQFv?~0gaRv?U=@>+q&H=mQ~ z82yp9Avud+)pjr=XC;AG^0CWqcuGjnG~+T6>AXuP4;>Kk3hYCbp$w=u0_!X!YNIA= zyUZT+%Xv_DA4W=;SbWhY*c5&-?#PYrwho z9BYL7n2F&3B|KH(`~~1w<1M?~*5DEDCCJkn;77xox|O^kcSyJ&zaws@TSXcs=T;F9 z3vs%$t(T+?r|(o1YS;|C-!moHi-`amih!Qf5Db<8cd5Y@;3o^(2aHLmC36hn`TeW}z69hxf88Z;H_cc4(PyevLJF5jEufB$Zda|s zy-@e{)ylb{HQ+kGuxyO}$5mW5j8vA*ScX5K$p=VZHfLEg2~Oj=Yp-R^Dq5DkIxr^P zm*7i3P27}bfhFm_vZd?Bj2SY-T2>aDSW9BYJjP>LJ)+y1<$7Q`;mbo);wpBX&lx>Dp=BiG;dWjVK%VtC8=)mkZOF{TH)Opun^fL* z65X%fTj-%*l)Fum0$i6`I4{GWGU)zZVt&Oz{k9wcQ)OE;-(f~`4t^^NIOmT zh>lU-g+u6Z;eaaq!&Jy-a{}|4_=@-q(>yI|8_li6Y!;%MIw7Wi!SkKrp*?J-#wnaL zEdTtYFC5tn2g&@%`H5q~NNz}uRsR(K^`$wd=?ypYV@eUD%=`+RqI^0`P8`EB2m^#_73Guv(cg(*bLbP)cZF3QYle3%IEFQGf zr*Ozgvs}!Ko!Pa;GQ&mGHi)tK+uiKCg-l`_vS|;UmTO&tln_DH9@&))LG1DDL=k-A z5+vq|ZZk8xun<4Gh{C1)Di?h(=hKHXwQBFQyk-vg5g=Cue-^6CYniq>#8#zol{MJ} zOnHZM)?rMh-AYw1O>{k;&gA3q&}q3`bT#tQJ>=4rA*oL@wP5eG>Q^w!KXAB3D8-}& zuHLOoyQFZFf-*|dEu$f*;>$DbSfQ2#QL)A`h1xVI(~cC1w`3;eNEbyGYBbCITbKi8 zqjBcn2__{FD@$iym;GCvb}`q9BftE<)im>>Snj$A-4*U4N}kR<4We}s7jZgQ)`WL5 zzY?OVF>9u-twCo*m2aBKksGIV3m37E*3LzYSe^Ni5dMBH=A&Fp&z+g7vaNN05k}ma zi&!%+Ga$qYH}wGdF8FiwAS?4_OoW0hEUUupOf^gthtqm{be3#8J{S4GjLgv?9NubaZy!9%Ug0cc~!H(hsT4lBUOFIL&x`$}dPRBBV+)s-E) z!R+lnpQ$dr%_AtU^BPQ`R2#OcHnliO$=Sn;68&jrCZDEq+AMMj z^)V{fa*uY-tSrO^7g0GEv1vi31_EuqaS>&W)8}b&HklIn^tDWu-kdhKT&m*tsMw{d zmg&>iUxrWUZbNl6Qv6mx|L6|b&|ST2%n9sWoMit&pwQ<8wl_+$ z|5W2W#2h%5psR(9Ait@Qmy&d*+-bYtxH|z;(Nq&kv`Dhw6DlW&dhcEa-TakkArTpc zl5~>XX{T3SYqAL#5kYg&hC?B(h9=o;vp^97W9KE=4=jM5Z-nZz*-7?71=4gVV{EG= zZue41Li+}y+WE@b{y=5^g|CE)!C}XCn6KTTTzk4UtIe1eo1yxrCzI?F;?|1H2g8zV zcNi&cTVF`BeW2Rw?VhytVZ%_LWP4AGJ!Ml8@4KL>6{KN<3p9Chl)}a_JnMs2N!LV| zX*?k5njtfb`+Jh^(9uHDdw$X>k+@!(bjpy>7ucQA$mUPV-dNInDlWTqJxGg zPtv`g7f06n{-jl6Iq4?7>V6Hg-ggtxaGJ6g%i^TDaCGpx9CQB<$6`@E*FWiTQR!xE z%=362Rn&n7MU74B>lc-V`cU=#KeF&)QXG<`I^AKsOVuSLt4{f(t}5=WCc)}S%|*1_ zC2F3B$n*zW@d|76^rS?MdphPLS5-zQahNd3bz} z2^s5@3A);mbWfoIZq9;17HyPKd3;*Ebo(ci@AM2zYqANreK_(4c2BpzSL$yEQQud< z(fxTnePDOhh^n8Z+lNKCH%NF`gr+Y|Dx7Zb6Y69TwJ#SHe?8saEY$5FYI80sW_r54 z5LD-+AZnpOq5ar-{&agWu?%NP+1Dc7eo=&v1PS%oCO73|Cta5(IGwu(QBUQfd@9-VmA=(h$ap|Z^)7Gb77UG>i+b+J+o&S@5N};3CCZS&pnNR7Y z|KiR_VJV)IzE?!oqQ{PzV5RRfM6TQ~a^*hxT>4IkGD-w?A~&L9`a24x1x|JGl`qj9 zGDNOQpfF4m(y>kYY~g1F%4GPe+Uo=DGJIu{&ZR$*|0ODqr&9VT^Du5x`jGr+;Qu+j z9pqiZ121Lx9*QfT-qJWfm?vkaR}iLY;D-!f#fnYR6QfKTPS^hCI8%B#tcC-$p!B{@ zFBw8k4OH&RRTP2rLMEm$E&aG;Gf?ch%M=TN|J$6GeJa_mLNUo)Oe4YG< zcxDr`COi3$P&IUaam8Aaf;g|m|@PU zQP3mjtdXPka#2k35w(|@KY|%MFZnwcLqoT8PVycj4{W!B2uy93yoa{bOcsY8Ox{D| zV6N_lYfnYWkdkM%(rRV0W>?*6x+=VVpOq=nVil7$&FUtnA%CykZ{uPW)!MHanyis$ zw<#`FAdeMvzL9J~RPo2;DI(ehQ6#da7^*;rZobNKJCg?prJ4a|fQy;a%~!LmJ7P|5 zn@41OBT{GEwk8BlcJsv-9pv&g{9h9W@^@#@c#iZZYek`l?ztoXHC>IY-ydfQU?lG> zdaTK@4xF=)7uzPe7MG)SzryN8kHes60op~~;}aeh1A1fD;{zU611k%QC4rb9^mCS# zkpnj^=SyuN3@bD(ryq+6ezUVUn99L0Epo^9PEIA29&F%rQ`wBHjiFR_64)L}(aB> z;UG6F180HLX8Gb^dF$T3@(y99_xx%|GAng*1)}_q21zzPc=?|MGBqza06|wwm+l$r@p`zunn(^JE1ULOSKgyI@}J>$Hfw1G)L)q0RXsl#?kbS2?55cxQn-x1 z6jU;#7NxEOm!a{uCbBw_L)zKH2rsWoxS@z_tss$m`z4d6WnE<0e=$;#SZ)r5LCv-< z)&eS94X{n=aQkUS4Qgq6o(xRu=}YGOKdNQn*I~*#MDE7O;YRowG>*9l!$Ybwz22qH z_-BXz8WP+C!Ci^VUo`x;P~0Tq#uIm>a5$$sTm{w>x7K{`BwSzeQtNf`An;{5X4HL> zunKGb=9m4l;TH?wqkTk!k6!#v0p;K~;Os8$kG;gfAsAS|LIY^F3*u!(W%Q z*Ij9^8w5>J|Ks6r5EYYSwgZNneV1vHwY_>cM}^?n?Q$&071iZzc(xG7T|{=SV%si+ zKWA8SgdzXWhFNTj&tB@vaTd=Jk4IgFZ zo;;)VDEiz&pG(tCFNCv$11b$t$aGyJBf^huH-^_umJASIUJ9>EiJ9;GJbE|WoIcmP z2u}S!YGa#dF(*v(p{1b)zR*;YHmP8?zg5aE7Bb z*1qlggw_KzOmDR~!*f>AuRysbn?P~$pQqZ68J--s;Ux6#g$&P? zMB3~(&>ndm?__xRl!w#z^Ps%{m|7fkc_zA0Xw2~AN=QKBe!B29# zDM)Kbkn78DMBht0W-~mxWhP=+hUYM|l-M_}Q)#_w;{5|37?+J4C%*)j?SBpCH zGdx&ptCun=?EOY`^6U zaF~QKzcB#YI#jo?S4booF=B!n;D)8VwxXhs*ua%$AA?K zmsupr2wp}Sw5G}`^``u;+7VDJ7;3_c#Oipo#_a}( z(%FCKp|k(4#@IKv=#G zqNwbPd1YU`-xSs3rBL@rGi)^h1E;!7e*0`5tJ`Pqw|e(S#Z@da!#*Ld!@;CZ3z^3tr$u@ecdHgo9%aVOSjsk z411mEb_VIz<)u@50ZyJ!~g8pa|vr4$*}dlXmEUxa9J)Pbj$89 z(i%skZAyy_o4K(wxLuG*pK;IC_NDuoQd)>9xpsy<0j4^GKMQhA$jde1ey-%&Q3HpK zvoh>w@xOBMftG`P>Hfj)LPdt1m6tc`e%`VLjhclsc$;ZCLmmt!I6N=Y@cWrK1fjg) zcxoYsOb#;TZ6W=(+eAhU8k2=)eHqgy9mNgn9?!5%@0*6uP?O7Y9`X{>GHkV^L*5O_ z)Aduiw#v9)iG(yURd_tZZYQQ+gG}vQCVYqX*KT(|SB1yL6@M(l)&yi|$skwryh$~` zpDF&Bm=e2X*oDQkD#%ngFH>Q|6fB6Mu}q98iO8Y8%BALI*d_AT4YehS-P|5L&~d1* zNX$2EGA>VP!I55QW$&r; zdTrHTQfU2X#_LUJg_gKd-v~*a(q>V{o9s~4ABZO{CkyjdOn*m zk#t5hcQu}9-jli6o>)`q1RfjiD;9nfW+t%N!+q6?G)0vo;&cmTwp%DihEwqd=o`ry zBNHrpbYCrC^%|IgtKki#u*{VzZ;O3{@jB(%(y(fc!n-r0y(TR~%!`9U-)7X5QU_e6 zYMNG)=d_v`HA5rf*4~Vo^~~M?a7{z|vEU3+{l`;Mb z#uCrtY%;_jjH>_WJkl6qX09FZ_?1tk&I*}9xtwX{%BgchaqkefvWhW{UT_-Alpi&q zzm>X1BwIoM2pmV$qCfnpT0@kF{c#=mlgRN2sh^5)iDmtXE`P=o_u|8;dLL-w>Js-L zMm=(d2zI)Ro&dqvd8x;>(3}QxFreGuj@*@XLYC2WfJZk&k^;-}#L90CrIhM(IR!Y<@kU+vMF0>75kGL=K} z&SRgkY1K=k{pa_>As#LPe@(PJk?RaAYYaw!73*!04@dawgyr#Z z?)@>p93eI62p!CQd|#choE0s(yzsFlAaw+@!zsDO5tjLUD*`v)hxVH>!e3L6HB1_7&djSr6Hk0k28}%rd(>l zgBPFm(|M?(Wm0>fKc3=@*{hZ@wMY3-%h>96YMCG|Yly*>;r7eXeG&QokEsbpq-oYu z6HSdE9>+5??=+rk^-4{thnp7qoEKqP51QqV)T+iU!OmQsS_7-#>%z8iv1#|Pf&Y%7 z&s?6`(Iv8Iv(n~yJy}K})<VoV7X0-vP>&XA z+CCyF5fj;*$fg+Vpb>+4J>$TT((A*$o^(?3b9I>g64fqhnv$COkegI`qA`*6*CYgV zWhry&Ly(!1A+h7Vo^Di=$?URrrnY9AGHqjyzRb7rT8_PBzgg9N*Xv1zX54Q4m}4PU z&Xa&Hq=@~3I|Mcrbmm{S@aj#a{KQWOrYV%d1Fb-gc8YIGo4BWfrIjzo zUJCmM>K0UQH*+M(y%>z_zdZsh8_Y=}uEr+n>{wk5@%98#SP8HJ-CkOSh+`5qo}#Du z;R*no7R_URv42F3mAnZX_YjP_0^rhmU|l%^tqg^9+5+djD*zM@&y5XT0T863P0$qp zmp%kOfQ{;E2lgvZQUS%3$t71UZt^72K5D9*d>8tetWUS})m~@ZSdn6Cv91kf9W#?} zXWSmid^*RTgR!R$gm{%CaC%eJOTI?}8>Gc8E16y8b~+rm=i$g4dtR2YRif9EjC(#Y z&f#i{!zz>gz#fXaFyEQ+=-u+Ai@>j35AdB2wu`jZ`ek07-_t;>?E3e7$CRH#K-Ogk zrtix0z+%|t7zL{HK&`r5LIJFLxgt=Z1VZj=->q^m?-VJqQOJ3sf1WJNPk^D7vhW0{ zN$*2#a_spOBFZ)NdUPu5$m{zsKn zJd@I!&y`)@f37h4TTMvk7Ln(8#{b7Jz%Ykyi|nF!4HK<}M2(7X24gw>(GR5~ESoj0;V(%-IjmZX9Dl z16h+_%Rc1wRHeWt>O{-#*%*(}@0EvC;2h)h>|RWWCjLrO1!yd?;F+ zew60!?Lo)b{W&pY?#kn$ImUxzzM#N=cz6v^>F?$qoM&x4Tyy3>uZNFpwb**d@64ZW zVv4&S@=-EOn}PLs$VWAD>_ri5&))iwKgV9kFxUJt-K{x>hGD|vbQxPaL3|Kkz~gLf zW?5G$;462j8VfTl=fhWYmgS>1RSqymF@p!vS~K(HxX zNU6g)spd46j+_ZUU^TUcS25+)`j~#vQ8=#swL!&rPh6Tad8J<f}9>l*E#9z$CS2Y?g6&_sJ6IM(3{4i46)PQVX zu2L}#$PBNiI{q|?x3-?`RQRj1ZFBk4%h+@K2ZV+JLlpRg2h4Pp6T6=6hj~~4%)E7z|xY2ROFr*+F90@Y`z(Dd!zE zNclbVNf)LjvFm|Xg=q)|qd)z+Floe|27acTceKy37e|mYtMIW}Q#tPSG-tOwJMi~w ze*za3ppY70yG7_mDxsl@>SUieDd-Q7Jtg5!m#UuUKUH zU@#?cgkY^y^+#YEsA!&XIT)&%xJ<+a+lgn5+bqVTIgnBOXoYb=$g|w4M8e%oKlQ;+v z>S&+3=lY8phzayK@dUMK$*WWo$sH1*6J~C@i=>OlSBsoD(p~goFkMeX<50qUBh|BI z6MD{5qr$IcKjih))FI0)A7c=D-|I}U&53u#nSw5D;cA2{KXJtmR&gAJdTgwBWX96!Mkj(=g zeO*(<<@n)sTH@;~$;aY7Lg033LNEuN_7320w*l%MghQ(o#P=9D9gQT z7ps#311&_v$1zoPrtnhSzSs(MRe%%vH0O?vMbyC(wC^5MCoT$4_@mTOXH{2q58;FnS7 z?zQZ*rXrZ$++C8P4Kf4De%vrN2h*6Ts|J(}8KWWb57h`W!nEk?`i%5?63DE1sXTRH zK{GQ;D5vRCA+{e`ulMqL>J>C|tky@p9(HL#%07j_gHwI^{4ez|^aZ$SZ**Uh$g-@5 zcYE!-tOexY7WvE?)q=NZw112J-k82XWUZoPBl|QVwqE8g2QI5~T!#_^Pnqz>`r8r6Tl%ZrX0eTvn z{LbIBfVvXM*~IAJ#?!z=jmAFi2g&!4gn`bGn8Bc41k91+oNq1X5FJf|c-}u0Y9g$;QUSv$Q*&pZGNLxFjK3;o#A{55}-Dn)YS$xkE`W0Y4XdkCLym1G( zrNBzo7wMF4hADs@ZgzTJbm1A8QX43sG&a;AA`Rqt8 z53^4WgJ2-gR{{F1n<#QqljnG@POwkXG~Hy-esdOUCs!C!YH7=d%x4(H zb|#3M^M7$y6M{)@RFc!g=1#(ba<5W+Mx`%vF(I*6=|z|KmAbkl%;n0(Wmxuku2Fb4 zOk!Q%GHs>Xzi80n;>+EK=bR@RU!5LAw+vi(##hR_RKY;hv%b>)<80Tt>QZh$&a3h6I^_1fjDz9iP`Xa@AsIA0#QRS__djT`P%3S_aZO zhoog#(S#(fy2J(EeU6Xn;*`1udU{C}rR%6y@y1v86IX{gQk*UanPf75HHW+OxH)XP z@nP5DbkoGJU}d;^R|dleu8neiU^>H+VL`XK2EE*B`U~oIjjLSq&$H|c0pgY^&RjHc zZH>s>ps8V3i7-O1(!&0W8wRI;A!Wz8#j!=(6Nxj|yi9fDj#{2n#r-9^X-3GkQkI+K3fb*zyrZG9*7WFy+44{lLrcIzv940~hQqo=z zOH|H`83~p>ZMuHu)0pr=($lDzY&YdOLRl>8>DQ1W)tRvs$|>{o<9|i;PZ)Ye7dv>T zc8NV@G;EE$9xt@BE~%Ak#He7$GV~Y%4A3<04PtvBih}a&z@u(6oVY!a_b#3t-{)A@ z!%UkqxaQBacC)_KJnby_S-=d*8!Rry4Y&P^`OyOE4%*M#uLCOyXk*3gZNL`f?TkYn zwu5a_&7+d{81i=31AQ3yQURLL+j#Ts|0s~i18wJRqq!D!cQ#|zfTZ2kjU;BR#pl=D zq0ISO!?1g_W$6^p9X#H%yFU-8c!zf>QC}{t?MtUuxjomfiBEbPv+?7zxp{%eL0nn9G;@W-{}W*7eDJ!J3Gq> zp44mtWz9h8dKPrd_=8JZtPxum;*dny+g6mb{*Pr#(LqsQ~rqEHni{do-o)3q*&a%CuktApNqt-#?t}*o6 zUxKzSP+Ng#cxVPRQeZp}J;?uE?x*r>AI<}Fo4W%P=*@%Bqbckg(Q=mDQZ=P9Or4&_ z#y9wO%6&!tdjcpG`60K+vnSjua_XEgr`!_H&SrHex5()~)mvqouLfvzcwdp<4Hmh+ zG%(!rL^P>T;#+?}9tCYmeCto>Od;M~NCYLmxe_IQLM2{;hR26Z=G?|?1i;BC8)@b5 zuA{^^Hzm5E<-Axz!6F0(gBZNP~N=& z{Hnlfmi1rygS-D#U=x8#KzS*(JIA^iZT$n%Q3NDL>s{_UotJ(k(wTB9LvxXv^le*W z$kVMj*U#pdwe(5&zaksB3ukl8GWs+(u2(RwI%4d)ayk-Ff|%F51PewcU~v*a#1?&& z{^k=(K>E0C(>SzJ8aJ4hHv5p0c^Xmf_KO=AEx&0N=V%6_woOL2+}bfm>#L!-kkX$M zr+04|@um`(CNZehHZ00JgV3x*#!v;>+>NByN(D^5xffP^4j|iBZ;JXoKbA|B{RHr2>7R^L0uL&N^!`~4ETklE_j3!1)`ILx+qpzy zC&WBd!>&TjoA1vrb+^Dlh5hGM1u)h>j57auPk|LY902wyBM(WzJ#KTm@f{<}OLWH? z*U@O+o6v7O2ki;qM+Nkt2z~Ej<53>20GAY?2LAImaJQ&JnzI!Ed{TO^>6_cm3---- z)XF0DT-Klq=%`S!*C(@_6KH^P|9v%WW}mRG~TFAYNt zyAau#KUA+I*FTHcEI10BSU-XXfj)wHoBrBV2`9aEdDk=ViEgP%eY>SA zx~N2Jhl!EQiwbLeNV1Ze7Lq)Nfd55_?idv9jc&{^FC<)*_NLpx%s-*rnlXi)t{QZk z!G=Z@^K)E;iA!*+{epsub1(7|%g|sAyA8dT&KFb!Z`U))aE?jRng%gV#OaQ%pENb~ zHZ@&u$QN`I#;v`#7X_)aB!{LWxRh+&4z(KYaK?E;jj$@{J0~eLJ*$GgbB27s0x))^ zZ)(6{mUOTEEA>m;MizX-m+l8yM3lf1+WHzEAqIC#y4OBMCuFa7PdK(0T<1J@#3AC9t+iN$1MqjwBQ42#gHUTi)$ep#wmu^2Ccy|$V`?Ey(dVB5X=^^9J zYWt(Fa$EYWiC%M2%HsO)t=K^T6|gO+74Lh^MJbDQghQxU?CPSrrh0iphYGWUDBGZ- z1`O(t3Y=E=ENxGEEvtKNuk=Z?9;Fzbeag$~FkCviS8R}%l?+dHU3)Ngp7&Y>?d9Q_ zgswGIIuC|+gsSy_Cd)!Vr#{~O60l^jOSm7KvqAIK#lF6s22(yuG8qe2JL1(@vfPvY z-oMRW;w#swwU^-vmob5U{44K7 zV?6EG9JSp$gU(-D>=@l(Cghngo_c4;Vkh@;;29LZ1gM z=YDSVnaQH9I?`JuM2q$P)|vy}Dut!7E44}$NsS(Ed8Hh3$HxsS`E>1KYY#RT_p} z$BH&<7Ip=obooJ6*v+7F_CR8KDvfUcgq5xR*ZP<5q-xgV6?D@yUD** zF_?T7$q!Q|`LKs6EYE9vGR3pJJSpx8MSVxiVXSK{xES^_wsDqg3vrYFVJ}lH3Jv6W z$bqnzsZAmMUS?PfT@9?iCTu2|Sw0q`YQKifBs=EN`N!E|GZ`lt=JqYaW?~K#Kd@Pt zf9AvYB+YDPB$4+1kzrHAC2CDf))Ql`u&G6jWuELmif1xs+;i6Ku&Io=NE_Rfd^3y# z6{L}4<-ZF-f^4(=d|$FQA!HhyU_udaX;_BB*EZK`Dt(7l5{8Q8V528Ywfkk=QA7@g z#0E7b2ScDPG%)bRa$chJbSfPR#j8TM2FW2 zt6JHOMzyL9!z4NI`^&zPJ=cVlLx9baNPa4v6)&r=ct%z)XEJ4vD4%78Rls$Wo3P?Q z5#=WFN?2*7JS4~JgrZi87+;C)YZ{Z%=zyvFub@YZH3ST8eG|gUYUxnlsSSG&sHi}F z9-07Y3RLBx8=!C3`6e(Td!;#{F~Cp-I`S|V$R@o`mUVDlSgcV2RBv+m(fqL3P{<`sSER~gM$=xaVB#tCaoqI`BNI0)?NZs z7c7}&S?xzTp6ZN1A6J`Xy#3Yvs3nf-n4TJJhrI!;BvPE!`ESbL6C!tWLFMCDEyu%` z!H2)CU@uI2yxlGZhlgkvy zTIutaGF*?RIG!+ZvCGgX1VUYNvnT*k1`Xz2G2=M_QdRTMDWZx>Jz}R_?%|a>xb+EqLA~vOS{5K+Lj$o;2<+TPNRS zfJMxUUSl!C`!{e`WBRI{iRF9Qbc-5DCUwzI0V><*w;X#im2LewvSs#+zjivP>}2YR ziXc2c;4{k3KJ0gFzeZ7yVqP@c5GTzrnQZmmQH-YT4qEq}-^)^E9=*n~hakVN9NNf# zy=zeZkYYjkm64wul<(M2gv2uP=757W}q9V8C>L7xX--q^W- zl8@emvAUF8JCH_kSBi7N6fgSW=;8gVno4nj%Ii0Zzd+=(5Y9gATxcL=3GV|m;BjRZ$+uYnJQ_KkS zf!pT%B-{$&QiRjBzwpuMMC^4=3Fl{hQx^r>k$(agb)oRvEU`iqV}99{m@Jp`%_$+wJw~NBS&ShROf*q4@f)D7 zQVLeYQOB;&I^kQ@P<5^U7xb(JRKrMXjiC<^>Hstm{v#fy0+SVZj|X0g=X+5e$Ey@) z?H`2J0;?3b#ls2Uxb&y(RsP;G3%cXYx^179|Et=wXya!A%vncA(r2QDqwvedddF@q z1zDJK*1dtio4{oSn7u?50t%4PK5Ont(^{9at`m{FjFeqSDeu^=CFS2_Y~2WPvvL;2 zz%@$Cm+SDrC`!;DmHY@H91vE-2sI5=@?tiz}k{+8}wGdu2Dtn63Agdn#x-D?&D6 zlzZqCN7FqnU`Ldn0ljm^t+2JYJZ7u&qk88!Hsp*GE!rc1&+-m1gs?vdmmf}#l8kxX~waf|UIY-=<2w}YrIJ_)G zRufm2>9vEhb|u5FW1Gm@g+p3tF>1zk)zhQe&AnBfO%#80KO)Qr%-(+0Z8tX=jVO#x zK)b3&vrW>B*?W|K7(aumN|X)>sZooX3``t_D7Q$E{ZMD;6=X+EhvJ0VDXYA-FBx|4)kgT~tHU}o($)>YBrMIsUO&tbk#4H6x ze;WN7gZ4+ST6TZEkM!|1wwC2vs&L3*Mro&ma`?{c^7;;L*8OuSfssCkK_Da>UvnxO zl4GtBDl=-vvmvj{OdK7?Sl06;oN^eU?;xa_q0IX7)Xu(>HBqpf_4@9MhCz+>sz(pc zp3!yreHk0P#&FujRS)6j`7M2;Z2abwCiH)r-FH%h(o)9V5QRaCWu-Kc{y1**c3=Z> zvu39>sS%8mSx%b+wJA+0SFP6MFAWr@OWF{HxT6+(VDxK6r!=LHT>m-d+K>VXo|XSW zzd|%``I`Za@Uu?ehqic)qjz!N!C>+YwLzVcyZW9>X`zYghR$&G1iC8FoQJ1?apbiV z_IEdTnXloQks0Yzijmz?(oH_aQX3l=tDBXQj%iIbCtvBcO}-#KFgoRtTv9DaV2MW< znguBXg*I?w*+9vesaH6&&5NVAk0hLQ}- zgWWVJ8%w(Ou7NwN4Dz$cpMSn<@0w8*o-z1ABEP^1I#Fu+GSJ3IwZ`Kt6?`We_>G!k zxI2JbSk`_grK(9t2v>`$DMmcV&ZAQ*hmc)eWMz{v9mL=MOG-)zsYR%=WFW;flEO~> zJ0&@UooiSFjW)_iD51vR)Uu7=A`P~rP=-#T`@f|pty8Gb7`hL)(@lwemeyDwKex7G z>5Z37SJ1cwt)|-*)SO*hD@@L&xR}SR;?f084Bq5R@oc&kn9G0vSMhOL7#RX; zb20Pvf%rI?XNg3A^hUfc#c{Es$K&&NBehd^nzIxL*rN1%IWV5fjzrCIh;l=&3s@FmnI+`duC0?_QM<1#N9D z_+X6Hd~8F5*u4hVuRYn!hrt#rq1@*G0Nzcn82#{eZ|8+ zHza|N-)C&lF{r15i%QR!mB7oS9`%s>cGK%e|AXNq ziipDuJus0Sa}LnQU=Vc}8%mJ^KERP81@mTPy*+l!Sj)4|FghQo`mc@+JoJGt$@9TC zfnFc@(mfyC3A{?!uWo;93C4iXPi0tEgRV>?p{naV9pfB5J@cHWYVc{ICqB+W|2ezu zUebSSA0)SIVE3wMS)VN8`QRG6SDF!mUoMEquD#^Y{L@@GyooAL&UaEP1pSL3A;{6k8P1ktd6S( ziG6<5u3+@QwKSM9qxEfX1pf0Oi-#mZq|6X)SBgg7Q=t^(TkXUb9ZZIipEQbO)=X@? zU0EYPqs$;k2Z%I2NU9>7HQA0=oQikb5i=vS!4u)*GwK)ZQmSNu8QXk?Jlp;VEZ^pP zz%Cm2WE+E&MRox(s_eI?x{L*IFRWT$6HVqnFB00TV%xzD4Q92Z0Mp|FqZOd3D!|CB zKtKWJ=LJ3jwkg2cOM#z(9~hoR? zMfab;Gd!m7xI?R(X1!&&cbpZOQ$Cl|VjyFr?kE@dBFMO-dEi3mad;sA4lY=45~#9+ z<08-HScR98kuZ~yP4gKKd_3PCVgA2r4_9Wle1!`#%5iUU-r1I1Z27lk7mNZN1%Bh9 zI*>x)7~<{_TVekSHbFvX0v$t)69_y`_UnzZd}g!E&I*AeJA6gGFN!~KVTUilzX9|j zq?pymou9z^4p}a^5SXjLJ|5NsZ<1yjv#)w9Oq#zs)inD`TMCK=pn`iT!!Y(yI%%&F zqU9?1iz?I}C4>RF{&hHqmc>d&o1Fr+m*+vYpJLs$8A;7p8e$uhT}VTVX191?Zc-?o z02?FiLX>8qYN%jX&lnXh^ZBO`x)}V5rKJ(%$q++njGThuB!ZrY&39o zv2WLDUW$wsdK-8vmCy_=x6t7kW9`Zg9NFzl_TuFjtNkvFH3w{p(HpgQPgNSP!b=q` z^qvCicsK%lDNRNEkTms{;u}{Xw6dwKaAJ&&1iV4zpp|kp5<8&W?)s24M>jUD*s*L5 zmu_}kY(+v9jFPM>Y5UXep#gh09p)&M?1-U#<19W&Qf?T@%Fu(+LDk3f{vWX?%xOl| ziLC?FRNxsN+5xSku!v3RdYdF>Xc@wwsqVbs3NlV2Fd?My3ZrnJ#2%4+ci^K4XpF|J z_{Gjq0F7f`29_CxaRn*-Q5|DdKb6iLi;u!HYL$q#eE%#}*NM{Y`sP>-G;%dv`A6*C zb=p0Sn6P_TYw?MiN98ky=3{7fvT^VoHc^6=LH$W~ADX(4cCb_JouS~r z1-|yPo6>2=GG2pGn%a8#no1wFaP8)UJqi5BDC6mPHphBoI?v`k?#HV+OKhU3G9XlO z;>y`cHfl9yIgtq3ZxbC|&Q4LGH)h2n_6BfGfj*X97HZp?I{>Q&fbT5f|hjEl$_;=tmf%mUaTM!%< ztH7^3V8FNs7&tX#O%BH^WEyq&X{8#bqQRSiX?qw&S0R{1wDG-9Sm3a?k;%B0K>bh# zrYi#tYpJyFzdi~gUq39(Lv^=YMo-)(!7D(apcPBlw;4e4Gvcux|O zI8NB`1cNbmY3WlBZZe5xFpfqbZa&_kb4?9Ts8sl6Mpt4!7j}KJj{I?O%Z{TtiCcmH zaB$0x+X$?;S_h@(7{$(&m|K`e+Iub}csoQNmJ13t1CNHhUZYS-EG-a{x)+*HLsH2= z+}DzYx`W&1SZVP*8$*5Cf_}^%+{Ye~z`v1)6%auJ1ikD7(HMAeAJQE>5)ss{IBHjY zi@N}zksZx4>t_iLAN@Tu3^YC#caHjcW}Iag;WbH-7zO-1R0GO2AwXA@_ARUo**;y$ zp_el+QafCU=Ttsv=RjsfkG4ac{o$m^cV$wPMV?TA)QY?WWV5jonOtgR_}Djm=0#R; z=?>Czv|Gn=J~M0ePiSe(J$#%VCPeP&z%ABvQk8wiyqII9_v3kys>NsL@rE%JQ4s+{ z9ed0>JbVFs%*G;n%r*4I-KUf?^F2Zm@g?KesCPnTN zbKByI12@H`s?h2DTD?lxf6$ug+c#{N6ha!M}j-6gbXc>#A+(`ABklJzgVDK<%m{zy~HFl$`SrCV3@`!X6PbW zvw;_a{c+=S>hHokC32^`^Z7fXTbMhjX?)e~en0;~-EX2F$8LOAQx!1z#PB{oCbeUqf46T;k!oq(da z+))2@xF!-{`?)>z4#Ktoo0Sck)ciMdtd{D)%#y->25z31eBiNtye`m-DNn1$zV(>u zL{J~&FZLu*tSG9qWLBVtZhsji8f@tFnz^}(qU9>+IB>P!uNTnfj!3r2aPX9^9{djV zaDbJX*m6s-1#ty<<`;D(s7<`{C;0Et&GZ@jk7I8<#V%e5@RcS|!suq-eSnAtK%JgM z=C_slMHMBfZ)FFDjw?2j)@VkOt*Tp|*m6>emn*~cGn60CoVGO6^54uKbF9`6k?dqS z#FsQ#4hQJ$;@yBwJ;C3I)9>%fW$TuvKX$$>B6;iyB#M!?u9^8VMJ<0#HvbYgC>YmB zrixgX+b6UhC4QreNn2mtX)PC9VbZ=v+I(2YEIpHy%F#b4tmAI4FJGxHe(IxRZ(-=aH$}sP1S!CM&rM zc=(L-caGJzJ0)St<={$uCX7K^@jrmG3Q#sBiU14?JYoJyJkg<-sH#v?9=Za$MJ}w9 z>sw*etrFz01UnTyVIz2$2QVe@gi#?%ybLTWWqFExmt(a{QD4ok*7Ln9Y5WiDg02XS za0zCeB^cg#iu}d{gOw5=l7n`sp)SfZzo4536*~1jBr)AcOm`*9tOsefU5U(POY99v zq}3{MOcL9MJoY|;P0)7&`1Od2M@%E-W+GigiBqutB-YKACrX}Ts=#n*L1DDrW!YCK zs)GZ;s3$^A{tZ)Aaf_zyA(EU4#dG&~<-1g6WMXnR_^D9M||HSgPRpIz~gV z7oE})1JA{ z=(hqJ4ze!z*M%IbV*|u4HDY^EL;kuAb#b6Dft+w2DE5+7sgyaf)?~={-pine{zK{= z_?Y-_dG2V$sQeBbgNw>mlA7l^@H-D7QuayYk$DF*k~Di~aL6$##4QWI}6m+}E# zO~FLpkqp(;KZ?(D(qlP?8wBODYGs$w79GPxzfh{I?A95V`JhDLpF>=NHy)1ML$xBs&v3X@4S^$j{!2L@N2KuUx7w1tpE#F+eTpdC`2YO0~aW#RL6_Ci? z0G~KDD;Y4-d-^sfK2U@1^YCTSECl~Ga8!M%S;^>pPI{tNSuGMI_?d<9aawovUi0pn z|1!L6?a<%^~U4Zc(bL`kydkj4l|ec`VVqq#qIdNV+>~GVzvOMgssPR;C(InJbg*ZKV+QBmL|)n!qxxfyUUdYZW5i43s~DNguN8 z?WGlm6K&HDD{?YIHGvZ^y!+on+P&l%N29S*U@{T}6LCF*C#O&;zXf#~#yN7E)uzB? ze5~(XZAg{zA|AnbW-sbwv%jbB8D7Y$k8$$pGeb&i@$4L{AG%uUCaqNz(Bc5;ECOCs z;B_8$09zE;#KZT%*Lb1ftOBPMaf;(jA;znqbApUzqb$3uFUVMy*+bbf42~jBk?VfC zgfyt-&5)K^l15Q}fbmCBpk zzXLcGZ*RrRm>Jq-|4V@ynQD-&e4iGz-_~bdjtvGW!3pJnvSLSY0tzJ5Q2@aSoq%=< zAUJ_3U&0`Aknht3Nhceljs|l<1H2)aji(k_+6d=qS0%?9&C5LKj}^7IQbxyS(~h;P zhmY`2n1*RS2+$f7G zqe;&;i^E^O569-kDAZ+jFl5<+7hFRyNT@lg&6Y*3e`#HV;iUSy?fYPgzmD-?h&=+H0-7_S$Rjb8f;^s!VdhBrtCi7E7X-$R+~Rp9wr-KPB8Qg!zd5 z^trb|n9bPVE_*Ssv=Ck|mK5l3#!_nhROP=FmQjtxy}1#KJ4YD($KL~eX$`P`LAYNM z+YNIxJW2Qp%$GKT`O+qG))C~bd90%5XzGu?jz^c5z5w*EfU;6bUM3eEI9f^K4Ihlc^=L237nVUA%H8^eo~d`sUal0%pS z)5_}r@?TWD+W{oQD({dyH!T@gBuh`~l0SxxpT{`Mk1_mM8E3~-cbsD?fVbHl=NLBl zV;c216i+*XnnFWT|Z>c^WXsMB(`VOS>0-}PawwwQicJz6aje^iq@+Z?I6lkNPBBOZ9muiN4H8Q9Bjs#`;%X2+Ap$BgyO1Xsi|wx z6tm~uVO>T=260WRcWz;*?@k22Z3I?x-@DU^AjyfW=Dv656G5~SpNEa_t|9Ul!n+6X zu)cfl4aNe#wgRrY1bB&t{~f9iEo*zq19w ze|MsMpnCN<$6{%X4UxpTM4||TA?UknX7eF~)Qu(QYRFnq-@_X&<5g?sRM)r|6bTCIvnBx4#+}`>#I+@)bRK7=enX=ou}DxeVfOQ z3c$0}-O#_wxLIVOMriS8Rw(lZ*1ECx5Fm_s1Hw4AmGHPE5XP}@5`HHMgmLW0gb!J3 zZxAN^NZ=(XX7vrL4Raie|2UiVrTImAXu$L{!v8ot7uWN<=YxCmZz+x;M4jVMiz*>h z`EWpSCf3C>-|0pi0h5y&fl1|mHbN3EiN;N)DW}KW1kZ2W$>S&JX-FSsAgDyjVp;b}>f z6Zw^qZjNh{l#K8X1d*1iLL%=G*btaid0qnawnc$wfAxnyv%rDPwp5{le2ORfMs5{= zk)Tya8^moKHU=2Q!Z5ZS)Z<)3*S3b6*dYGD$br6Q>?tb$(`D><%P`0LUcP z+~kufJlx#DM(8i#=zpsE18T84j)&LUQ9K^&ef)@?W@r+c711m(Tz;Wdt9; z)iq&c#N6Rmz{mG&Sb}Oa$4}eI2lO+mpxyYM1eV13pAnj*39Yd1mJH3hhmLWM zEd4`J=M$gz2KFru3csRuno&QKadCIP`Y(pH||dGC6UN}p5h zq(`M6NOa4}E$qJq5n~+Z4!@q8cmDUDa$E4zYGzUxOL)Y&ZnLCe8NkY}a z690f-bQyIAiD!yx{cjUg2E0n~g@htWK#Qa+2%99qN}g0pxEZ(uo+EM>;ivAJU8mIy zpN0|W$NLxje|^ix z$9B^cV6*qEM}i}IS-rgg{`cP1Z_rb+wWQ0~)lDBA!vD^{BK56T1CS{>;W|ldBXTF< zj(8Gx#_~an`$`2j`82YJ`j$t~vQ5gdLur9NYP}OT9bCGv+KQjHOw(Cha%4?%w(rP9e$k=jxl4xBtO6%b_KlvQ2E zquC&&1^NB?a`kA+CBC~0aS~3crVH3rJp~JD0*2~@z2NX@p@ZA|;{-QQTihbn@1q!l zeO@r$i%)Z=^_MI(H( z7leA1{)bBcaGOs=6HE*NqsO7jWjvYkzTV6@-qgnrfMqRt@2KnF=hEI$NxBH117QTM zZ(pEo7x8vs;@>cp&2KRaCMFPgi-E(*B8T z+8e>KgTv&7CVzWhV7yD!BElLEV5za(oOmfZD>xPi-*O|$fq5;JuB4;y3`@OeXlNkkCML; zcplJfWlfqil`wV&iT?r8R-Q^rmipfcA`s!}L*iI7{2v@+yT&iq)tk&&_o2t9kMVpJ z(r{eAnBAEpmH1goIYN^osR}(So@Nz%hM9DHv_oNOk6|e;b$tip>27*Rmb1EN0${L> zn(biljO}93ie?iGs*hjL2ZL)hY{=wba6>O_2LlX$ux~AJ`{v?d?<|&wxLR5B4kW|D z);a;vTii1MPOxMI0%kubJ`*Bi_(c8Wc-Tlg#sT}`Aob+&uu<|5u8i=*8S1E%W;?3m z!mgIB(N$Is}0IIQ_Ui_6|CL82@%hvE5PBL1NP|Dtj+X2r$=GvO?oH(jr zuO&xIg4vZ^J%Nw$lA1(h8X;Zay#c&);AHZA!W`g<%k`N8ak&QHkGoA|-~}3q$2FPh zlzhHSpQjRuP5Ho^x<|hd3a6aB>TkIlBYedGUL^wC&K!LWN5eR3n#*2 zhgV5cs+bwVZs;0xNdIxJ>N>#>F+~`fK_9Q9j!ca_&7h|-ARhdHQOcax+1bdopJ%%T z#?#p@jQgZ-E%I_$&NJ7#w9p0ll-IUUX2a8ElI>-Q(ZCS*S07_0mB`Y4_D%*>LiTY{ z>Ys}L_H1M;8N(*|0!d(;C+{TOEs5U~d6n=YggyJuM7|(=Ac^CKIXRxdzQT8Q7m-zj z72iyAlv`LE$S zy2%vvhfl&rRcCoRQkYq)iB7jr=9PQ9jCbO};G|IIWF+H%rHRgOBZ%Yel_!ZjPr&%_ zz4A*UpAuNReXso1FsGm{rbObedgUk-!TD-V!7Q1wa4k6>3i|I9;5=PnWcWXQ5$>3| z{M?7}4hma*r=Q9@y7A3$r_b?J@%|}FJ00mbX{&vohK;YbfIC`Dka{fE@0xl2hCbQq zJ`5k~vpDcxfZ>aIiL}RF8Erkr1UxBswz~t)+1*JIJ}Y}kVw?!s7S?U#r8|gGH$b|V z3{ji{y<6yD#8yXJ4`ZNoA7FCDR#!8q`YZ;ufv}#MdtT5rrN6JEt^G`|&*ZX8?AKJ> z!(uxH=fsqoAk-KxK&Xo8}o`H4l7Tg^W zM8B^_aqjs5)Pdz-`p`5$mdkiYhD2L(pz_%Z^gl8Lf;_YUwf@kpx&qUQ3cjg056y=f zzzJPD|BIgrK5`koiGAIa{e%b6Urkly&Zes$q~s=YKPG%2N;J2< z%e3o71CCrAtv5fPUx|q2vOK0l5CQ@a4}mYYlhi0eEXNdFYB5G$%$DQxbyD;h*=Wd= z@%-G3&Fol+ms-NnzX*{vijp!`Wj2CY+AEmKP5V%7H$>cJ2AX}Nyr zP0@Ovf8|QSD*5devtO~3{Y9jgou#QPbKLC5qWXKb&|joGh>IFbpC?DeT+Na4<21%w znj<$x zTQ4)KPKO~o_by^!7_uqyaOTJx8ScFpE@sL-gu5km5s^m;k3gGyHv{7oq+$2=#TQbF z_DOk}@RC@I_r48?=TU*YZr!{WJ)45!O*yQKzN6@M!+#2KGVf(+Okp`qLC2UXjL2!i zSCWV_%+%^oK75i&ATol$Z|<0C3K66sb*v;{W$GM4mLzhCVA`bSf`eK?M_(HLFJF_A zmEI0G}H_WLM35iTHb%W&GLF#-$z9Xcfwd-DNIHY{sWVHgYP=c zy}*wm$1vFy?CYclhET1V0Fi3=|H*5IP4zG!_7ZkV;wd61@2SrS%vM@*Q|=%7SAwqB zvQnjgQ_+Vq)+PFY!YzpqDYDAklAnuwxg|keQtOtyTHU88N*6V_MPl`Ojbe03vsrwZvlmDII{ znZ~%&Orh!=V!Q7rg)UBumIQ*CmPts1Y`cLxY9&%sp#R*N+Qy4crO3F~|Kh z_Sy;w&;)05Q>iysrh6)A2=mZ;_c7bQoFEl2M9D+rn)l@x(f%)I_sJ}E^vRc-l=WrU zc$+EQxQTWTtBfzhQmTvkka=ZN&oZPBeq#-J&yRkcrt`_01N=XqNaN4NEIFI;qt?PZcHwG`u+4-x|kM-30?0W2u0pn1=Q?8wV2k3E?*3#>LRFQ7qUrq%&;~9B7$q>F9vE=oD9uN(}SCVL~$A_oB7UO(0Tb_`k+YZr;oCo%TP3FD0?V zFw+@I+K&!#j2{lL1jr|Vqy4vzH~jxI%q32GG4;9cY&=FiNl$xbGhx!dCQHV*=N!Y#2ogjE?^#7; zGGT%wAX0{uW=rBqBFK5h7D=GCGM*+pAqn`K!DP&M2mbA8q?6wn{;#+-Xztlb?k9v3 zlK2@Bh??;wX2qHx>zz69RlYFcT0IAx?f#EV&iwhRyl;u{Qj5Itqi~$5_thPJ%VE9o zW4p9eOTWS($=CElrHuMZwC@e<@2^KgizhZ2<}@ET{2&R|scA8UC?U*W(CSZIJBE+^ zF4HK+eAk~wOmv={Kk1gqRG#RyM2SqB&bXcc`DqIX^Yk<|e#`*B)gbsa0_Y75DPz<> z<~u|Cx~Ol742?4fDKBw`_Vv|$%XJA>fGCx(?^UzE4vQXx5_R;1Lpf2Snm&38@bXS3 zyt?M=u*~Z3yZX%b6|554(7h1(#bRgJA4glSVy=DrD8s5RV-%|i@`}t+A2YUk85>K_ zw5t%Wd%n}HEW?NkjkY$6Iq)2MO0nD2EPx|DtU0_bu{~4;HroO#d$nzISvypJIfI8}e;xyC)RpG2G0W_@c0A^sAD%?y2;uh(-VQnlf0rlNv0_0-B+?RNKAwqq2{12}BFCmi zJ8k1PVQskc-8Jrb1WGPdJIT`*pq#3enjm(8^OKC)GA1pY&e=wV%ys#dlwKQe6+3y!{I0uC=87cb?<~VC{R8`xAQiI2 zDe-;u7&i-Jhyp&1s1XPI!+`KiTGvvAIjzUG>Ih@gZ<8x!_<;KEzAkfUDJ_}>)DMf0 zlkXmbILy%LT+lT65hIf~8JROCpl!bEkYgNZ_+2MCD+uSUCGol$%clT3BnZf-kv%w+ zMZ*6>iokfCnyfA}F82VUI%iztb~WQx5;wLVx{|iufUHy7{(R z@I%;H)oGJ6Ctr5)rRf=|8L6q0OEz3paqZ-^)HMF5W~@t_nx2_Db8`9A)Kudo0I&-r zNNnqePB4rF`DFmZ2)>SeH0!x8^P&BRNdECgLLKy+Ttn@iN`IkJRzsKhGo#k2?s>`f_4n~n-W*;yET)}zrkG2)EVKdX*lGJ-9v&}H~nh1l+VO&E1`J~( zcirfGV}w(aTUU|_F@4nhX`<<)`MUqczWd|*HN0lYm@LuGn}!n2WT$9!+)^vq^Cen) zi)4>8ErH%(a>i(MY3Dt3ZsCE;6ZC-C^&RbzQREu<|W;s-|9I9Ck)hvfnZ9f}XM8ZQ#E5g!nX?QtbH*^KM3YQ1jg)81kf?s) zWED_`9?4uLi98}0&6(RIkwfGU7}l9D4wnXqhjoE`l*-2zFt9MTXVP}&B1zm%1j~Eo z1CnSk%(MEDkeBsZ>@&_{GkMm9lK2HPjO7uONIXL%ju0t{HX`c?T;w;b-x5KXXH}O= z>TP1cpT%a(usS37_>_?pGmtEtt7l1Wmw{|s--GEt$&yzn@ms*=tR}+!k{Cdwo$yOZ z3@7q;!ZAsVV>+|V$P(XmNE#8gL0RJ@F^4rTi=B7Y5=osy?lHnhP(mDh=zZMwAxHINYBoc#C1g05DFx5D-n1( zTlglgvYy>a_=P0yC-OJKQAxm^IT3_VNnk0@kq5%&j5dPw%Ug<4XOSP8O4ee6ussw; z&RI@a#xO(Arpgl75GN%|$X!nmeulDro5Pfz!voPqsN^!Y=Wr}xgkC}9YrwNkbC1n zt2Z9r8wYYve#a>l3=52$J>1IggIsSs*e5@{Hx7uNI)K;+2=fi~A%uwLYSRpBILs#w1!v5UZ^f5UpyFc*v=$i%bI8w)ZBX_EMe$N~Z{0yM0D z61kXAB#CY!OtA%cjE#^mI36+>yvsp53rp9>9>oZW);cDU{A1*|iLRrm?4B325VQiB zM&tmYRZ8X&IZQYtiKRr|C%h*K_U{Y6CCHKxatY!RPl%Pol|%rNlOmmk=5(2L)raUU z+f|{Vi!~BAcA2*qy4fcLw{2SCege^+LjNrjNM8V@fN;Jfz9Yh5bBalXh7qYC$Z`@I zNdyY#+#(6qpPYS!U6PnY-*QO+hn+LSztm}3S_N- zlThV7x|9xj`X=21fqx3V4(#;O90C3{?AvPBHxh&I+FuJ~Mp$u=sEj=I|Ww z)aQJWfo$Kfa9)8kI8-uMvSkZ6^%h5FhCH`+NZ_i_YCM6`IAmt{;>cL+@fXc0#@u0U zUV=G(*y6}|RMSBo2b~&uzIkANh`=ihUmd=R?3Z-ytYMo6_%Y*u$qSGC1H!}W%y6e4 z>Gow_p%E@=x{!36nPDu7bkewfULooA7PUBXF1G2fyevipQgribZ<~ZzAC_;sx-vEp zS^b*84(aXd*G|iX*+LAOCZN4u?}e5ylsq;bhs+^{49qaz@BoL;Ot2*5Hw?%lh*Raa z|4tCzv92?feGB5$bb@5Usl~cUcFc8* z_y`9}QzK)MqBnc#ydv78@>^y<52*y$$&SE;=Yg{le2i1=92poiwBujeX*AweZ6gCw z)qkSR*a4B@{sAKftcV_D1~C%fF%ymO@Hydr^z2b{AaP;fyECG?lSqkJ~cN9UH@v1g9QK0laKxZbHc-c+A9&AXY>|}f_dM8 z8QRO)ziCD}Vk!dg0Tgh>RLlM1$gE)^UB^}1sKC%kANFM$#1`&2r2f0+RxfQoQf6FW zMC1vFIa*3(78%CJDkUy3%KSu~%a`v{&Q=ouT%~(CsRf7)tnk5|KD``u>U^%AhzrET zeBo8mXgYXEh3Ebe7q}4zYNcu^jrz5b5pJC}4R-#G;D4=;}4|M5YwFU2?X(0*3bT(8jixdo~4 zx>w<6l=+;5Q_BHx(ktK0`YZ22==qa!%NXR9H-n(RvZquQ3n`!Om0z*XFa{;{lrQ%x zto16mPK}-#4gg=SSAJ76Di`7H`O_WP=Xm9}WjvQWKCpR3XvJ0Qwp?=AbB$Gj30FP$ z`sabG2Ppp!fk^e&?*p-F^Y?*fYm{k3s5`$8M60Dg1QONE9|Ey{bH?M(Rs0ax9GEjX zJIa^37wiN4>|J(L=%AXKU){KuJ*%XPB7Aa+?Z!g~)#);DV#yEfGLjFf_%M5Tb*B|N zXuDJ7qgnEC-ofFtO704n%e`ns=%88$xUSWGW~<3SrIi#-j-be?YUnf@!7|+`MCmdk za9Nddo2ZoA(<`iYQ#~JM4>Av_--g+9&3Y9cuzzhfKlfI^jyGePEq>erZ|kq#v0@WB z08T7+QmS7+d!u(}?2qNl&-EFB6=2d(V}|bIVHP&oC@78GLCeV2J*~2` z3#l0@-31R8>b%unmqC~j?(wOB}?Bx`@*!kV;a$9!2=f zU|EuvcFN0=MEH8*2&otM>V>=Q94s+i9WX9}!k39=|LteUlG&fVInz)>xUL z%KF>0hnEX03ap$a%f!4EKDp)P>ec>sMs-q=%od@%vFeQY+OTa#c4GFpp2D?^+p7mG z`D4ngO16yD&>FAzLls9TDbo z>*Ub7Xuj&A?~11IuITz`|CZ{#R(F)~+LP3Ea#d^Hb0I-IW~qq|27M3JD) zfmknkVP}jliy5xfoq1s=gtPkP8hfok4Bx@MhF=;`i&TWr-TR}bb<|E`E+#em25d9V z8`p23ni;fb`w#bPQr8CUN!8gFuP?sDiij~cSux4fOm6WBW%p!SC++rrPSgV^E>sz8 zag1feQ#U@jKUH5yg)wP~2$PkZ37E`min2Q#Fj-bZzmpD_EEkLbfU~J|n_7L)sg`PW z+Z|4|R2ixKxqS(S!lQ^71k#F0@}=#yl3IMe^t~EGz8#9KI}s7eVc@gzq8~My7qO5f zO5T2mbv*1~z>PyN`2&xOHs%4{s}d1!USV~H9SE3L^i-fc9<8WzMUOgv(o|Y%ybuV= zPlxf<5}>iHIu3NI6kFl7fxXgRMGUq_8Egh$@#QtF4jt{9vYKya#%nd(HOJ+J!I zz`CHhhTn&64EnEQ7B&X=k@jeNS%YQN@G}NhjjzGy!w7PDz8-POXZXGsqV`&?;itmg z_`jD2`;;?@ThO+mSm{zwgO$nfSc8V@L_MGzB3Pq++oM>d{oA8N9yKM_ zqvK*lXluiFhdbKT>xGgSXjdCv7tU9GcmrQO%}^!TzG?`4y5DwDPd&Ivfw@*^^Q*%g zrVBAkpklJsFNlmc_iOE^V`r2J1s)pgl)7;(P12Sb5@fWE{hIp8VEaJiRk)0{Lc?^T zdfL!vL$UgCh&{9#K9``i8cp7;gVwSTy$xk20W{(V)F@BNm(n>xm zxdT#wD&%O46-u{iXbT`TF0nSDM&r#@R%)HkT^lrYb2cSGUTm-Aaz4uC6k1bI7dmAt zt>k<#%wOlPJWc1o6Z9KpbzNzdi3V1kL+z*$8x9IP3al96e5$sBa*5?ungwcLG`8i2 z{lQ+214qDMa%4G~R#}xBY4&w%efAiRBbkbq2O_NNcUJdkq>Z3#`6{%aR3Ip#h=6r@ zlw@zy+1to=W%+VAtHnw+N85vam$#{d(RQkDV~hGc+D?-LW>Xp;XF=0a9<$d<%ywhI z=q;5sG~2|ga`Uc?cj^Uyx^+)*TIi;FS%o#|Q@qxQwvLx*p-jDc9Z1M@82%j7LI ztkYL+S4U#(VZq&qlJHDRk#S{<`X^Q!vN#)d7ydZ12 zb+-del)>viX_KV7N7&hBzM36t z$IX#aR{+-_1PxaIYm9!r!cnw*RRFbENB$+t;H5hN0~A>9inSAbt52(!V(l^JQT2YT zUBuU%k#;g)mpfmLBkhaL*yp|*Y1^h5t3u-JNoJy&8fOn#sMSrW)jh0kI0JO?SXw8l zuE45`X+rotyqCh|WCW%*W?u{d`oRlzCA7Ce9vbwyA%_*~8P@ zq|I_GBa4rmGOfy>VPQ)SaP^u*)K?KB(D=`g&P`Tx;t`HiwKm=!o|`IaXoVG1!bgL7 zkR28EfN*YMn7jeZZG&nSr4fwMoRQ+AQD`1KI&Otj^-{c@FhDmVOLufqos75ReCKwl z{s{;O-{&USV@GtLxB~@ai*awBsyC#4G7V-4Cn99_E?dBIMHwa*dv1ZXnlBG*2~YG$mNlT@#AiVE z`4P#!Ez-=1du%&DD$(0ro}Y)_cF{dQpI$`bq_)IMc_p|`)LO(vDQX;SOU3p#&qEf?Ym?e9Z5E)QG zR(fy4QW0@I&Vm{Yd-GHemkLf=#sNP=Xj5M%+CzK=U8>($drDCO+-vnCj|cr+jBrdZ zZ3?VlNV%BRxvP8?L94;P*Uz_%nm@#DMIr6PThVPE_FFNzLW{_*zE7+qRw>C#?wDE+IHw*Tk0?M_==`tNPq)mcgQ zaPx>-kz|jpKH^gOlnl6+%!|oSfy^m7zqe;6|1vjU6Iu^r@hOY9qaxc)<`Jy{m~;$d zF$*!-E3JLzVQp19G;_0;Tl>^ENp?h1K#1cLQ<0Yp!zU-&C{gbZV2di$i(?lG}m zPMHbhi%$b=7neJ0mxH9cYUF0Be@?KI1|Kj4sMb6}3!|_@B~P>y%?7n>B6Bi1APde$ zD+#%=ic3B2i>ou&a_5|pTwsL^s_7~g9U>(Ko_>%XfjOznGBN;?Q38;XGXEBHuT_Tq z-MfF&Rc1l1Su8p$Sb26kj9#ioU`%Ss1xwS%=EK#IWU(a5z7T7?z=}=sSFl@4LTy<2 zMc^d^Hzpm_C^EB*N$9MVYQZG?FIa(b$#!f?UXpBb9JOsM%ab*90~>v=IK@deZIyJ^@2j3#SA6!ud~5_jQ#93Ds&W2$9>8b8@ya9M*)vW-@5p+hH8yT&aI zR`?x8TB20DfD1(8OZ>M?jqa^HA?mC|#;u9H?q}kmgW772TLcXjrk=w{*Lx3!us-x$|*Y0r>H^~g-EL!BXrPlr$|c#oVzVmT`|QT zfyMNbDfY13>?Du0x79{^xZYM9;Sb>d(7Y$%u1Lmh^#NbDi}P*uVN`dtvT^G{brNWK zhtKl_=+?vM1vD8$#{?YO-+DOTZ`XJu{tv~{mOs6M7`40AvJ@8Q-Rg=Iti|2xE>g>C zPg$Y2^zk6pw#rsPQ>eDn@^2Tnm5{3zr~MV$QEb$9iNrX$r}(uC=|cYrEn3v~DOk5H zYCSjKvMRh7KBXOlC|+uF`amUtV1$$*{F#HPHwyDOfwR-F`_^rwD;$ib|;jTW>3jDY;nPz8CYvV95#)@m~9=F zus}zT8sf|cE9aln^3pUr%{-xYrr9&ABLev7D3y*P0<;s)zfl|21EQ9l0Nv{f8P3SP zgg5fq?4YKIp8mDjLIzzWGlFfqn4&<;jOf$|k^+g$9I^LGtdi;$GfhNzqE-vpdb&^0 z@!Z4&DVU@anNA{EClVYBz{o7c9$oKHY<{CYl+x5AE(cFC^Z9c`{WaFACXitXJ7N3o zF0xM8UAFJeB6TF)?&o{$v^th<$InM=$FK~EZt-Q8fDs ztBAEoa1@gKCQE$n7${iH5tNft9Od7F3Uc6=I35A%sx$(+YMJ;=g*s=t&CWx8 zH{G7V*Vq~Q>pc0&P}k0|V+Ypk_h~k0tX|!(nr7Guaj`V_ZAr8O0!mM;_SgvTfTKO} zx#KhJ6w_=}Q8NM5sOHSn8{myI?eWn#c%m^;bJuCPbIH?`q?%{i@sRe7nNX=keKyk` zi=7jBmOVc0D4u&~6ip}7iHeC~JQO7hT~FMlv_|s2BdY8yd(<@eEyi$Sa!*gXcsB|s z$eJ6BqcBdK9%Yq!$^vzFnR@vwJA8;3(I&ItG|Fnwc?bs zW71%M7F5e-*`unlGo{xIq?b!f!kV8YMrgmQ6Lq|T2reEY<7dZ2Cd*{IUEo$e5+SR) zZg(WY%Fa&IaxOBo0IMe+A&)=9+Sb`YunbD}hA~vv=OD%cn8Z%VirMZeAD7k(V%4B5 zJ31y`$gt50#yhIXEzQkW*;(lBe6?A=EboiVA(<%8Mkf!TI6GWYy! zd(=p5=nN3bIN;jWo|y$3_E_rFYxwSXe85o{d(rdKM(iTJ?^69apF4*jao{ zn+t*`RN-9K|9ExvT;^1~+BMgnJTD6lhHlpefR(YpjXCnRFgGdG|3z0$hD)YCX^p60 znvD#s#m$$b~;~GWJb4^gmN%0XW+s+7tgjB>K%sii`3jqdldw{y z&9gT{?FZ)BF<753%(G*wnQkm81=bOt;|f6r=<*Tf2ouz5@g4BVJauzV%Ax-XYqzht zM=l;Y#awdKQFFOI?FANU%(RD2FjHNNNNAdRKs7%sC0vU|4j z3NDLYRq4~bHhc`J5v7)euw}`r1v*|{Ib$lX1VwFf>?{>~ z!7sd(3Olzm#r<~&ITIYumUH}?BuN;4u`+gU$0^qv^#HUA0IlD4#Rh%Tu(ZT3+j&gy z<8-uBnUQxYlyT}Q$Vg|6Rk?DkY;q}dEiG5yFSH|L+E~Zvde=!0 zh9=3bI+b*`9Xrcwkpl|QOHk@~ae$Yo56`wQ9@e4_UJ=z71I{w3YrUAQiWlK2II6B+#N6Ah9$sWmMyLOA z5%x>F^5xod_?nk%PvvV%uAN<-9pksZaFy6g*)is7XbIGp`Wk;EM54U{>S*4*aKIAr z5Z=AO{aZFw5`8hxqJqwSF~7&?ezA#u9&r01!5XQ-mA%;1$I2wp(-CoRA${q1&~Kk~ zZF3T=s(LcKbUdIfR4*ZIy}0L9)6~_pxv5IsznJk?srMG!XPJjp%sKYhjDwbeA9@Ae zju!3nmLc49Lfi;?2sgpx^)3vTPc??R@*I1HX{eu{W6w$kfY>$omqfgEPc`)xmoH)A zF*#0Q)_K_~xWpb(U4zw{ggkM>M_kHuSaX^+!iP5UQgq)F6}OeXW>te7AoCl4px3TF z*tcDK&@&-wh%y4ZXQjFEuq)&BKGn1YMSfVlw!}`XzOmclT~l}>PnoqiBxQ&q_tn@? z90so75ArL2&JYT;5lZAhZjT8~SXMF?3IzTA+iwl8JJzh5;k#qv*7hnCu-FUUV-!2nH? zs)Dr+NyMnDDzpp+z0zv14msW_KvWeicP~B>J+3E=K(0D@$S>k8;&x+=_D<<&?Q@IH zwNreolh@?4udY;k^X)P7VLTem%ICnq?fB7lne`gUmMDw0%l|{Shza0G`vWh?RCE5o ztR-Jr%j|@_e9IVvHXGCES~pTbiYqOB2v{JFVFyN|hWTTp2eT2F_iLEW&TDy-x^kI4 zrXQH`V?T0Ct?plDPvbPIV;OU-O+}uM>EEX2p06{vo{u(aQ+v<1lQAt1pKp(-Mo+R8 zu!=i<=EZtp0g+c?#dKY1#m>-FWiYQqEb_KWuN3GVvkdW-G8Q`r(^qP&P|OKjV@NzpzzQ1z6 z;|rYhIR*BF;O=sO%PvuqFeB-?Z3XrO4E79x@*YI~tQJ+DL@dRz$n0*SPa`&%v1Mf4~Q4skY% z1!T4OkNDjgYTkDWk0Bc+M9JJ8yWKI6boJe_YQSoH#<0eo?)Nn7r~_@!0d?VOdzg>! zYggOj<@>?atTxH&x2x^7vr4qD2C#vY$frThH8Z3eZv<=Y{|-rWE8dGvW8QN#Ds)dLygQ4xJk^kviD5@_(r z?<tb%N5&=%+0;_Mf6C3VwUdq~oQonmdu>SaE7I_Ov*PFzEGKpN+r zQome_Sn+*qtvzgT>_F|vl2Yl?I4?$p6*0qOR7w%*I7a0cF-2n3b!4urbFH~}CcQq) z^%^xg1sQYu0Mif!?Uj42ht$a;Ebx34eF3Xiy*lp# z&QR*rh70W2pxiri;0T~}L)~)$Qo#2wFR;`3e(uW)n7O|6Je9DHGv}kv<*u_!d@Lf5 zU8I-N6BmK}VKw+-tc}Ae`(it7{PfJAxz15=61}iDDmum;(DVki^I|(;D!$@1EG^0XjTxKPg z_;0##FAy3{iS!i1piJ{3tEj@f=*+xzlDF>6ybC4o!ZY&0%U?3bgd8)9 z)Qu(f(AhJJ#0$e#BM^gHr~?JPUWqE9*6RJ1QA~b|Tnbvx4A|$>_b)XF?k~JqVn+?5 z&NXz}@koX^CUF^r@}2H4*uNyNxaUB0F0n zmu#!MgrwViR#~0N7g(TV*X<{i(Ahl*y{C;5EC|1DDwG=cD-LmLCSw6?!J?p4X7; zj7bz8WlUrJ2UcmxGNO%E@nx)Cmv!{ktqUFAPU@h3M?~K274CCiA@}S#A?=P-fIYb=hSYU?&(iMk1=}3bK0~e!J^6R(5LTK)j)~1sVC5EtRT$x2 z25M8Qtf7ffAr(dj{L{&`LyqOjV041GV@|rMxNr^9^>b()I;0z4L6>iJi#z_Iyyw-` zsZsH{=tXaU#$$=w0tX%je#>C-m1_SHDqc?)H@>u!`Iqf=bk>g&FHmXHFi=Oi`2)aAkZmN z+T#v#+p1SL+R+J}J>Xv>>Ty9+L1@>$UwyX`ChS)km+P-hm)p}xHC=8`NJUV_qtTL1 zi0L4^QGuK&?jjidSi@c`h-zNuvEj8W_5J1csD*hlU$=ADB}kbztX|6tdY<6d3M}81 zJ-y$PWAP&lW!7$gv!5Q9=WEhh;=sRn# zm7UM0p0K)&N>*z&VVLBrZJX?+nC@?GvL{6!IN%t@8nVYH)u|#kv)~<3b2i&CLyrIu zK9|?X;f2debx@U2#^P|xX6*ZT_3&oav3T`|&Gz^SC64ICRKVC)xe?`_c|6C7kVj!g zu|HGAU4gqTQ_Xh1)?Q(cu*;In0+_wOK~-PD%Gs(~q_9=}hOdpS!tzopz8J{GWsb!7 zMKYi5Nagwo(?cvcNjV-O*<3u^0l|@kKq~W1lhDhx7?m{;cmq=%>FHCdmX+JX20eSy zx!d8={n=axn_LH*-2WAu(lfB(F&6Ew(*2hHM{LObf5E2I#ir&AY#Nf(Iafmb0=4l< zj@sMQU01^2Hg(`iP6FE0U!AXkTkKKk&u5C|r788i(HA#TtmB$!6750rc|#R%v7>!_ z3n3z(kLm4Ni_?L4r@MHkyLhL&ctv+{X^lO-9pJWnFJDM`y-BpEw*$!Y7Nn`z>Fhw| zzjU@^pL%!;f__B3vBkb)%_&D9gD{jEum3Xfr&1aZyW_{h-SMs?-3SShc_U@9@H=)q z%NBfK(F!_NxgOKvCiPf_9lg5AGDf&BHnv7In4u5(AC4Z6W^^`ii!pgogH{0L=S_#j zhXin$6`StAqgJK}pci-Ja1+7trq$vcHFB$SEiVT7O;p~cUQa!Z0U6?c)@StYugrHEI9 zIdKQJDUQxDm=0OXHBsbP*o-cg<3l1bi98crEUO%U7La3r9OavdvCnSNN-Pbc>Rw$E z-fax;#{ja&ipG(4Em7i)_2Qm4R`!n7|C%YF^}0Dsd=`IlmsCmEZI08zjOh;eX7`DE z>+UcMJLAt@3ro9?9Z*3)b$A8AfGmgF>=>3i#iJ~v8I~^wQh{~6f7<}zhM*o_n4*ui zH6i0G)QPK^WBDp@jXh@+OP(B6MaAOxY3$z|+2bn%R{Tj-at$+YpSt53dl75ITeR?v zKB)#*+DXxtvsR4POqUT0o8k|uWtH~Og3NtBSu)nNx(Fvoh8RvP5PCQ|Luwp!X_}B( zFHUg1$8+NvsJ__(JHD_gGPV-jTN$X)(CF%PK6C=*H&#o4H%yL+R@*V@qw z3ee!lH3efzJwK;82H9J$mvkT-BHJQo!?-g6*>$u_D#)ZXhjpp&>sX^KwfZ`HRCJ4T z5&FoWcLux52Ll}5uI{`}UuA2)&YqASfz2i)Y~lB64)NBU-uU)V9bYZuHn5kNazgsC zb;`OPM@zg)z21(^kI(n0IX3>h|8Oyfp^B|94Vx{V?nY)#hSY@8NMk&XJ2wo_oy_LA zWVQQxPBt@~W9?3>OWdNNa_4JobCtO8d*bk;C!X0G_XleB8X;~2A(8WN!8i*?B2dO9 zo@uLq*Z5Sl7P48zlrOXDd`&)|npwq-!#ro_8x)=F{7LN&#}Ia&8Yn@IJ%^_`9wnJ! z@gpC5IqpJ{F38b|Gb?2J?;g6>%3OesU63PjLqAG5{?xzSYRZKto}eUk%$dqz$#!o!cNVK>+#vq_#kam811BiX>}T)Ew%yPe#iKEILMhV41bK{*~W zCpV;q-x5qqye1}e^caiDqcb`DS??(I$sNgkqGwdq`km*NeL2oW8mJTHKG~z`aFBBg zinNxQC<#Q}NmL)^LQPMRBq-vKqabq<46&dAO8y$|Eekr6qMTVE(L`rw;znIfGbu~^ z{dC=ILmt2qtu%>q7N&xZ_MEerlPV(Qxh02JB>dY0ZX!9}@_0zpeMky8$#@l=(*}w9 zx5aq%+jXxp)?}h34#?!g0p~F)$vzygwzU~DY|Y=vnt`jV;Bm9YdrpWUPfk+%YEZ#R z>R^pM&Mub4XFZFLnsSppQ4P7t4w|KE+)dnCDmAQaM+BZ|jLDoha%WS}+^o2I$bq!?~Q8P!gc z5@84LonUUE*9$$7n~05K`6}UDgufCX^2g{##yc~tWpsTKUFk_WG9pPo$I~-Or<91- zXeIX?LfpBd+fFHSl-j^p1U&VCy5MGefcV8_>fqE|!Q2edlL}l?qIL_Pw4Qe3dOoHk zGF#lcttqKBmPehGtW(a-a%r2x!NJ9Sr(CKf+bdSoU@Xtv#3uT$<-%xUi_cuWh+)wr zwFytMbC1PLN#t~jhufSflUmLlCr8p#o5Tn1)bE(2rO}}ek4*ZQ0O^03}xmM*c}tUwfcIx5y*39Vx@kSx=$pT$f= zg&Xp02#$?Lzt}d(8fyBfeVojRq8F1jt=ux;$vXC;@M&FdwtBgiO-H3VT8mX)XBl`8 zt=;m#mUo(GrnQNWW0O?^JnlmZf75d^yvdWcFJ89TngwaiS{KRGNvmKUF{$*VNUPLN z5S?E|zK~ldYGj6Jh-up`voN|R?$n`{px&VFyoKk!8?k0Fr=9BUy^18QJ)ozo7L>G( zHosZyf6m;TrAkqXLI+K@%HDibf!2PM$RN{e)ZMq)k!R~_oPoGxNv{X2Bb~Zd zBSI?~h;8UrM;&PiP2XLprCduydXswZR;JHB%i1m%STwEEn;b`!aIZOFWoIRNNRiqu zdecF%HG=!+HC4SyYx`jeT_r6KidkV-8@XerCW3_aUJA-nxpbztxLUZ=y5$ZBZ(q`S zO6*dtlVW_^Wb!%VHDtUoy#7iiz8-Z@uSjmxzpc-xW7HpRv!gerpOUk7M7^6hT73(|jED#iBERnhy))3qNzBot3?J`8%_uGcr_u z9rVjE{M&=>dXkYL_PW+68Rc3Yytw~XkCGXcy%I#+zb)CNVg`y;oPdHz4f%R#B&Hr@ zd&fgvxPX}8ay~uZm>B_p2)SAXZ zAgonQw{vupq~5yS&NZ{uh&$|wBa$qmLpIP>N7U{idiXBrY4xi34tr!|(2`9FE<%s) z(+;ZoJJ`;|s$bl}MbJd`=R52bIQCM1VqXXFM}J}`1ZQ?@8oT0{c~l+yi5(Mj%rZ{N zcBH}2lV;AfD6pGxOhs(BQ@Nlzd%JzBnWfsdv)PGKUEA>#MX4b_wafUr`KR`E)d#s7 zA)CXba(yD_$iZ1Uml2RFMv<&eGU~J1p(LZuTE$0UDWaoo-m{L!O0}N2`}PgxMtv(BAUb&*j|ACS-2E4nrG8d1UKyhLPflC2TGg1l@RG4#xC<9MS9$KTCk*Bd z(%X5^Syl!;%Gq`5@w@EU>`s{|B~}?%%1bl|Aj}q7!iQ9}p2JSJeijwurD7HJ^gNeA zWp%24_4bG?Ru*QuepIE*I_&>cT)9F~0oIC*?p^`3@*Dl$Z9o_9+$42Ty&VZzw${V9 zR<)}hS!-2?NX0}UeGGAKlC$u*Vllg2S$Ff$AAn^YZs!okncuoQxEBv`tax5v;b@I% zhYbJS2YCayGx8ZFAfy-k23}h5i1*~UCjPV}#}sJLLj?O7Vv_r|>PNq~dee7qqufEc zR8K#NyAmQ%>_cJ7+?E(m`n@zQwCwaL^3oJ(IiLtwA({=sDEc2&ro#Wr9#h?*?+;3e z$U%0wBL~?HjvR=Alns%bt5s%pGM8!C%t~&Q{%XkI)PpzA1^ zx6hF#nvQDGCls1!Mdm2@pMjNndSSmNs6`=yR%TtoFUN~S-NOAl+fK{qYzVsjTThPF5ZQs^-YZ5+s>>{_alRH}H zUf2V|$xXB-u@GJ03~@mNt@#zDKJC;8_p%+~5lpR3WyUSYb$w>Mr3I;nb~#nDX1M~l zkR3I>udz<@`T+*6X}1tRXV2b#VZ6Tj#G5~Sr{t8{9g~}Vp_6@~+b}+lfpFZYhrN(t z2Yp*dTR~A&UM8zwgbX_38br&>%uv5qJThEt8QP^$VQqbdcTzNQGgZf&)ntAIwspV} zVjT}PtbPn=eng^Z9F4l09}>}<@9{rN7K{~E#0X4p7f4C6=s`UT=9eVEKHh2P#Md0t_7MRiXpU>MJ$z>MA>sh4zwY*L(}0&hM@Z^qPG zbz~=ZIQahD{f^jW4-1i^D7PreEs9bU#c}sKc^5}WC)7&kt7aDq)(O?J%bqx(LM%L? z8SPU}sN=ir1oOaiq4(K~Ead*&y|k-TmCo0L@^wrd-fNE?$=axI&h2+@&T*|r9{QCBvB zRe{>mWJj;(zJlX2Ho7A4ylFxhT}dpDTF#9xcFTTGL|#X!>qVX2xz5El@^T%gK4A18 zXq-$|(GPPcELp95*q%O_bwuC$I<7BuQ;8~{p;UPM!76BTeM`>hKF?RrKWxXw=37P> z&)-^Mvad@%CL2?kKQyGqKOVNDs;PmT=rS!WZfRl9Hg36<$P(flA{d{alJ#6TZhR4t zG2=ec(5N3H3rphR-UqclZ(-MhPg9lxgM?!xi*OnzPviEXhu9e80Ope@5x()5X~^Cb-zUi; zd=slbL5(oitY|s?$~@k~nomyjh~p=xdJy|G*dvag)b@y@L|t)|s4I>Vb;VJlAS2v$ z#&k47c&U$k>#shkJ|Z2!>5m8-gT&`7JKyIV`6^r=h}5fN4&~yVL2^S zn_BGn=}C^xf)5?po}FrRqy|Azbhg*fi8^}J=*U&Cw%DaeL-J$x0#rfyV>|Wd{-t-mg4=lo0q1RPC!T)qn%Z<$SKXt0#J%+P7pgwubF63*$<95a+F^*wf z$Q0KIL!ORGCojOnbthm)Yo&doA(#24O>is*<867e3LJs_c5)K8qV#@lV?EgB>vX{W==8tJ~E1Pcp7HRposB z>`8mf)HWW+VqL+_XEljUj~ z5wWew8ZoE-)kvN``ZO;YEma>qZI2ne z-O*4zEV!;-#kR7lH>f$S=$8hyy49Xka@aZ2;uwmTn(+%Ybfp=7eHpLgpsft`I$q!D zUI)KErsq2N^|9Vbg>fD4fpd?djq9tteZKSzEh~&oF`V)zi<|iM~H~t9PHV7n(&X?pb@tER4s>&?@IavHj-p|EI3E0f?)( z`iJjb2H3sXBulb^1(sx!Y?4hvlo(=AQ8A)oMS}(vBR1GzB@q?PYSB``geXQdL@|RF z6_vKMqQ#00T5Qo`i;9&#<*Bp}RaCTSX}cO!s%YQeIWu?J=>J^}cg}pAIdkUBnKR#} zb|WK@`L`Lh_XW=X8z84rtxUw<%H_4cbe-yP7oj9kmHRih{Pi!5-Uj|7x zGB^Ly&)a|DpeO2=Kj}dh{qmI_Fd<(?dR*S( zA+;iwSIA`o=E0F1v^$n6a_W8YgYB7c@c7%Wh8U{o9Ghs;0l%aUiI+5Ph1 zv*?90dh>6cJ!nqWK1cT{p>*dsE^?oyTFOPYm@u=qu_c4AgR*zu9{wUfX@yd^SU1=Wj zpUoG(>CZz4HprakU0JnVYP}~9gF&tl;?{!$dZXQ>y6*{9@{qTc)e$q4_R$*;LA}x5 zj7%&sivmo}@aC7OZhG)2#LR$)3OtT2QGPvCKzg+HN-^Iv%TtPCTc&V>BtH25Pyz0e z;{m*(k?7rj3P}_P4e>b!aA-FrcGlbG*t%) zBLoJ@{7QHdV(fR(7mGZEnUH8N_E3jB_BXD@$8d5r8GyL4$)U6C(Ph*nM6hPw#`x*CcQ0gD&WmU40l3^~!(uVT(<#-1GwPQ@`j1 z7{~{vHC^@8h+W4O25A?nQ^(q`@+-qWo(e-M2gDunuA`hgh-s%7v+sI*@B ztruNsC-!Dzs)|PQM$-hYGqro`rU@DpT}eBiuC#+O)x@19qiLFy554G0NotDtkqVa> zD(p=S@^>%d5}b0HZTX&4R39+$(X>nvBY8}6u#%UJsZTptWdH$pZwKp&X+ea2>x(cG zrQ*V=?&C5J4$>W5tXL0r;|LJO$%KJ@?c#xOx5Jn7uqdx~VAMr+g!)n0C*&=^buCY& zI8dPF)j$lPv`uCNKlfYL;=qAP>hZ4-Wns+S@O=UY^9;wqLfd_K`nS-8n3FpGCD-a@ z!)o=Cx7F`%fiZz9C@qW5w-~z{Ju-m89_-?Fosrd+F_qa3G31%wgzB>||<4LhuPDQf}12I)Aat~wH zL8A-@vDXYroZCV;czDb2Tx~FZWMlvxWu;7enLqjJa}9l(Wy{MD+BW&h%MjW&>3YSr z1tXM8UV*ynk~h8rVeOKSyn-kb@=ve0j&n3l$;4M(=ceT8(RV;Ek+5{#)gZ5W6)UU_ zA->`l#N9P*uc?t!Ed*i))VOPAwr1ewu>+&HTc8r>TMH+hhxQv;$Akf>4O-TXP(FYWPA? zTIIplFkz2-^ImfWQ{2(I+6|je*VS&nJo1|B6-<`?`VTM|%H)TC07+%i`#NlwGMW22 z`sg~j?RD6fW%7pCUB~7@gn9*zzf6kO_}TL>cMJ=o4_iLOglLJUogZW(+%X&Q$N8PYXb@(p=oaJnFk`9oD8wC1*%ICWY3%osZ4_1i z`@JNXyFFN0B*WT?Q&t`=Yx|okZKmvR&81pU==OI|lPwYM5*$ydD%gn zG|{Q=^wD{0X8xT48hJTtNk;CNoRtx{snJt0@2sdHt5Q4T!eR744B+$!W@M>J+=-Rk zQjM@i*CI8@J5h@Z9bvavs7~jCNZZ?)aD(BBq(Rg$%og&me{?OV1(W%%4ZZbRvuG>4 z)n;vsX0T(Ql^Hx8`<g?s)T#`@rXXToxCvt!wEaEVp5j->GvL(&<2l|2W;H9+1W zjDbQ`sWJHB8^vEN96ciH@vS;J`X?T6;26CZhrW}C zapa*>o;&Qi-!T@E6T_}Tvt4fdU)R}=wpLI=?c=?X=n&;S zo-XAv#Cx5*0>u$98Hw>RwWaqmNgOaG&3XW&{k=&(@dkFfH_1P~foYZw`7xl{<~rWa zLWw8HttW#fBBZ&w(kF&!T~84(F@zf?Z6)#dL0XzB5&4({kIsfDPn?j1C+P;BR+s=& zS@o>tg-y!KtB|hajB&bCk4h%;0&!0J)~Sg+@>hl&3NTh9Ul?)um)GFFNkU8#^)~oj zhB<(0ETu(_`nRhO{l&G2?(qe?Fpz=mkzG!v4rTUE;S!WA>Wr4=opwH5zZHk>AvVMY z^>fe&;GJ>#oxflcV+S2nQ$O;Bmdq3fKg4oQ=1CY8oRrG|!YQ8)dlNqs`fer}N)Sr- z2GGQps}deyc^Aw9UqpG>X3o1Pw`M*$K_cnNcRNB^WMbI>Nxt^yQ3dxU?+%gL)LQ)A zae4e-T}zJ7qe)|2Cmn~4Qd`Af{7?dw4|0Lr$HBmWSthy?u<5FdNK%Y_-!Jd{D>lVq z3TT4X&?4ptt)b0^{`#+2)KZ}(DwJ$V#`(VTzDRk4VI~iww09Z2am17ILaE;Grjy@n zW4>RRM}lU%QNE~?8VE(M%tMonI=7|Hy6yf>>R3o z!uD1HR+v57U8wj*-lZPeA%GT1{CTTE4*ef4`EKHkUKe4b*QAy-6+Y%ZH0ny8+vZd! zqL6+pUoIbY{R+!rZ;fIPSe2X}b!A)vT^mFt2RFdV-;f7Qju}SvLnc=ZkgDA!QhcoW z=`4nt76Ena#gThHEWv9I6Z^)%n-u^dOM*;c7-*C-$K>kyG*1gHl)o;Rp zE|rhJiD~RoIrFCL4t#EV3kF7?{KH$Wlkl;|5T#ERjN!=}h$?My9*XZx1pipu@0hWR zO-v~lT0ddJ)TX37i@HT@lc70!c!Cq|6ndyhJd~LhJS>yD-a*$@CJ(&h+Hef#`CTzatpXMjP32r3HfS=COa7gafHF)ehaF8a@(woO zOi1fpbRiRR)w{0aawcFPVwxE!{3-&mQj)WQ7>ZpzAD@WzQ zcOj1Bx&kosMc0W&YoWp;Uw9X*24(Uu@4A+xPDHt09#NBWT&63$GHD$5-g<>GjvFt; zWZXbJXrLVspckR1j)UhRxosRg&y#nIyOy0f+E}HpIas z-5&L>fgwP1!S!)t>Rt|oxkY|N`GR}Hm}3#6jvlqonM1!@B$vF0Dle9K?_reQB7g9n z>+G~55#{Q42e6c2XK`h{9DC1|=D2cF&b;SJUwP%EFz_;km=m>DDjM496a`C~6E2eIkk%f&Pc?WT;5!F(wqnC^- z+dCJPhZce<`1Uy6P*nUvEt)N+9Q-@l;i&xg-(8z(cTSNZd94UTN8oK_;tvRk&W!K$ zc;lRZ?9Et6h2Mmg4s2VLwqw?5(36RMgk)j9@HE+kqIs zu$o?^!B!<>S0-%@(goNRreoGSL_uZZ`YpE@e(WTK{fQsSybBz{&de@s_r>58uQvF^ zZUEF9+QG1V;0=DTBwR%&$3VRXWYPyvl(?wj19X2)+T_QPZ|ssY+h~1>&jN#@lO|~N z$O~L24bwoGmBdNY0vuCx?XI2l}-Sl;0IJdX3qggoU#S4#N=@2KM$y;tDIK4aUhFG=Rg zc@?8Y>Qzw|I4PFx#yfOfFW4(cuZD08bDp6Y1W0WzksjNyJ}49n?j&Dl}C12-9AiqWq%qjw}j4!gxMWkv(u*Sg36x1E%XIrWD= zoZNSUGmH=r2?4S54`X~@f6JH-8Y&L)7MwKhY60o}IZ-lSZIJ)^rz>?4U!%je%d5?y z#4s<`K74PIxeB{q%)9)u;9ssM9e1_K>3_M-KIPB==Cti@&O9`#t>HqbILgO7ggxG1OVUx1<-?-xKP(&_`xR%ko<6xJ02#tr{b4tWwJeLtZ{f>m2R7xte z^3bSaQZ>+ZRt;vqLmd1V9EnDa4m>q}$}UuB=;KVlCkJ^FhEU7#ELP`mwuEqihxiOT z&XhPTLq;Y!du;QUcn6A`s^onU*YffzS|TkL6}z#(D#931kqSnFrb)ud{AilQ6hjub zb9gU|3unM9juhwK0^0eDR1})bIS*D0Qn==`r3mds>wp`FBRGOm>gmP4-R^%Jp$?#JZaBsKTpNE9^ z_F>Z3F7&-Hy)dYuP1I^+W8ORFW;5H4(d?9|M_lP^oyabltQmSNlyD=HkG*cwVMS&Yf}<`>IKeAN9k$k=fiQZ<=y#tZkmg zH3A3)viqDxY$s}Glz{u3B=I{%Vv%mVW=ol-o1!-L*fIdL_ra{8GA_ZPINiqX>%>}; zokdrRJ+7q4y`q>lQ00h3taGF1$DM=lK9miPl6FB~Kr%;}UJ<56;I1`_@Tte`r}SrU<{k3_{^1*-W#2eDHZ{o zswDNnQIAx}tj}EDlPZYHVvz&QWebmS1Z>4-36a%F70;!gYHcLDFcnsC9KC`~v_^~fhb!;E}iG~Y7545SRHIN2vCK6D*|;~S0BFk`~q&lJ7as0#Io zL08<`z0W5eJcG!WSU_@&PeS@!2~Qv#!Nug+KtMJX+=_mhUp?ZfrI}-WFeZ#?QK}t| z<|RGLmhcgEXF8#UlMqF{mEapk{I&`wC!f>ciQgjuCCiL35SuUTQY3*u)ba}-904l| z5J+}rI{D#8?T(=rq5^W=e2$06#o-P`ZZ;(*mQ&>pk+|K!;&wxfxYes!k_l%gUhy-M zs6ZdBsg52RB=}QY&Scl5b^|9N{nRb1{)1H~NSA89G^edI{1l$pp(l#I;Ri#HG|*A; zFrEt|k3^cG_%t_*nv?AY%BT}9TF0QsLCIjVXuxxvJH+_y6_LiDkwqOrhRh53?^HB^5Pj>wpc9hnnCB}lh4n% zR)zX=;|`8OPN)K>`vn7R)lCm@vxLK|O?H4cGpTh+~f8u$#f zF7{^~vgk`p8#76`oOyoB0C$D$NaKykQ1z)83L+wM5$W;L(`?k^0v>%Xoq%#r)P zYh8@LzqU@n-!H9GVUV0`TI;dd;9Ao<&a626sEG)4te$%zZ-{eM-Ol;sOJh8&BiZwh z$`9AMhiI@!osQD~=V!{?IBUs*Uih<(MAeNkwJ@D7_93 zxy4z&6Wjj(qijbQ-r!Ivc|2>6nvnk4GC3A!t-}n{JYlWKY|)kjcuh}4R*D>|Bkls8 zouR2+^+Up+cgyXIz5X6F4LUiAM>6Emb z)@od&neDX7D_RY@J(H#5vIdVWG~~R{m@^jzyR5;Wy@jlP;7v6jb>pmtcF(uMX0y3T zyjmhigSYB+5xowWM5ue^U*1A(i z)hN|Z!vy*v*Yl~rhLGTX5@qd@A1L89Sj-l3qfjx&WylSQ8JB0eEn4W><+j!>f-uu) z$7>(gqvX}H(`}_;vgG$}D~Qje+d2`SRdcNu9VZC+kGWQcD}ok;N;|=jN%O3i94GkX z$UJK~eZQP%1y4Ppgc=ZDu1LZBRN!HeLYrh&V^MTdgb=tD+60blvbWIcux42{-||7Q zZki8*TcyOOs9iOG55F<{)PCWQndm>EUzfQ2D8VLgeyoAKqq#FTPQY;X4e!>41F^z#&}{#wt7Hrj(pBzrI+UD%BG93@SF}$ zYMq!vh@wt4zlD5GY}7a@d;LhN_Ra!TSw~ZKVyj%AWF^KyW8b7-B-0nTU+xiJ3n z!RdUuyKOdy+;Xkw=$<~Jl9YXJIiwUdLC#9&y#2-<#^R1+PwY50y+cn<7$-No9c5^s z4nc>%0iwTioQl5A9p^fr&X2;=nUEBzt1Fm=Igs->xfSnNeZ+w_ObwoYsyUrJEmtnE zRyy!KZ-KP}Yz;4fe$0{gEwGkh4{Xl@Yt5p3V!>A7$3#CT1uduK%g+{|8mi=?h1NzI zBH-akk>Zaj;3=4l$MBIXnDCA>Sg1;WH*25mhf65(czrR<`yV3JSsLle(pS-CH&#TZ=-c z&-_1H?djObr5X}(3AoS9m#-yTYtdK#CmAZlEf=R)>BrE?KDr4uD<6LCJ2q*#k_`22$uYjs8e@R9M7Ux?Bb(jtob zfq-x2$YXub;oWkp&su+4H+(68VzP zT7^FTpFU(?BHgKIXeDx8sU5$akEH*r}grvdT{obm?<#Aek8(yTR?=Ih=Qmr95^ zo|u++K|Z=K)z4p0gy#__>&mok3vgE3T+pTEDQ3G9%g6;?a!ERxPnSHIK11?S`e14; z-AZ2trNpvXrlgxYgbT1YK`mSpsi1UgiTqVMWTZrnrCZCEpub#>*1DWV1bKAnAj!JE zb zeAWcgreYbq*@)35P}Ey~o`Jdw%ap~?n_+pj`g~t~o>*+H`))hEAc{#OY{Q_pz#}F% zwoW#CkZ)xt%@yLxFro^@(wNB`v$FJFBrD$-Z?^i#8!U=?%e*C)*H=j*ar6&aT-_`y zmsqF4T6uDbb^MBOFc~>5#}(%Ivp%?tZbf!H(H47_;OcSd3RrZ*-->{>1fMhTS&W97 zi6zU-Y{%XClnL$O;UDt2rbX@vSeHO^kK*IFCL%X2wU*GgWU0kZ>155>9dn2{D`(E` z*+ax4Cwx?Bo!Mj_<vrM2{!!bV#Fc83qNT^2TN8+^eSLL(8nxGts+{s&n#9A~j^rQ`d4`P9fXS+#Iee zP~w-8&y_&IHJCn}&EdLf`QA0po36eKjHQd8IGM32H;pR0Bn z6DF`aoGmY1j;4w?V^Sh50n__!}dQEYR@R` zIoKiQxOLm3eIR>A34*=D3%+|M41FI7trYI1$x`}e;jU7>S#!@c_F~uRt)>h#%>u%@ z0p1?+gthJE$1OaXLMXhVNu;^#)(yu-_Vs$B4x zqdgLq*O5L$-VKB5oD(^Fb6`9m0ZK{@rU8;z9UGy!8Oyi@XdP90rOcVNeYRgA7+PXvM#@e7|xvi zA(}nUKzV2enj<})N3=SQxjv@JJy|N`-65#(Qu$=aTD%DAat?afIi;)@7}Jw=^6ik7 z?07PQN2smk8{JydVIK~yV`>xQ=XrEY5P5?dxLJWH^^cYmzo3n1%?h-;1j;gxZRkK$jq@b>mK6w1-Vpk+gAh| zc}PhF%=-QJi$1h=lNtJSwQN~qEvbcG395|{qAqScPVb4JTvasi025m@p-_y?#q_|6 zGV;4;%81E@C1_DpTY!08MY|QpsOFv#Wa(6j(kkCq6!3YaPG7y*RqqOY;9rn?ZN5upmFvhD8pIl0QKCMnGPk z36ueOull^CKA&a6&Vc!~0YqhYke$(C{#@OyPDzpSOVsLigbtab$p{`unNHCJBXEXW z{#M#hbG6z^GE-F@9qeivXw}MecF6tftQ@Nq0|_-|kb~>2RN6>`$t00gz&#q)A6*^F zgeT{KNKkJi>SCDAJ`%C5V16Sn@~Ouatb8(tvCv^Sc^Od&y6NghGjW7@xhIU}9uhh# z5NtgNr@#|q9&=7~Z2gtMbJEtLQZGr?Wuh;>&Vz+iphSu(w;tvYe@&yr>DVI}9U(N0 zVcHFioyNIw;n2e(x6k4VM@%y?<-$HnrP53o%45e^-t6K&7hnC!iLn9Kz+%fKVuW7k z(su%xRqZalSxZG4lA&W^6PXct_OUR>g7VH|t!mi$BFkD;+pmTI$S)4ZmhI7i=|D+5 zFc0$!qC4KS-zDUyvvQPT)4HxGltonOHjHD5B7ln()INEHI0k`EKe3C)k9vju-0nt7 zjR@)Po_!P?A5B*qLhgUG3gl()@xr4G?HcHV0kqD z3$dZW8P-sT*v7D*zzH|MdxD$V_N6;y(GKAqKFGPrG9xTx-X8GbYBHFkrrcqCX}=|JNd5FD;=* zIgUz)^9k(z9bKo!e?#(*$6@{=BtJaP@-K#FfLxb~K3X3u)vbl%67e}QxWUTCgx4h- zFnOFO@7jRguHTcm?Ot&(#1q=YrPe~;#7)lLOyJN9`BZegV1(?)9H8nbUm^;=-$8!F zu`-|iNHe+Ntr~Ed&$(yzk!DTQ@~^UKJ27rCm`~?kMBAdFMYd{2$sv=@Vp*JRtw=#U zQXpgV@o4*2+GIzIc3)-7rfe$(`;|Mgtqm(C#$(>21}O>C!;ab7WGPK_9@>chH6Q~U z(E|?4{EgPq3&J#6yHzxq*gitIkX zY3r+lA|Brl-63)dMRl`7v^n~e=K!T1!cDAr!nT*aHYtQY?5h{_ZWE=Yx%+?!WnxK- zLF%ut-ofsEdF!{Vv|7gQ1@Y`lbLLLr@d)_forMsW=qS$sC8lZc*l4-9Js;z^Zv=7V zlb~yz!kG&_O%Z4&8=#-vmC!1N@Mbd5p*VuFGRQ^rcropXCsN7h54fm$V9k}T7+#bJSuE+HPhjwWSd)#sx+GI zbTV%OB8Wm4V7iZ^+5SP!?DPOftD+!!V4LNIIGQDJ1yD{N`%f~VxnOm+$jKGC`7yqV z|IEEJaw)x=Ylj|aHgrv$*)0rtN1=6$2YB@7KVK{ahTb&x=tU42i%Ornw}@LCm#F#8JduGD1O^1FA0-+(XU?^bE6Nc@p(rY&$d@r+3t7}IxXU@StTOe%FT&pzes|#e3kXdTh7CR2Y*uK^XFMfm@aw!JWLpk%72_^E#6qc@!i7B z^7x%rLhWIRDW4EVL%e8;?@hqbiN-|HoY;~`bd_Us^A;;(5x6)WhZ7B>0*7P=;wk6~ zudLc)C9f`E3K?Yuc;*r1Lk=bTuf~N%^+jAc9bxbVfS~RS;sYbJ(mfbRl;~ZD%KYC>%ld&wj9C~9^x8? zSo=kQeZB_<2s8;15*Nek&@ZYi}! zeKuw3WF=M)d4xMgr1traLb0!eA}Ecwk8=%%P#~ICR*L7gERGKfxOLtJUfIZRYx_F# z+Xh7~2+S&?Lfl?I8};@Ec5@+a@23LgmSVY!qU}fBd4x}OCwBrsiI^>oV=4`pjT;Xj z90OdnbUL0$ptR(Mv!832HeVW|*2`jdKqdBy%4&*u01?525WjKOgHDY+o0zBphz$C< zK?mN>t&79)oQ60%5LVt%fwTUTh)U4GZt4JhoaI60^#wRUgMj97A|}vpikUc6FMRGp z(LieugRvRT{=NbBsKE`FT@KOX=!_E`@txcbCDZ`={{l*PC|}lWwN{=BK|&?eh(_#r z5Upmri7j?LB;Wna7TH1ALOG&EHzL_fIFz)t)KDObpT#Kg?E1gAS}8Ps7sAUDcR%x@ z8E7fb2UL7??A!()EMZDnq8>y<1G|$c+Cv}{XuVjHWKhY2pWF}U%|>g3AV7Bq$-fO$ z+3wYkjLhPFWP;r!sTA+g83Gk!AIp|c7F)||fzmDfA<-1q!W?}ppDGo~qgAu`$3bey zc}-k~AD2>SxXA=Z#@Xj5Why)BUbCi5(Gl0lm3Wjt7r3LCs6@k3N~;6B$MnvY3oU;M zid+WHcbZ}X`#p)&$59Gg;mu0-iE5$%O-PwT>eatC&DAH7)-K=A1LO|mh&-0{u5tO> z3o$kw7e=c?jK#Mnh|YwDMA4Mk#hUghP~aAAVvKWqYLE(oX3;O&;vqCjdH=#oC>!EC zScHBN!jrZTl=vYAp9Wz;%+j>RiT1cjF80%C?oJFeCmdozN&e6U9Pms&q4%(gd2WE* zLy3(}(d-;y(e5>b(Gw?HMTZbQ=wFBj&w~dj8dtq`v%2_AzWmii)*7tQzkiW+Y&Ihv z5_O!WAM~O@aGIAmMD-XiO%p$>+ququXUMxQw*2yni?J%n?(EZpm_HDu+^%1N+he;S zL4=S5Qq|ilEJUiac@_MCKk0B22R}rKb)w_$4w+Yi3GTZ)h!U79ZJu6_==Dr55OoV1 z7gE$ilN5v_GuZ7vK+V>aZRCSIykS_u%|xXsJIRl2NKx8Lv=CXP(7hQiqePBBQ;V&2=t8AH{VGT2UFE;VSg*-2+DC|R87 zb~d|gKjiieZ(u1BC78PCM5S`X%Tau2n|>y;nSqj0>O3j*KE#Jb-@|3UuZydhsunxw ziJ|4?m;qBUX~#S=R0Stxj2<)#F^yM;KM`rQBNlE-bsG+&o2-DagxwJPv= z9G_DmaZWMd9-l8J=SSvK(l^fIc11CzS8xGc~Mb-)Wc6ms&nLY@919!xa2(1*wC)3U-5q;1w(9@jPnfqj7cd z&;$MPIKe)UKylu$#4H`DPW0^AdF1m}15PxW*t$E#`F()O1P-XKY_J@?KgId5hKWEz z_=jA$*NuGt(I79o44p?G_EW*$s&k++C%HrWC%iH-6o=K-dzAk$v8)gMH)id|IKO{$ ze%SrSs5RzDj;;b&PtfXR<&+(H8hYpz;X2B#fssDoGjUVR5F?9pD(jD;e-x5)zHJ3P zAx4GXfwkC2S@Kl)UY$+8$g)8+qfO&w0o*z>8ZXAlcW|1sw}0 z(~sc=#56LsK|rXcEHO2|?&x^jZUaFv?1?auA4713s7q>05{*fNNn$K%CW(<`%D2j_ zloFrf5D(J=A`6>V+VNf~Vwm?I9fW3ypl%h!QjeA$Di8%Et$2_=iig1>dEVvN8TVk1 zFkpoZV@?y-DJZr2(9}^;ADY&nHxefrMLYGe<|B|5gH0?OLYLp8j4ks~H?=>WW-%XC zL{c|qK3YJD(8w^{4pRqZu6?vskVQZ$+xVi24Y3OMH3#N<7j;Z(e*Br z?UxgB?hfn3`N&;}5&TD^3Ci0y?f_B!aX>yC z2dy>EMfp6f$ewjn$ac?=M~rxexbt=n zb0G9tk{Y>H8+Yq|fsmbDtJR)$q0XX|TYn3SvO8{o#k<@XKC=f7*M zSAMm;3z18`DeC48%ojuRC+3UD{IP{%VqpUt z9Q5qFQ$&)+7l_FP$~seCy$fQz0yV;*1GGGoU@orId*HPeu%SM;Vdks>vNP$YdOER#AG1p+b68S68KemV|zc2}b4P8?u~3L=|& z*zt)y46Z=+LK#7;uoSF-xB$Uq{0x~uXPb0P2R-t%zafKiOb353+#E|E@{1Awn4kSR zg@Jy&3(q-<4u6;OL&k#`y{1j3Qxt!ve6zwj35QzJc3LM@pvv<_YuZGbh@`b;h>nb& zWuk9c{c?_qK-9QL4H8X1I7lNz(VjM(CdSg5GDJ&8$1>5iY-$-t2Q!^CebJv@pCKAE zT9=9TWfLlBLO#C}>&z@ceRw#G;;%vZY~8!2o26g(x#pUF23cCx2AK-#m+`D1*Ac7C zOt6EbpZwP$P8Al8c!mfs^38^j8@Z2?7w)zY!1d#xB{v%08@f3YF7BD)nHi(<`KxfqBU7%av~I+4fk!HF^rA^7 zUu_lQv*T)O!$Oen5fyFdp`q#t+lgNJ)2pq;o?bFZLlwF|Jib!CakaH^c{NqK*Dt1B zZA{?tvmQ-kvzW&>%VV#>`aSmlUxOnD&GLuWSWD+ZC1}5bmb_+xKDtsV#=L1t9%94PT-+wjDl30(KcnGh zwRk{YPz6hCK;DYad_fZnjX3R3i1Lf%udAR1eK=o^2CVD?^9&oDbjc zY9SW^QMaX?L(i(wjLL)>WwrOM0`gIP4c#A>B?hb!OEmaenX~62Z;T}JMPVgncQF|(R;2a-_aLV&2Cc}gh1Sb37t$9ee{;R%#twtQ>#g+T zpf9l8#of&%U<4+I*uA|E_vc`e57SO!((0WfhTRbs{<1Qey4y;x9dxx?qI=E|H-O8_ zSP+@pm(Nh<_%^bXR$1qp=oO%Z7o+|W|*`mwprjd%dvr>w%wPNmA zqL@gWV3o16MdpRA#kFn3N?Lyki1G&J&`#ioUg7fX1UsYd339hNlrrB{EDTunWSGNR z?LZ%-?7>!6Ays?gd2b5WY{_>&tI1UcS~zF{T<4~ z-}^m-CVfVo^mn{-0X~m;2zbmV=&zsu1`5bsarnv`to`QUBR5*1gbVX;bL@-TTrW27 zRR<#jwCs)5SUP=Bv3X%tlH>cg8JqW+o9i8?@5KfI`g!RO;#A>Nn9p(cl2?HKz`qv{ zBwNcI>+)pP53IxMM&MhlP*DT}H>^>#V>0n6+>8wH#b!_TtCq#Lz&xLjb+=$a4)6DL z-GW7+dO3(s>J;MSoc@jcj>|k$Yb{&60ikAS^TN7Xpgg1g%Dolv(0H>$GOyNJtzpOrhI)ElR% zFpc)~4q3OyN=`d{5^)Mt`dBH-#|4{vtmO#-1eb4?2kWdwjx*|I1b#3WynC(Xi;55w z&{d#wEU1!&d#&_KNaiXxFDygVownBr06)#Mv-9CDQ@q}1Y_2!=(w+(YG>Ws^;cnJx z?S`R=#wnD(z1YpsEl2jkU;_cBbMwL?%a4$#FxfGTl3=}kxG;ZEoR#3lv-?u3j zjpJqlBe+$55fOya#b9GpVo(R*KJszE|E32 zp>=1=mfNhgwap05`(~3WVUoU?#U(`6*Rr@I2#M+4ys+yQmY5g0A!(AfjUm2W8F_G{ z0=G?r(OF9R@?1J+2lx558wL~QSqeYacbi-_ZSy7IH& zMt)_bGIG1MVRa`UzYfxvt{Q-!jY(G)9snwAfNBcM$_6yqX4%vL#oi)&8>~%>Mq_a3 z_&68gyu(^@ZX<#Uzsa%dM!uQFb>M(eqvGy^dU2pJ!w00$A6(=emf<_B<*8K9eK9C? zjyU$vg&fc5Lauk0Hb4StDBrs+N6sTFGbbq0(tJO}W?&b1!jd z;OK@~Ukty3m?q()1QDaYRr(vP^wS8e`KAQyYleTx(RI0R5`Lveqra^{HZ@{L_icDN zw$VySC5g~{=Z2$myS-EPA-DCt2+sMY95zhBzfv`OxKvjKB5_r@`z~CJP$>)VLh&nP z_%3Vhx&R^+9ZkkPRq)fT46dk-!Sif`ccCq|$%(tb#*lR1jb5&uBFC^qS5@=4%)cAi z)X2)aacmxI#0__&%4%dUzy%Kwjij;y_y^h^n2{5A1Lu%*9{|oycm`wmsAIJb$@~L| z)gUVn3mX?3=u;>=$g@Qb9zf}Oq`L`FnapakR;A_v5lk8CpWupS_jt9eLac-$c(rVn zZ{KhE(v8juK(Run+5JRN4mP3KrE;RlT72S@5k%{^`z_bzy%t~{_2=Di*W3LeU1Nry zZU$XBGVdVB?UH2&!IyH`KoIsT(g*Lq(kCD%4ubfAbl(H0PiE4mOcv6|BP;K*Hi7Hy z_gGsn!#;Hn*x4mR_o9dHM>g5o#LJ~TBgRY9vg}^)V?wswYo#QW!;@+zn?vc&x`BIv zt>I8JO4cv^&6td-k|oW+8IX<5Ai^iRnvrd*9BM{>*d}=&sCLVO`{3!66$BN@ru&e< zEBo(5a{r-2@bk*vLsq&g!1>U#dxeL9EK^n;vd+N=fy=S+bnK9|DYcd8iK!f~qOD~} zW=VAZ9$6r*l?(14g*Spj}rtx`QkRUq)shABG13ajx&mK*}s)Czdz z#WWhl5aWxELoFbQkjAR;0AM3x&MA~dEzoc^fMQLwEES9y-o_R%0#-|lbzIs)l90ie zCZQ?!_Dc8tpge%!f*9%6<$jDv%a8Hb$&xE%DUyL7HTR>+!m|5*@Oem%60UxviESww z*S99V=C5&`-_on5<+iyx=hY(yL_W5^Wystq3E046>V z%nc#pxSv3R`PwAF9t~6NBK`dV4f9D1z&3trVHDn~!{;!()p0-R2|}pq+;M-OhWYC9 zh~pO{8s;aS0FP;SK79cbmnc0G5^+4!ci7!({lhe84o^RbDdnu%{q2zd5rge;7!%6(Znr?IO?I6A3-MdGV>8M zw4khc#M++Jf=Eu}g_4N55l3g6oJ43+2;Ou=lDwGN$|}9_QKZH5;g157Th2Uc zEw8PBy^W~xW%dwK!&gKcJt(k)0#TIsFbySvw_bT{`~RxOcY+aGQoN zh#0lGS@5XT9uUG@YQFs%-i_VSWq^Ykz7;UBJfz`6Xea>fhLZRw!aD)$DoyN0cv(#N z9}qqbSaUdWG*TP4GdCu}B(`8z0k#SHoNnj0yL{L z^O3(UvFki_cLj3<1i3DWI36SfIN3u4y2>L)K@s49PJbg{s=^8lKL~gPaHWQyix_Is zf#F)i^?PJMLPIPkgnvSWcEGw0UGLI;7l3uEaD4^18*r;aXf25t=YRl{6c12XYa+On z0#2Qwbtc^?f%xM(d?#*^AdXfMjP`Hc6fx9L*m^8t6p@g&=b z;lJ7Q2O54KFv&oshNmDS9>7|rtS{+`CBQy}<4Gc84i4``JqS+u8oc6b@cOU8Cj)Mp z&2UZu;9kJG0CO(HwHJa2Pz24nlCHr33_U^Te2qDk@F-Ot3||kp3ox??;n0L?8bTwu zmu{y(c%g>708^D^Y4|0;#337o=2LSII(!0f7~!Q3(!a=H8XiON&_aYa+zmC!pc1(K zxP^i;)a~4TY{a-I8$w#9!*e2zU%C;lS?tb-nLu@J!{?CM5CdNTA+7?POZxwj(% zQS1ebX5+pV5%K`*-rZe`@IehzcoV`408_iC^baF^A}0Lj2q%K=^uLZ6CCz~IG{Juc zO!?Jn7P-+GsCf__0qs=Hfhc&cmkuHz0SOJ|8L;O(G`u=uY!4wkSHl}%I8g?=Rn3Kr zsHqPf{;h~(&p7hO%e35k%>_&LkPsDX7~Q9u6VVB-0^Eo2QVstg;<&X2@B$rwKV9+x zSeI~aGs20*q$kij&V}YHgN)57(&>K@any|FGl)Y3QzRuv4-V8(v(X6VqnU-X0qYFrA4d@Y>pGl&2Ew}lYl7y(BnuA#)&$Sripd|6fm}tv z{L5)F2n6ZAVE(R%abq7~JO1}^&q6g3(4`YJ;vwl?MDS?%0lZp0i11bocjDRM3WR5B z_?IA%N@NrGB3-2cxL${ksH-z!D3~9zVwEv_nH0cGmTSxddBJ?AIW>FFpPh%yjNV7QUW`q|aTuXJ*?SS*6 z2#q9k-v=NgjvkHgG1NI_XvgmY+y|HofcBsCe8jjX01vI1l3oQ&CCJkV#sPN$j%fH3 zAOL9Vg#~C<_qG9UP~i(a5V{~>-T5q71_P%@lQt!3kCm_JD zBcOL%@C>AQ0qQkF5cqw3AMRPL|J^?sahwp|xFa%i3jQ5s^@kEg9 zPdmegi18#LXx0f10geFf*YI<6M=fBjTD{;?VDddvPW}J5O0Woup$)^1KO6wd4IRHEV)OvEN3)BdIeYqI z;JYHYjTf-)TNWKcZ`lOcrBwSOnDx(jkbk^SBYYZlNF~;FxCnOsZ$h(u!=gW;1XT#v zC0O*gi1ETG!nM#YA{i(_xKCw}3>oMLM@+B6pN#JI=6;0hR+XHNX2@%0x=xaVm=LB2 z**ZZMO%Q{nTJa>G1*tAZxHdSF!GTw(j&)zK5Ss7R2Ee+`ldk{_e6)uSY%`Lp1y`fLlR;4WqMpgW^x>_%Fih9RRGGY4WSkjOBne z2b1537$YPDGde!{mcKYbiyoLHe-Wv5)HWi*LdCKa*!_Pk0)_o5K??N32Y!TW0#jDt z;Dr}Pq*I4)fa1zRxF#UwbP&)9SXWU>5$YWHY?h~>``s4+tO-oH26p|exw8q{5P&vl4-ra57L3KN^nicrp_O)Iyw6 z`{#(`mPtgQfd@2I$~%A|R8b256*2ye1knuti*RDO&d@i9PD`M()Ex4qL>$inc2b2y zulSZiX2uaeSK;@ed%oE-i@(-)0;HBQ)GYIzfd~P>y50KDr(4VclT?Evz8w)W1qiar zRTcOuF=5exa4p2X8?oiR0&t!VuK|qk`4tL|JBav=(fGB7?>2Ze!9x#~eD{H%2Ee-i z_dSAXHI&HI&C1t>nSLsPmU7=qD6wB7q!Ry;Rss+|OB3*J#PPFfga>p1{u6Pq&B+Bu z`%iU69FMtYBc!6g{%Lg#oD(tK1JDyy3SlamA2Hac&~;dR08IUVY6CWSgT;0`O~v5y<{m`Q97t^i+!+IRVB2>E zVBPto{vLBY=K$7oKB<2N2Ri`kky7gW=xj)D=vI>Y5n4^Af?dSgCITSjX(b>a8?Z_9 zFCZYT3<%5MVP|l4#PPjpz`9kW-GmaNPVEw=L1u311FV~6+C9ji1+dm5X%B%QDxpo_ z;~=OSuuTw}WgT%enfOl>{T3c1gmW}Jgl5wRc$tQYrNjZv(zFjDbUwhErD@Rp)iZ$c z>I30Rj|WW6P7{z04pt8UPSxQn0CxedwG(WF2bI81a7M&&Lpg-3Stmd3YYzF(ikQC)0H$`0mgGk>e30VnI`)@gg##e=#jEhE z5uac?{`UdrA%7G9F@k;Q%_4|EB_Im#1Hv-ES~2`8L|sF1Gv^R>ya@Jt$-3}1Q~uH1Q>v5p0`e`t$?R4RR-$$8IojTBe;-(NruNs zaEf#$|Ax9I$tNx$lg04}p9UPzFsz!#W8`Qt<`5ny!M5XLaKnbJ9UsHJ+MmT_u=oZ< zh|K__m!HKVK!5PF>X-}jvvQl5cn3tWAF!{ZGRktKTvxkJYqAr3vg@(7()LzHiKs)jvvKl z0B!l>*bFc=_oLVhAn8Af!M}7N;28Y1OIO1qCWED?MjY)i87#dB;V~I3h0)O-lflwG zfMYYbA8a|MZ>?3nNEam{*j&nuWEti%pX!N$(WsuN0xZzN(1@13gGLpMfg=&~rvbo5 z1~=wqklCkNX2X|bNbp1x!3zKKB!vG8u+DG!(ui4mPBT367r@gnmT!ufj~4^h2$$zY z%#NZM_-r7ca81ziizDXQq-v&g`fCv08WVnN#C)s^s-{2@xcm-!VG-SDosKUfwPqIRJegSVl0-3Zt9 z5xfidMgclCz82Vw9eFVk9)*BqN%u>j3wYxv7O-FhpO2V7D~yQ-w%v+eHo>XG{|Gt? z2(K;&ps*1W<3o1ncx`kU<|{oxzF?kPBxFoC|{50c*)# zkspz(e`hUQPqJaBfp&Q6<(N1-P)Nd|3$fxlgty6>-+^}!nK+^gjc&yc;oXO5P7Obe ztOI~;w7uv~`v3+|(G>r85yuAr>+GWb2|Xo++wchL5Ug=!>Y_qzKh=w1P5MgA2gtPF z5rH{2Ivq+HMEndyEb1dqAVJA!?I#TBHHziX@3CdE15P`?2cU_jD5|Cp zMo`yZ0d7-FTM5nj)Q_Zp0KA=mw{B)D--P!;z^0D&PgFCt7ma3>1I6qFsEfJE3o!`* zE>OihkM%?%uI|_Z8Rgyu5Pz zwKs$hFCDTTGY|jykJb$fvGcF+J?jl~lMKFZ{qAu5->pPb{^NZs?eLrl%R3i`QUae? z=Q+;El2xBri!Eg0*w+P3*CqQtv6jS-8IJqQWbY@|^7sgxRkHI_IKi;{>y*<2XOnUU z;B1qnpIXZj?gyItyJS5@#v51<_*INfI5Xuid|iET=3!{)JMJGwj>kB)!w{xfLfd-%vzW*P9>kv2q diff --git a/roms/seabios-hppa b/roms/seabios-hppa index 17ca7a9998..458626c4c6 160000 --- a/roms/seabios-hppa +++ b/roms/seabios-hppa @@ -1 +1 @@ -Subproject commit 17ca7a9998c1755d42321cfc0afb5f480f5a58ff +Subproject commit 458626c4c6441045c0612f24313c7cf1f95e71c6 From 12629fcf4df783f67e84173a18c9a511d37eb62d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 10:02:24 -0700 Subject: [PATCH 530/935] target/m68k: Clear mach in m68k_cpu_disas_set_info Zero selects all cpu features in disas/m68k.c, which is really what we want -- not limited to 68040. Signed-off-by: Richard Henderson Reviewed-by: Laurent Vivier Message-Id: <20220430170225.326447-2-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- target/m68k/cpu.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index c7aeb7da9c..5671067923 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -75,12 +75,8 @@ static void m68k_cpu_reset(DeviceState *dev) static void m68k_cpu_disas_set_info(CPUState *s, disassemble_info *info) { - M68kCPU *cpu = M68K_CPU(s); - CPUM68KState *env = &cpu->env; info->print_insn = print_insn_m68k; - if (m68k_feature(env, M68K_FEATURE_M68000)) { - info->mach = bfd_mach_m68040; - } + info->mach = 0; } /* CPU models */ From abc098351e533de5ca0ed9c90901f9f4dac348fc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 30 Apr 2022 10:02:25 -0700 Subject: [PATCH 531/935] target/m68k: Enable halt insn for 68060 Signed-off-by: Richard Henderson Reviewed-by: Laurent Vivier Message-Id: <20220430170225.326447-3-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- target/m68k/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 4026572ed8..e4efd988d2 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -6003,6 +6003,7 @@ void register_m68k_insns (CPUM68KState *env) INSN(tas, 4ac0, ffc0, M68000); #if defined(CONFIG_SOFTMMU) INSN(halt, 4ac8, ffff, CF_ISA_A); + INSN(halt, 4ac8, ffff, M68060); #endif INSN(pulse, 4acc, ffff, CF_ISA_A); BASE(illegal, 4afc, ffff); From f73eb9484bf07812db21de985cb9c1e4ad3c82a9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 7 May 2022 07:48:26 +0200 Subject: [PATCH 532/935] pseries: allow setting stdout-path even on machines with a VGA -machine graphics=off is the usual way to tell the firmware or the OS that the user wants a serial console. The pseries machine however does not support this, and never adds the stdout-path node to the device tree if a VGA device is provided. This is in addition to the other magic behavior of VGA devices, which is to add a keyboard and mouse to the default USB bus. Split spapr->has_graphics in two variables so that the two behaviors can be separated: the USB devices remains the same, but the stdout-path is added even with "-device VGA -machine graphics=off". Reviewed-by: Daniel Henrique Barboza Signed-off-by: Paolo Bonzini Message-Id: <20220507054826.124936-1-pbonzini@redhat.com> Signed-off-by: Daniel Henrique Barboza --- hw/ppc/spapr.c | 12 ++++++++---- include/hw/ppc/spapr.h | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 6de800524a..d112b85b4f 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1066,7 +1066,7 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset) _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-device", boot_device)); } - if (!spapr->has_graphics && stdout_path) { + if (spapr->want_stdout_path && stdout_path) { /* * "linux,stdout-path" and "stdout" properties are * deprecated by linux kernel. New platforms should only @@ -2712,6 +2712,7 @@ static void spapr_machine_init(MachineState *machine) const char *kernel_filename = machine->kernel_filename; const char *initrd_filename = machine->initrd_filename; PCIHostState *phb; + bool has_vga; int i; MemoryRegion *sysmem = get_system_memory(); long load_limit, fw_size; @@ -2950,9 +2951,12 @@ static void spapr_machine_init(MachineState *machine) } /* Graphics */ - if (spapr_vga_init(phb->bus, &error_fatal)) { - spapr->has_graphics = true; + has_vga = spapr_vga_init(phb->bus, &error_fatal); + if (has_vga) { + spapr->want_stdout_path = !machine->enable_graphics; machine->usb |= defaults_enabled() && !machine->usb_disabled; + } else { + spapr->want_stdout_path = true; } if (machine->usb) { @@ -2962,7 +2966,7 @@ static void spapr_machine_init(MachineState *machine) pci_create_simple(phb->bus, -1, "nec-usb-xhci"); } - if (spapr->has_graphics) { + if (has_vga) { USBBus *usb_bus = usb_bus_find(-1); usb_create_simple(usb_bus, "usb-kbd"); diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 14b01c3f59..072dda2c72 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -194,7 +194,7 @@ struct SpaprMachineState { Vof *vof; uint64_t rtc_offset; /* Now used only during incoming migration */ struct PPCTimebase tb; - bool has_graphics; + bool want_stdout_path; uint32_t vsmt; /* Virtual SMT mode (KVM's "core stride") */ /* Nested HV support (TCG only) */ From 1e665723e92cd3dae4d8943bf7bd1799a3b4a82a Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Thu, 5 May 2022 18:18:01 +0200 Subject: [PATCH 533/935] hw/ppc/e500: Remove unused BINARY_DEVICE_TREE_FILE Commit 28290f37e20cda27574f15be9e9499493e3d0fe8 'PPC: E500: Generate device tree on reset' improved device tree generation and made BINARY_DEVICE_TREE_FILE obsolete. Signed-off-by: Bernhard Beschow Reviewed-by: Daniel Henrique Barboza Message-Id: <20220505161805.11116-8-shentey@gmail.com> Signed-off-by: Daniel Henrique Barboza --- hw/ppc/e500.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 2bc3dce1fb..7f7f5b3452 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -47,7 +47,6 @@ #include "hw/irq.h" #define EPAPR_MAGIC (0x45504150) -#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" #define DTC_LOAD_PAD 0x1800000 #define DTC_PAD_MASK 0xFFFFF #define DTB_MAX_SIZE (8 * MiB) From 5bb55f3e3b00679519a83ffe688eae0e68e305a7 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 4 May 2022 16:55:36 +1000 Subject: [PATCH 534/935] spapr: Use address from elf parser for kernel address tl;dr: This allows Big Endian zImage booting via -kernel + x-vof=on. QEMU loads the kernel at 0x400000 by default which works most of the time as Linux kernels are relocatable, 64bit and compiled with "-pie" (position independent code). This works for a little endian zImage too. However a big endian zImage is compiled without -pie, is 32bit, linked to 0x4000000 so current QEMU ends up loading it at 0x4400000 but keeps spapr->kernel_addr unchanged so booting fails. This uses the kernel address returned from load_elf(). If the default kernel_addr is used, there is no change in behavior (as translate_kernel_address() takes care of this), which is: LE/BE vmlinux and LE zImage boot, BE zImage does not. If the VM created with "-machine kernel-addr=0,x-vof=on", then QEMU prints a warning and BE zImage boots. Note #1: SLOF (x-vof=off) still cannot boot a big endian zImage as SLOF enables MSR_SF for everything loaded by QEMU and this leads to early crash of 32bit zImage. Note #2: BE/LE vmlinux images set MSR_SF in early boot so these just work; a LE zImage restores MSR_SF after every CI call and we are lucky enough not to crash before the first CI call. Signed-off-by: Alexey Kardashevskiy Tested-by: Joel Stanley Reviewed-by: Fabiano Rosas Message-Id: <20220504065536.3534488-1-aik@ozlabs.ru> [danielhb: use PRIx64 instead of lx in warn_report] Signed-off-by: Daniel Henrique Barboza --- hw/ppc/spapr.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index d112b85b4f..fd4942e881 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2975,14 +2975,16 @@ static void spapr_machine_init(MachineState *machine) } if (kernel_filename) { + uint64_t loaded_addr = 0; + spapr->kernel_size = load_elf(kernel_filename, NULL, translate_kernel_address, spapr, - NULL, NULL, NULL, NULL, 1, + NULL, &loaded_addr, NULL, NULL, 1, PPC_ELF_MACHINE, 0, 0); if (spapr->kernel_size == ELF_LOAD_WRONG_ENDIAN) { spapr->kernel_size = load_elf(kernel_filename, NULL, translate_kernel_address, spapr, - NULL, NULL, NULL, NULL, 0, + NULL, &loaded_addr, NULL, NULL, 0, PPC_ELF_MACHINE, 0, 0); spapr->kernel_le = spapr->kernel_size > 0; } @@ -2992,6 +2994,13 @@ static void spapr_machine_init(MachineState *machine) exit(1); } + if (spapr->kernel_addr != loaded_addr) { + warn_report("spapr: kernel_addr changed from 0x%"PRIx64 + " to 0x%"PRIx64, + spapr->kernel_addr, loaded_addr); + spapr->kernel_addr = loaded_addr; + } + /* load initrd */ if (initrd_filename) { /* Try to locate the initrd in the gap between the kernel From 162eec18c0aed28eda472bacf207b7b222894169 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Fri, 6 May 2022 15:51:24 +1000 Subject: [PATCH 535/935] spapr/docs: Add a few words about x-vof The alternative small firmware needs a few words of what it can and absolutely cannot do; this adds those words. Reviewed-by: Daniel Henrique Barboza Signed-off-by: Alexey Kardashevskiy Message-Id: <20220506055124.3822112-1-aik@ozlabs.ru> [danielhb: added linebreaks before and after table] Signed-off-by: Daniel Henrique Barboza --- docs/system/ppc/pseries.rst | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/system/ppc/pseries.rst b/docs/system/ppc/pseries.rst index d9b65ad4e8..3e1bbe6726 100644 --- a/docs/system/ppc/pseries.rst +++ b/docs/system/ppc/pseries.rst @@ -32,14 +32,43 @@ Missing devices Firmware ======== +The pSeries platform in QEMU comes with 2 firmwares: + `SLOF `_ (Slimline Open Firmware) is an implementation of the `IEEE 1275-1994, Standard for Boot (Initialization Configuration) Firmware: Core Requirements and Practices `_. +SLOF performs bus scanning, PCI resource allocation, provides the client +interface to boot from block devices and network. + QEMU includes a prebuilt image of SLOF which is updated when a more recent version is required. +VOF (Virtual Open Firmware) is a minimalistic firmware to work with +``-machine pseries,x-vof=on``. When enabled, the firmware acts as a slim +shim and QEMU implements parts of the IEEE 1275 Open Firmware interface. + +VOF does not have device drivers, does not do PCI resource allocation and +relies on ``-kernel`` used with Linux kernels recent enough (v5.4+) +to PCI resource assignment. It is ideal to use with petitboot. + +Booting via ``-kernel`` supports the following: + ++-------------------+-------------------+------------------+ +| kernel | pseries,x-vof=off | pseries,x-vof=on | ++===================+===================+==================+ +| vmlinux BE | ✓ | ✓ | ++-------------------+-------------------+------------------+ +| vmlinux LE | ✓ | ✓ | ++-------------------+-------------------+------------------+ +| zImage.pseries BE | x | ✓¹ | ++-------------------+-------------------+------------------+ +| zImage.pseries LE | ✓ | ✓ | ++-------------------+-------------------+------------------+ + +¹ must set kernel-addr=0 + Build directions ================ From c9f8004b6adf7020ba742d16b132e84ff6e57863 Mon Sep 17 00:00:00 2001 From: Murilo Opsfelder Araujo Date: Tue, 10 May 2022 20:54:39 -0300 Subject: [PATCH 536/935] mos6522: fix linking error when CONFIG_MOS6522 is not set When CONFIG_MOS6522 is not set, building ppc64-softmmu target fails: /usr/bin/ld: libqemu-ppc64-softmmu.fa.p/monitor_misc.c.o:(.data+0x1158): undefined reference to `hmp_info_via' Make devices configuration available in hmp-commands*.hx and check for CONFIG_MOS6522. Fixes: 409e9f7131e5 (mos6522: add "info via" HMP command for debugging) Signed-off-by: Murilo Opsfelder Araujo Cc: Mark Cave-Ayland Cc: Fabiano Rosas Cc: Thomas Huth Reviewed-by: Thomas Huth Message-Id: <20220510235439.54775-1-muriloo@linux.ibm.com> Signed-off-by: Daniel Henrique Barboza --- hmp-commands-info.hx | 2 +- monitor/misc.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index adfa085a9b..834bed089e 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -880,7 +880,7 @@ SRST Show intel SGX information. ERST -#if defined(TARGET_M68K) || defined(TARGET_PPC) +#if defined(CONFIG_MOS6522) { .name = "via", .args_type = "", diff --git a/monitor/misc.c b/monitor/misc.c index 6c5bb82d3b..3d2312ba8d 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -84,6 +84,9 @@ #include "hw/s390x/storage-attributes.h" #endif +/* Make devices configuration available for use in hmp-commands*.hx templates */ +#include CONFIG_DEVICES + /* file descriptors passed via SCM_RIGHTS */ typedef struct mon_fd_t mon_fd_t; struct mon_fd_t { From 4ddc104689b186c4e4ed30be59a54463501761cf Mon Sep 17 00:00:00 2001 From: Leandro Lupori Date: Tue, 3 May 2022 13:39:04 -0300 Subject: [PATCH 537/935] target/ppc: Fix tlbie Commit 74c4912f097bab98 changed check_tlb_flush() to use tlb_flush_all_cpus_synced() instead of calling tlb_flush() on each CPU. However, as side effect of this, a CPU executing a ptesync after a tlbie will have its TLB flushed only after exiting its current Translation Block (TB). This causes memory accesses to invalid pages to succeed, if they happen to be on the same TB as the ptesync. To fix this, use tlb_flush_all_cpus() instead, that immediately flushes the TLB of the CPU executing the ptesync instruction. Fixes: 74c4912f097bab98 ("target/ppc: Fix synchronization of mttcg with broadcast TLB flushes") Signed-off-by: Leandro Lupori Reviewed-by: Fabiano Rosas Message-Id: <20220503163904.22575-1-leandro.lupori@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/helper_regs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index 6159a15b7b..12235ea2e9 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -292,7 +292,7 @@ void check_tlb_flush(CPUPPCState *env, bool global) if (global && (env->tlb_need_flush & TLB_NEED_GLOBAL_FLUSH)) { env->tlb_need_flush &= ~TLB_NEED_GLOBAL_FLUSH; env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; - tlb_flush_all_cpus_synced(cs); + tlb_flush_all_cpus(cs); return; } From 3278677f6a5e048b17ea7623c107786448fdf6f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Tue, 17 May 2022 13:15:20 -0300 Subject: [PATCH 538/935] target/ppc: Fix FPSCR.FI bit being cleared when it shouldn't MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to Power ISA, the FI bit in FPSCR is non-sticky. This means that if an instruction is said to modify the FI bit, then it should be set or cleared depending on the result of the instruction. Otherwise, it should be kept as was before. However, the following inconsistency was found when comparing results from the hardware (tested on both a Power 9 processor and in Power 10 Mambo): (FI bit is set before the execution of the instruction) Hardware: xscmpeqdp(0xff..ff, 0xff..ff) = FI: SET -> SET QEMU: xscmpeqdp(0xff..ff, 0xff..ff) = FI: SET -> CLEARED As the FI bit is non-sticky, and xscmpeqdp does not list it as a field that is changed by the instruction, it should not be changed after its execution. This is happening to multiple instructions in the vsx implementations. If the ISA does not list the FI bit as altered for a particular instruction, then it should be kept as it was before the instruction. QEMU is not following this behavior. Affected instructions include: - xv* (all vsx-vector instructions); - xscmp*, xsmax*, xsmin*; - xstdivdp and similars; (to identify the affected instructions, just search in the ISA for the instructions that does not list FI in "Special Registers Altered") Most instructions use the function do_float_check_status() to commit changes in the inexact flag. So the fix is to add a parameter to it that will control if the bit FI should be changed or not. All users of do_float_check_status() are then modified to provide this argument, controlling if that specific instruction changes bit FI or not. Some macro helpers are responsible for both instructions that change and instructions that aren't suposed to change FI. This seems to always overlap with the sfprf flag. So, reuse this flag for this purpose when applicable. Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Message-Id: <20220517161522.36132-2-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 2 + target/ppc/fpu_helper.c | 122 +++++++++++++++++++++------------------- 2 files changed, 66 insertions(+), 58 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 48596cfb25..901ded79e9 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -735,6 +735,8 @@ enum { (1 << FPSCR_VXSOFT) | (1 << FPSCR_VXSQRT) | \ (1 << FPSCR_VXCVI)) +FIELD(FPSCR, FI, FPSCR_FI, 1) + #define FP_DRN2 (1ull << FPSCR_DRN2) #define FP_DRN1 (1ull << FPSCR_DRN1) #define FP_DRN0 (1ull << FPSCR_DRN0) diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index f6c8318a71..f1ea4aa10e 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -370,7 +370,6 @@ static inline void float_inexact_excp(CPUPPCState *env) { CPUState *cs = env_cpu(env); - env->fpscr |= FP_FI; env->fpscr |= FP_XX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; @@ -462,7 +461,8 @@ void helper_fpscr_check_status(CPUPPCState *env) } } -static void do_float_check_status(CPUPPCState *env, uintptr_t raddr) +static void do_float_check_status(CPUPPCState *env, bool change_fi, + uintptr_t raddr) { CPUState *cs = env_cpu(env); int status = get_float_exception_flags(&env->fp_status); @@ -474,8 +474,10 @@ static void do_float_check_status(CPUPPCState *env, uintptr_t raddr) } if (status & float_flag_inexact) { float_inexact_excp(env); - } else { - env->fpscr &= ~FP_FI; /* clear the FPSCR[FI] bit */ + } + if (change_fi) { + env->fpscr = FIELD_DP64(env->fpscr, FPSCR, FI, + !!(status & float_flag_inexact)); } if (cs->exception_index == POWERPC_EXCP_PROGRAM && @@ -490,7 +492,7 @@ static void do_float_check_status(CPUPPCState *env, uintptr_t raddr) void helper_float_check_status(CPUPPCState *env) { - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); } void helper_reset_fpstatus(CPUPPCState *env) @@ -684,7 +686,7 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \ } else { \ farg.d = cvtr(arg, &env->fp_status); \ } \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, true, GETPC()); \ return farg.ll; \ } @@ -710,7 +712,7 @@ static uint64_t do_fri(CPUPPCState *env, uint64_t arg, /* fri* does not set FPSCR[XX] */ set_float_exception_flags(flags & ~float_flag_inexact, &env->fp_status); - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); return arg; } @@ -1721,7 +1723,7 @@ void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \ } \ } \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfprf, GETPC()); \ } VSX_ADD_SUB(xsadddp, add, 1, float64, VsrD(0), 1, 0) @@ -1757,7 +1759,7 @@ void helper_xsaddqp(CPUPPCState *env, uint32_t opcode, helper_compute_fprf_float128(env, t.f128); *xt = t; - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); } /* @@ -1798,7 +1800,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfprf, GETPC()); \ } VSX_MUL(xsmuldp, 1, float64, VsrD(0), 1, 0) @@ -1828,7 +1830,7 @@ void helper_xsmulqp(CPUPPCState *env, uint32_t opcode, helper_compute_fprf_float128(env, t.f128); *xt = t; - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); } /* @@ -1872,7 +1874,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfprf, GETPC()); \ } VSX_DIV(xsdivdp, 1, float64, VsrD(0), 1, 0) @@ -1905,7 +1907,7 @@ void helper_xsdivqp(CPUPPCState *env, uint32_t opcode, helper_compute_fprf_float128(env, t.f128); *xt = t; - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); } /* @@ -1940,7 +1942,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfprf, GETPC()); \ } VSX_RE(xsredp, 1, float64, VsrD(0), 1, 0) @@ -1985,7 +1987,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfprf, GETPC()); \ } VSX_SQRT(xssqrtdp, 1, float64, VsrD(0), 1, 0) @@ -2029,7 +2031,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfprf, GETPC()); \ } VSX_RSQRTE(xsrsqrtedp, 1, float64, VsrD(0), 1, 0) @@ -2182,7 +2184,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ } \ } \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfprf, GETPC()); \ } VSX_MADD(XSMADDDP, 1, float64, VsrD(0), MADD_FLGS, 1) @@ -2234,7 +2236,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *s1, ppc_vsr_t *s2,\ \ helper_compute_fprf_float128(env, t.f128); \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, true, GETPC()); \ } VSX_MADDQ(XSMADDQP, MADD_FLGS, 0) @@ -2283,7 +2285,7 @@ VSX_MADDQ(XSNMSUBQPO, NMSUB_FLGS, 0) \ memset(xt, 0, sizeof(*xt)); \ memset(&xt->fld, -r, sizeof(xt->fld)); \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, false, GETPC()); \ } VSX_SCALAR_CMP(XSCMPEQDP, float64, eq, VsrD(0), 0) @@ -2319,7 +2321,7 @@ void helper_xscmpexpdp(CPUPPCState *env, uint32_t opcode, env->fpscr |= cc << FPSCR_FPCC; env->crf[BF(opcode)] = cc; - do_float_check_status(env, GETPC()); + do_float_check_status(env, false, GETPC()); } void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode, @@ -2348,7 +2350,7 @@ void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode, env->fpscr |= cc << FPSCR_FPCC; env->crf[BF(opcode)] = cc; - do_float_check_status(env, GETPC()); + do_float_check_status(env, false, GETPC()); } static inline void do_scalar_cmp(CPUPPCState *env, ppc_vsr_t *xa, ppc_vsr_t *xb, @@ -2401,7 +2403,7 @@ static inline void do_scalar_cmp(CPUPPCState *env, ppc_vsr_t *xa, ppc_vsr_t *xb, float_invalid_op_vxvc(env, 0, GETPC()); } - do_float_check_status(env, GETPC()); + do_float_check_status(env, false, GETPC()); } void helper_xscmpodp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa, @@ -2466,7 +2468,7 @@ static inline void do_scalar_cmpq(CPUPPCState *env, ppc_vsr_t *xa, float_invalid_op_vxvc(env, 0, GETPC()); } - do_float_check_status(env, GETPC()); + do_float_check_status(env, false, GETPC()); } void helper_xscmpoqp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa, @@ -2505,7 +2507,7 @@ void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, false, GETPC()); \ } VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, VsrD(0)) @@ -2688,7 +2690,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfprf, GETPC()); \ } VSX_CVT_FP_TO_FP(xscvspdp, 1, float32, float64, VsrW(0), VsrD(0), 1) @@ -2714,7 +2716,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfprf, GETPC()); \ } VSX_CVT_FP_TO_FP2(xvcvdpsp, 2, float64, float32, 0) @@ -2750,7 +2752,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, true, GETPC()); \ } VSX_CVT_FP_TO_FP_VECTOR(xscvdpqp, 1, float64, float128, VsrD(0), f128, 1) @@ -2785,7 +2787,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfprf, GETPC()); \ } VSX_CVT_FP_TO_FP_HP(xscvdphp, 1, float64, float16, VsrD(0), VsrH(3), 1) @@ -2810,7 +2812,7 @@ void helper_XVCVSPBF16(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) } *xt = t; - do_float_check_status(env, GETPC()); + do_float_check_status(env, false, GETPC()); } void helper_XSCVQPDP(CPUPPCState *env, uint32_t ro, ppc_vsr_t *xt, @@ -2833,7 +2835,7 @@ void helper_XSCVQPDP(CPUPPCState *env, uint32_t ro, ppc_vsr_t *xt, helper_compute_fprf_float64(env, t.VsrD(0)); *xt = t; - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); } uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb) @@ -2889,9 +2891,10 @@ uint64_t helper_xscvspdpn(CPUPPCState *env, uint64_t xb) * ttp - target type (int32, uint32, int64 or uint64) * sfld - source vsr_t field * tfld - target vsr_t field + * sfi - set FI * rnan - resulting NaN */ -#define VSX_CVT_FP_TO_INT(op, nels, stp, ttp, sfld, tfld, rnan) \ +#define VSX_CVT_FP_TO_INT(op, nels, stp, ttp, sfld, tfld, sfi, rnan) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ { \ int all_flags = env->fp_status.float_exception_flags, flags; \ @@ -2910,20 +2913,23 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ \ *xt = t; \ env->fp_status.float_exception_flags = all_flags; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfi, GETPC()); \ } -VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0), VsrD(0), \ +VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0), VsrD(0), true, \ 0x8000000000000000ULL) -VSX_CVT_FP_TO_INT(xscvdpuxds, 1, float64, uint64, VsrD(0), VsrD(0), 0ULL) -VSX_CVT_FP_TO_INT(xvcvdpsxds, 2, float64, int64, VsrD(i), VsrD(i), \ +VSX_CVT_FP_TO_INT(xscvdpuxds, 1, float64, uint64, VsrD(0), VsrD(0), true, 0ULL) +VSX_CVT_FP_TO_INT(xvcvdpsxds, 2, float64, int64, VsrD(i), VsrD(i), false, \ 0x8000000000000000ULL) -VSX_CVT_FP_TO_INT(xvcvdpuxds, 2, float64, uint64, VsrD(i), VsrD(i), 0ULL) -VSX_CVT_FP_TO_INT(xvcvspsxds, 2, float32, int64, VsrW(2 * i), VsrD(i), \ +VSX_CVT_FP_TO_INT(xvcvdpuxds, 2, float64, uint64, VsrD(i), VsrD(i), false, \ + 0ULL) +VSX_CVT_FP_TO_INT(xvcvspsxds, 2, float32, int64, VsrW(2 * i), VsrD(i), false, \ 0x8000000000000000ULL) -VSX_CVT_FP_TO_INT(xvcvspsxws, 4, float32, int32, VsrW(i), VsrW(i), 0x80000000U) -VSX_CVT_FP_TO_INT(xvcvspuxds, 2, float32, uint64, VsrW(2 * i), VsrD(i), 0ULL) -VSX_CVT_FP_TO_INT(xvcvspuxws, 4, float32, uint32, VsrW(i), VsrW(i), 0U) +VSX_CVT_FP_TO_INT(xvcvspsxws, 4, float32, int32, VsrW(i), VsrW(i), false, \ + 0x80000000ULL) +VSX_CVT_FP_TO_INT(xvcvspuxds, 2, float32, uint64, VsrW(2 * i), VsrD(i), \ + false, 0ULL) +VSX_CVT_FP_TO_INT(xvcvspuxws, 4, float32, uint32, VsrW(i), VsrW(i), false, 0U) #define VSX_CVT_FP_TO_INT128(op, tp, rnan) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ @@ -2940,7 +2946,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, true, GETPC()); \ } VSX_CVT_FP_TO_INT128(XSCVQPUQZ, uint128, 0) @@ -2955,7 +2961,7 @@ VSX_CVT_FP_TO_INT128(XSCVQPSQZ, int128, 0x8000000000000000ULL); * words 0 and 1 (and words 2 and 3) of the result register, as * is required by this version of the architecture. */ -#define VSX_CVT_FP_TO_INT2(op, nels, stp, ttp, rnan) \ +#define VSX_CVT_FP_TO_INT2(op, nels, stp, ttp, sfi, rnan) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ { \ int all_flags = env->fp_status.float_exception_flags, flags; \ @@ -2977,13 +2983,13 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ \ *xt = t; \ env->fp_status.float_exception_flags = all_flags; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfi, GETPC()); \ } -VSX_CVT_FP_TO_INT2(xscvdpsxws, 1, float64, int32, 0x80000000U) -VSX_CVT_FP_TO_INT2(xscvdpuxws, 1, float64, uint32, 0U) -VSX_CVT_FP_TO_INT2(xvcvdpsxws, 2, float64, int32, 0x80000000U) -VSX_CVT_FP_TO_INT2(xvcvdpuxws, 2, float64, uint32, 0U) +VSX_CVT_FP_TO_INT2(xscvdpsxws, 1, float64, int32, true, 0x80000000U) +VSX_CVT_FP_TO_INT2(xscvdpuxws, 1, float64, uint32, true, 0U) +VSX_CVT_FP_TO_INT2(xvcvdpsxws, 2, float64, int32, false, 0x80000000U) +VSX_CVT_FP_TO_INT2(xvcvdpuxws, 2, float64, uint32, false, 0U) /* * VSX_CVT_FP_TO_INT_VECTOR - VSX floating point to integer conversion @@ -3008,7 +3014,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, true, GETPC()); \ } VSX_CVT_FP_TO_INT_VECTOR(xscvqpsdz, float128, int64, f128, VsrD(0), \ @@ -3047,7 +3053,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfprf, GETPC()); \ } VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, VsrD(0), VsrD(0), 1, 0) @@ -3073,7 +3079,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, false, GETPC()); \ } VSX_CVT_INT_TO_FP2(xvcvsxdsp, int64, float32) @@ -3085,7 +3091,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)\ helper_reset_fpstatus(env); \ xt->f128 = tp##_to_float128(xb->s128, &env->fp_status); \ helper_compute_fprf_float128(env, xt->f128); \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, true, GETPC()); \ } VSX_CVT_INT128_TO_FP(XSCVUQQP, uint128); @@ -3109,7 +3115,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \ helper_compute_fprf_##ttp(env, t.tfld); \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, true, GETPC()); \ } VSX_CVT_INT_TO_FP_VECTOR(xscvsdqp, int64, float128, VsrD(0), f128) @@ -3167,7 +3173,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ } \ \ *xt = t; \ - do_float_check_status(env, GETPC()); \ + do_float_check_status(env, sfprf, GETPC()); \ } VSX_ROUND(xsrdpi, 1, float64, VsrD(0), float_round_ties_away, 1) @@ -3195,7 +3201,7 @@ uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb) uint64_t xt = do_frsp(env, xb, GETPC()); helper_compute_fprf_float64(env, xt); - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); return xt; } @@ -3355,7 +3361,7 @@ void helper_xsrqpi(CPUPPCState *env, uint32_t opcode, } helper_compute_fprf_float128(env, t.f128); - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); *xt = t; } @@ -3408,7 +3414,7 @@ void helper_xsrqpxp(CPUPPCState *env, uint32_t opcode, helper_compute_fprf_float128(env, t.f128); *xt = t; - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); } void helper_xssqrtqp(CPUPPCState *env, uint32_t opcode, @@ -3434,7 +3440,7 @@ void helper_xssqrtqp(CPUPPCState *env, uint32_t opcode, helper_compute_fprf_float128(env, t.f128); *xt = t; - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); } void helper_xssubqp(CPUPPCState *env, uint32_t opcode, @@ -3460,5 +3466,5 @@ void helper_xssubqp(CPUPPCState *env, uint32_t opcode, helper_compute_fprf_float128(env, t.f128); *xt = t; - do_float_check_status(env, GETPC()); + do_float_check_status(env, true, GETPC()); } From c582a1dbc8e44f5e976ce9c2ac4ce0bc38a33cae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Tue, 17 May 2022 13:15:21 -0300 Subject: [PATCH 539/935] target/ppc: Fix FPSCR.FI changing in float_overflow_excp() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes another not-so-clear situation in Power ISA regarding the inexact bits in FPSCR. The ISA states that: """ When Overflow Exception is disabled (OE=0) and an Overflow Exception occurs, the following actions are taken: ... 2. Inexact Exception is set XX <- 1 ... FI is set to 1 ... """ However, when tested on a Power 9 hardware, some instructions that trigger an OX don't set the FI bit: xvcvdpsp(0x4050533fcdb7b95ff8d561c40bf90996) = FI: CLEARED -> CLEARED xvnmsubmsp(0xf3c0c1fc8f3230, 0xbeaab9c5) = FI: CLEARED -> CLEARED (just a few examples. Other instructions are also affected) The root cause for this seems to be that only instructions that list the bit FI in the "Special Registers Altered" should modify it. QEMU is, today, not working like the hardware: xvcvdpsp(0x4050533fcdb7b95ff8d561c40bf90996) = FI: CLEARED -> SET xvnmsubmsp(0xf3c0c1fc8f3230, 0xbeaab9c5) = FI: CLEARED -> SET (all tests assume FI is cleared beforehand) Fix this by making float_overflow_excp() return float_flag_inexact if it should update the inexact flags. Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Reviewed-by: Rashmica Gupta Message-Id: <20220517161522.36132-3-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/fpu_helper.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index f1ea4aa10e..88f9e756a5 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -329,24 +329,25 @@ static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr) } } -static inline void float_overflow_excp(CPUPPCState *env) +static inline int float_overflow_excp(CPUPPCState *env) { CPUState *cs = env_cpu(env); env->fpscr |= FP_OX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; - if (env->fpscr & FP_OE) { + + bool overflow_enabled = !!(env->fpscr & FP_OE); + if (overflow_enabled) { /* XXX: should adjust the result */ /* Update the floating-point enabled exception summary */ env->fpscr |= FP_FEX; /* We must update the target FPR before raising the exception */ cs->exception_index = POWERPC_EXCP_PROGRAM; env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX; - } else { - env->fpscr |= FP_XX; - env->fpscr |= FP_FI; } + + return overflow_enabled ? 0 : float_flag_inexact; } static inline void float_underflow_excp(CPUPPCState *env) @@ -468,7 +469,7 @@ static void do_float_check_status(CPUPPCState *env, bool change_fi, int status = get_float_exception_flags(&env->fp_status); if (status & float_flag_overflow) { - float_overflow_excp(env); + status |= float_overflow_excp(env); } else if (status & float_flag_underflow) { float_underflow_excp(env); } From dd657a35b429e9affa373a0e6162dd930854ba78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Tue, 17 May 2022 13:15:22 -0300 Subject: [PATCH 540/935] target/ppc: Rename sfprf to sfifprf where it's also used as set fi flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bit FI fix used the sfprf flag as a flag for the set_fi parameter in do_float_check_status where applicable. Now, this patch rename this flag to sfifprf to state this dual usage. Signed-off-by: Víctor Colombo Reviewed-by: Richard Henderson Reviewed-by: Rashmica Gupta Message-Id: <20220517161522.36132-4-victor.colombo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/fpu_helper.c | 112 ++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 88f9e756a5..8592727792 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -1693,9 +1693,9 @@ uint32_t helper_efdcmpeq(CPUPPCState *env, uint64_t op1, uint64_t op2) * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) * fld - vsr_t field (VsrD(*) or VsrW(*)) - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_ADD_SUB(name, op, nels, tp, fld, sfprf, r2sp) \ +#define VSX_ADD_SUB(name, op, nels, tp, fld, sfifprf, r2sp) \ void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \ ppc_vsr_t *xa, ppc_vsr_t *xb) \ { \ @@ -1712,19 +1712,19 @@ void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ float_invalid_op_addsub(env, tstat.float_exception_flags, \ - sfprf, GETPC()); \ + sfifprf, GETPC()); \ } \ \ if (r2sp) { \ t.fld = do_frsp(env, t.fld, GETPC()); \ } \ \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_float64(env, t.fld); \ } \ } \ *xt = t; \ - do_float_check_status(env, sfprf, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_ADD_SUB(xsadddp, add, 1, float64, VsrD(0), 1, 0) @@ -1769,9 +1769,9 @@ void helper_xsaddqp(CPUPPCState *env, uint32_t opcode, * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) * fld - vsr_t field (VsrD(*) or VsrW(*)) - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_MUL(op, nels, tp, fld, sfprf, r2sp) \ +#define VSX_MUL(op, nels, tp, fld, sfifprf, r2sp) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ ppc_vsr_t *xa, ppc_vsr_t *xb) \ { \ @@ -1788,20 +1788,20 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ float_invalid_op_mul(env, tstat.float_exception_flags, \ - sfprf, GETPC()); \ + sfifprf, GETPC()); \ } \ \ if (r2sp) { \ t.fld = do_frsp(env, t.fld, GETPC()); \ } \ \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_float64(env, t.fld); \ } \ } \ \ *xt = t; \ - do_float_check_status(env, sfprf, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_MUL(xsmuldp, 1, float64, VsrD(0), 1, 0) @@ -1840,9 +1840,9 @@ void helper_xsmulqp(CPUPPCState *env, uint32_t opcode, * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) * fld - vsr_t field (VsrD(*) or VsrW(*)) - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_DIV(op, nels, tp, fld, sfprf, r2sp) \ +#define VSX_DIV(op, nels, tp, fld, sfifprf, r2sp) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ ppc_vsr_t *xa, ppc_vsr_t *xb) \ { \ @@ -1859,7 +1859,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ float_invalid_op_div(env, tstat.float_exception_flags, \ - sfprf, GETPC()); \ + sfifprf, GETPC()); \ } \ if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) { \ float_zero_divide_excp(env, GETPC()); \ @@ -1869,13 +1869,13 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ t.fld = do_frsp(env, t.fld, GETPC()); \ } \ \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_float64(env, t.fld); \ } \ } \ \ *xt = t; \ - do_float_check_status(env, sfprf, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_DIV(xsdivdp, 1, float64, VsrD(0), 1, 0) @@ -1917,9 +1917,9 @@ void helper_xsdivqp(CPUPPCState *env, uint32_t opcode, * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) * fld - vsr_t field (VsrD(*) or VsrW(*)) - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_RE(op, nels, tp, fld, sfprf, r2sp) \ +#define VSX_RE(op, nels, tp, fld, sfifprf, r2sp) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ { \ ppc_vsr_t t = { }; \ @@ -1937,13 +1937,13 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ t.fld = do_frsp(env, t.fld, GETPC()); \ } \ \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_float64(env, t.fld); \ } \ } \ \ *xt = t; \ - do_float_check_status(env, sfprf, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_RE(xsredp, 1, float64, VsrD(0), 1, 0) @@ -1957,9 +1957,9 @@ VSX_RE(xvresp, 4, float32, VsrW(i), 0, 0) * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) * fld - vsr_t field (VsrD(*) or VsrW(*)) - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_SQRT(op, nels, tp, fld, sfprf, r2sp) \ +#define VSX_SQRT(op, nels, tp, fld, sfifprf, r2sp) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ { \ ppc_vsr_t t = { }; \ @@ -1975,20 +1975,20 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ float_invalid_op_sqrt(env, tstat.float_exception_flags, \ - sfprf, GETPC()); \ + sfifprf, GETPC()); \ } \ \ if (r2sp) { \ t.fld = do_frsp(env, t.fld, GETPC()); \ } \ \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_float64(env, t.fld); \ } \ } \ \ *xt = t; \ - do_float_check_status(env, sfprf, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_SQRT(xssqrtdp, 1, float64, VsrD(0), 1, 0) @@ -2002,9 +2002,9 @@ VSX_SQRT(xvsqrtsp, 4, float32, VsrW(i), 0, 0) * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) * fld - vsr_t field (VsrD(*) or VsrW(*)) - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_RSQRTE(op, nels, tp, fld, sfprf, r2sp) \ +#define VSX_RSQRTE(op, nels, tp, fld, sfifprf, r2sp) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ { \ ppc_vsr_t t = { }; \ @@ -2020,19 +2020,19 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ float_invalid_op_sqrt(env, tstat.float_exception_flags, \ - sfprf, GETPC()); \ + sfifprf, GETPC()); \ } \ if (r2sp) { \ t.fld = do_frsp(env, t.fld, GETPC()); \ } \ \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_float64(env, t.fld); \ } \ } \ \ *xt = t; \ - do_float_check_status(env, sfprf, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_RSQRTE(xsrsqrtedp, 1, float64, VsrD(0), 1, 0) @@ -2158,9 +2158,9 @@ VSX_TSQRT(xvtsqrtsp, 4, float32, VsrW(i), -126, 23) * fld - vsr_t field (VsrD(*) or VsrW(*)) * maddflgs - flags for the float*muladd routine that control the * various forms (madd, msub, nmadd, nmsub) - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_MADD(op, nels, tp, fld, maddflgs, sfprf) \ +#define VSX_MADD(op, nels, tp, fld, maddflgs, sfifprf) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ ppc_vsr_t *s1, ppc_vsr_t *s2, ppc_vsr_t *s3) \ { \ @@ -2177,15 +2177,15 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ float_invalid_op_madd(env, tstat.float_exception_flags, \ - sfprf, GETPC()); \ + sfifprf, GETPC()); \ } \ \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_float64(env, t.fld); \ } \ } \ *xt = t; \ - do_float_check_status(env, sfprf, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_MADD(XSMADDDP, 1, float64, VsrD(0), MADD_FLGS, 1) @@ -2670,9 +2670,9 @@ VSX_CMP(xvcmpnesp, 4, float32, VsrW(i), eq, 0, 0) * ttp - target type (float32 or float64) * sfld - source vsr_t field * tfld - target vsr_t field (f32 or f64) - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_CVT_FP_TO_FP(op, nels, stp, ttp, sfld, tfld, sfprf) \ +#define VSX_CVT_FP_TO_FP(op, nels, stp, ttp, sfld, tfld, sfifprf) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ { \ ppc_vsr_t t = { }; \ @@ -2685,19 +2685,19 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ float_invalid_op_vxsnan(env, GETPC()); \ t.tfld = ttp##_snan_to_qnan(t.tfld); \ } \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_##ttp(env, t.tfld); \ } \ } \ \ *xt = t; \ - do_float_check_status(env, sfprf, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_CVT_FP_TO_FP(xscvspdp, 1, float32, float64, VsrW(0), VsrD(0), 1) VSX_CVT_FP_TO_FP(xvcvspdp, 2, float32, float64, VsrW(2 * i), VsrD(i), 0) -#define VSX_CVT_FP_TO_FP2(op, nels, stp, ttp, sfprf) \ +#define VSX_CVT_FP_TO_FP2(op, nels, stp, ttp, sfifprf) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ { \ ppc_vsr_t t = { }; \ @@ -2710,14 +2710,14 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ float_invalid_op_vxsnan(env, GETPC()); \ t.VsrW(2 * i) = ttp##_snan_to_qnan(t.VsrW(2 * i)); \ } \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_##ttp(env, t.VsrW(2 * i)); \ } \ t.VsrW(2 * i + 1) = t.VsrW(2 * i); \ } \ \ *xt = t; \ - do_float_check_status(env, sfprf, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_CVT_FP_TO_FP2(xvcvdpsp, 2, float64, float32, 0) @@ -2733,9 +2733,9 @@ VSX_CVT_FP_TO_FP2(xscvdpsp, 1, float64, float32, 1) * tfld - target vsr_t field (f32 or f64) * sfprf - set FPRF */ -#define VSX_CVT_FP_TO_FP_VECTOR(op, nels, stp, ttp, sfld, tfld, sfprf) \ -void helper_##op(CPUPPCState *env, uint32_t opcode, \ - ppc_vsr_t *xt, ppc_vsr_t *xb) \ +#define VSX_CVT_FP_TO_FP_VECTOR(op, nels, stp, ttp, sfld, tfld, sfprf) \ +void helper_##op(CPUPPCState *env, uint32_t opcode, \ + ppc_vsr_t *xt, ppc_vsr_t *xb) \ { \ ppc_vsr_t t = *xt; \ int i; \ @@ -2767,9 +2767,9 @@ VSX_CVT_FP_TO_FP_VECTOR(xscvdpqp, 1, float64, float128, VsrD(0), f128, 1) * ttp - target type * sfld - source vsr_t field * tfld - target vsr_t field - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_CVT_FP_TO_FP_HP(op, nels, stp, ttp, sfld, tfld, sfprf) \ +#define VSX_CVT_FP_TO_FP_HP(op, nels, stp, ttp, sfld, tfld, sfifprf) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ { \ ppc_vsr_t t = { }; \ @@ -2782,13 +2782,13 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ float_invalid_op_vxsnan(env, GETPC()); \ t.tfld = ttp##_snan_to_qnan(t.tfld); \ } \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_##ttp(env, t.tfld); \ } \ } \ \ *xt = t; \ - do_float_check_status(env, sfprf, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_CVT_FP_TO_FP_HP(xscvdphp, 1, float64, float16, VsrD(0), VsrH(3), 1) @@ -3035,9 +3035,9 @@ VSX_CVT_FP_TO_INT_VECTOR(xscvqpuwz, float128, uint32, f128, VsrD(0), 0x0ULL) * sfld - source vsr_t field * tfld - target vsr_t field * jdef - definition of the j index (i or 2*i) - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_CVT_INT_TO_FP(op, nels, stp, ttp, sfld, tfld, sfprf, r2sp) \ +#define VSX_CVT_INT_TO_FP(op, nels, stp, ttp, sfld, tfld, sfifprf, r2sp)\ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ { \ ppc_vsr_t t = { }; \ @@ -3048,13 +3048,13 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ if (r2sp) { \ t.tfld = do_frsp(env, t.tfld, GETPC()); \ } \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_float64(env, t.tfld); \ } \ } \ \ *xt = t; \ - do_float_check_status(env, sfprf, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, VsrD(0), VsrD(0), 1, 0) @@ -3136,9 +3136,9 @@ VSX_CVT_INT_TO_FP_VECTOR(xscvudqp, uint64, float128, VsrD(0), f128) * tp - type (float32 or float64) * fld - vsr_t field (VsrD(*) or VsrW(*)) * rmode - rounding mode - * sfprf - set FPRF + * sfifprf - set FI and FPRF */ -#define VSX_ROUND(op, nels, tp, fld, rmode, sfprf) \ +#define VSX_ROUND(op, nels, tp, fld, rmode, sfifprf) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ { \ ppc_vsr_t t = { }; \ @@ -3158,7 +3158,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ } else { \ t.fld = tp##_round_to_int(xb->fld, &env->fp_status); \ } \ - if (sfprf) { \ + if (sfifprf) { \ helper_compute_fprf_float64(env, t.fld); \ } \ } \ @@ -3174,7 +3174,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ } \ \ *xt = t; \ - do_float_check_status(env, sfprf, GETPC()); \ + do_float_check_status(env, sfifprf, GETPC()); \ } VSX_ROUND(xsrdpi, 1, float64, VsrD(0), float_round_ties_away, 1) From d5aa9e79048bfc42616949391591fe7947574e5d Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Mon, 23 May 2022 17:18:59 +0200 Subject: [PATCH 541/935] pnv/xive2: Don't overwrite PC registers when writing TCTXT registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When writing a register from the TCTXT memory region (4th page within the IC BAR), we were overwriting the Presentation Controller (PC) register at the same offset. It looks like a silly cut and paste error. We were somehow lucky: the TCTXT registers being touched are TCTXT_ENx/_SET/_RESET to enable physical threads and the PC registers at the same offset are either not used by our model or the update was harmless. Found through code inspection. Signed-off-by: Frederic Barrat Reviewed-by: Cédric Le Goater Message-Id: <20220523151859.72283-1-fbarrat@linux.ibm.com> Signed-off-by: Daniel Henrique Barboza --- hw/intc/pnv_xive2.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/hw/intc/pnv_xive2.c b/hw/intc/pnv_xive2.c index 87303b4064..a39e070e82 100644 --- a/hw/intc/pnv_xive2.c +++ b/hw/intc/pnv_xive2.c @@ -1295,7 +1295,6 @@ static void pnv_xive2_ic_tctxt_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { PnvXive2 *xive = PNV_XIVE2(opaque); - uint32_t reg = offset >> 3; switch (offset) { /* @@ -1322,8 +1321,6 @@ static void pnv_xive2_ic_tctxt_write(void *opaque, hwaddr offset, xive2_error(xive, "TCTXT: invalid write @%"HWADDR_PRIx, offset); return; } - - xive->pc_regs[reg] = val; } static const MemoryRegionOps pnv_xive2_ic_tctxt_ops = { From 8f6086044b4de2907ee9660690b709b488b3d55b Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 17 May 2022 09:39:18 -0300 Subject: [PATCH 542/935] target/ppc: declare darn32/darn64 helpers with TCG_CALL_NO_RWG Signed-off-by: Matheus Ferst Reviewed-by: Richard Henderson Message-Id: <20220517123929.284511-2-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/helper.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/ppc/helper.h b/target/ppc/helper.h index aa6773c4a5..44eb6b7b7c 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -59,8 +59,8 @@ DEF_HELPER_FLAGS_2(cmpeqb, TCG_CALL_NO_RWG_SE, i32, tl, tl) DEF_HELPER_FLAGS_1(popcntw, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_2(bpermd, TCG_CALL_NO_RWG_SE, i64, i64, i64) DEF_HELPER_3(srad, tl, env, tl, tl) -DEF_HELPER_0(darn32, tl) -DEF_HELPER_0(darn64, tl) +DEF_HELPER_FLAGS_0(darn32, TCG_CALL_NO_RWG, tl) +DEF_HELPER_FLAGS_0(darn64, TCG_CALL_NO_RWG, tl) #endif DEF_HELPER_FLAGS_1(cntlsw32, TCG_CALL_NO_RWG_SE, i32, i32) From 9aa898b8977abca0af6b2ed9ec0f7cfa20b9d7f5 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 17 May 2022 09:39:19 -0300 Subject: [PATCH 543/935] target/ppc: use TCG_CALL_NO_RWG in vector helpers without env Helpers of vector instructions without cpu_env as an argument do not access globals. Signed-off-by: Matheus Ferst Reviewed-by: Richard Henderson Message-Id: <20220517123929.284511-3-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/helper.h | 162 ++++++++++++++++++++++---------------------- 1 file changed, 81 insertions(+), 81 deletions(-) diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 44eb6b7b7c..da740ad9af 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -133,15 +133,15 @@ DEF_HELPER_FLAGS_1(ftsqrt, TCG_CALL_NO_RWG_SE, i32, i64) #define dh_ctype_vsr ppc_vsr_t * #define dh_typecode_vsr dh_typecode_ptr -DEF_HELPER_3(vavgub, void, avr, avr, avr) -DEF_HELPER_3(vavguh, void, avr, avr, avr) -DEF_HELPER_3(vavguw, void, avr, avr, avr) -DEF_HELPER_3(vabsdub, void, avr, avr, avr) -DEF_HELPER_3(vabsduh, void, avr, avr, avr) -DEF_HELPER_3(vabsduw, void, avr, avr, avr) -DEF_HELPER_3(vavgsb, void, avr, avr, avr) -DEF_HELPER_3(vavgsh, void, avr, avr, avr) -DEF_HELPER_3(vavgsw, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vavgub, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vavguh, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vavguw, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vabsdub, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vabsduh, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vabsduw, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vavgsb, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vavgsh, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vavgsw, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_4(vcmpeqfp, void, env, avr, avr, avr) DEF_HELPER_4(vcmpgefp, void, env, avr, avr, avr) DEF_HELPER_4(vcmpgtfp, void, env, avr, avr, avr) @@ -153,12 +153,12 @@ DEF_HELPER_4(vcmpeqfp_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpgefp_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpgtfp_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpbfp_dot, void, env, avr, avr, avr) -DEF_HELPER_3(vmrglb, void, avr, avr, avr) -DEF_HELPER_3(vmrglh, void, avr, avr, avr) -DEF_HELPER_3(vmrglw, void, avr, avr, avr) -DEF_HELPER_3(vmrghb, void, avr, avr, avr) -DEF_HELPER_3(vmrghh, void, avr, avr, avr) -DEF_HELPER_3(vmrghw, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vmrglb, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vmrglh, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vmrglw, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vmrghb, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vmrghh, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vmrghw, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(VMULESB, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(VMULESH, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(VMULESW, TCG_CALL_NO_RWG, void, avr, avr, avr) @@ -171,15 +171,15 @@ DEF_HELPER_FLAGS_3(VMULOSW, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(VMULOUB, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(VMULOUH, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(VMULOUW, TCG_CALL_NO_RWG, void, avr, avr, avr) -DEF_HELPER_3(vslo, void, avr, avr, avr) -DEF_HELPER_3(vsro, void, avr, avr, avr) -DEF_HELPER_3(vsrv, void, avr, avr, avr) -DEF_HELPER_3(vslv, void, avr, avr, avr) -DEF_HELPER_3(vaddcuw, void, avr, avr, avr) -DEF_HELPER_2(vprtybw, void, avr, avr) -DEF_HELPER_2(vprtybd, void, avr, avr) -DEF_HELPER_2(vprtybq, void, avr, avr) -DEF_HELPER_3(vsubcuw, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vslo, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vsro, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vsrv, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vslv, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vaddcuw, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_2(vprtybw, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vprtybd, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vprtybq, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_3(vsubcuw, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_5(vaddsbs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) DEF_HELPER_FLAGS_5(vaddshs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) DEF_HELPER_FLAGS_5(vaddsws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) @@ -192,19 +192,19 @@ DEF_HELPER_FLAGS_5(vadduws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) DEF_HELPER_FLAGS_5(vsububs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) DEF_HELPER_FLAGS_5(vsubuhs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) DEF_HELPER_FLAGS_5(vsubuws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) -DEF_HELPER_3(vadduqm, void, avr, avr, avr) -DEF_HELPER_4(vaddecuq, void, avr, avr, avr, avr) -DEF_HELPER_4(vaddeuqm, void, avr, avr, avr, avr) -DEF_HELPER_3(vaddcuq, void, avr, avr, avr) -DEF_HELPER_3(vsubuqm, void, avr, avr, avr) -DEF_HELPER_4(vsubecuq, void, avr, avr, avr, avr) -DEF_HELPER_4(vsubeuqm, void, avr, avr, avr, avr) -DEF_HELPER_3(vsubcuq, void, avr, avr, avr) -DEF_HELPER_4(vsldoi, void, avr, avr, avr, i32) -DEF_HELPER_3(vextractub, void, avr, avr, i32) -DEF_HELPER_3(vextractuh, void, avr, avr, i32) -DEF_HELPER_3(vextractuw, void, avr, avr, i32) -DEF_HELPER_3(vextractd, void, avr, avr, i32) +DEF_HELPER_FLAGS_3(vadduqm, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_4(vaddecuq, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) +DEF_HELPER_FLAGS_4(vaddeuqm, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) +DEF_HELPER_FLAGS_3(vaddcuq, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vsubuqm, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_4(vsubecuq, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) +DEF_HELPER_FLAGS_4(vsubeuqm, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) +DEF_HELPER_FLAGS_3(vsubcuq, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_4(vsldoi, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) +DEF_HELPER_FLAGS_3(vextractub, TCG_CALL_NO_RWG, void, avr, avr, i32) +DEF_HELPER_FLAGS_3(vextractuh, TCG_CALL_NO_RWG, void, avr, avr, i32) +DEF_HELPER_FLAGS_3(vextractuw, TCG_CALL_NO_RWG, void, avr, avr, i32) +DEF_HELPER_FLAGS_3(vextractd, TCG_CALL_NO_RWG, void, avr, avr, i32) DEF_HELPER_4(VINSBLX, void, env, avr, i64, tl) DEF_HELPER_4(VINSHLX, void, env, avr, i64, tl) DEF_HELPER_4(VINSWLX, void, env, avr, i64, tl) @@ -213,16 +213,16 @@ DEF_HELPER_FLAGS_2(VSTRIBL, TCG_CALL_NO_RWG, i32, avr, avr) DEF_HELPER_FLAGS_2(VSTRIBR, TCG_CALL_NO_RWG, i32, avr, avr) DEF_HELPER_FLAGS_2(VSTRIHL, TCG_CALL_NO_RWG, i32, avr, avr) DEF_HELPER_FLAGS_2(VSTRIHR, TCG_CALL_NO_RWG, i32, avr, avr) -DEF_HELPER_2(vnegw, void, avr, avr) -DEF_HELPER_2(vnegd, void, avr, avr) -DEF_HELPER_2(vupkhpx, void, avr, avr) -DEF_HELPER_2(vupklpx, void, avr, avr) -DEF_HELPER_2(vupkhsb, void, avr, avr) -DEF_HELPER_2(vupkhsh, void, avr, avr) -DEF_HELPER_2(vupkhsw, void, avr, avr) -DEF_HELPER_2(vupklsb, void, avr, avr) -DEF_HELPER_2(vupklsh, void, avr, avr) -DEF_HELPER_2(vupklsw, void, avr, avr) +DEF_HELPER_FLAGS_2(vnegw, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vnegd, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vupkhpx, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vupklpx, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vupkhsb, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vupkhsh, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vupkhsw, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vupklsb, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vupklsh, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vupklsw, TCG_CALL_NO_RWG, void, avr, avr) DEF_HELPER_5(vmsumubm, void, env, avr, avr, avr, avr) DEF_HELPER_5(vmsummbm, void, env, avr, avr, avr, avr) DEF_HELPER_FLAGS_4(VPERM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) @@ -239,14 +239,14 @@ DEF_HELPER_4(vpkudus, void, env, avr, avr, avr) DEF_HELPER_4(vpkuhum, void, env, avr, avr, avr) DEF_HELPER_4(vpkuwum, void, env, avr, avr, avr) DEF_HELPER_4(vpkudum, void, env, avr, avr, avr) -DEF_HELPER_3(vpkpx, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vpkpx, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_5(vmhaddshs, void, env, avr, avr, avr, avr) DEF_HELPER_5(vmhraddshs, void, env, avr, avr, avr, avr) DEF_HELPER_5(vmsumuhm, void, env, avr, avr, avr, avr) DEF_HELPER_5(vmsumuhs, void, env, avr, avr, avr, avr) DEF_HELPER_5(vmsumshm, void, env, avr, avr, avr, avr) DEF_HELPER_5(vmsumshs, void, env, avr, avr, avr, avr) -DEF_HELPER_4(vmladduhm, void, avr, avr, avr, avr) +DEF_HELPER_FLAGS_4(vmladduhm, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) DEF_HELPER_FLAGS_2(mtvscr, TCG_CALL_NO_RWG, void, env, i32) DEF_HELPER_FLAGS_1(mfvscr, TCG_CALL_NO_RWG, i32, env) DEF_HELPER_3(lvebx, void, env, avr, tl) @@ -289,43 +289,43 @@ DEF_HELPER_4(vcfsx, void, env, avr, avr, i32) DEF_HELPER_4(vctuxs, void, env, avr, avr, i32) DEF_HELPER_4(vctsxs, void, env, avr, avr, i32) -DEF_HELPER_2(vclzb, void, avr, avr) -DEF_HELPER_2(vclzh, void, avr, avr) -DEF_HELPER_2(vctzb, void, avr, avr) -DEF_HELPER_2(vctzh, void, avr, avr) -DEF_HELPER_2(vctzw, void, avr, avr) -DEF_HELPER_2(vctzd, void, avr, avr) -DEF_HELPER_2(vpopcntb, void, avr, avr) -DEF_HELPER_2(vpopcnth, void, avr, avr) -DEF_HELPER_2(vpopcntw, void, avr, avr) -DEF_HELPER_2(vpopcntd, void, avr, avr) -DEF_HELPER_1(vclzlsbb, tl, avr) -DEF_HELPER_1(vctzlsbb, tl, avr) -DEF_HELPER_3(vbpermd, void, avr, avr, avr) -DEF_HELPER_3(vbpermq, void, avr, avr, avr) -DEF_HELPER_3(vpmsumb, void, avr, avr, avr) -DEF_HELPER_3(vpmsumh, void, avr, avr, avr) -DEF_HELPER_3(vpmsumw, void, avr, avr, avr) -DEF_HELPER_3(vpmsumd, void, avr, avr, avr) -DEF_HELPER_2(vextublx, tl, tl, avr) -DEF_HELPER_2(vextuhlx, tl, tl, avr) -DEF_HELPER_2(vextuwlx, tl, tl, avr) -DEF_HELPER_2(vextubrx, tl, tl, avr) -DEF_HELPER_2(vextuhrx, tl, tl, avr) -DEF_HELPER_2(vextuwrx, tl, tl, avr) +DEF_HELPER_FLAGS_2(vclzb, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vclzh, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vctzb, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vctzh, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vctzw, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vctzd, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vpopcntb, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vpopcnth, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vpopcntw, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_2(vpopcntd, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_1(vclzlsbb, TCG_CALL_NO_RWG, tl, avr) +DEF_HELPER_FLAGS_1(vctzlsbb, TCG_CALL_NO_RWG, tl, avr) +DEF_HELPER_FLAGS_3(vbpermd, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vbpermq, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vpmsumb, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vpmsumh, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vpmsumw, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vpmsumd, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_2(vextublx, TCG_CALL_NO_RWG, tl, tl, avr) +DEF_HELPER_FLAGS_2(vextuhlx, TCG_CALL_NO_RWG, tl, tl, avr) +DEF_HELPER_FLAGS_2(vextuwlx, TCG_CALL_NO_RWG, tl, tl, avr) +DEF_HELPER_FLAGS_2(vextubrx, TCG_CALL_NO_RWG, tl, tl, avr) +DEF_HELPER_FLAGS_2(vextuhrx, TCG_CALL_NO_RWG, tl, tl, avr) +DEF_HELPER_FLAGS_2(vextuwrx, TCG_CALL_NO_RWG, tl, tl, avr) DEF_HELPER_5(VEXTDUBVLX, void, env, avr, avr, avr, tl) DEF_HELPER_5(VEXTDUHVLX, void, env, avr, avr, avr, tl) DEF_HELPER_5(VEXTDUWVLX, void, env, avr, avr, avr, tl) DEF_HELPER_5(VEXTDDVLX, void, env, avr, avr, avr, tl) -DEF_HELPER_2(vsbox, void, avr, avr) -DEF_HELPER_3(vcipher, void, avr, avr, avr) -DEF_HELPER_3(vcipherlast, void, avr, avr, avr) -DEF_HELPER_3(vncipher, void, avr, avr, avr) -DEF_HELPER_3(vncipherlast, void, avr, avr, avr) -DEF_HELPER_3(vshasigmaw, void, avr, avr, i32) -DEF_HELPER_3(vshasigmad, void, avr, avr, i32) -DEF_HELPER_4(vpermxor, void, avr, avr, avr, avr) +DEF_HELPER_FLAGS_2(vsbox, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_3(vcipher, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vcipherlast, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vncipher, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vncipherlast, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_3(vshasigmaw, TCG_CALL_NO_RWG, void, avr, avr, i32) +DEF_HELPER_FLAGS_3(vshasigmad, TCG_CALL_NO_RWG, void, avr, avr, i32) +DEF_HELPER_FLAGS_4(vpermxor, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) DEF_HELPER_4(bcdadd, i32, avr, avr, avr, i32) DEF_HELPER_4(bcdsub, i32, avr, avr, avr, i32) From 491bcaaa35a68157c0546c65fe6b91e65357b6c9 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 17 May 2022 09:39:20 -0300 Subject: [PATCH 544/935] target/ppc: use TCG_CALL_NO_RWG in BCD helpers Helpers of BCD instructions only access the VSRs supplied by the TCGv_ptr arguments, no globals are accessed. Signed-off-by: Matheus Ferst Reviewed-by: Richard Henderson Message-Id: <20220517123929.284511-4-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/helper.h | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/target/ppc/helper.h b/target/ppc/helper.h index da740ad9af..a02c4be906 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -327,21 +327,21 @@ DEF_HELPER_FLAGS_3(vshasigmaw, TCG_CALL_NO_RWG, void, avr, avr, i32) DEF_HELPER_FLAGS_3(vshasigmad, TCG_CALL_NO_RWG, void, avr, avr, i32) DEF_HELPER_FLAGS_4(vpermxor, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) -DEF_HELPER_4(bcdadd, i32, avr, avr, avr, i32) -DEF_HELPER_4(bcdsub, i32, avr, avr, avr, i32) -DEF_HELPER_3(bcdcfn, i32, avr, avr, i32) -DEF_HELPER_3(bcdctn, i32, avr, avr, i32) -DEF_HELPER_3(bcdcfz, i32, avr, avr, i32) -DEF_HELPER_3(bcdctz, i32, avr, avr, i32) -DEF_HELPER_3(bcdcfsq, i32, avr, avr, i32) -DEF_HELPER_3(bcdctsq, i32, avr, avr, i32) -DEF_HELPER_4(bcdcpsgn, i32, avr, avr, avr, i32) -DEF_HELPER_3(bcdsetsgn, i32, avr, avr, i32) -DEF_HELPER_4(bcds, i32, avr, avr, avr, i32) -DEF_HELPER_4(bcdus, i32, avr, avr, avr, i32) -DEF_HELPER_4(bcdsr, i32, avr, avr, avr, i32) -DEF_HELPER_4(bcdtrunc, i32, avr, avr, avr, i32) -DEF_HELPER_4(bcdutrunc, i32, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(bcdadd, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(bcdsub, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32) +DEF_HELPER_FLAGS_3(bcdcfn, TCG_CALL_NO_RWG, i32, avr, avr, i32) +DEF_HELPER_FLAGS_3(bcdctn, TCG_CALL_NO_RWG, i32, avr, avr, i32) +DEF_HELPER_FLAGS_3(bcdcfz, TCG_CALL_NO_RWG, i32, avr, avr, i32) +DEF_HELPER_FLAGS_3(bcdctz, TCG_CALL_NO_RWG, i32, avr, avr, i32) +DEF_HELPER_FLAGS_3(bcdcfsq, TCG_CALL_NO_RWG, i32, avr, avr, i32) +DEF_HELPER_FLAGS_3(bcdctsq, TCG_CALL_NO_RWG, i32, avr, avr, i32) +DEF_HELPER_FLAGS_4(bcdcpsgn, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32) +DEF_HELPER_FLAGS_3(bcdsetsgn, TCG_CALL_NO_RWG, i32, avr, avr, i32) +DEF_HELPER_FLAGS_4(bcds, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(bcdus, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(bcdsr, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(bcdtrunc, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(bcdutrunc, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32) DEF_HELPER_4(xsadddp, void, env, vsr, vsr, vsr) DEF_HELPER_5(xsaddqp, void, env, i32, vsr, vsr, vsr) From f2454bfe73d1ae9e7561fc3c29e0d2729381d27c Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 17 May 2022 09:39:21 -0300 Subject: [PATCH 545/935] target/ppc: use TCG_CALL_NO_RWG in VSX helpers without env Helpers of VSX instructions without cpu_env as an argument do not access globals. Signed-off-by: Matheus Ferst Reviewed-by: Richard Henderson Message-Id: <20220517123929.284511-5-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/helper.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target/ppc/helper.h b/target/ppc/helper.h index a02c4be906..f82c5bd0db 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -533,10 +533,10 @@ DEF_HELPER_FLAGS_5(XXPERMX, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, tl) DEF_HELPER_4(xxinsertw, void, env, vsr, vsr, i32) DEF_HELPER_3(xvxsigsp, void, env, vsr, vsr) DEF_HELPER_FLAGS_5(XXEVAL, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, i32) -DEF_HELPER_5(XXBLENDVB, void, vsr, vsr, vsr, vsr, i32) -DEF_HELPER_5(XXBLENDVH, void, vsr, vsr, vsr, vsr, i32) -DEF_HELPER_5(XXBLENDVW, void, vsr, vsr, vsr, vsr, i32) -DEF_HELPER_5(XXBLENDVD, void, vsr, vsr, vsr, vsr, i32) +DEF_HELPER_FLAGS_5(XXBLENDVB, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, i32) +DEF_HELPER_FLAGS_5(XXBLENDVH, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, i32) +DEF_HELPER_FLAGS_5(XXBLENDVW, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, i32) +DEF_HELPER_FLAGS_5(XXBLENDVD, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, i32) DEF_HELPER_2(efscfsi, i32, env, i32) DEF_HELPER_2(efscfui, i32, env, i32) From eb69a84bb07be94179eb2275cd9d4bed12afc66f Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 17 May 2022 09:39:22 -0300 Subject: [PATCH 546/935] target/ppc: Use TCG_CALL_NO_RWG_SE in fsel helper fsel doesn't change FPSCR and CR1 is handled by gen_set_cr1_from_fpscr, so helper_fsel doesn't need the env argument and can be declared with TCG_CALL_NO_RWG_SE. We also take this opportunity to move the insn to decodetree. Signed-off-by: Matheus Ferst Reviewed-by: Richard Henderson Message-Id: <20220517123929.284511-6-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/fpu_helper.c | 15 +++++++-------- target/ppc/helper.h | 2 +- target/ppc/insn32.decode | 7 +++++++ target/ppc/translate/fp-impl.c.inc | 30 ++++++++++++++++++++++++++++-- target/ppc/translate/fp-ops.c.inc | 1 - 5 files changed, 43 insertions(+), 12 deletions(-) diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 8592727792..588448702f 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -919,18 +919,17 @@ float64 helper_frsqrtes(CPUPPCState *env, float64 arg) } /* fsel - fsel. */ -uint64_t helper_fsel(CPUPPCState *env, uint64_t arg1, uint64_t arg2, - uint64_t arg3) +uint64_t helper_FSEL(uint64_t a, uint64_t b, uint64_t c) { - CPU_DoubleU farg1; + CPU_DoubleU fa; - farg1.ll = arg1; + fa.ll = a; - if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && - !float64_is_any_nan(farg1.d)) { - return arg2; + if ((!float64_is_neg(fa.d) || float64_is_zero(fa.d)) && + !float64_is_any_nan(fa.d)) { + return c; } else { - return arg3; + return b; } } diff --git a/target/ppc/helper.h b/target/ppc/helper.h index f82c5bd0db..ddfa0308bc 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -120,7 +120,7 @@ DEF_HELPER_2(fre, i64, env, i64) DEF_HELPER_2(fres, i64, env, i64) DEF_HELPER_2(frsqrte, i64, env, i64) DEF_HELPER_2(frsqrtes, i64, env, i64) -DEF_HELPER_4(fsel, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_3(FSEL, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64) DEF_HELPER_FLAGS_2(ftdiv, TCG_CALL_NO_RWG_SE, i32, i64, i64) DEF_HELPER_FLAGS_1(ftsqrt, TCG_CALL_NO_RWG_SE, i32, i64) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index 39372fe673..1d0b55bde3 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -17,6 +17,9 @@ # License along with this library; if not, see . # +&A frt fra frb frc rc:bool +@A ...... frt:5 fra:5 frb:5 frc:5 ..... rc:1 &A + &D rt ra si:int64_t @D ...... rt:5 ra:5 si:s16 &D @@ -308,6 +311,10 @@ STFDU 110111 ..... ...... ............... @D STFDX 011111 ..... ...... .... 1011010111 - @X STFDUX 011111 ..... ...... .... 1011110111 - @X +### Floating-Point Select Instruction + +FSEL 111111 ..... ..... ..... ..... 10111 . @A + ### Move To/From System Register Instructions SETBC 011111 ..... ..... ----- 0110000000 - @X_bi diff --git a/target/ppc/translate/fp-impl.c.inc b/target/ppc/translate/fp-impl.c.inc index cfb27bd020..f9b58b844e 100644 --- a/target/ppc/translate/fp-impl.c.inc +++ b/target/ppc/translate/fp-impl.c.inc @@ -222,8 +222,34 @@ static void gen_frsqrtes(DisasContext *ctx) tcg_temp_free_i64(t1); } -/* fsel */ -_GEN_FLOAT_ACB(sel, 0x3F, 0x17, 0, PPC_FLOAT_FSEL); +static bool trans_FSEL(DisasContext *ctx, arg_A *a) +{ + TCGv_i64 t0, t1, t2; + + REQUIRE_INSNS_FLAGS(ctx, FLOAT_FSEL); + REQUIRE_FPU(ctx); + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); + + get_fpr(t0, a->fra); + get_fpr(t1, a->frb); + get_fpr(t2, a->frc); + + gen_helper_FSEL(t0, t0, t1, t2); + set_fpr(a->frt, t0); + if (a->rc) { + gen_set_cr1_from_fpscr(ctx); + } + + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + + return true; +} + /* fsub - fsubs */ GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT); /* Optional: */ diff --git a/target/ppc/translate/fp-ops.c.inc b/target/ppc/translate/fp-ops.c.inc index 4260635a12..0538ab2d2d 100644 --- a/target/ppc/translate/fp-ops.c.inc +++ b/target/ppc/translate/fp-ops.c.inc @@ -24,7 +24,6 @@ GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT), GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT), GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES), GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE), -_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL), GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT), GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT), GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT), From cf862bee0e0d31de4809ac7bacb1d65ff7e8b9ce Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 17 May 2022 09:39:23 -0300 Subject: [PATCH 547/935] target/ppc: declare xscvspdpn helper with call flags Move xscvspdpn to decodetree, declare helper_xscvspdpn with TCG_CALL_NO_RWG_SE and drop the unused env argument. Signed-off-by: Matheus Ferst Reviewed-by: Richard Henderson Message-Id: <20220517123929.284511-7-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/fpu_helper.c | 2 +- target/ppc/helper.h | 2 +- target/ppc/insn32.decode | 1 + target/ppc/translate/vsx-impl.c.inc | 22 +++++++++++++++++++++- target/ppc/translate/vsx-ops.c.inc | 1 - 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 588448702f..55ef4b5d48 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -2878,7 +2878,7 @@ uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb) return (result << 32) | result; } -uint64_t helper_xscvspdpn(CPUPPCState *env, uint64_t xb) +uint64_t helper_XSCVSPDPN(uint64_t xb) { return helper_todouble(xb >> 32); } diff --git a/target/ppc/helper.h b/target/ppc/helper.h index ddfa0308bc..9be69fa91e 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -395,7 +395,7 @@ DEF_HELPER_3(XSCVSQQP, void, env, vsr, vsr) DEF_HELPER_3(xscvhpdp, void, env, vsr, vsr) DEF_HELPER_4(xscvsdqp, void, env, i32, vsr, vsr) DEF_HELPER_3(xscvspdp, void, env, vsr, vsr) -DEF_HELPER_2(xscvspdpn, i64, env, i64) +DEF_HELPER_FLAGS_1(XSCVSPDPN, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_3(xscvdpsxds, void, env, vsr, vsr) DEF_HELPER_3(xscvdpsxws, void, env, vsr, vsr) DEF_HELPER_3(xscvdpuxds, void, env, vsr, vsr) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index 1d0b55bde3..d4c2615b1a 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -708,6 +708,7 @@ XSCVUQQP 111111 ..... 00011 ..... 1101000100 - @X_tb XSCVSQQP 111111 ..... 01011 ..... 1101000100 - @X_tb XVCVBF16SPN 111100 ..... 10000 ..... 111011011 .. @XX2 XVCVSPBF16 111100 ..... 10001 ..... 111011011 .. @XX2 +XSCVSPDPN 111100 ..... ----- ..... 101001011 .. @XX2 ## VSX Vector Test Least-Significant Bit by Byte Instruction diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index 3692740736..9b4f309d9d 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -1045,7 +1045,27 @@ GEN_VSX_HELPER_R2(xscvqpuwz, 0x04, 0x1A, 0x01, PPC2_ISA300) GEN_VSX_HELPER_X2(xscvhpdp, 0x16, 0x15, 0x10, PPC2_ISA300) GEN_VSX_HELPER_R2(xscvsdqp, 0x04, 0x1A, 0x0A, PPC2_ISA300) GEN_VSX_HELPER_X2(xscvspdp, 0x12, 0x14, 0, PPC2_VSX) -GEN_VSX_HELPER_XT_XB_ENV(xscvspdpn, 0x16, 0x14, 0, PPC2_VSX207) + +bool trans_XSCVSPDPN(DisasContext *ctx, arg_XX2 *a) +{ + TCGv_i64 tmp; + + REQUIRE_INSNS_FLAGS2(ctx, VSX207); + REQUIRE_VSX(ctx); + + tmp = tcg_temp_new_i64(); + get_cpu_vsr(tmp, a->xb, true); + + gen_helper_XSCVSPDPN(tmp, tmp); + + set_cpu_vsr(a->xt, tmp, true); + set_cpu_vsr(a->xt, tcg_constant_i64(0), false); + + tcg_temp_free_i64(tmp); + + return true; +} + GEN_VSX_HELPER_X2(xscvdpsxds, 0x10, 0x15, 0, PPC2_VSX) GEN_VSX_HELPER_X2(xscvdpsxws, 0x10, 0x05, 0, PPC2_VSX) GEN_VSX_HELPER_X2(xscvdpuxds, 0x10, 0x14, 0, PPC2_VSX) diff --git a/target/ppc/translate/vsx-ops.c.inc b/target/ppc/translate/vsx-ops.c.inc index b8fd116728..52d7ab30cd 100644 --- a/target/ppc/translate/vsx-ops.c.inc +++ b/target/ppc/translate/vsx-ops.c.inc @@ -200,7 +200,6 @@ GEN_XX2FORM(xscvdpspn, 0x16, 0x10, PPC2_VSX207), GEN_XX2FORM_EO(xscvhpdp, 0x16, 0x15, 0x10, PPC2_ISA300), GEN_VSX_XFORM_300_EO(xscvsdqp, 0x04, 0x1A, 0x0A, 0x00000001), GEN_XX2FORM(xscvspdp, 0x12, 0x14, PPC2_VSX), -GEN_XX2FORM(xscvspdpn, 0x16, 0x14, PPC2_VSX207), GEN_XX2FORM(xscvdpsxds, 0x10, 0x15, PPC2_VSX), GEN_XX2FORM(xscvdpsxws, 0x10, 0x05, PPC2_VSX), GEN_XX2FORM(xscvdpuxds, 0x10, 0x14, PPC2_VSX), From c36ab970ac0ce257a6badb30f6a485a81c2289d2 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 17 May 2022 09:39:24 -0300 Subject: [PATCH 548/935] target/ppc: declare xvxsigsp helper with call flags Move xvxsigsp to decodetree, declare helper_xvxsigsp with TCG_CALL_NO_RWG, and drop the unused env argument. Signed-off-by: Matheus Ferst Reviewed-by: Richard Henderson Message-Id: <20220517123929.284511-8-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/fpu_helper.c | 2 +- target/ppc/helper.h | 2 +- target/ppc/insn32.decode | 4 ++++ target/ppc/translate/vsx-impl.c.inc | 18 +++++++++++++++++- target/ppc/translate/vsx-ops.c.inc | 1 - 5 files changed, 23 insertions(+), 4 deletions(-) diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 55ef4b5d48..9489e06504 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -3205,7 +3205,7 @@ uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb) return xt; } -void helper_xvxsigsp(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) +void helper_XVXSIGSP(ppc_vsr_t *xt, ppc_vsr_t *xb) { ppc_vsr_t t = { }; uint32_t exp, i, fraction; diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 9be69fa91e..aed1b24fdb 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -531,7 +531,7 @@ DEF_HELPER_FLAGS_2(XXGENPCVDM_le_comp, TCG_CALL_NO_RWG, void, vsr, avr) DEF_HELPER_4(xxextractuw, void, env, vsr, vsr, i32) DEF_HELPER_FLAGS_5(XXPERMX, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, tl) DEF_HELPER_4(xxinsertw, void, env, vsr, vsr, i32) -DEF_HELPER_3(xvxsigsp, void, env, vsr, vsr) +DEF_HELPER_FLAGS_2(XVXSIGSP, TCG_CALL_NO_RWG, void, vsr, vsr) DEF_HELPER_FLAGS_5(XXEVAL, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, i32) DEF_HELPER_FLAGS_5(XXBLENDVB, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, i32) DEF_HELPER_FLAGS_5(XXBLENDVH, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, i32) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index d4c2615b1a..483349ff6d 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -710,6 +710,10 @@ XVCVBF16SPN 111100 ..... 10000 ..... 111011011 .. @XX2 XVCVSPBF16 111100 ..... 10001 ..... 111011011 .. @XX2 XSCVSPDPN 111100 ..... ----- ..... 101001011 .. @XX2 +## VSX Binary Floating-Point Math Support Instructions + +XVXSIGSP 111100 ..... 01001 ..... 111011011 .. @XX2 + ## VSX Vector Test Least-Significant Bit by Byte Instruction XVTLSBB 111100 ... -- 00010 ..... 111011011 . - @XX2_bf_xb diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index 9b4f309d9d..ca11e2c4b8 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -2151,7 +2151,23 @@ static void gen_xvxexpdp(DisasContext *ctx) tcg_temp_free_i64(xbl); } -GEN_VSX_HELPER_X2(xvxsigsp, 0x00, 0x04, 0, PPC2_ISA300) +static bool trans_XVXSIGSP(DisasContext *ctx, arg_XX2 *a) +{ + TCGv_ptr t, b; + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VSX(ctx); + + t = gen_vsr_ptr(a->xt); + b = gen_vsr_ptr(a->xb); + + gen_helper_XVXSIGSP(t, b); + + tcg_temp_free_ptr(t); + tcg_temp_free_ptr(b); + + return true; +} static void gen_xvxsigdp(DisasContext *ctx) { diff --git a/target/ppc/translate/vsx-ops.c.inc b/target/ppc/translate/vsx-ops.c.inc index 52d7ab30cd..4524c5b02a 100644 --- a/target/ppc/translate/vsx-ops.c.inc +++ b/target/ppc/translate/vsx-ops.c.inc @@ -156,7 +156,6 @@ GEN_XX3FORM(xviexpdp, 0x00, 0x1F, PPC2_ISA300), GEN_XX2FORM_EO(xvxexpdp, 0x16, 0x1D, 0x00, PPC2_ISA300), GEN_XX2FORM_EO(xvxsigdp, 0x16, 0x1D, 0x01, PPC2_ISA300), GEN_XX2FORM_EO(xvxexpsp, 0x16, 0x1D, 0x08, PPC2_ISA300), -GEN_XX2FORM_EO(xvxsigsp, 0x16, 0x1D, 0x09, PPC2_ISA300), /* DCMX = bit[25] << 6 | bit[29] << 5 | bit[11:15] */ #define GEN_XX2FORM_DCMX(name, opc2, opc3, fl2) \ From 8f5eeee3f1f1e7da4a1bf1ecb5527071fde1b2d5 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 17 May 2022 09:39:25 -0300 Subject: [PATCH 549/935] target/ppc: declare xxextractuw and xxinsertw helpers with call flags Move xxextractuw and xxinsertw to decodetree, declare both helpers with TCG_CALL_NO_RWG, and drop the unused env argument. Signed-off-by: Matheus Ferst Reviewed-by: Richard Henderson Message-Id: <20220517123929.284511-9-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/helper.h | 4 +- target/ppc/insn32.decode | 9 ++++- target/ppc/int_helper.c | 6 +-- target/ppc/translate/vsx-impl.c.inc | 63 +++++++++++++---------------- target/ppc/translate/vsx-ops.c.inc | 2 - 5 files changed, 39 insertions(+), 45 deletions(-) diff --git a/target/ppc/helper.h b/target/ppc/helper.h index aed1b24fdb..640a70cd5c 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -528,9 +528,9 @@ DEF_HELPER_FLAGS_2(XXGENPCVDM_be_exp, TCG_CALL_NO_RWG, void, vsr, avr) DEF_HELPER_FLAGS_2(XXGENPCVDM_be_comp, TCG_CALL_NO_RWG, void, vsr, avr) DEF_HELPER_FLAGS_2(XXGENPCVDM_le_exp, TCG_CALL_NO_RWG, void, vsr, avr) DEF_HELPER_FLAGS_2(XXGENPCVDM_le_comp, TCG_CALL_NO_RWG, void, vsr, avr) -DEF_HELPER_4(xxextractuw, void, env, vsr, vsr, i32) +DEF_HELPER_FLAGS_3(XXEXTRACTUW, TCG_CALL_NO_RWG, void, vsr, vsr, i32) DEF_HELPER_FLAGS_5(XXPERMX, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, tl) -DEF_HELPER_4(xxinsertw, void, env, vsr, vsr, i32) +DEF_HELPER_FLAGS_3(XXINSERTW, TCG_CALL_NO_RWG, void, vsr, vsr, i32) DEF_HELPER_FLAGS_2(XVXSIGSP, TCG_CALL_NO_RWG, void, vsr, vsr) DEF_HELPER_FLAGS_5(XXEVAL, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, i32) DEF_HELPER_FLAGS_5(XXBLENDVB, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, i32) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index 483349ff6d..435cf1320c 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -161,8 +161,10 @@ &XX2 xt xb @XX2 ...... ..... ..... ..... ......... .. &XX2 xt=%xx_xt xb=%xx_xb -&XX2_uim2 xt xb uim:uint8_t -@XX2_uim2 ...... ..... ... uim:2 ..... ......... .. &XX2_uim2 xt=%xx_xt xb=%xx_xb +&XX2_uim xt xb uim:uint8_t +@XX2_uim2 ...... ..... ... uim:2 ..... ......... .. &XX2_uim xt=%xx_xt xb=%xx_xb + +@XX2_uim4 ...... ..... . uim:4 ..... ......... .. &XX2_uim xt=%xx_xt xb=%xx_xb &XX2_bf_xb bf xb @XX2_bf_xb ...... bf:3 .. ..... ..... ......... . . &XX2_bf_xb xb=%xx_xb @@ -666,6 +668,9 @@ XXSPLTW 111100 ..... ---.. ..... 010100100 . . @XX2_uim2 ## VSX Permute Instructions +XXEXTRACTUW 111100 ..... - .... ..... 010100101 .. @XX2_uim4 +XXINSERTW 111100 ..... - .... ..... 010110101 .. @XX2_uim4 + XXPERM 111100 ..... ..... ..... 00011010 ... @XX3 XXPERMR 111100 ..... ..... ..... 00111010 ... @XX3 XXPERMDI 111100 ..... ..... ..... 0 .. 01010 ... @XX3_dm diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index 8c1674510b..9a361ad241 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -1647,8 +1647,7 @@ VSTRI(VSTRIHL, H, 8, true) VSTRI(VSTRIHR, H, 8, false) #undef VSTRI -void helper_xxextractuw(CPUPPCState *env, ppc_vsr_t *xt, - ppc_vsr_t *xb, uint32_t index) +void helper_XXEXTRACTUW(ppc_vsr_t *xt, ppc_vsr_t *xb, uint32_t index) { ppc_vsr_t t = { }; size_t es = sizeof(uint32_t); @@ -1663,8 +1662,7 @@ void helper_xxextractuw(CPUPPCState *env, ppc_vsr_t *xt, *xt = t; } -void helper_xxinsertw(CPUPPCState *env, ppc_vsr_t *xt, - ppc_vsr_t *xb, uint32_t index) +void helper_XXINSERTW(ppc_vsr_t *xt, ppc_vsr_t *xb, uint32_t index) { ppc_vsr_t t = *xt; size_t es = sizeof(uint32_t); diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index ca11e2c4b8..900c1a1ab2 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -1585,7 +1585,7 @@ static bool trans_XXSEL(DisasContext *ctx, arg_XX4 *a) return true; } -static bool trans_XXSPLTW(DisasContext *ctx, arg_XX2_uim2 *a) +static bool trans_XXSPLTW(DisasContext *ctx, arg_XX2_uim *a) { int tofs, bofs; @@ -1795,42 +1795,35 @@ static void gen_xxsldwi(DisasContext *ctx) tcg_temp_free_i64(xtl); } -#define VSX_EXTRACT_INSERT(name) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_ptr xt, xb; \ - TCGv_i32 t0; \ - TCGv_i64 t1; \ - uint8_t uimm = UIMM4(ctx->opcode); \ - \ - if (unlikely(!ctx->vsx_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VSXU); \ - return; \ - } \ - xt = gen_vsr_ptr(xT(ctx->opcode)); \ - xb = gen_vsr_ptr(xB(ctx->opcode)); \ - t0 = tcg_temp_new_i32(); \ - t1 = tcg_temp_new_i64(); \ - /* \ - * uimm > 15 out of bound and for \ - * uimm > 12 handle as per hardware in helper \ - */ \ - if (uimm > 15) { \ - tcg_gen_movi_i64(t1, 0); \ - set_cpu_vsr(xT(ctx->opcode), t1, true); \ - set_cpu_vsr(xT(ctx->opcode), t1, false); \ - return; \ - } \ - tcg_gen_movi_i32(t0, uimm); \ - gen_helper_##name(cpu_env, xt, xb, t0); \ - tcg_temp_free_ptr(xb); \ - tcg_temp_free_ptr(xt); \ - tcg_temp_free_i32(t0); \ - tcg_temp_free_i64(t1); \ +static bool do_vsx_extract_insert(DisasContext *ctx, arg_XX2_uim *a, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_i32)) +{ + TCGv_i64 zero = tcg_constant_i64(0); + TCGv_ptr xt, xb; + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VSX(ctx); + + /* + * uim > 15 out of bound and for + * uim > 12 handle as per hardware in helper + */ + if (a->uim > 15) { + set_cpu_vsr(a->xt, zero, true); + set_cpu_vsr(a->xt, zero, false); + } else { + xt = gen_vsr_ptr(a->xt); + xb = gen_vsr_ptr(a->xb); + gen_helper(xt, xb, tcg_constant_i32(a->uim)); + tcg_temp_free_ptr(xb); + tcg_temp_free_ptr(xt); + } + + return true; } -VSX_EXTRACT_INSERT(xxextractuw) -VSX_EXTRACT_INSERT(xxinsertw) +TRANS(XXEXTRACTUW, do_vsx_extract_insert, gen_helper_XXEXTRACTUW) +TRANS(XXINSERTW, do_vsx_extract_insert, gen_helper_XXINSERTW) #ifdef TARGET_PPC64 static void gen_xsxexpdp(DisasContext *ctx) diff --git a/target/ppc/translate/vsx-ops.c.inc b/target/ppc/translate/vsx-ops.c.inc index 4524c5b02a..bff14bbece 100644 --- a/target/ppc/translate/vsx-ops.c.inc +++ b/target/ppc/translate/vsx-ops.c.inc @@ -320,5 +320,3 @@ VSX_LOGICAL(xxlorc, 0x8, 0x15, PPC2_VSX207), GEN_XX3FORM(xxmrghw, 0x08, 0x02, PPC2_VSX), GEN_XX3FORM(xxmrglw, 0x08, 0x06, PPC2_VSX), GEN_XX3FORM_DM(xxsldwi, 0x08, 0x00), -GEN_XX2FORM_EXT(xxextractuw, 0x0A, 0x0A, PPC2_ISA300), -GEN_XX2FORM_EXT(xxinsertw, 0x0A, 0x0B, PPC2_ISA300), From ffc2a2818a6ae321830de2a8c93c78d437c64171 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 17 May 2022 09:39:26 -0300 Subject: [PATCH 550/935] target/ppc: introduce do_va_helper Signed-off-by: Matheus Ferst Reviewed-by: Richard Henderson Message-Id: <20220517123929.284511-10-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/translate/vmx-impl.c.inc | 32 +++++------------------------ 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc index 764ac45409..e66301c007 100644 --- a/target/ppc/translate/vmx-impl.c.inc +++ b/target/ppc/translate/vmx-impl.c.inc @@ -2553,20 +2553,17 @@ static void gen_vmladduhm(DisasContext *ctx) tcg_temp_free_ptr(rd); } -static bool trans_VPERM(DisasContext *ctx, arg_VA *a) +static bool do_va_helper(DisasContext *ctx, arg_VA *a, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr)) { TCGv_ptr vrt, vra, vrb, vrc; - - REQUIRE_INSNS_FLAGS(ctx, ALTIVEC); REQUIRE_VECTOR(ctx); vrt = gen_avr_ptr(a->vrt); vra = gen_avr_ptr(a->vra); vrb = gen_avr_ptr(a->vrb); vrc = gen_avr_ptr(a->rc); - - gen_helper_VPERM(vrt, vra, vrb, vrc); - + gen_helper(vrt, vra, vrb, vrc); tcg_temp_free_ptr(vrt); tcg_temp_free_ptr(vra); tcg_temp_free_ptr(vrb); @@ -2575,27 +2572,8 @@ static bool trans_VPERM(DisasContext *ctx, arg_VA *a) return true; } -static bool trans_VPERMR(DisasContext *ctx, arg_VA *a) -{ - TCGv_ptr vrt, vra, vrb, vrc; - - REQUIRE_INSNS_FLAGS2(ctx, ISA300); - REQUIRE_VECTOR(ctx); - - vrt = gen_avr_ptr(a->vrt); - vra = gen_avr_ptr(a->vra); - vrb = gen_avr_ptr(a->vrb); - vrc = gen_avr_ptr(a->rc); - - gen_helper_VPERMR(vrt, vra, vrb, vrc); - - tcg_temp_free_ptr(vrt); - tcg_temp_free_ptr(vra); - tcg_temp_free_ptr(vrb); - tcg_temp_free_ptr(vrc); - - return true; -} +TRANS_FLAGS(ALTIVEC, VPERM, do_va_helper, gen_helper_VPERM) +TRANS_FLAGS2(ISA300, VPERMR, do_va_helper, gen_helper_VPERMR) static bool trans_VSEL(DisasContext *ctx, arg_VA *a) { From b2dc03a5c3a2bbfdf74121cd10d007803ea61e34 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 17 May 2022 09:39:27 -0300 Subject: [PATCH 551/935] target/ppc: declare vmsum[um]bm helpers with call flags Move vmsumubm and vmsummbm to decodetree, declare both helpers with TCG_CALL_NO_RWG, and drop the unused env argument. Signed-off-by: Matheus Ferst Reviewed-by: Richard Henderson Message-Id: <20220517123929.284511-11-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/helper.h | 4 ++-- target/ppc/insn32.decode | 3 +++ target/ppc/int_helper.c | 6 ++---- target/ppc/translate/vmx-impl.c.inc | 5 ++++- target/ppc/translate/vmx-ops.c.inc | 2 -- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 640a70cd5c..f0761fe38d 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -223,8 +223,8 @@ DEF_HELPER_FLAGS_2(vupkhsw, TCG_CALL_NO_RWG, void, avr, avr) DEF_HELPER_FLAGS_2(vupklsb, TCG_CALL_NO_RWG, void, avr, avr) DEF_HELPER_FLAGS_2(vupklsh, TCG_CALL_NO_RWG, void, avr, avr) DEF_HELPER_FLAGS_2(vupklsw, TCG_CALL_NO_RWG, void, avr, avr) -DEF_HELPER_5(vmsumubm, void, env, avr, avr, avr, avr) -DEF_HELPER_5(vmsummbm, void, env, avr, avr, avr, avr) +DEF_HELPER_FLAGS_4(VMSUMUBM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) +DEF_HELPER_FLAGS_4(VMSUMMBM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) DEF_HELPER_FLAGS_4(VPERM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) DEF_HELPER_FLAGS_4(VPERMR, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) DEF_HELPER_4(vpkshss, void, env, avr, avr, avr) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index 435cf1320c..fdb8d76456 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -599,6 +599,9 @@ VMULLD 000100 ..... ..... ..... 00111001001 @VX ## Vector Multiply-Sum Instructions +VMSUMUBM 000100 ..... ..... ..... ..... 100100 @VA +VMSUMMBM 000100 ..... ..... ..... ..... 100101 @VA + VMSUMCUD 000100 ..... ..... ..... ..... 010111 @VA VMSUMUDM 000100 ..... ..... ..... ..... 100011 @VA diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index 9a361ad241..85a7442103 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -875,8 +875,7 @@ VMRG(w, u32, VsrW) #undef VMRG_DO #undef VMRG -void helper_vmsummbm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, - ppc_avr_t *b, ppc_avr_t *c) +void helper_VMSUMMBM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int32_t prod[16]; int i; @@ -928,8 +927,7 @@ void helper_vmsumshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, } } -void helper_vmsumubm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, - ppc_avr_t *b, ppc_avr_t *c) +void helper_VMSUMUBM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { uint16_t prod[16]; int i; diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc index e66301c007..4cbd724641 100644 --- a/target/ppc/translate/vmx-impl.c.inc +++ b/target/ppc/translate/vmx-impl.c.inc @@ -2587,9 +2587,12 @@ static bool trans_VSEL(DisasContext *ctx, arg_VA *a) return true; } -GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18) GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19) GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20) + +TRANS_FLAGS(ALTIVEC, VMSUMUBM, do_va_helper, gen_helper_VMSUMUBM) +TRANS_FLAGS(ALTIVEC, VMSUMMBM, do_va_helper, gen_helper_VMSUMMBM) + GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23) GEN_VXFORM_NOA(vclzb, 1, 28) diff --git a/target/ppc/translate/vmx-ops.c.inc b/target/ppc/translate/vmx-ops.c.inc index d960648d52..5b85322c06 100644 --- a/target/ppc/translate/vmx-ops.c.inc +++ b/target/ppc/translate/vmx-ops.c.inc @@ -221,11 +221,9 @@ GEN_VXFORM_UIMM(vcfsx, 5, 13), GEN_VXFORM_UIMM(vctuxs, 5, 14), GEN_VXFORM_UIMM(vctsxs, 5, 15), - #define GEN_VAFORM_PAIRED(name0, name1, opc2) \ GEN_HANDLER(name0##_##name1, 0x04, opc2, 0xFF, 0x00000000, PPC_ALTIVEC) GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16), -GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18), GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19), GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20), GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23), From 89a5a1aee2df29c311d11386923b750bf1ea6bc2 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 17 May 2022 09:39:28 -0300 Subject: [PATCH 552/935] target/ppc: declare vmsumuh[ms] helper with call flags Move vmsumuhm and vmsumuhs to decodetree, declare vmsumuhm helper with TCG_CALL_NO_RWG, and drop the unused env argument. Signed-off-by: Matheus Ferst Reviewed-by: Richard Henderson Message-Id: <20220517123929.284511-12-matheus.ferst@eldorado.org.br> [danielhb: added #undef VMSUMUHM to fix ppc64 build] Signed-off-by: Daniel Henrique Barboza --- target/ppc/helper.h | 4 ++-- target/ppc/insn32.decode | 2 ++ target/ppc/int_helper.c | 5 ++--- target/ppc/translate/vmx-impl.c.inc | 24 ++++++++++++++++++++++-- target/ppc/translate/vmx-ops.c.inc | 1 - tcg/ppc/tcg-target.c.inc | 1 + 6 files changed, 29 insertions(+), 8 deletions(-) diff --git a/target/ppc/helper.h b/target/ppc/helper.h index f0761fe38d..5127851f2c 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -242,8 +242,8 @@ DEF_HELPER_4(vpkudum, void, env, avr, avr, avr) DEF_HELPER_FLAGS_3(vpkpx, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_5(vmhaddshs, void, env, avr, avr, avr, avr) DEF_HELPER_5(vmhraddshs, void, env, avr, avr, avr, avr) -DEF_HELPER_5(vmsumuhm, void, env, avr, avr, avr, avr) -DEF_HELPER_5(vmsumuhs, void, env, avr, avr, avr, avr) +DEF_HELPER_FLAGS_4(VMSUMUHM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) +DEF_HELPER_5(VMSUMUHS, void, env, avr, avr, avr, avr) DEF_HELPER_5(vmsumshm, void, env, avr, avr, avr, avr) DEF_HELPER_5(vmsumshs, void, env, avr, avr, avr, avr) DEF_HELPER_FLAGS_4(vmladduhm, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index fdb8d76456..43ea03c3e7 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -601,6 +601,8 @@ VMULLD 000100 ..... ..... ..... 00111001001 @VX VMSUMUBM 000100 ..... ..... ..... ..... 100100 @VA VMSUMMBM 000100 ..... ..... ..... ..... 100101 @VA +VMSUMUHM 000100 ..... ..... ..... ..... 100110 @VA +VMSUMUHS 000100 ..... ..... ..... ..... 100111 @VA VMSUMCUD 000100 ..... ..... ..... ..... 010111 @VA VMSUMUDM 000100 ..... ..... ..... ..... 100011 @VA diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index 85a7442103..9285a1c2a1 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -942,8 +942,7 @@ void helper_VMSUMUBM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } } -void helper_vmsumuhm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, - ppc_avr_t *b, ppc_avr_t *c) +void helper_VMSUMUHM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { uint32_t prod[8]; int i; @@ -957,7 +956,7 @@ void helper_vmsumuhm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, } } -void helper_vmsumuhs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, +void helper_VMSUMUHS(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { uint32_t prod[8]; diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc index 4cbd724641..da81296b96 100644 --- a/target/ppc/translate/vmx-impl.c.inc +++ b/target/ppc/translate/vmx-impl.c.inc @@ -2587,11 +2587,31 @@ static bool trans_VSEL(DisasContext *ctx, arg_VA *a) return true; } -GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19) GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20) - TRANS_FLAGS(ALTIVEC, VMSUMUBM, do_va_helper, gen_helper_VMSUMUBM) TRANS_FLAGS(ALTIVEC, VMSUMMBM, do_va_helper, gen_helper_VMSUMMBM) +TRANS_FLAGS(ALTIVEC, VMSUMUHM, do_va_helper, gen_helper_VMSUMUHM) + +static bool do_va_env_helper(DisasContext *ctx, arg_VA *a, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr)) +{ + TCGv_ptr vrt, vra, vrb, vrc; + REQUIRE_VECTOR(ctx); + + vrt = gen_avr_ptr(a->vrt); + vra = gen_avr_ptr(a->vra); + vrb = gen_avr_ptr(a->vrb); + vrc = gen_avr_ptr(a->rc); + gen_helper(cpu_env, vrt, vra, vrb, vrc); + tcg_temp_free_ptr(vrt); + tcg_temp_free_ptr(vra); + tcg_temp_free_ptr(vrb); + tcg_temp_free_ptr(vrc); + + return true; +} + +TRANS_FLAGS(ALTIVEC, VMSUMUHS, do_va_env_helper, gen_helper_VMSUMUHS) GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23) diff --git a/target/ppc/translate/vmx-ops.c.inc b/target/ppc/translate/vmx-ops.c.inc index 5b85322c06..15b3e06410 100644 --- a/target/ppc/translate/vmx-ops.c.inc +++ b/target/ppc/translate/vmx-ops.c.inc @@ -224,7 +224,6 @@ GEN_VXFORM_UIMM(vctsxs, 5, 15), #define GEN_VAFORM_PAIRED(name0, name1, opc2) \ GEN_HANDLER(name0##_##name1, 0x04, opc2, 0xFF, 0x00000000, PPC_ALTIVEC) GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16), -GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19), GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20), GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23), diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index cfcd121f9c..fc8ae47293 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -4008,3 +4008,4 @@ void tcg_register_jit(const void *buf, size_t buf_size) #undef VMULOUB #undef VMULOUH #undef VMULOUW +#undef VMSUMUHM From 6f52f731a666d8aeaac5a10b208e9ca6773fb1a6 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 17 May 2022 09:39:29 -0300 Subject: [PATCH 553/935] target/ppc: declare vmsumsh[ms] helper with call flags Move vmsumshm and vmsumshs to decodetree, declare vmsumshm helper with TCG_CALL_NO_RWG, and drop the unused env argument. Signed-off-by: Matheus Ferst Reviewed-by: Richard Henderson Message-Id: <20220517123929.284511-13-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/helper.h | 4 ++-- target/ppc/insn32.decode | 2 ++ target/ppc/int_helper.c | 5 ++--- target/ppc/translate/vmx-impl.c.inc | 3 ++- target/ppc/translate/vmx-ops.c.inc | 1 - 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 5127851f2c..5e43920b9e 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -244,8 +244,8 @@ DEF_HELPER_5(vmhaddshs, void, env, avr, avr, avr, avr) DEF_HELPER_5(vmhraddshs, void, env, avr, avr, avr, avr) DEF_HELPER_FLAGS_4(VMSUMUHM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) DEF_HELPER_5(VMSUMUHS, void, env, avr, avr, avr, avr) -DEF_HELPER_5(vmsumshm, void, env, avr, avr, avr, avr) -DEF_HELPER_5(vmsumshs, void, env, avr, avr, avr, avr) +DEF_HELPER_FLAGS_4(VMSUMSHM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) +DEF_HELPER_5(VMSUMSHS, void, env, avr, avr, avr, avr) DEF_HELPER_FLAGS_4(vmladduhm, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) DEF_HELPER_FLAGS_2(mtvscr, TCG_CALL_NO_RWG, void, env, i32) DEF_HELPER_FLAGS_1(mfvscr, TCG_CALL_NO_RWG, i32, env) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index 43ea03c3e7..f001c02a8c 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -601,6 +601,8 @@ VMULLD 000100 ..... ..... ..... 00111001001 @VX VMSUMUBM 000100 ..... ..... ..... ..... 100100 @VA VMSUMMBM 000100 ..... ..... ..... ..... 100101 @VA +VMSUMSHM 000100 ..... ..... ..... ..... 101000 @VA +VMSUMSHS 000100 ..... ..... ..... ..... 101001 @VA VMSUMUHM 000100 ..... ..... ..... ..... 100110 @VA VMSUMUHS 000100 ..... ..... ..... ..... 100111 @VA diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index 9285a1c2a1..b9dd15d607 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -890,8 +890,7 @@ void helper_VMSUMMBM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } } -void helper_vmsumshm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, - ppc_avr_t *b, ppc_avr_t *c) +void helper_VMSUMSHM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int32_t prod[8]; int i; @@ -905,7 +904,7 @@ void helper_vmsumshm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, } } -void helper_vmsumshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, +void helper_VMSUMSHS(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int32_t prod[8]; diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc index da81296b96..d7524c3204 100644 --- a/target/ppc/translate/vmx-impl.c.inc +++ b/target/ppc/translate/vmx-impl.c.inc @@ -2587,9 +2587,9 @@ static bool trans_VSEL(DisasContext *ctx, arg_VA *a) return true; } -GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20) TRANS_FLAGS(ALTIVEC, VMSUMUBM, do_va_helper, gen_helper_VMSUMUBM) TRANS_FLAGS(ALTIVEC, VMSUMMBM, do_va_helper, gen_helper_VMSUMMBM) +TRANS_FLAGS(ALTIVEC, VMSUMSHM, do_va_helper, gen_helper_VMSUMSHM) TRANS_FLAGS(ALTIVEC, VMSUMUHM, do_va_helper, gen_helper_VMSUMUHM) static bool do_va_env_helper(DisasContext *ctx, arg_VA *a, @@ -2612,6 +2612,7 @@ static bool do_va_env_helper(DisasContext *ctx, arg_VA *a, } TRANS_FLAGS(ALTIVEC, VMSUMUHS, do_va_env_helper, gen_helper_VMSUMUHS) +TRANS_FLAGS(ALTIVEC, VMSUMSHS, do_va_env_helper, gen_helper_VMSUMSHS) GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23) diff --git a/target/ppc/translate/vmx-ops.c.inc b/target/ppc/translate/vmx-ops.c.inc index 15b3e06410..d7cc57868e 100644 --- a/target/ppc/translate/vmx-ops.c.inc +++ b/target/ppc/translate/vmx-ops.c.inc @@ -224,7 +224,6 @@ GEN_VXFORM_UIMM(vctsxs, 5, 15), #define GEN_VAFORM_PAIRED(name0, name1, opc2) \ GEN_HANDLER(name0##_##name1, 0x04, opc2, 0xFF, 0x00000000, PPC_ALTIVEC) GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16), -GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20), GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23), GEN_VXFORM_DUAL(vclzb, vpopcntb, 1, 28, PPC_NONE, PPC2_ALTIVEC_207), From fcb830af30adaef6219f6b712f24ec3e794cf2c8 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 19 May 2022 23:59:05 +1000 Subject: [PATCH 554/935] target/ppc: Fix eieio memory ordering semantics The generated eieio memory ordering semantics do not match the instruction definition in the architecture. Add a big comment to explain this strange instruction and correct the memory ordering behaviour. Signed-off: Nicholas Piggin Reviewed-by: Richard Henderson Message-Id: <20220519135908.21282-2-npiggin@gmail.com> Signed-off-by: Daniel Henrique Barboza --- target/ppc/translate.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index fa34f81c30..eb42f7e459 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -3513,7 +3513,32 @@ static void gen_stswx(DisasContext *ctx) /* eieio */ static void gen_eieio(DisasContext *ctx) { - TCGBar bar = TCG_MO_LD_ST; + TCGBar bar = TCG_MO_ALL; + + /* + * eieio has complex semanitcs. It provides memory ordering between + * operations in the set: + * - loads from CI memory. + * - stores to CI memory. + * - stores to WT memory. + * + * It separately also orders memory for operations in the set: + * - stores to cacheble memory. + * + * It also serializes instructions: + * - dcbt and dcbst. + * + * It separately serializes: + * - tlbie and tlbsync. + * + * And separately serializes: + * - slbieg, slbiag, and slbsync. + * + * The end result is that CI memory ordering requires TCG_MO_ALL + * and it is not possible to special-case more relaxed ordering for + * cacheable accesses. TCG_BAR_SC is required to provide this + * serialization. + */ /* * POWER9 has a eieio instruction variant using bit 6 as a hint to From 9d82353826422ed0e34ad76961fe0cae5f67e58e Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 19 May 2022 23:59:06 +1000 Subject: [PATCH 555/935] tcg/ppc: ST_ST memory ordering is not provided with eieio eieio does not provide ordering between stores to CI memory and stores to cacheable memory so it can't be used as a general ST_ST barrier. Reviewed-by: Richard Henderson Signed-of-by: Nicholas Piggin Message-Id: <20220519135908.21282-3-npiggin@gmail.com> Signed-off-by: Daniel Henrique Barboza --- tcg/ppc/tcg-target.c.inc | 2 -- 1 file changed, 2 deletions(-) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index fc8ae47293..4750091c9c 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -1836,8 +1836,6 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0) a0 &= TCG_MO_ALL; if (a0 == TCG_MO_LD_LD) { insn = LWSYNC; - } else if (a0 == TCG_MO_ST_ST) { - insn = EIEIO; } tcg_out32(s, insn); } From fc879703f74851e3e861894a0c4a6902877d0c2c Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 19 May 2022 23:59:07 +1000 Subject: [PATCH 556/935] tcg/ppc: Optimize memory ordering generation with lwsync lwsync orders more than just LD_LD, importantly it matches x86 and s390 default memory ordering. Signed-off-by: Nicholas Piggin Reviewed-by: Richard Henderson Message-Id: <20220519135908.21282-4-npiggin@gmail.com> Signed-off-by: Daniel Henrique Barboza --- tcg/ppc/tcg-target.c.inc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 4750091c9c..de4483e43b 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -1832,11 +1832,14 @@ static void tcg_out_brcond2 (TCGContext *s, const TCGArg *args, static void tcg_out_mb(TCGContext *s, TCGArg a0) { - uint32_t insn = HWSYNC; - a0 &= TCG_MO_ALL; - if (a0 == TCG_MO_LD_LD) { + uint32_t insn; + + if (a0 & TCG_MO_ST_LD) { + insn = HWSYNC; + } else { insn = LWSYNC; } + tcg_out32(s, insn); } From 03abfd90cfb02aa08f44bbb7141b0aaaf69042ef Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 19 May 2022 23:59:08 +1000 Subject: [PATCH 557/935] target/ppc: Implement lwsync with weaker memory ordering This allows an x86 host to no-op lwsyncs, and ppc host can use lwsync rather than sync. Signed-off-by: Nicholas Piggin Reviewed-by: Richard Henderson Message-Id: <20220519135908.21282-5-npiggin@gmail.com> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 4 +++- target/ppc/cpu_init.c | 13 +++++++------ target/ppc/machine.c | 3 ++- target/ppc/translate.c | 8 +++++++- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 901ded79e9..bf8f8aad2c 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -2273,6 +2273,8 @@ enum { PPC2_ISA300 = 0x0000000000080000ULL, /* POWER ISA 3.1 */ PPC2_ISA310 = 0x0000000000100000ULL, + /* lwsync instruction */ + PPC2_MEM_LWSYNC = 0x0000000000200000ULL, #define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \ PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \ @@ -2281,7 +2283,7 @@ enum { PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \ PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP | \ PPC2_FP_CVT_S64 | PPC2_TM | PPC2_PM_ISA206 | \ - PPC2_ISA300 | PPC2_ISA310) + PPC2_ISA300 | PPC2_ISA310 | PPC2_MEM_LWSYNC) }; /*****************************************************************************/ diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 527ad40fcb..0f891afa04 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -5769,7 +5769,7 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void *data) PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_64B | PPC_ALTIVEC | PPC_SEGMENT_64B | PPC_SLBI; - pcc->insns_flags2 = PPC2_FP_CVT_S64; + pcc->insns_flags2 = PPC2_FP_CVT_S64 | PPC2_MEM_LWSYNC; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_VR) | (1ull << MSR_POW) | @@ -5846,7 +5846,7 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data) PPC_64B | PPC_POPCNTB | PPC_SEGMENT_64B | PPC_SLBI; - pcc->insns_flags2 = PPC2_FP_CVT_S64; + pcc->insns_flags2 = PPC2_FP_CVT_S64 | PPC2_MEM_LWSYNC; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_VR) | (1ull << MSR_POW) | @@ -5985,7 +5985,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | PPC2_FP_CVT_S64 | - PPC2_PM_ISA206; + PPC2_PM_ISA206 | PPC2_MEM_LWSYNC; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_VR) | (1ull << MSR_VSX) | @@ -6159,7 +6159,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 | PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 | - PPC2_TM | PPC2_PM_ISA206; + PPC2_TM | PPC2_PM_ISA206 | PPC2_MEM_LWSYNC; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_HV) | (1ull << MSR_TM) | @@ -6379,7 +6379,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 | PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 | - PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL; + PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL | PPC2_MEM_LWSYNC; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_HV) | (1ull << MSR_TM) | @@ -6596,7 +6596,8 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data) PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 | PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 | - PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL | PPC2_ISA310; + PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL | PPC2_ISA310 | + PPC2_MEM_LWSYNC; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_HV) | (1ull << MSR_TM) | diff --git a/target/ppc/machine.c b/target/ppc/machine.c index 7104a5c67e..a7d9036c09 100644 --- a/target/ppc/machine.c +++ b/target/ppc/machine.c @@ -157,7 +157,8 @@ static int cpu_pre_save(void *opaque) | PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 - | PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 | PPC2_TM; + | PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 | PPC2_TM + | PPC2_MEM_LWSYNC; env->spr[SPR_LR] = env->lr; env->spr[SPR_CTR] = env->ctr; diff --git a/target/ppc/translate.c b/target/ppc/translate.c index eb42f7e459..1d6daa4608 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -4041,8 +4041,13 @@ static void gen_stqcx_(DisasContext *ctx) /* sync */ static void gen_sync(DisasContext *ctx) { + TCGBar bar = TCG_MO_ALL; uint32_t l = (ctx->opcode >> 21) & 3; + if ((l == 1) && (ctx->insns_flags2 & PPC2_MEM_LWSYNC)) { + bar = TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST; + } + /* * We may need to check for a pending TLB flush. * @@ -4054,7 +4059,8 @@ static void gen_sync(DisasContext *ctx) if (((l == 2) || !(ctx->insns_flags & PPC_64B)) && !ctx->pr) { gen_check_tlb_flush(ctx, true); } - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); + + tcg_gen_mb(bar | TCG_BAR_SC); } /* wait */ From a702c5339eda791b969ed531ce99456df7ca8451 Mon Sep 17 00:00:00 2001 From: "Lucas Mateus Castro (alqotel)" Date: Tue, 24 May 2022 11:05:30 -0300 Subject: [PATCH 558/935] target/ppc: Implement xxm[tf]acc and xxsetaccz Implement the following PowerISA v3.1 instructions: xxmfacc: VSX Move From Accumulator xxmtacc: VSX Move To Accumulator xxsetaccz: VSX Set Accumulator to Zero The PowerISA 3.1 mentions that for the current version of the architecture, "the hardware implementation provides the effect of ACC[i] and VSRs 4*i to 4*i + 3 logically containing the same data" and "The Accumulators introduce no new logical state at this time" (page 501). For now it seems unnecessary to create new structures, so this patch just uses ACC[i] as VSRs 4*i to 4*i+3 and therefore move to and from accumulators are no-ops. Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20220524140537.27451-2-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 5 +++++ target/ppc/insn32.decode | 9 +++++++++ target/ppc/translate/vsx-impl.c.inc | 31 +++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index bf8f8aad2c..c865206827 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -2663,6 +2663,11 @@ static inline int vsr_full_offset(int i) return offsetof(CPUPPCState, vsr[i].u64[0]); } +static inline int acc_full_offset(int i) +{ + return vsr_full_offset(i * 4); +} + static inline int fpr_offset(int i) { return vsr64_offset(i, true); diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index f001c02a8c..c0f545ca38 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -154,6 +154,9 @@ &X_vrt_frbp vrt frbp @X_vrt_frbp ...... vrt:5 ..... ....0 .......... . &X_vrt_frbp frbp=%x_frbp +&X_a ra +@X_a ...... ra:3 .. ..... ..... .......... . &X_a + %xx_xt 0:1 21:5 %xx_xb 1:1 11:5 %xx_xa 2:1 16:5 @@ -734,3 +737,9 @@ XVTLSBB 111100 ... -- 00010 ..... 111011011 . - @XX2_bf_xb &XL_s s:uint8_t @XL_s ......-------------- s:1 .......... - &XL_s RFEBB 010011-------------- . 0010010010 - @XL_s + +## Accumulator Instructions + +XXMFACC 011111 ... -- 00000 ----- 0010110001 - @X_a +XXMTACC 011111 ... -- 00001 ----- 0010110001 - @X_a +XXSETACCZ 011111 ... -- 00011 ----- 0010110001 - @X_a diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index 900c1a1ab2..235be360e2 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -2816,6 +2816,37 @@ static bool trans_XVCVBF16SPN(DisasContext *ctx, arg_XX2 *a) return true; } + /* + * The PowerISA 3.1 mentions that for the current version of the + * architecture, "the hardware implementation provides the effect of + * ACC[i] and VSRs 4*i to 4*i + 3 logically containing the same data" + * and "The Accumulators introduce no new logical state at this time" + * (page 501). For now it seems unnecessary to create new structures, + * so ACC[i] is the same as VSRs 4*i to 4*i+3 and therefore + * move to and from accumulators are no-ops. + */ +static bool trans_XXMFACC(DisasContext *ctx, arg_X_a *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + return true; +} + +static bool trans_XXMTACC(DisasContext *ctx, arg_X_a *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + return true; +} + +static bool trans_XXSETACCZ(DisasContext *ctx, arg_X_a *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + tcg_gen_gvec_dup_imm(MO_64, acc_full_offset(a->ra), 64, 64, 0); + return true; +} + #undef GEN_XX2FORM #undef GEN_XX3FORM #undef GEN_XX2IFORM From 345531533f26df49e74f16dafc88408408173ece Mon Sep 17 00:00:00 2001 From: "Lucas Mateus Castro (alqotel)" Date: Tue, 24 May 2022 11:05:31 -0300 Subject: [PATCH 559/935] target/ppc: Implemented xvi*ger* instructions Implement the following PowerISA v3.1 instructions: xvi4ger8: VSX Vector 8-bit Signed/Unsigned Integer GER (rank-4 update) xvi4ger8pp: VSX Vector 8-bit Signed/Unsigned Integer GER (rank-4 update) Positive multiply, Positive accumulate xvi8ger4: VSX Vector 4-bit Signed Integer GER (rank-8 update) xvi8ger4pp: VSX Vector 4-bit Signed Integer GER (rank-8 update) Positive multiply, Positive accumulate xvi8ger4spp: VSX Vector 8-bit Signed/Unsigned Integer GER (rank-4 update) with Saturate Positive multiply, Positive accumulate xvi16ger2: VSX Vector 16-bit Signed Integer GER (rank-2 update) xvi16ger2pp: VSX Vector 16-bit Signed Integer GER (rank-2 update) Positive multiply, Positive accumulate xvi16ger2s: VSX Vector 16-bit Signed Integer GER (rank-2 update) with Saturation xvi16ger2spp: VSX Vector 16-bit Signed Integer GER (rank-2 update) with Saturation Positive multiply, Positive accumulate Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20220524140537.27451-3-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 1 + target/ppc/helper.h | 13 +++ target/ppc/insn32.decode | 18 ++++ target/ppc/int_helper.c | 130 ++++++++++++++++++++++++++++ target/ppc/internal.h | 15 ++++ target/ppc/translate/vsx-impl.c.inc | 41 +++++++++ 6 files changed, 218 insertions(+) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index c865206827..dff3ca8222 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -238,6 +238,7 @@ typedef union _ppc_vsr_t { typedef ppc_vsr_t ppc_avr_t; typedef ppc_vsr_t ppc_fprp_t; +typedef ppc_vsr_t ppc_acc_t; #if !defined(CONFIG_USER_ONLY) /* Software TLB cache */ diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 5e43920b9e..1666797edf 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -133,6 +133,10 @@ DEF_HELPER_FLAGS_1(ftsqrt, TCG_CALL_NO_RWG_SE, i32, i64) #define dh_ctype_vsr ppc_vsr_t * #define dh_typecode_vsr dh_typecode_ptr +#define dh_alias_acc ptr +#define dh_ctype_acc ppc_acc_t * +#define dh_typecode_acc dh_typecode_ptr + DEF_HELPER_FLAGS_3(vavgub, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(vavguh, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(vavguw, TCG_CALL_NO_RWG, void, avr, avr, avr) @@ -537,6 +541,15 @@ DEF_HELPER_FLAGS_5(XXBLENDVB, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, i32) DEF_HELPER_FLAGS_5(XXBLENDVH, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, i32) DEF_HELPER_FLAGS_5(XXBLENDVW, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, i32) DEF_HELPER_FLAGS_5(XXBLENDVD, TCG_CALL_NO_RWG, void, vsr, vsr, vsr, vsr, i32) +DEF_HELPER_5(XVI4GER8, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVI4GER8PP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVI8GER4, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVI8GER4PP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVI8GER4SPP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVI16GER2, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVI16GER2S, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVI16GER2PP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVI16GER2SPP, void, env, vsr, vsr, acc, i32) DEF_HELPER_2(efscfsi, i32, env, i32) DEF_HELPER_2(efscfui, i32, env, i32) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index c0f545ca38..0e189fe2da 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -175,6 +175,12 @@ &XX3 xt xa xb @XX3 ...... ..... ..... ..... ........ ... &XX3 xt=%xx_xt xa=%xx_xa xb=%xx_xb +# 32 bit GER instructions have all mask bits considered 1 +&MMIRR_XX3 xa xb xt pmsk xmsk ymsk +%xx_at 23:3 +@XX3_at ...... ... .. ..... ..... ........ ... &MMIRR_XX3 xt=%xx_at xb=%xx_xb \ + pmsk=255 xmsk=15 ymsk=15 + &XX3_dm xt xa xb dm @XX3_dm ...... ..... ..... ..... . dm:2 ..... ... &XX3_dm xt=%xx_xt xa=%xx_xa xb=%xx_xb @@ -743,3 +749,15 @@ RFEBB 010011-------------- . 0010010010 - @XL_s XXMFACC 011111 ... -- 00000 ----- 0010110001 - @X_a XXMTACC 011111 ... -- 00001 ----- 0010110001 - @X_a XXSETACCZ 011111 ... -- 00011 ----- 0010110001 - @X_a + +## VSX GER instruction + +XVI4GER8 111011 ... -- ..... ..... 00100011 ..- @XX3_at xa=%xx_xa +XVI4GER8PP 111011 ... -- ..... ..... 00100010 ..- @XX3_at xa=%xx_xa +XVI8GER4 111011 ... -- ..... ..... 00000011 ..- @XX3_at xa=%xx_xa +XVI8GER4PP 111011 ... -- ..... ..... 00000010 ..- @XX3_at xa=%xx_xa +XVI16GER2 111011 ... -- ..... ..... 01001011 ..- @XX3_at xa=%xx_xa +XVI16GER2PP 111011 ... -- ..... ..... 01101011 ..- @XX3_at xa=%xx_xa +XVI8GER4SPP 111011 ... -- ..... ..... 01100011 ..- @XX3_at xa=%xx_xa +XVI16GER2S 111011 ... -- ..... ..... 00101011 ..- @XX3_at xa=%xx_xa +XVI16GER2SPP 111011 ... -- ..... ..... 00101010 ..- @XX3_at xa=%xx_xa diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index b9dd15d607..105b626d1b 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -782,6 +782,136 @@ VCT(uxs, cvtsduw, u32) VCT(sxs, cvtsdsw, s32) #undef VCT +typedef int64_t do_ger(uint32_t, uint32_t, uint32_t); + +static int64_t ger_rank8(uint32_t a, uint32_t b, uint32_t mask) +{ + int64_t psum = 0; + for (int i = 0; i < 8; i++, mask >>= 1) { + if (mask & 1) { + psum += sextract32(a, 4 * i, 4) * sextract32(b, 4 * i, 4); + } + } + return psum; +} + +static int64_t ger_rank4(uint32_t a, uint32_t b, uint32_t mask) +{ + int64_t psum = 0; + for (int i = 0; i < 4; i++, mask >>= 1) { + if (mask & 1) { + psum += sextract32(a, 8 * i, 8) * (int64_t)extract32(b, 8 * i, 8); + } + } + return psum; +} + +static int64_t ger_rank2(uint32_t a, uint32_t b, uint32_t mask) +{ + int64_t psum = 0; + for (int i = 0; i < 2; i++, mask >>= 1) { + if (mask & 1) { + psum += sextract32(a, 16 * i, 16) * sextract32(b, 16 * i, 16); + } + } + return psum; +} + +static void xviger(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, ppc_acc_t *at, + uint32_t mask, bool sat, bool acc, do_ger ger) +{ + uint8_t pmsk = FIELD_EX32(mask, GER_MSK, PMSK), + xmsk = FIELD_EX32(mask, GER_MSK, XMSK), + ymsk = FIELD_EX32(mask, GER_MSK, YMSK); + uint8_t xmsk_bit, ymsk_bit; + int64_t psum; + int i, j; + for (i = 0, xmsk_bit = 1 << 3; i < 4; i++, xmsk_bit >>= 1) { + for (j = 0, ymsk_bit = 1 << 3; j < 4; j++, ymsk_bit >>= 1) { + if ((xmsk_bit & xmsk) && (ymsk_bit & ymsk)) { + psum = ger(a->VsrW(i), b->VsrW(j), pmsk); + if (acc) { + psum += at[i].VsrSW(j); + } + if (sat && psum > INT32_MAX) { + set_vscr_sat(env); + at[i].VsrSW(j) = INT32_MAX; + } else if (sat && psum < INT32_MIN) { + set_vscr_sat(env); + at[i].VsrSW(j) = INT32_MIN; + } else { + at[i].VsrSW(j) = (int32_t) psum; + } + } else { + at[i].VsrSW(j) = 0; + } + } + } +} + +QEMU_FLATTEN +void helper_XVI4GER8(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + xviger(env, a, b, at, mask, false, false, ger_rank8); +} + +QEMU_FLATTEN +void helper_XVI4GER8PP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + xviger(env, a, b, at, mask, false, true, ger_rank8); +} + +QEMU_FLATTEN +void helper_XVI8GER4(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + xviger(env, a, b, at, mask, false, false, ger_rank4); +} + +QEMU_FLATTEN +void helper_XVI8GER4PP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + xviger(env, a, b, at, mask, false, true, ger_rank4); +} + +QEMU_FLATTEN +void helper_XVI8GER4SPP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + xviger(env, a, b, at, mask, true, true, ger_rank4); +} + +QEMU_FLATTEN +void helper_XVI16GER2(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + xviger(env, a, b, at, mask, false, false, ger_rank2); +} + +QEMU_FLATTEN +void helper_XVI16GER2S(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + xviger(env, a, b, at, mask, true, false, ger_rank2); +} + +QEMU_FLATTEN +void helper_XVI16GER2PP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + xviger(env, a, b, at, mask, false, true, ger_rank2); +} + +QEMU_FLATTEN +void helper_XVI16GER2SPP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + xviger(env, a, b, at, mask, true, true, ger_rank2); +} + target_ulong helper_vclzlsbb(ppc_avr_t *r) { target_ulong count = 0; diff --git a/target/ppc/internal.h b/target/ppc/internal.h index 8094e0b033..2add128cd1 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -18,6 +18,8 @@ #ifndef PPC_INTERNAL_H #define PPC_INTERNAL_H +#include "hw/registerfields.h" + #define FUNC_MASK(name, ret_type, size, max_val) \ static inline ret_type name(uint##size##_t start, \ uint##size##_t end) \ @@ -291,4 +293,17 @@ G_NORETURN void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr addr, uintptr_t retaddr); #endif +FIELD(GER_MSK, XMSK, 0, 4) +FIELD(GER_MSK, YMSK, 4, 4) +FIELD(GER_MSK, PMSK, 8, 8) + +static inline int ger_pack_masks(int pmsk, int ymsk, int xmsk) +{ + int msk = 0; + msk = FIELD_DP32(msk, GER_MSK, XMSK, xmsk); + msk = FIELD_DP32(msk, GER_MSK, YMSK, ymsk); + msk = FIELD_DP32(msk, GER_MSK, PMSK, pmsk); + return msk; +} + #endif /* PPC_INTERNAL_H */ diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index 235be360e2..6026b203e0 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -17,6 +17,13 @@ static inline TCGv_ptr gen_vsr_ptr(int reg) return r; } +static inline TCGv_ptr gen_acc_ptr(int reg) +{ + TCGv_ptr r = tcg_temp_new_ptr(); + tcg_gen_addi_ptr(r, cpu_env, acc_full_offset(reg)); + return r; +} + #define VSX_LOAD_SCALAR(name, operation) \ static void gen_##name(DisasContext *ctx) \ { \ @@ -2847,6 +2854,40 @@ static bool trans_XXSETACCZ(DisasContext *ctx, arg_X_a *a) return true; } +static bool do_ger(DisasContext *ctx, arg_MMIRR_XX3 *a, + void (*helper)(TCGv_env, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32)) +{ + uint32_t mask; + TCGv_ptr xt, xa, xb; + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + if (unlikely((a->xa / 4 == a->xt) || (a->xb / 4 == a->xt))) { + gen_invalid(ctx); + return true; + } + + xt = gen_acc_ptr(a->xt); + xa = gen_vsr_ptr(a->xa); + xb = gen_vsr_ptr(a->xb); + + mask = ger_pack_masks(a->pmsk, a->ymsk, a->xmsk); + helper(cpu_env, xa, xb, xt, tcg_constant_i32(mask)); + tcg_temp_free_ptr(xt); + tcg_temp_free_ptr(xa); + tcg_temp_free_ptr(xb); + return true; +} + +TRANS(XVI4GER8, do_ger, gen_helper_XVI4GER8) +TRANS(XVI4GER8PP, do_ger, gen_helper_XVI4GER8PP) +TRANS(XVI8GER4, do_ger, gen_helper_XVI8GER4) +TRANS(XVI8GER4PP, do_ger, gen_helper_XVI8GER4PP) +TRANS(XVI8GER4SPP, do_ger, gen_helper_XVI8GER4SPP) +TRANS(XVI16GER2, do_ger, gen_helper_XVI16GER2) +TRANS(XVI16GER2PP, do_ger, gen_helper_XVI16GER2PP) +TRANS(XVI16GER2S, do_ger, gen_helper_XVI16GER2S) +TRANS(XVI16GER2SPP, do_ger, gen_helper_XVI16GER2SPP) + #undef GEN_XX2FORM #undef GEN_XX3FORM #undef GEN_XX2IFORM From 6d525ca972085fb82fe2dec04fdf257318f9e5a5 Mon Sep 17 00:00:00 2001 From: "Lucas Mateus Castro (alqotel)" Date: Tue, 24 May 2022 11:05:32 -0300 Subject: [PATCH 560/935] target/ppc: Implemented pmxvi*ger* instructions Implement the following PowerISA v3.1 instructions: pmxvi4ger8: Prefixed Masked VSX Vector 8-bit Signed/Unsigned Integer GER (rank-4 update) pmxvi4ger8pp: Prefixed Masked VSX Vector 8-bit Signed/Unsigned Integer GER (rank-4 update) Positive multiply, Positive accumulate pmxvi8ger4: Prefixed Masked VSX Vector 4-bit Signed Integer GER (rank-8 update) pmxvi8ger4pp: Prefixed Masked VSX Vector 4-bit Signed Integer GER (rank-8 update) Positive multiply, Positive accumulate pmxvi8ger4spp: Prefixed Masked VSX Vector 8-bit Signed/Unsigned Integer GER (rank-4 update) with Saturate Positive multiply, Positive accumulate pmxvi16ger2: Prefixed Masked VSX Vector 16-bit Signed Integer GER (rank-2 update) pmxvi16ger2pp: Prefixed Masked VSX Vector 16-bit Signed Integer GER (rank-2 update) Positive multiply, Positive accumulate pmxvi16ger2s: Prefixed Masked VSX Vector 16-bit Signed Integer GER (rank-2 update) with Saturation pmxvi16ger2spp: Prefixed Masked VSX Vector 16-bit Signed Integer GER (rank-2 update) with Saturation Positive multiply, Positive accumulate Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20220524140537.27451-4-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/insn64.decode | 30 +++++++++++++++++++++++++++++ target/ppc/translate/vsx-impl.c.inc | 10 ++++++++++ 2 files changed, 40 insertions(+) diff --git a/target/ppc/insn64.decode b/target/ppc/insn64.decode index 691e8fe6c0..0eed35c8cd 100644 --- a/target/ppc/insn64.decode +++ b/target/ppc/insn64.decode @@ -68,6 +68,15 @@ ...... ..... ..... ..... ..... .. .... \ &8RR_XX4_uim3 xt=%8rr_xx_xt xa=%8rr_xx_xa xb=%8rr_xx_xb xc=%8rr_xx_xc +# Format MMIRR:XX3 +&MMIRR_XX3 !extern xa xb xt pmsk xmsk ymsk +%xx3_xa 2:1 16:5 +%xx3_xb 1:1 11:5 +%xx3_at 23:3 +@MMIRR_XX3 ...... .. .... .. . . ........ xmsk:4 ymsk:4 \ + ...... ... .. ..... ..... ........ ... \ + &MMIRR_XX3 xa=%xx3_xa xb=%xx3_xb xt=%xx3_at + ### Fixed-Point Load Instructions PLBZ 000001 10 0--.-- .................. \ @@ -115,6 +124,27 @@ PSTFS 000001 10 0--.-- .................. \ PSTFD 000001 10 0--.-- .................. \ 110110 ..... ..... ................ @PLS_D +## VSX GER instruction + +PMXVI4GER8 000001 11 1001 -- - - pmsk:8 ........ \ + 111011 ... -- ..... ..... 00100011 ..- @MMIRR_XX3 +PMXVI4GER8PP 000001 11 1001 -- - - pmsk:8 ........ \ + 111011 ... -- ..... ..... 00100010 ..- @MMIRR_XX3 +PMXVI8GER4 000001 11 1001 -- - - pmsk:4 ---- ........ \ + 111011 ... -- ..... ..... 00000011 ..- @MMIRR_XX3 +PMXVI8GER4PP 000001 11 1001 -- - - pmsk:4 ---- ........ \ + 111011 ... -- ..... ..... 00000010 ..- @MMIRR_XX3 +PMXVI16GER2 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 01001011 ..- @MMIRR_XX3 +PMXVI16GER2PP 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 01101011 ..- @MMIRR_XX3 +PMXVI8GER4SPP 000001 11 1001 -- - - pmsk:4 ---- ........ \ + 111011 ... -- ..... ..... 01100011 ..- @MMIRR_XX3 +PMXVI16GER2S 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 00101011 ..- @MMIRR_XX3 +PMXVI16GER2SPP 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 00101010 ..- @MMIRR_XX3 + ### Prefixed No-operation Instruction @PNOP 000001 11 0000-- 000000000000000000 \ diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index 6026b203e0..b10eded1da 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -2888,6 +2888,16 @@ TRANS(XVI16GER2PP, do_ger, gen_helper_XVI16GER2PP) TRANS(XVI16GER2S, do_ger, gen_helper_XVI16GER2S) TRANS(XVI16GER2SPP, do_ger, gen_helper_XVI16GER2SPP) +TRANS64(PMXVI4GER8, do_ger, gen_helper_XVI4GER8) +TRANS64(PMXVI4GER8PP, do_ger, gen_helper_XVI4GER8PP) +TRANS64(PMXVI8GER4, do_ger, gen_helper_XVI8GER4) +TRANS64(PMXVI8GER4PP, do_ger, gen_helper_XVI8GER4PP) +TRANS64(PMXVI8GER4SPP, do_ger, gen_helper_XVI8GER4SPP) +TRANS64(PMXVI16GER2, do_ger, gen_helper_XVI16GER2) +TRANS64(PMXVI16GER2PP, do_ger, gen_helper_XVI16GER2PP) +TRANS64(PMXVI16GER2S, do_ger, gen_helper_XVI16GER2S) +TRANS64(PMXVI16GER2SPP, do_ger, gen_helper_XVI16GER2SPP) + #undef GEN_XX2FORM #undef GEN_XX3FORM #undef GEN_XX2IFORM From c29018cc7395fdb7efd5e21c6f6c4d9cfbcf9a3c Mon Sep 17 00:00:00 2001 From: "Lucas Mateus Castro (alqotel)" Date: Tue, 24 May 2022 11:05:33 -0300 Subject: [PATCH 561/935] target/ppc: Implemented xvf*ger* Implement the following PowerISA v3.1 instructions: xvf32ger: VSX Vector 32-bit Floating-Point GER (rank-1 update) xvf32gernn: VSX Vector 32-bit Floating-Point GER (rank-1 update) Negative multiply, Negative accumulate xvf32gernp: VSX Vector 32-bit Floating-Point GER (rank-1 update) Negative multiply, Positive accumulate xvf32gerpn: VSX Vector 32-bit Floating-Point GER (rank-1 update) Positive multiply, Negative accumulate xvf32gerpp: VSX Vector 32-bit Floating-Point GER (rank-1 update) Positive multiply, Positive accumulate xvf64ger: VSX Vector 64-bit Floating-Point GER (rank-1 update) xvf64gernn: VSX Vector 64-bit Floating-Point GER (rank-1 update) Negative multiply, Negative accumulate xvf64gernp: VSX Vector 64-bit Floating-Point GER (rank-1 update) Negative multiply, Positive accumulate xvf64gerpn: VSX Vector 64-bit Floating-Point GER (rank-1 update) Positive multiply, Negative accumulate xvf64gerpp: VSX Vector 64-bit Floating-Point GER (rank-1 update) Positive multiply, Positive accumulate Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20220524140537.27451-5-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 4 + target/ppc/fpu_helper.c | 194 +++++++++++++++++++++++++++- target/ppc/helper.h | 10 ++ target/ppc/insn32.decode | 13 ++ target/ppc/translate/vsx-impl.c.inc | 12 ++ 5 files changed, 231 insertions(+), 2 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index dff3ca8222..40c779f246 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -2643,6 +2643,8 @@ static inline bool lsw_reg_in_range(int start, int nregs, int rx) #define VsrSW(i) s32[i] #define VsrD(i) u64[i] #define VsrSD(i) s64[i] +#define VsrSF(i) f32[i] +#define VsrDF(i) f64[i] #else #define VsrB(i) u8[15 - (i)] #define VsrSB(i) s8[15 - (i)] @@ -2652,6 +2654,8 @@ static inline bool lsw_reg_in_range(int start, int nregs, int rx) #define VsrSW(i) s32[3 - (i)] #define VsrD(i) u64[1 - (i)] #define VsrSD(i) s64[1 - (i)] +#define VsrSF(i) f32[3 - (i)] +#define VsrDF(i) f64[1 - (i)] #endif static inline int vsr64_offset(int i, bool high) diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 9489e06504..712c71162c 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -414,7 +414,7 @@ void helper_store_fpscr(CPUPPCState *env, uint64_t val, uint32_t nibbles) ppc_store_fpscr(env, val); } -void helper_fpscr_check_status(CPUPPCState *env) +static void do_fpscr_check_status(CPUPPCState *env, uintptr_t raddr) { CPUState *cs = env_cpu(env); target_ulong fpscr = env->fpscr; @@ -455,13 +455,19 @@ void helper_fpscr_check_status(CPUPPCState *env) } cs->exception_index = POWERPC_EXCP_PROGRAM; env->error_code = error | POWERPC_EXCP_FP; + env->fpscr |= error ? FP_FEX : 0; /* Deferred floating-point exception after target FPSCR update */ if (fp_exceptions_enabled(env)) { raise_exception_err_ra(env, cs->exception_index, - env->error_code, GETPC()); + env->error_code, raddr); } } +void helper_fpscr_check_status(CPUPPCState *env) +{ + do_fpscr_check_status(env, GETPC()); +} + static void do_float_check_status(CPUPPCState *env, bool change_fi, uintptr_t raddr) { @@ -3468,3 +3474,187 @@ void helper_xssubqp(CPUPPCState *env, uint32_t opcode, *xt = t; do_float_check_status(env, true, GETPC()); } + +static inline void vsxger_excp(CPUPPCState *env, uintptr_t retaddr) +{ + /* + * XV*GER instructions execute and set the FPSCR as if exceptions + * are disabled and only at the end throw an exception + */ + target_ulong enable; + enable = env->fpscr & (FP_ENABLES | FP_FI | FP_FR); + env->fpscr &= ~(FP_ENABLES | FP_FI | FP_FR); + int status = get_float_exception_flags(&env->fp_status); + if (unlikely(status & float_flag_invalid)) { + if (status & float_flag_invalid_snan) { + float_invalid_op_vxsnan(env, 0); + } + if (status & float_flag_invalid_imz) { + float_invalid_op_vximz(env, false, 0); + } + if (status & float_flag_invalid_isi) { + float_invalid_op_vxisi(env, false, 0); + } + } + do_float_check_status(env, false, retaddr); + env->fpscr |= enable; + do_fpscr_check_status(env, retaddr); +} + +typedef void vsxger_zero(ppc_vsr_t *at, int, int); + +typedef void vsxger_muladd_f(ppc_vsr_t *, ppc_vsr_t *, ppc_vsr_t *, int, int, + int flags, float_status *s); + +static void vsxger_muladd32(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i, + int j, int flags, float_status *s) +{ + at[i].VsrSF(j) = float32_muladd(a->VsrSF(i), b->VsrSF(j), + at[i].VsrSF(j), flags, s); +} + +static void vsxger_mul32(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i, + int j, int flags, float_status *s) +{ + at[i].VsrSF(j) = float32_mul(a->VsrSF(i), b->VsrSF(j), s); +} + +static void vsxger_zero32(ppc_vsr_t *at, int i, int j) +{ + at[i].VsrSF(j) = float32_zero; +} + +static void vsxger_muladd64(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i, + int j, int flags, float_status *s) +{ + if (j >= 2) { + j -= 2; + at[i].VsrDF(j) = float64_muladd(a[i / 2].VsrDF(i % 2), b->VsrDF(j), + at[i].VsrDF(j), flags, s); + } +} + +static void vsxger_mul64(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i, + int j, int flags, float_status *s) +{ + if (j >= 2) { + j -= 2; + at[i].VsrDF(j) = float64_mul(a[i / 2].VsrDF(i % 2), b->VsrDF(j), s); + } +} + +static void vsxger_zero64(ppc_vsr_t *at, int i, int j) +{ + if (j >= 2) { + j -= 2; + at[i].VsrDF(j) = float64_zero; + } +} + +static void vsxger(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask, bool acc, bool neg_mul, + bool neg_acc, vsxger_muladd_f mul, vsxger_muladd_f muladd, + vsxger_zero zero) +{ + int i, j, xmsk_bit, ymsk_bit, op_flags; + uint8_t xmsk = mask & 0x0F; + uint8_t ymsk = (mask >> 4) & 0x0F; + float_status *excp_ptr = &env->fp_status; + op_flags = (neg_acc ^ neg_mul) ? float_muladd_negate_c : 0; + op_flags |= (neg_mul) ? float_muladd_negate_result : 0; + helper_reset_fpstatus(env); + for (i = 0, xmsk_bit = 1 << 3; i < 4; i++, xmsk_bit >>= 1) { + for (j = 0, ymsk_bit = 1 << 3; j < 4; j++, ymsk_bit >>= 1) { + if ((xmsk_bit & xmsk) && (ymsk_bit & ymsk)) { + if (acc) { + muladd(at, a, b, i, j, op_flags, excp_ptr); + } else { + mul(at, a, b, i, j, op_flags, excp_ptr); + } + } else { + zero(at, i, j); + } + } + } + vsxger_excp(env, GETPC()); +} + +QEMU_FLATTEN +void helper_XVF32GER(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, false, false, false, vsxger_mul32, + vsxger_muladd32, vsxger_zero32); +} + +QEMU_FLATTEN +void helper_XVF32GERPP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, true, false, false, vsxger_mul32, + vsxger_muladd32, vsxger_zero32); +} + +QEMU_FLATTEN +void helper_XVF32GERPN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, true, false, true, vsxger_mul32, + vsxger_muladd32, vsxger_zero32); +} + +QEMU_FLATTEN +void helper_XVF32GERNP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, true, true, false, vsxger_mul32, + vsxger_muladd32, vsxger_zero32); +} + +QEMU_FLATTEN +void helper_XVF32GERNN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, true, true, true, vsxger_mul32, + vsxger_muladd32, vsxger_zero32); +} + +QEMU_FLATTEN +void helper_XVF64GER(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, false, false, false, vsxger_mul64, + vsxger_muladd64, vsxger_zero64); +} + +QEMU_FLATTEN +void helper_XVF64GERPP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, true, false, false, vsxger_mul64, + vsxger_muladd64, vsxger_zero64); +} + +QEMU_FLATTEN +void helper_XVF64GERPN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, true, false, true, vsxger_mul64, + vsxger_muladd64, vsxger_zero64); +} + +QEMU_FLATTEN +void helper_XVF64GERNP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, true, true, false, vsxger_mul64, + vsxger_muladd64, vsxger_zero64); +} + +QEMU_FLATTEN +void helper_XVF64GERNN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger(env, a, b, at, mask, true, true, true, vsxger_mul64, + vsxger_muladd64, vsxger_zero64); +} diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 1666797edf..f38cdbe1d8 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -550,6 +550,16 @@ DEF_HELPER_5(XVI16GER2, void, env, vsr, vsr, acc, i32) DEF_HELPER_5(XVI16GER2S, void, env, vsr, vsr, acc, i32) DEF_HELPER_5(XVI16GER2PP, void, env, vsr, vsr, acc, i32) DEF_HELPER_5(XVI16GER2SPP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF32GER, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF32GERPP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF32GERPN, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF32GERNP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF32GERNN, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF64GER, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF64GERPP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF64GERPN, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF64GERNP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF64GERNN, void, env, vsr, vsr, acc, i32) DEF_HELPER_2(efscfsi, i32, env, i32) DEF_HELPER_2(efscfui, i32, env, i32) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index 0e189fe2da..6b644155ec 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -178,6 +178,7 @@ # 32 bit GER instructions have all mask bits considered 1 &MMIRR_XX3 xa xb xt pmsk xmsk ymsk %xx_at 23:3 +%xx_xa_pair 2:1 17:4 !function=times_2 @XX3_at ...... ... .. ..... ..... ........ ... &MMIRR_XX3 xt=%xx_at xb=%xx_xb \ pmsk=255 xmsk=15 ymsk=15 @@ -761,3 +762,15 @@ XVI16GER2PP 111011 ... -- ..... ..... 01101011 ..- @XX3_at xa=%xx_xa XVI8GER4SPP 111011 ... -- ..... ..... 01100011 ..- @XX3_at xa=%xx_xa XVI16GER2S 111011 ... -- ..... ..... 00101011 ..- @XX3_at xa=%xx_xa XVI16GER2SPP 111011 ... -- ..... ..... 00101010 ..- @XX3_at xa=%xx_xa + +XVF32GER 111011 ... -- ..... ..... 00011011 ..- @XX3_at xa=%xx_xa +XVF32GERPP 111011 ... -- ..... ..... 00011010 ..- @XX3_at xa=%xx_xa +XVF32GERPN 111011 ... -- ..... ..... 10011010 ..- @XX3_at xa=%xx_xa +XVF32GERNP 111011 ... -- ..... ..... 01011010 ..- @XX3_at xa=%xx_xa +XVF32GERNN 111011 ... -- ..... ..... 11011010 ..- @XX3_at xa=%xx_xa + +XVF64GER 111011 ... -- .... 0 ..... 00111011 ..- @XX3_at xa=%xx_xa_pair +XVF64GERPP 111011 ... -- .... 0 ..... 00111010 ..- @XX3_at xa=%xx_xa_pair +XVF64GERPN 111011 ... -- .... 0 ..... 10111010 ..- @XX3_at xa=%xx_xa_pair +XVF64GERNP 111011 ... -- .... 0 ..... 01111010 ..- @XX3_at xa=%xx_xa_pair +XVF64GERNN 111011 ... -- .... 0 ..... 11111010 ..- @XX3_at xa=%xx_xa_pair diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index b10eded1da..cc754ab175 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -2898,6 +2898,18 @@ TRANS64(PMXVI16GER2PP, do_ger, gen_helper_XVI16GER2PP) TRANS64(PMXVI16GER2S, do_ger, gen_helper_XVI16GER2S) TRANS64(PMXVI16GER2SPP, do_ger, gen_helper_XVI16GER2SPP) +TRANS(XVF32GER, do_ger, gen_helper_XVF32GER) +TRANS(XVF32GERPP, do_ger, gen_helper_XVF32GERPP) +TRANS(XVF32GERPN, do_ger, gen_helper_XVF32GERPN) +TRANS(XVF32GERNP, do_ger, gen_helper_XVF32GERNP) +TRANS(XVF32GERNN, do_ger, gen_helper_XVF32GERNN) + +TRANS(XVF64GER, do_ger, gen_helper_XVF64GER) +TRANS(XVF64GERPP, do_ger, gen_helper_XVF64GERPP) +TRANS(XVF64GERPN, do_ger, gen_helper_XVF64GERPN) +TRANS(XVF64GERNP, do_ger, gen_helper_XVF64GERNP) +TRANS(XVF64GERNN, do_ger, gen_helper_XVF64GERNN) + #undef GEN_XX2FORM #undef GEN_XX3FORM #undef GEN_XX2IFORM From 2d9cba74ef72232189ac5611968c1b9045a3e1a7 Mon Sep 17 00:00:00 2001 From: "Lucas Mateus Castro (alqotel)" Date: Tue, 24 May 2022 11:05:34 -0300 Subject: [PATCH 562/935] target/ppc: Implemented xvf16ger* Implement the following PowerISA v3.1 instructions: xvf16ger2: VSX Vector 16-bit Floating-Point GER (rank-2 update) xvf16ger2nn: VSX Vector 16-bit Floating-Point GER (rank-2 update) Negative multiply, Negative accumulate xvf16ger2np: VSX Vector 16-bit Floating-Point GER (rank-2 update) Negative multiply, Positive accumulate xvf16ger2pn: VSX Vector 16-bit Floating-Point GER (rank-2 update) Positive multiply, Negative accumulate xvf16ger2pp: VSX Vector 16-bit Floating-Point GER (rank-2 update) Positive multiply, Positive accumulate Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20220524140537.27451-6-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 3 + target/ppc/fpu_helper.c | 95 +++++++++++++++++++++++++++++ target/ppc/helper.h | 5 ++ target/ppc/insn32.decode | 6 ++ target/ppc/translate/vsx-impl.c.inc | 6 ++ 5 files changed, 115 insertions(+) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 40c779f246..6d78078f37 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -227,6 +227,7 @@ typedef union _ppc_vsr_t { int16_t s16[8]; int32_t s32[4]; int64_t s64[2]; + float16 f16[8]; float32 f32[4]; float64 f64[2]; float128 f128; @@ -2643,6 +2644,7 @@ static inline bool lsw_reg_in_range(int start, int nregs, int rx) #define VsrSW(i) s32[i] #define VsrD(i) u64[i] #define VsrSD(i) s64[i] +#define VsrHF(i) f16[i] #define VsrSF(i) f32[i] #define VsrDF(i) f64[i] #else @@ -2654,6 +2656,7 @@ static inline bool lsw_reg_in_range(int start, int nregs, int rx) #define VsrSW(i) s32[3 - (i)] #define VsrD(i) u64[1 - (i)] #define VsrSD(i) s64[1 - (i)] +#define VsrHF(i) f16[7 - (i)] #define VsrSF(i) f32[3 - (i)] #define VsrDF(i) f64[1 - (i)] #endif diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 712c71162c..a9b2ef370f 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -36,6 +36,15 @@ static inline float128 float128_snan_to_qnan(float128 x) #define float32_snan_to_qnan(x) ((x) | 0x00400000) #define float16_snan_to_qnan(x) ((x) | 0x0200) +static inline float32 bfp32_neg(float32 a) +{ + if (unlikely(float32_is_any_nan(a))) { + return a; + } else { + return float32_chs(a); + } +} + static inline bool fp_exceptions_enabled(CPUPPCState *env) { #ifdef CONFIG_USER_ONLY @@ -3501,6 +3510,57 @@ static inline void vsxger_excp(CPUPPCState *env, uintptr_t retaddr) do_fpscr_check_status(env, retaddr); } +typedef float64 extract_f16(float16, float_status *); + +static float64 extract_hf16(float16 in, float_status *fp_status) +{ + return float16_to_float64(in, true, fp_status); +} + +static void vsxger16(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask, bool acc, + bool neg_mul, bool neg_acc, extract_f16 extract) +{ + float32 r, aux_acc; + float64 psum, va, vb, vc, vd; + int i, j, xmsk_bit, ymsk_bit; + uint8_t pmsk = FIELD_EX32(mask, GER_MSK, PMSK), + xmsk = FIELD_EX32(mask, GER_MSK, XMSK), + ymsk = FIELD_EX32(mask, GER_MSK, YMSK); + float_status *excp_ptr = &env->fp_status; + for (i = 0, xmsk_bit = 1 << 3; i < 4; i++, xmsk_bit >>= 1) { + for (j = 0, ymsk_bit = 1 << 3; j < 4; j++, ymsk_bit >>= 1) { + if ((xmsk_bit & xmsk) && (ymsk_bit & ymsk)) { + va = !(pmsk & 2) ? float64_zero : + extract(a->VsrHF(2 * i), excp_ptr); + vb = !(pmsk & 2) ? float64_zero : + extract(b->VsrHF(2 * j), excp_ptr); + vc = !(pmsk & 1) ? float64_zero : + extract(a->VsrHF(2 * i + 1), excp_ptr); + vd = !(pmsk & 1) ? float64_zero : + extract(b->VsrHF(2 * j + 1), excp_ptr); + psum = float64_mul(va, vb, excp_ptr); + psum = float64r32_muladd(vc, vd, psum, 0, excp_ptr); + r = float64_to_float32(psum, excp_ptr); + if (acc) { + aux_acc = at[i].VsrSF(j); + if (neg_mul) { + r = bfp32_neg(r); + } + if (neg_acc) { + aux_acc = bfp32_neg(aux_acc); + } + r = float32_add(r, aux_acc, excp_ptr); + } + at[i].VsrSF(j) = r; + } else { + at[i].VsrSF(j) = float32_zero; + } + } + } + vsxger_excp(env, GETPC()); +} + typedef void vsxger_zero(ppc_vsr_t *at, int, int); typedef void vsxger_muladd_f(ppc_vsr_t *, ppc_vsr_t *, ppc_vsr_t *, int, int, @@ -3579,6 +3639,41 @@ static void vsxger(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, vsxger_excp(env, GETPC()); } +QEMU_FLATTEN +void helper_XVF16GER2(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, false, false, false, extract_hf16); +} + +QEMU_FLATTEN +void helper_XVF16GER2PP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, true, false, false, extract_hf16); +} + +QEMU_FLATTEN +void helper_XVF16GER2PN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, true, false, true, extract_hf16); +} + +QEMU_FLATTEN +void helper_XVF16GER2NP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, true, true, false, extract_hf16); +} + +QEMU_FLATTEN +void helper_XVF16GER2NN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, true, true, true, extract_hf16); +} + QEMU_FLATTEN void helper_XVF32GER(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, ppc_acc_t *at, uint32_t mask) diff --git a/target/ppc/helper.h b/target/ppc/helper.h index f38cdbe1d8..4070c0891c 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -550,6 +550,11 @@ DEF_HELPER_5(XVI16GER2, void, env, vsr, vsr, acc, i32) DEF_HELPER_5(XVI16GER2S, void, env, vsr, vsr, acc, i32) DEF_HELPER_5(XVI16GER2PP, void, env, vsr, vsr, acc, i32) DEF_HELPER_5(XVI16GER2SPP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF16GER2, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF16GER2PP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF16GER2PN, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF16GER2NP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVF16GER2NN, void, env, vsr, vsr, acc, i32) DEF_HELPER_5(XVF32GER, void, env, vsr, vsr, acc, i32) DEF_HELPER_5(XVF32GERPP, void, env, vsr, vsr, acc, i32) DEF_HELPER_5(XVF32GERPN, void, env, vsr, vsr, acc, i32) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index 6b644155ec..b8e317159c 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -763,6 +763,12 @@ XVI8GER4SPP 111011 ... -- ..... ..... 01100011 ..- @XX3_at xa=%xx_xa XVI16GER2S 111011 ... -- ..... ..... 00101011 ..- @XX3_at xa=%xx_xa XVI16GER2SPP 111011 ... -- ..... ..... 00101010 ..- @XX3_at xa=%xx_xa +XVF16GER2 111011 ... -- ..... ..... 00010011 ..- @XX3_at xa=%xx_xa +XVF16GER2PP 111011 ... -- ..... ..... 00010010 ..- @XX3_at xa=%xx_xa +XVF16GER2PN 111011 ... -- ..... ..... 10010010 ..- @XX3_at xa=%xx_xa +XVF16GER2NP 111011 ... -- ..... ..... 01010010 ..- @XX3_at xa=%xx_xa +XVF16GER2NN 111011 ... -- ..... ..... 11010010 ..- @XX3_at xa=%xx_xa + XVF32GER 111011 ... -- ..... ..... 00011011 ..- @XX3_at xa=%xx_xa XVF32GERPP 111011 ... -- ..... ..... 00011010 ..- @XX3_at xa=%xx_xa XVF32GERPN 111011 ... -- ..... ..... 10011010 ..- @XX3_at xa=%xx_xa diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index cc754ab175..01978a585a 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -2898,6 +2898,12 @@ TRANS64(PMXVI16GER2PP, do_ger, gen_helper_XVI16GER2PP) TRANS64(PMXVI16GER2S, do_ger, gen_helper_XVI16GER2S) TRANS64(PMXVI16GER2SPP, do_ger, gen_helper_XVI16GER2SPP) +TRANS(XVF16GER2, do_ger, gen_helper_XVF16GER2) +TRANS(XVF16GER2PP, do_ger, gen_helper_XVF16GER2PP) +TRANS(XVF16GER2PN, do_ger, gen_helper_XVF16GER2PN) +TRANS(XVF16GER2NP, do_ger, gen_helper_XVF16GER2NP) +TRANS(XVF16GER2NN, do_ger, gen_helper_XVF16GER2NN) + TRANS(XVF32GER, do_ger, gen_helper_XVF32GER) TRANS(XVF32GERPP, do_ger, gen_helper_XVF32GERPP) TRANS(XVF32GERPN, do_ger, gen_helper_XVF32GERPN) From 6f642338dc929a513ba5ba8f07a23894ba235bd0 Mon Sep 17 00:00:00 2001 From: "Lucas Mateus Castro (alqotel)" Date: Tue, 24 May 2022 11:05:35 -0300 Subject: [PATCH 563/935] target/ppc: Implemented pmxvf*ger* Implement the following PowerISA v3.1 instructions: pmxvf16ger2: Prefixed Masked VSX Vector 16-bit Floating-Point GER (rank-2 update) pmxvf16ger2nn: Prefixed Masked VSX Vector 16-bit Floating-Point GER (rank-2 update) Negative multiply, Negative accumulate pmxvf16ger2np: Prefixed Masked VSX Vector 16-bit Floating-Point GER (rank-2 update) Negative multiply, Positive accumulate pmxvf16ger2pn: Prefixed Masked VSX Vector 16-bit Floating-Point GER (rank-2 update) Positive multiply, Negative accumulate pmxvf16ger2pp: Prefixed Masked VSX Vector 16-bit Floating-Point GER (rank-2 update) Positive multiply, Positive accumulate pmxvf32ger: Prefixed Masked VSX Vector 32-bit Floating-Point GER (rank-1 update) pmxvf32gernn: Prefixed Masked VSX Vector 32-bit Floating-Point GER (rank-1 update) Negative multiply, Negative accumulate pmxvf32gernp: Prefixed Masked VSX Vector 32-bit Floating-Point GER (rank-1 update) Negative multiply, Positive accumulate pmxvf32gerpn: Prefixed Masked VSX Vector 32-bit Floating-Point GER (rank-1 update) Positive multiply, Negative accumulate pmxvf32gerpp: Prefixed Masked VSX Vector 32-bit Floating-Point GER (rank-1 update) Positive multiply, Positive accumulate pmxvf64ger: Prefixed Masked VSX Vector 64-bit Floating-Point GER (rank-1 update) pmxvf64gernn: Prefixed Masked VSX Vector 64-bit Floating-Point GER (rank-1 update) Negative multiply, Negative accumulate pmxvf64gernp: Prefixed Masked VSX Vector 64-bit Floating-Point GER (rank-1 update) Negative multiply, Positive accumulate pmxvf64gerpn: Prefixed Masked VSX Vector 64-bit Floating-Point GER (rank-1 update) Positive multiply, Negative accumulate pmxvf64gerpp: Prefixed Masked VSX Vector 64-bit Floating-Point GER (rank-1 update) Positive multiply, Positive accumulate Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20220524140537.27451-7-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/insn64.decode | 38 +++++++++++++++++++++++++++++ target/ppc/translate/vsx-impl.c.inc | 18 ++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/target/ppc/insn64.decode b/target/ppc/insn64.decode index 0eed35c8cd..5ecc5c85bf 100644 --- a/target/ppc/insn64.decode +++ b/target/ppc/insn64.decode @@ -73,10 +73,15 @@ %xx3_xa 2:1 16:5 %xx3_xb 1:1 11:5 %xx3_at 23:3 +%xx3_xa_pair 2:1 17:4 !function=times_2 @MMIRR_XX3 ...... .. .... .. . . ........ xmsk:4 ymsk:4 \ ...... ... .. ..... ..... ........ ... \ &MMIRR_XX3 xa=%xx3_xa xb=%xx3_xb xt=%xx3_at +@MMIRR_XX3_NO_P ...... .. .... .. . . ........ xmsk:4 .... \ + ...... ... .. ..... ..... ........ ... \ + &MMIRR_XX3 xb=%xx3_xb xt=%xx3_at pmsk=1 + ### Fixed-Point Load Instructions PLBZ 000001 10 0--.-- .................. \ @@ -145,6 +150,39 @@ PMXVI16GER2S 000001 11 1001 -- - - pmsk:2 ------ ........ \ PMXVI16GER2SPP 000001 11 1001 -- - - pmsk:2 ------ ........ \ 111011 ... -- ..... ..... 00101010 ..- @MMIRR_XX3 +PMXVF16GER2 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 00010011 ..- @MMIRR_XX3 +PMXVF16GER2PP 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 00010010 ..- @MMIRR_XX3 +PMXVF16GER2PN 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 10010010 ..- @MMIRR_XX3 +PMXVF16GER2NP 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 01010010 ..- @MMIRR_XX3 +PMXVF16GER2NN 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 11010010 ..- @MMIRR_XX3 + +PMXVF32GER 000001 11 1001 -- - - -------- .... ymsk:4 \ + 111011 ... -- ..... ..... 00011011 ..- @MMIRR_XX3_NO_P xa=%xx3_xa +PMXVF32GERPP 000001 11 1001 -- - - -------- .... ymsk:4 \ + 111011 ... -- ..... ..... 00011010 ..- @MMIRR_XX3_NO_P xa=%xx3_xa +PMXVF32GERPN 000001 11 1001 -- - - -------- .... ymsk:4 \ + 111011 ... -- ..... ..... 10011010 ..- @MMIRR_XX3_NO_P xa=%xx3_xa +PMXVF32GERNP 000001 11 1001 -- - - -------- .... ymsk:4 \ + 111011 ... -- ..... ..... 01011010 ..- @MMIRR_XX3_NO_P xa=%xx3_xa +PMXVF32GERNN 000001 11 1001 -- - - -------- .... ymsk:4 \ + 111011 ... -- ..... ..... 11011010 ..- @MMIRR_XX3_NO_P xa=%xx3_xa + +PMXVF64GER 000001 11 1001 -- - - -------- .... ymsk:2 -- \ + 111011 ... -- ....0 ..... 00111011 ..- @MMIRR_XX3_NO_P xa=%xx3_xa_pair +PMXVF64GERPP 000001 11 1001 -- - - -------- .... ymsk:2 -- \ + 111011 ... -- ....0 ..... 00111010 ..- @MMIRR_XX3_NO_P xa=%xx3_xa_pair +PMXVF64GERPN 000001 11 1001 -- - - -------- .... ymsk:2 -- \ + 111011 ... -- ....0 ..... 10111010 ..- @MMIRR_XX3_NO_P xa=%xx3_xa_pair +PMXVF64GERNP 000001 11 1001 -- - - -------- .... ymsk:2 -- \ + 111011 ... -- ....0 ..... 01111010 ..- @MMIRR_XX3_NO_P xa=%xx3_xa_pair +PMXVF64GERNN 000001 11 1001 -- - - -------- .... ymsk:2 -- \ + 111011 ... -- ....0 ..... 11111010 ..- @MMIRR_XX3_NO_P xa=%xx3_xa_pair + ### Prefixed No-operation Instruction @PNOP 000001 11 0000-- 000000000000000000 \ diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index 01978a585a..e79752899a 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -2916,6 +2916,24 @@ TRANS(XVF64GERPN, do_ger, gen_helper_XVF64GERPN) TRANS(XVF64GERNP, do_ger, gen_helper_XVF64GERNP) TRANS(XVF64GERNN, do_ger, gen_helper_XVF64GERNN) +TRANS64(PMXVF16GER2, do_ger, gen_helper_XVF16GER2) +TRANS64(PMXVF16GER2PP, do_ger, gen_helper_XVF16GER2PP) +TRANS64(PMXVF16GER2PN, do_ger, gen_helper_XVF16GER2PN) +TRANS64(PMXVF16GER2NP, do_ger, gen_helper_XVF16GER2NP) +TRANS64(PMXVF16GER2NN, do_ger, gen_helper_XVF16GER2NN) + +TRANS64(PMXVF32GER, do_ger, gen_helper_XVF32GER) +TRANS64(PMXVF32GERPP, do_ger, gen_helper_XVF32GERPP) +TRANS64(PMXVF32GERPN, do_ger, gen_helper_XVF32GERPN) +TRANS64(PMXVF32GERNP, do_ger, gen_helper_XVF32GERNP) +TRANS64(PMXVF32GERNN, do_ger, gen_helper_XVF32GERNN) + +TRANS64(PMXVF64GER, do_ger, gen_helper_XVF64GER) +TRANS64(PMXVF64GERPP, do_ger, gen_helper_XVF64GERPP) +TRANS64(PMXVF64GERPN, do_ger, gen_helper_XVF64GERPN) +TRANS64(PMXVF64GERNP, do_ger, gen_helper_XVF64GERNP) +TRANS64(PMXVF64GERNN, do_ger, gen_helper_XVF64GERNN) + #undef GEN_XX2FORM #undef GEN_XX3FORM #undef GEN_XX2IFORM From 5724e131ca6cd970555e66fb47b90b287ffa8ea0 Mon Sep 17 00:00:00 2001 From: "Lucas Mateus Castro (alqotel)" Date: Tue, 24 May 2022 11:05:36 -0300 Subject: [PATCH 564/935] target/ppc: Implemented [pm]xvbf16ger2* Implement the following PowerISA v3.1 instructions: xvbf16ger2: VSX Vector bfloat16 GER (rank-2 update) xvbf16ger2nn: VSX Vector bfloat16 GER (rank-2 update) Negative multiply, Negative accumulate xvbf16ger2np: VSX Vector bfloat16 GER (rank-2 update) Negative multiply, Positive accumulate xvbf16ger2pn: VSX Vector bfloat16 GER (rank-2 update) Positive multiply, Negative accumulate xvbf16ger2pp: VSX Vector bfloat16 GER (rank-2 update) Positive multiply, Positive accumulate pmxvbf16ger2: Prefixed Masked VSX Vector bfloat16 GER (rank-2 update) pmxvbf16ger2nn: Prefixed Masked VSX Vector bfloat16 GER (rank-2 update) Negative multiply, Negative accumulate pmxvbf16ger2np: Prefixed Masked VSX Vector bfloat16 GER (rank-2 update) Negative multiply, Positive accumulate pmxvbf16ger2pn: Prefixed Masked VSX Vector bfloat16 GER (rank-2 update) Positive multiply, Negative accumulate pmxvbf16ger2pp: Prefixed Masked VSX Vector bfloat16 GER (rank-2 update) Positive multiply, Positive accumulate Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20220524140537.27451-8-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/fpu_helper.c | 40 +++++++++++++++++++++++++++++ target/ppc/helper.h | 5 ++++ target/ppc/insn32.decode | 6 +++++ target/ppc/insn64.decode | 11 ++++++++ target/ppc/translate/vsx-impl.c.inc | 12 +++++++++ 5 files changed, 74 insertions(+) diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index a9b2ef370f..fed0ce420a 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -3517,6 +3517,11 @@ static float64 extract_hf16(float16 in, float_status *fp_status) return float16_to_float64(in, true, fp_status); } +static float64 extract_bf16(bfloat16 in, float_status *fp_status) +{ + return bfloat16_to_float64(in, fp_status); +} + static void vsxger16(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, ppc_acc_t *at, uint32_t mask, bool acc, bool neg_mul, bool neg_acc, extract_f16 extract) @@ -3639,6 +3644,41 @@ static void vsxger(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, vsxger_excp(env, GETPC()); } +QEMU_FLATTEN +void helper_XVBF16GER2(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, false, false, false, extract_bf16); +} + +QEMU_FLATTEN +void helper_XVBF16GER2PP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, true, false, false, extract_bf16); +} + +QEMU_FLATTEN +void helper_XVBF16GER2PN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, true, false, true, extract_bf16); +} + +QEMU_FLATTEN +void helper_XVBF16GER2NP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, true, true, false, extract_bf16); +} + +QEMU_FLATTEN +void helper_XVBF16GER2NN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, + ppc_acc_t *at, uint32_t mask) +{ + vsxger16(env, a, b, at, mask, true, true, true, extract_bf16); +} + QEMU_FLATTEN void helper_XVF16GER2(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, ppc_acc_t *at, uint32_t mask) diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 4070c0891c..6233e28d85 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -555,6 +555,11 @@ DEF_HELPER_5(XVF16GER2PP, void, env, vsr, vsr, acc, i32) DEF_HELPER_5(XVF16GER2PN, void, env, vsr, vsr, acc, i32) DEF_HELPER_5(XVF16GER2NP, void, env, vsr, vsr, acc, i32) DEF_HELPER_5(XVF16GER2NN, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVBF16GER2, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVBF16GER2PP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVBF16GER2PN, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVBF16GER2NP, void, env, vsr, vsr, acc, i32) +DEF_HELPER_5(XVBF16GER2NN, void, env, vsr, vsr, acc, i32) DEF_HELPER_5(XVF32GER, void, env, vsr, vsr, acc, i32) DEF_HELPER_5(XVF32GERPP, void, env, vsr, vsr, acc, i32) DEF_HELPER_5(XVF32GERPN, void, env, vsr, vsr, acc, i32) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index b8e317159c..18a94fa3b5 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -763,6 +763,12 @@ XVI8GER4SPP 111011 ... -- ..... ..... 01100011 ..- @XX3_at xa=%xx_xa XVI16GER2S 111011 ... -- ..... ..... 00101011 ..- @XX3_at xa=%xx_xa XVI16GER2SPP 111011 ... -- ..... ..... 00101010 ..- @XX3_at xa=%xx_xa +XVBF16GER2 111011 ... -- ..... ..... 00110011 ..- @XX3_at xa=%xx_xa +XVBF16GER2PP 111011 ... -- ..... ..... 00110010 ..- @XX3_at xa=%xx_xa +XVBF16GER2PN 111011 ... -- ..... ..... 10110010 ..- @XX3_at xa=%xx_xa +XVBF16GER2NP 111011 ... -- ..... ..... 01110010 ..- @XX3_at xa=%xx_xa +XVBF16GER2NN 111011 ... -- ..... ..... 11110010 ..- @XX3_at xa=%xx_xa + XVF16GER2 111011 ... -- ..... ..... 00010011 ..- @XX3_at xa=%xx_xa XVF16GER2PP 111011 ... -- ..... ..... 00010010 ..- @XX3_at xa=%xx_xa XVF16GER2PN 111011 ... -- ..... ..... 10010010 ..- @XX3_at xa=%xx_xa diff --git a/target/ppc/insn64.decode b/target/ppc/insn64.decode index 5ecc5c85bf..de115c1943 100644 --- a/target/ppc/insn64.decode +++ b/target/ppc/insn64.decode @@ -150,6 +150,17 @@ PMXVI16GER2S 000001 11 1001 -- - - pmsk:2 ------ ........ \ PMXVI16GER2SPP 000001 11 1001 -- - - pmsk:2 ------ ........ \ 111011 ... -- ..... ..... 00101010 ..- @MMIRR_XX3 +PMXVBF16GER2 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 00110011 ..- @MMIRR_XX3 +PMXVBF16GER2PP 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 00110010 ..- @MMIRR_XX3 +PMXVBF16GER2PN 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 10110010 ..- @MMIRR_XX3 +PMXVBF16GER2NP 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 01110010 ..- @MMIRR_XX3 +PMXVBF16GER2NN 000001 11 1001 -- - - pmsk:2 ------ ........ \ + 111011 ... -- ..... ..... 11110010 ..- @MMIRR_XX3 + PMXVF16GER2 000001 11 1001 -- - - pmsk:2 ------ ........ \ 111011 ... -- ..... ..... 00010011 ..- @MMIRR_XX3 PMXVF16GER2PP 000001 11 1001 -- - - pmsk:2 ------ ........ \ diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index e79752899a..7acdbceec4 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -2898,6 +2898,12 @@ TRANS64(PMXVI16GER2PP, do_ger, gen_helper_XVI16GER2PP) TRANS64(PMXVI16GER2S, do_ger, gen_helper_XVI16GER2S) TRANS64(PMXVI16GER2SPP, do_ger, gen_helper_XVI16GER2SPP) +TRANS(XVBF16GER2, do_ger, gen_helper_XVBF16GER2) +TRANS(XVBF16GER2PP, do_ger, gen_helper_XVBF16GER2PP) +TRANS(XVBF16GER2PN, do_ger, gen_helper_XVBF16GER2PN) +TRANS(XVBF16GER2NP, do_ger, gen_helper_XVBF16GER2NP) +TRANS(XVBF16GER2NN, do_ger, gen_helper_XVBF16GER2NN) + TRANS(XVF16GER2, do_ger, gen_helper_XVF16GER2) TRANS(XVF16GER2PP, do_ger, gen_helper_XVF16GER2PP) TRANS(XVF16GER2PN, do_ger, gen_helper_XVF16GER2PN) @@ -2916,6 +2922,12 @@ TRANS(XVF64GERPN, do_ger, gen_helper_XVF64GERPN) TRANS(XVF64GERNP, do_ger, gen_helper_XVF64GERNP) TRANS(XVF64GERNN, do_ger, gen_helper_XVF64GERNN) +TRANS64(PMXVBF16GER2, do_ger, gen_helper_XVBF16GER2) +TRANS64(PMXVBF16GER2PP, do_ger, gen_helper_XVBF16GER2PP) +TRANS64(PMXVBF16GER2PN, do_ger, gen_helper_XVBF16GER2PN) +TRANS64(PMXVBF16GER2NP, do_ger, gen_helper_XVBF16GER2NP) +TRANS64(PMXVBF16GER2NN, do_ger, gen_helper_XVBF16GER2NN) + TRANS64(PMXVF16GER2, do_ger, gen_helper_XVF16GER2) TRANS64(PMXVF16GER2PP, do_ger, gen_helper_XVF16GER2PP) TRANS64(PMXVF16GER2PN, do_ger, gen_helper_XVF16GER2PN) From 96c343cc774b52b010e464a219d13f8e55e1003f Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 24 May 2022 11:05:37 -0300 Subject: [PATCH 565/935] linux-user: Add PowerPC ISA 3.1 and MMA to hwcap These are new hwcap bits added for power10. Signed-off-by: Joel Stanley Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20220524140537.27451-9-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- linux-user/elfload.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index acc21748f9..f7eae357f4 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -779,6 +779,8 @@ enum { QEMU_PPC_FEATURE2_DARN = 0x00200000, /* darn random number insn */ QEMU_PPC_FEATURE2_SCV = 0x00100000, /* scv syscall */ QEMU_PPC_FEATURE2_HTM_NO_SUSPEND = 0x00080000, /* TM w/o suspended state */ + QEMU_PPC_FEATURE2_ARCH_3_1 = 0x00040000, /* ISA 3.1 */ + QEMU_PPC_FEATURE2_MMA = 0x00020000, /* Matrix-Multiply Assist */ }; #define ELF_HWCAP get_elf_hwcap() @@ -836,6 +838,8 @@ static uint32_t get_elf_hwcap2(void) QEMU_PPC_FEATURE2_VEC_CRYPTO); GET_FEATURE2(PPC2_ISA300, QEMU_PPC_FEATURE2_ARCH_3_00 | QEMU_PPC_FEATURE2_DARN | QEMU_PPC_FEATURE2_HAS_IEEE128); + GET_FEATURE2(PPC2_ISA310, QEMU_PPC_FEATURE2_ARCH_3_1 | + QEMU_PPC_FEATURE2_MMA); #undef GET_FEATURE #undef GET_FEATURE2 From 06680b15b4ee3184b57c9c910886a9ff8a7e58c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 25 May 2022 16:41:26 +0200 Subject: [PATCH 566/935] include: move qemu_*_exec_dir() to cutils MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function is required by get_relocated_path() (already in cutils), and used by qemu-ga and may be generally useful. Signed-off-by: Marc-André Lureau Reviewed-by: Markus Armbruster Message-Id: <20220525144140.591926-2-marcandre.lureau@redhat.com> --- include/qemu/cutils.h | 7 ++ include/qemu/osdep.h | 8 -- qemu-io.c | 1 + storage-daemon/qemu-storage-daemon.c | 1 + tests/qtest/fuzz/fuzz.c | 1 + util/cutils.c | 117 +++++++++++++++++++++++++++ util/oslib-posix.c | 86 +------------------- util/oslib-win32.c | 36 --------- 8 files changed, 129 insertions(+), 128 deletions(-) diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h index 5c6572d444..40e10e19a7 100644 --- a/include/qemu/cutils.h +++ b/include/qemu/cutils.h @@ -193,6 +193,13 @@ int uleb128_decode_small(const uint8_t *in, uint32_t *n); */ int qemu_pstrcmp0(const char **str1, const char **str2); +/* Find program directory, and save it for later usage with + * qemu_get_exec_dir(). + * Try OS specific API first, if not working, parse from argv0. */ +void qemu_init_exec_dir(const char *argv0); + +/* Get the saved exec dir. */ +const char *qemu_get_exec_dir(void); /** * get_relocated_path: diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index a72e99db85..b1c161c035 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -557,14 +557,6 @@ void qemu_set_cloexec(int fd); */ char *qemu_get_local_state_dir(void); -/* Find program directory, and save it for later usage with - * qemu_get_exec_dir(). - * Try OS specific API first, if not working, parse from argv0. */ -void qemu_init_exec_dir(const char *argv0); - -/* Get the saved exec dir. */ -const char *qemu_get_exec_dir(void); - /** * qemu_getauxval: * @type: the auxiliary vector key to lookup diff --git a/qemu-io.c b/qemu-io.c index d70d3dd4fd..2bd7bfb650 100644 --- a/qemu-io.c +++ b/qemu-io.c @@ -16,6 +16,7 @@ #endif #include "qemu/help-texts.h" +#include "qemu/cutils.h" #include "qapi/error.h" #include "qemu-io.h" #include "qemu/error-report.h" diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c index 9b8b17f52e..c104817cdd 100644 --- a/storage-daemon/qemu-storage-daemon.c +++ b/storage-daemon/qemu-storage-daemon.c @@ -44,6 +44,7 @@ #include "qemu/help-texts.h" #include "qemu-version.h" +#include "qemu/cutils.h" #include "qemu/config-file.h" #include "qemu/error-report.h" #include "qemu/help_option.h" diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index a7a5e14fa3..0ad4ba9e94 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -15,6 +15,7 @@ #include +#include "qemu/cutils.h" #include "qemu/datadir.h" #include "sysemu/sysemu.h" #include "sysemu/qtest.h" diff --git a/util/cutils.c b/util/cutils.c index b2777210e7..a58bcfd80e 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -26,6 +26,15 @@ #include "qemu/host-utils.h" #include +#ifdef __FreeBSD__ +#include +#include +#endif + +#ifdef __NetBSD__ +#include +#endif + #include "qemu/ctype.h" #include "qemu/cutils.h" #include "qemu/error-report.h" @@ -931,6 +940,114 @@ static inline const char *next_component(const char *dir, int *p_len) return dir; } +static const char *exec_dir; + +void qemu_init_exec_dir(const char *argv0) +{ +#ifdef G_OS_WIN32 + char *p; + char buf[MAX_PATH]; + DWORD len; + + if (exec_dir) { + return; + } + + len = GetModuleFileName(NULL, buf, sizeof(buf) - 1); + if (len == 0) { + return; + } + + buf[len] = 0; + p = buf + len - 1; + while (p != buf && *p != '\\') { + p--; + } + *p = 0; + if (access(buf, R_OK) == 0) { + exec_dir = g_strdup(buf); + } else { + exec_dir = CONFIG_BINDIR; + } +#else + char *p = NULL; + char buf[PATH_MAX]; + + if (exec_dir) { + return; + } + +#if defined(__linux__) + { + int len; + len = readlink("/proc/self/exe", buf, sizeof(buf) - 1); + if (len > 0) { + buf[len] = 0; + p = buf; + } + } +#elif defined(__FreeBSD__) \ + || (defined(__NetBSD__) && defined(KERN_PROC_PATHNAME)) + { +#if defined(__FreeBSD__) + static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; +#else + static int mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME}; +#endif + size_t len = sizeof(buf) - 1; + + *buf = '\0'; + if (!sysctl(mib, ARRAY_SIZE(mib), buf, &len, NULL, 0) && + *buf) { + buf[sizeof(buf) - 1] = '\0'; + p = buf; + } + } +#elif defined(__APPLE__) + { + char fpath[PATH_MAX]; + uint32_t len = sizeof(fpath); + if (_NSGetExecutablePath(fpath, &len) == 0) { + p = realpath(fpath, buf); + if (!p) { + return; + } + } + } +#elif defined(__HAIKU__) + { + image_info ii; + int32_t c = 0; + + *buf = '\0'; + while (get_next_image_info(0, &c, &ii) == B_OK) { + if (ii.type == B_APP_IMAGE) { + strncpy(buf, ii.name, sizeof(buf)); + buf[sizeof(buf) - 1] = 0; + p = buf; + break; + } + } + } +#endif + /* If we don't have any way of figuring out the actual executable + location then try argv[0]. */ + if (!p && argv0) { + p = realpath(argv0, buf); + } + if (p) { + exec_dir = g_path_get_dirname(p); + } else { + exec_dir = CONFIG_BINDIR; + } +#endif +} + +const char *qemu_get_exec_dir(void) +{ + return exec_dir; +} + char *get_relocated_path(const char *dir) { size_t prefix_len = strlen(CONFIG_PREFIX); diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 477990f39b..7a34c1657c 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -48,14 +48,13 @@ #endif #ifdef __FreeBSD__ -#include -#include #include +#include +#include #include #endif #ifdef __NetBSD__ -#include #include #endif @@ -283,87 +282,6 @@ void qemu_set_tty_echo(int fd, bool echo) tcsetattr(fd, TCSANOW, &tty); } -static const char *exec_dir; - -void qemu_init_exec_dir(const char *argv0) -{ - char *p = NULL; - char buf[PATH_MAX]; - - if (exec_dir) { - return; - } - -#if defined(__linux__) - { - int len; - len = readlink("/proc/self/exe", buf, sizeof(buf) - 1); - if (len > 0) { - buf[len] = 0; - p = buf; - } - } -#elif defined(__FreeBSD__) \ - || (defined(__NetBSD__) && defined(KERN_PROC_PATHNAME)) - { -#if defined(__FreeBSD__) - static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; -#else - static int mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME}; -#endif - size_t len = sizeof(buf) - 1; - - *buf = '\0'; - if (!sysctl(mib, ARRAY_SIZE(mib), buf, &len, NULL, 0) && - *buf) { - buf[sizeof(buf) - 1] = '\0'; - p = buf; - } - } -#elif defined(__APPLE__) - { - char fpath[PATH_MAX]; - uint32_t len = sizeof(fpath); - if (_NSGetExecutablePath(fpath, &len) == 0) { - p = realpath(fpath, buf); - if (!p) { - return; - } - } - } -#elif defined(__HAIKU__) - { - image_info ii; - int32_t c = 0; - - *buf = '\0'; - while (get_next_image_info(0, &c, &ii) == B_OK) { - if (ii.type == B_APP_IMAGE) { - strncpy(buf, ii.name, sizeof(buf)); - buf[sizeof(buf) - 1] = 0; - p = buf; - break; - } - } - } -#endif - /* If we don't have any way of figuring out the actual executable - location then try argv[0]. */ - if (!p && argv0) { - p = realpath(argv0, buf); - } - if (p) { - exec_dir = g_path_get_dirname(p); - } else { - exec_dir = CONFIG_BINDIR; - } -} - -const char *qemu_get_exec_dir(void) -{ - return exec_dir; -} - #ifdef CONFIG_LINUX static void sigbus_handler(int signal, siginfo_t *siginfo, void *ctx) #else /* CONFIG_LINUX */ diff --git a/util/oslib-win32.c b/util/oslib-win32.c index dafef4f157..6c818749d2 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -269,42 +269,6 @@ void qemu_set_tty_echo(int fd, bool echo) } } -static const char *exec_dir; - -void qemu_init_exec_dir(const char *argv0) -{ - - char *p; - char buf[MAX_PATH]; - DWORD len; - - if (exec_dir) { - return; - } - - len = GetModuleFileName(NULL, buf, sizeof(buf) - 1); - if (len == 0) { - return; - } - - buf[len] = 0; - p = buf + len - 1; - while (p != buf && *p != '\\') { - p--; - } - *p = 0; - if (access(buf, R_OK) == 0) { - exec_dir = g_strdup(buf); - } else { - exec_dir = CONFIG_BINDIR; - } -} - -const char *qemu_get_exec_dir(void) -{ - return exec_dir; -} - int getpagesize(void) { SYSTEM_INFO system_info; From 49e0128c483aa4a49860210ea51e00523ec26aaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 25 May 2022 16:41:27 +0200 Subject: [PATCH 567/935] util/win32: simplify qemu_get_local_state_dir() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SHGetFolderPath() is a deprecated API: https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetfolderpatha It is a wrapper for SHGetKnownFolderPath() and CSIDL_COMMON_PATH is mapped to FOLDERID_ProgramData: https://docs.microsoft.com/en-us/windows/win32/shell/csidl g_get_system_data_dirs() is a suitable replacement, as it will have FOLDERID_ProgramData in the returned list. However, it follows the XDG Base Directory Specification, if `XDG_DATA_DIRS` is defined, it will be returned instead. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Weil Message-Id: <20220525144140.591926-3-marcandre.lureau@redhat.com> --- util/oslib-win32.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 6c818749d2..5723d3eb4c 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -40,9 +40,6 @@ #include "qemu/error-report.h" #include -/* this must come after including "trace.h" */ -#include - static int get_allocation_granularity(void) { SYSTEM_INFO system_info; @@ -237,17 +234,11 @@ int qemu_get_thread_id(void) char * qemu_get_local_state_dir(void) { - HRESULT result; - char base_path[MAX_PATH+1] = ""; + const char * const *data_dirs = g_get_system_data_dirs(); - result = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, - /* SHGFP_TYPE_CURRENT */ 0, base_path); - if (result != S_OK) { - /* misconfigured environment */ - g_critical("CSIDL_COMMON_APPDATA unavailable: %ld", (long)result); - abort(); - } - return g_strdup(base_path); + g_assert(data_dirs && data_dirs[0]); + + return g_strdup(data_dirs[0]); } void qemu_set_tty_echo(int fd, bool echo) From 56b6dab2743b276a50036cd0a115e98cb1134f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 25 May 2022 16:41:28 +0200 Subject: [PATCH 568/935] tests: make libqmp buildable for win32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Thomas Huth Message-Id: <20220525144140.591926-4-marcandre.lureau@redhat.com> --- tests/qtest/libqmp.c | 34 +++++++++++++++++++++++++++++----- tests/qtest/libqmp.h | 2 ++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/tests/qtest/libqmp.c b/tests/qtest/libqmp.c index 0358b8313d..ade26c15f0 100644 --- a/tests/qtest/libqmp.c +++ b/tests/qtest/libqmp.c @@ -18,6 +18,11 @@ #include "libqmp.h" +#ifndef _WIN32 +#include +#endif + +#include "qemu/cutils.h" #include "qapi/error.h" #include "qapi/qmp/json-parser.h" #include "qapi/qmp/qjson.h" @@ -87,6 +92,7 @@ QDict *qmp_fd_receive(int fd) return qmp.response; } +#ifndef _WIN32 /* Sends a message and file descriptors to the socket. * It's needed for qmp-commands like getfd/add-fd */ static void socket_send_fds(int socket_fd, int *fds, size_t fds_num, @@ -120,17 +126,23 @@ static void socket_send_fds(int socket_fd, int *fds, size_t fds_num, } while (ret < 0 && errno == EINTR); g_assert_cmpint(ret, >, 0); } +#endif /** * Allow users to send a message without waiting for the reply, * in the case that they choose to discard all replies up until * a particular EVENT is received. */ -void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num, - const char *fmt, va_list ap) +static void +_qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num, + const char *fmt, va_list ap) { QObject *qobj; +#ifdef _WIN32 + assert(fds_num == 0); +#endif + /* Going through qobject ensures we escape strings properly */ qobj = qobject_from_vjsonf_nofail(fmt, ap); @@ -148,10 +160,14 @@ void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num, if (log) { fprintf(stderr, "%s", str->str); } + +#ifndef _WIN32 /* Send QMP request */ if (fds && fds_num > 0) { socket_send_fds(fd, fds, fds_num, str->str, str->len); - } else { + } else +#endif + { socket_send(fd, str->str, str->len); } @@ -160,15 +176,23 @@ void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num, } } +#ifndef _WIN32 +void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num, + const char *fmt, va_list ap) +{ + _qmp_fd_vsend_fds(fd, fds, fds_num, fmt, ap); +} +#endif + void qmp_fd_vsend(int fd, const char *fmt, va_list ap) { - qmp_fd_vsend_fds(fd, NULL, 0, fmt, ap); + _qmp_fd_vsend_fds(fd, NULL, 0, fmt, ap); } QDict *qmp_fdv(int fd, const char *fmt, va_list ap) { - qmp_fd_vsend_fds(fd, NULL, 0, fmt, ap); + _qmp_fd_vsend_fds(fd, NULL, 0, fmt, ap); return qmp_fd_receive(fd); } diff --git a/tests/qtest/libqmp.h b/tests/qtest/libqmp.h index 5cb7eeaa18..3445b753ff 100644 --- a/tests/qtest/libqmp.h +++ b/tests/qtest/libqmp.h @@ -21,8 +21,10 @@ #include "qapi/qmp/qdict.h" QDict *qmp_fd_receive(int fd); +#ifndef _WIN32 void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num, const char *fmt, va_list ap) G_GNUC_PRINTF(4, 0); +#endif void qmp_fd_vsend(int fd, const char *fmt, va_list ap) G_GNUC_PRINTF(2, 0); void qmp_fd_send(int fd, const char *fmt, ...) G_GNUC_PRINTF(2, 3); void qmp_fd_send_raw(int fd, const char *fmt, ...) G_GNUC_PRINTF(2, 3); From 69f56c140de06fee0f266b93634475e1d968e430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 25 May 2022 16:41:29 +0200 Subject: [PATCH 569/935] qga: flatten safe_open_or_create() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a bit too much nesting in the function, this can be simplified a bit to improve readability. This also helps with the following error handling changes. Signed-off-by: Marc-André Lureau Reviewed-by: Markus Armbruster Message-Id: <20220525144140.591926-5-marcandre.lureau@redhat.com> --- qga/commands-posix.c | 126 +++++++++++++++++++++---------------------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 12b50b7124..3b2392398e 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -339,73 +339,73 @@ find_open_flag(const char *mode_str, Error **errp) static FILE * safe_open_or_create(const char *path, const char *mode, Error **errp) { - Error *local_err = NULL; int oflag; + int fd = -1; + FILE *f = NULL; - oflag = find_open_flag(mode, &local_err); - if (local_err == NULL) { - int fd; - - /* If the caller wants / allows creation of a new file, we implement it - * with a two step process: open() + (open() / fchmod()). - * - * First we insist on creating the file exclusively as a new file. If - * that succeeds, we're free to set any file-mode bits on it. (The - * motivation is that we want to set those file-mode bits independently - * of the current umask.) - * - * If the exclusive creation fails because the file already exists - * (EEXIST is not possible for any other reason), we just attempt to - * open the file, but in this case we won't be allowed to change the - * file-mode bits on the preexistent file. - * - * The pathname should never disappear between the two open()s in - * practice. If it happens, then someone very likely tried to race us. - * In this case just go ahead and report the ENOENT from the second - * open() to the caller. - * - * If the caller wants to open a preexistent file, then the first - * open() is decisive and its third argument is ignored, and the second - * open() and the fchmod() are never called. - */ - fd = open(path, oflag | ((oflag & O_CREAT) ? O_EXCL : 0), 0); - if (fd == -1 && errno == EEXIST) { - oflag &= ~(unsigned)O_CREAT; - fd = open(path, oflag); - } - - if (fd == -1) { - error_setg_errno(&local_err, errno, "failed to open file '%s' " - "(mode: '%s')", path, mode); - } else { - qemu_set_cloexec(fd); - - if ((oflag & O_CREAT) && fchmod(fd, DEFAULT_NEW_FILE_MODE) == -1) { - error_setg_errno(&local_err, errno, "failed to set permission " - "0%03o on new file '%s' (mode: '%s')", - (unsigned)DEFAULT_NEW_FILE_MODE, path, mode); - } else { - FILE *f; - - f = fdopen(fd, mode); - if (f == NULL) { - error_setg_errno(&local_err, errno, "failed to associate " - "stdio stream with file descriptor %d, " - "file '%s' (mode: '%s')", fd, path, mode); - } else { - return f; - } - } - - close(fd); - if (oflag & O_CREAT) { - unlink(path); - } - } + oflag = find_open_flag(mode, errp); + if (oflag < 0) { + goto end; } - error_propagate(errp, local_err); - return NULL; + /* If the caller wants / allows creation of a new file, we implement it + * with a two step process: open() + (open() / fchmod()). + * + * First we insist on creating the file exclusively as a new file. If + * that succeeds, we're free to set any file-mode bits on it. (The + * motivation is that we want to set those file-mode bits independently + * of the current umask.) + * + * If the exclusive creation fails because the file already exists + * (EEXIST is not possible for any other reason), we just attempt to + * open the file, but in this case we won't be allowed to change the + * file-mode bits on the preexistent file. + * + * The pathname should never disappear between the two open()s in + * practice. If it happens, then someone very likely tried to race us. + * In this case just go ahead and report the ENOENT from the second + * open() to the caller. + * + * If the caller wants to open a preexistent file, then the first + * open() is decisive and its third argument is ignored, and the second + * open() and the fchmod() are never called. + */ + fd = open(path, oflag | ((oflag & O_CREAT) ? O_EXCL : 0), 0); + if (fd == -1 && errno == EEXIST) { + oflag &= ~(unsigned)O_CREAT; + fd = open(path, oflag); + } + if (fd == -1) { + error_setg_errno(errp, errno, + "failed to open file '%s' (mode: '%s')", + path, mode); + goto end; + } + + qemu_set_cloexec(fd); + + if ((oflag & O_CREAT) && fchmod(fd, DEFAULT_NEW_FILE_MODE) == -1) { + error_setg_errno(errp, errno, "failed to set permission " + "0%03o on new file '%s' (mode: '%s')", + (unsigned)DEFAULT_NEW_FILE_MODE, path, mode); + goto end; + } + + f = fdopen(fd, mode); + if (f == NULL) { + error_setg_errno(errp, errno, "failed to associate stdio stream with " + "file descriptor %d, file '%s' (mode: '%s')", + fd, path, mode); + } + +end: + if (f == NULL && fd != -1) { + close(fd); + if (oflag & O_CREAT) { + unlink(path); + } + } + return f; } int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, From 0edbfbe31c532a98a8674b68c94a97537f4e4230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 25 May 2022 16:41:30 +0200 Subject: [PATCH 570/935] qga: add qga_open_cloexec() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QGA calls qemu_open_old() in various places. Calling qemu_open() instead isn't a great alternative, as it has special "/dev/fdset" handling and depends on QEMU internal monitor data structures. Instead, provide a simple helper for QGA needs, with Error* support. The following patches will make use of it. Signed-off-by: Marc-André Lureau Reviewed-by: Markus Armbruster Message-Id: <20220525144140.591926-6-marcandre.lureau@redhat.com> --- qga/cutils.c | 33 +++++++++++++++++++++++++++++++++ qga/cutils.h | 8 ++++++++ qga/meson.build | 1 + 3 files changed, 42 insertions(+) create mode 100644 qga/cutils.c create mode 100644 qga/cutils.h diff --git a/qga/cutils.c b/qga/cutils.c new file mode 100644 index 0000000000..b8e142ef64 --- /dev/null +++ b/qga/cutils.c @@ -0,0 +1,33 @@ +/* + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#include "cutils.h" + +#include "qapi/error.h" + +/** + * qga_open_cloexec: + * @name: the pathname to open + * @flags: as in open() + * @mode: as in open() + * + * A wrapper for open() function which sets O_CLOEXEC. + * + * On error, -1 is returned. + */ +int qga_open_cloexec(const char *name, int flags, mode_t mode) +{ + int ret; + +#ifdef O_CLOEXEC + ret = open(name, flags | O_CLOEXEC, mode); +#else + ret = open(name, flags, mode); + if (ret >= 0) { + qemu_set_cloexec(ret); + } +#endif + + return ret; +} diff --git a/qga/cutils.h b/qga/cutils.h new file mode 100644 index 0000000000..f0f30a7d28 --- /dev/null +++ b/qga/cutils.h @@ -0,0 +1,8 @@ +#ifndef CUTILS_H_ +#define CUTILS_H_ + +#include "qemu/osdep.h" + +int qga_open_cloexec(const char *name, int flags, mode_t mode); + +#endif /* CUTILS_H_ */ diff --git a/qga/meson.build b/qga/meson.build index 6d9f39bb32..35fe2229e9 100644 --- a/qga/meson.build +++ b/qga/meson.build @@ -65,6 +65,7 @@ qga_ss.add(files( 'commands.c', 'guest-agent-command-state.c', 'main.c', + 'cutils.c', )) qga_ss.add(when: 'CONFIG_POSIX', if_true: files( 'channel-posix.c', From 1a89a17b769352dbced5c6d8b0935e4d1f306c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 25 May 2022 16:41:31 +0200 Subject: [PATCH 571/935] qga: use qga_open_cloexec() for safe_open_or_create() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function takes care of setting CLOEXEC. Signed-off-by: Marc-André Lureau Reviewed-by: Markus Armbruster Message-Id: <20220525144140.591926-7-marcandre.lureau@redhat.com> --- qga/commands-posix.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 3b2392398e..2ecc43eca9 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -27,6 +27,7 @@ #include "qemu/cutils.h" #include "commands-common.h" #include "block/nvme.h" +#include "cutils.h" #ifdef HAVE_UTMPX #include @@ -370,10 +371,10 @@ safe_open_or_create(const char *path, const char *mode, Error **errp) * open() is decisive and its third argument is ignored, and the second * open() and the fchmod() are never called. */ - fd = open(path, oflag | ((oflag & O_CREAT) ? O_EXCL : 0), 0); + fd = qga_open_cloexec(path, oflag | ((oflag & O_CREAT) ? O_EXCL : 0), 0); if (fd == -1 && errno == EEXIST) { oflag &= ~(unsigned)O_CREAT; - fd = open(path, oflag); + fd = qga_open_cloexec(path, oflag, 0); } if (fd == -1) { error_setg_errno(errp, errno, @@ -382,8 +383,6 @@ safe_open_or_create(const char *path, const char *mode, Error **errp) goto end; } - qemu_set_cloexec(fd); - if ((oflag & O_CREAT) && fchmod(fd, DEFAULT_NEW_FILE_MODE) == -1) { error_setg_errno(errp, errno, "failed to set permission " "0%03o on new file '%s' (mode: '%s')", From 87ed8b2c2cd03d2596c11559f3e64ba15f58a99e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 25 May 2022 16:41:32 +0200 Subject: [PATCH 572/935] qga: throw an Error in ga_channel_open() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow for a single point of error reporting, and further refactoring. Signed-off-by: Marc-André Lureau Reviewed-by: Markus Armbruster Message-Id: <20220525144140.591926-8-marcandre.lureau@redhat.com> --- qga/channel-posix.c | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/qga/channel-posix.c b/qga/channel-posix.c index a996858e24..25fcc5cb1a 100644 --- a/qga/channel-posix.c +++ b/qga/channel-posix.c @@ -119,7 +119,7 @@ static int ga_channel_client_add(GAChannel *c, int fd) } static gboolean ga_channel_open(GAChannel *c, const gchar *path, - GAChannelMethod method, int fd) + GAChannelMethod method, int fd, Error **errp) { int ret; c->method = method; @@ -133,21 +133,20 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, #endif ); if (fd == -1) { - g_critical("error opening channel: %s", strerror(errno)); + error_setg_errno(errp, errno, "error opening channel"); return false; } #ifdef CONFIG_SOLARIS ret = ioctl(fd, I_SETSIG, S_OUTPUT | S_INPUT | S_HIPRI); if (ret == -1) { - g_critical("error setting event mask for channel: %s", - strerror(errno)); + error_setg_errno(errp, errno, "error setting event mask for channel"); close(fd); return false; } #endif ret = ga_channel_client_add(c, fd); if (ret) { - g_critical("error adding channel to main loop"); + error_setg(errp, "error adding channel to main loop"); close(fd); return false; } @@ -159,7 +158,7 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, assert(fd < 0); fd = qemu_open_old(path, O_RDWR | O_NOCTTY | O_NONBLOCK); if (fd == -1) { - g_critical("error opening channel: %s", strerror(errno)); + error_setg_errno(errp, errno, "error opening channel"); return false; } tcgetattr(fd, &tio); @@ -180,7 +179,7 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, tcsetattr(fd, TCSANOW, &tio); ret = ga_channel_client_add(c, fd); if (ret) { - g_critical("error adding channel to main loop"); + error_setg(errp, "error adding channel to main loop"); close(fd); return false; } @@ -188,12 +187,8 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, } case GA_CHANNEL_UNIX_LISTEN: { if (fd < 0) { - Error *local_err = NULL; - - fd = unix_listen(path, &local_err); - if (local_err != NULL) { - g_critical("%s", error_get_pretty(local_err)); - error_free(local_err); + fd = unix_listen(path, errp); + if (fd < 0) { return false; } } @@ -202,24 +197,19 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, } case GA_CHANNEL_VSOCK_LISTEN: { if (fd < 0) { - Error *local_err = NULL; SocketAddress *addr; char *addr_str; addr_str = g_strdup_printf("vsock:%s", path); - addr = socket_parse(addr_str, &local_err); + addr = socket_parse(addr_str, errp); g_free(addr_str); - if (local_err != NULL) { - g_critical("%s", error_get_pretty(local_err)); - error_free(local_err); + if (!addr) { return false; } - fd = socket_listen(addr, 1, &local_err); + fd = socket_listen(addr, 1, errp); qapi_free_SocketAddress(addr); - if (local_err != NULL) { - g_critical("%s", error_get_pretty(local_err)); - error_free(local_err); + if (fd < 0) { return false; } } @@ -227,7 +217,7 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, break; } default: - g_critical("error binding/listening to specified socket"); + error_setg(errp, "error binding/listening to specified socket"); return false; } @@ -272,12 +262,14 @@ GIOStatus ga_channel_read(GAChannel *c, gchar *buf, gsize size, gsize *count) GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path, int listen_fd, GAChannelCallback cb, gpointer opaque) { + Error *err = NULL; GAChannel *c = g_new0(GAChannel, 1); c->event_cb = cb; c->user_data = opaque; - if (!ga_channel_open(c, path, method, listen_fd)) { - g_critical("error opening channel"); + if (!ga_channel_open(c, path, method, listen_fd, &err)) { + g_critical("%s", error_get_pretty(err)); + error_free(err); ga_channel_free(c); return NULL; } From b9947c9ce7eec9f31c9adfea2cd1f42e0bfe76b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 25 May 2022 16:41:33 +0200 Subject: [PATCH 573/935] qga: replace qemu_open_old() with qga_open_cloexec() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qemu_open_old() uses qemu_open_internal() which handles special "/dev/fdset/" path for monitor fd sets, set CLOEXEC, and uses Error reporting (and some O_DIRECT special error casing). The monitor fdset handling is unnecessary for qga, use qga_open_cloexec() instead. Signed-off-by: Marc-André Lureau Reviewed-by: Konstantin Kostiuk Message-Id: <20220525144140.591926-9-marcandre.lureau@redhat.com> --- qga/channel-posix.c | 13 +++++++++---- qga/commands-posix.c | 8 ++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/qga/channel-posix.c b/qga/channel-posix.c index 25fcc5cb1a..6796a02cff 100644 --- a/qga/channel-posix.c +++ b/qga/channel-posix.c @@ -1,8 +1,10 @@ #include "qemu/osdep.h" +#include "qemu/cutils.h" #include #include "qapi/error.h" #include "qemu/sockets.h" #include "channel.h" +#include "cutils.h" #ifdef CONFIG_SOLARIS #include @@ -127,11 +129,14 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, switch (c->method) { case GA_CHANNEL_VIRTIO_SERIAL: { assert(fd < 0); - fd = qemu_open_old(path, O_RDWR | O_NONBLOCK + fd = qga_open_cloexec( + path, #ifndef CONFIG_SOLARIS - | O_ASYNC + O_ASYNC | #endif - ); + O_RDWR | O_NONBLOCK, + 0 + ); if (fd == -1) { error_setg_errno(errp, errno, "error opening channel"); return false; @@ -156,7 +161,7 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, struct termios tio; assert(fd < 0); - fd = qemu_open_old(path, O_RDWR | O_NOCTTY | O_NONBLOCK); + fd = qga_open_cloexec(path, O_RDWR | O_NOCTTY | O_NONBLOCK, 0); if (fd == -1) { error_setg_errno(errp, errno, "error opening channel"); return false; diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 2ecc43eca9..0047245273 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -1406,7 +1406,7 @@ static void get_nvme_smart(GuestDiskInfo *disk) | (((sizeof(log) >> 2) - 1) << 16) }; - fd = qemu_open_old(disk->name, O_RDONLY); + fd = qga_open_cloexec(disk->name, O_RDONLY, 0); if (fd == -1) { g_debug("Failed to open device: %s: %s", disk->name, g_strerror(errno)); return; @@ -1739,7 +1739,7 @@ int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints, } } - fd = qemu_open_old(mount->dirname, O_RDONLY); + fd = qga_open_cloexec(mount->dirname, O_RDONLY, 0); if (fd == -1) { error_setg_errno(errp, errno, "failed to open %s", mount->dirname); goto error; @@ -1806,7 +1806,7 @@ int64_t qmp_guest_fsfreeze_thaw(Error **errp) QTAILQ_FOREACH(mount, &mounts, next) { logged = false; - fd = qemu_open_old(mount->dirname, O_RDONLY); + fd = qga_open_cloexec(mount->dirname, O_RDONLY, 0); if (fd == -1) { continue; } @@ -1892,7 +1892,7 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp) QAPI_LIST_PREPEND(response->paths, result); - fd = qemu_open_old(mount->dirname, O_RDONLY); + fd = qga_open_cloexec(mount->dirname, O_RDONLY, 0); if (fd == -1) { result->error = g_strdup_printf("failed to open: %s", strerror(errno)); From 561bfcb69dbd3ad055f9f7ff53f04213c09b51e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 25 May 2022 16:41:34 +0200 Subject: [PATCH 574/935] qga: make build_fs_mount_list() return a bool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change build_fs_mount_list() to return bool, in accordance with the guidance under = Rules = in include/qapi/error.h Signed-off-by: Marc-André Lureau Suggested-by: Markus Armbruster Message-Id: <20220525144140.591926-10-marcandre.lureau@redhat.com> --- qga/commands-posix.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 0047245273..0469dc409d 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -673,7 +673,7 @@ static int dev_major_minor(const char *devpath, /* * Walk the mount table and build a list of local file systems */ -static void build_fs_mount_list_from_mtab(FsMountList *mounts, Error **errp) +static bool build_fs_mount_list_from_mtab(FsMountList *mounts, Error **errp) { struct mntent *ment; FsMount *mount; @@ -684,7 +684,7 @@ static void build_fs_mount_list_from_mtab(FsMountList *mounts, Error **errp) fp = setmntent(mtab, "r"); if (!fp) { error_setg(errp, "failed to open mtab file: '%s'", mtab); - return; + return false; } while ((ment = getmntent(fp))) { @@ -714,6 +714,7 @@ static void build_fs_mount_list_from_mtab(FsMountList *mounts, Error **errp) } endmntent(fp); + return true; } static void decode_mntname(char *name, int len) @@ -738,7 +739,7 @@ static void decode_mntname(char *name, int len) } } -static void build_fs_mount_list(FsMountList *mounts, Error **errp) +static bool build_fs_mount_list(FsMountList *mounts, Error **errp) { FsMount *mount; char const *mountinfo = "/proc/self/mountinfo"; @@ -751,8 +752,7 @@ static void build_fs_mount_list(FsMountList *mounts, Error **errp) fp = fopen(mountinfo, "r"); if (!fp) { - build_fs_mount_list_from_mtab(mounts, errp); - return; + return build_fs_mount_list_from_mtab(mounts, errp); } while (getline(&line, &n, fp) != -1) { @@ -794,6 +794,7 @@ static void build_fs_mount_list(FsMountList *mounts, Error **errp) free(line); fclose(fp); + return true; } #endif @@ -1592,8 +1593,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp) Error *local_err = NULL; QTAILQ_INIT(&mounts); - build_fs_mount_list(&mounts, &local_err); - if (local_err) { + if (!build_fs_mount_list(&mounts, &local_err)) { error_propagate(errp, local_err); return NULL; } @@ -1716,8 +1716,7 @@ int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints, } QTAILQ_INIT(&mounts); - build_fs_mount_list(&mounts, &local_err); - if (local_err) { + if (!build_fs_mount_list(&mounts, &local_err)) { error_propagate(errp, local_err); return -1; } @@ -1798,8 +1797,7 @@ int64_t qmp_guest_fsfreeze_thaw(Error **errp) Error *local_err = NULL; QTAILQ_INIT(&mounts); - build_fs_mount_list(&mounts, &local_err); - if (local_err) { + if (!build_fs_mount_list(&mounts, &local_err)) { error_propagate(errp, local_err); return 0; } @@ -1872,15 +1870,12 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp) FsMountList mounts; struct FsMount *mount; int fd; - Error *local_err = NULL; struct fstrim_range r; slog("guest-fstrim called"); QTAILQ_INIT(&mounts); - build_fs_mount_list(&mounts, &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (!build_fs_mount_list(&mounts, errp)) { return NULL; } From a85d09269bb1a7071d3ce0f2957e3ca9dba7c047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 25 May 2022 16:41:35 +0200 Subject: [PATCH 575/935] test/qga: use G_TEST_DIR to locate os-release test file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This a more accurate way to lookup the test data, and will allow to move the test in a subproject. Signed-off-by: Marc-André Lureau Reviewed-by: Konstantin Kostiuk Message-Id: <20220525144140.591926-11-marcandre.lureau@redhat.com> --- tests/unit/test-qga.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/unit/test-qga.c b/tests/unit/test-qga.c index d6df1ee92e..ab0b12a2dd 100644 --- a/tests/unit/test-qga.c +++ b/tests/unit/test-qga.c @@ -914,15 +914,14 @@ static void test_qga_guest_get_osinfo(gconstpointer data) { TestFixture fixture; const gchar *str; - gchar *cwd, *env[2]; - QDict *ret, *val; + QDict *ret = NULL; + char *env[2]; + QDict *val; - cwd = g_get_current_dir(); env[0] = g_strdup_printf( - "QGA_OS_RELEASE=%s%ctests%cdata%ctest-qga-os-release", - cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR, G_DIR_SEPARATOR); + "QGA_OS_RELEASE=%s%c..%cdata%ctest-qga-os-release", + g_test_get_dir(G_TEST_DIST), G_DIR_SEPARATOR, G_DIR_SEPARATOR, G_DIR_SEPARATOR); env[1] = NULL; - g_free(cwd); fixture_setup(&fixture, NULL, env); ret = qmp_fd(fixture.fd, "{'execute': 'guest-get-osinfo'}"); From 4f3c5778a9643c4026be47f161e63112a83db265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 25 May 2022 16:41:36 +0200 Subject: [PATCH 576/935] qga/wixl: prefer variables over environment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to setup an environment or to check if the variable is undefined manually. Signed-off-by: Marc-André Lureau Reviewed-by: Konstantin Kostiuk Message-Id: <20220525144140.591926-12-marcandre.lureau@redhat.com> --- qga/installer/qemu-ga.wxs | 30 +++++++++--------------------- qga/meson.build | 9 ++++----- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/qga/installer/qemu-ga.wxs b/qga/installer/qemu-ga.wxs index 0950e8c6be..8a19aa1656 100644 --- a/qga/installer/qemu-ga.wxs +++ b/qga/installer/qemu-ga.wxs @@ -1,17 +1,5 @@ - - - - - - - - - - - - @@ -43,20 +31,20 @@ Name="QEMU guest agent" Id="*" UpgradeCode="{EB6B8302-C06E-4BEC-ADAC-932C68A3A98D}" - Manufacturer="$(env.QEMU_GA_MANUFACTURER)" - Version="$(env.QEMU_GA_VERSION)" + Manufacturer="$(var.QEMU_GA_MANUFACTURER)" + Version="$(var.QEMU_GA_VERSION)" Language="1033"> NOT VersionNT64 - + - + - + - + @@ -133,9 +121,9 @@ + Key="Software\$(var.QEMU_GA_MANUFACTURER)\$(var.QEMU_GA_DISTRO)\Tools\QemuGA"> - + diff --git a/qga/meson.build b/qga/meson.build index 35fe2229e9..31370405f9 100644 --- a/qga/meson.build +++ b/qga/meson.build @@ -122,15 +122,14 @@ if targetos == 'windows' output: 'qemu-ga-@0@.msi'.format(host_arch), depends: deps, command: [ - find_program('env'), - 'QEMU_GA_VERSION=' + config_host['QEMU_GA_VERSION'], - 'QEMU_GA_MANUFACTURER=' + config_host['QEMU_GA_MANUFACTURER'], - 'QEMU_GA_DISTRO=' + config_host['QEMU_GA_DISTRO'], - 'BUILD_DIR=' + meson.build_root(), wixl, '-o', '@OUTPUT0@', '@INPUT0@', qemu_ga_msi_arch[cpu], qemu_ga_msi_vss, + '-D', 'BUILD_DIR=' + meson.build_root(), '-D', 'Mingw_bin=' + config_host['QEMU_GA_MSI_MINGW_BIN_PATH'], + '-D', 'QEMU_GA_VERSION=' + config_host['QEMU_GA_VERSION'], + '-D', 'QEMU_GA_MANUFACTURER=' + config_host['QEMU_GA_MANUFACTURER'], + '-D', 'QEMU_GA_DISTRO=' + config_host['QEMU_GA_DISTRO'], ]) all_qga += [qga_msi] alias_target('msi', qga_msi) From be2db8368f84d9053baa8388f037b7ff11035787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 25 May 2022 16:41:37 +0200 Subject: [PATCH 577/935] qga/wixl: require Mingw_bin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No clear reason to make guesses here. Signed-off-by: Marc-André Lureau Reviewed-by: Konstantin Kostiuk Message-Id: <20220525144140.591926-13-marcandre.lureau@redhat.com> --- qga/installer/qemu-ga.wxs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/qga/installer/qemu-ga.wxs b/qga/installer/qemu-ga.wxs index 8a19aa1656..651db6e51c 100644 --- a/qga/installer/qemu-ga.wxs +++ b/qga/installer/qemu-ga.wxs @@ -4,15 +4,6 @@ - - - - - - - - - From 0480a1b67b22218637ab299fb0ea7df2ff8287ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 25 May 2022 16:41:38 +0200 Subject: [PATCH 578/935] qga/wixl: simplify some pre-processing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sadly, wixl doesn't have 'elif'. Signed-off-by: Marc-André Lureau Reviewed-by: Konstantin Kostiuk Message-Id: <20220525144140.591926-14-marcandre.lureau@redhat.com> --- qga/installer/qemu-ga.wxs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/qga/installer/qemu-ga.wxs b/qga/installer/qemu-ga.wxs index 651db6e51c..e5b0958e18 100644 --- a/qga/installer/qemu-ga.wxs +++ b/qga/installer/qemu-ga.wxs @@ -1,21 +1,15 @@ - - - - - - - - - - - - - + + + + + + + Date: Wed, 25 May 2022 16:41:39 +0200 Subject: [PATCH 579/935] qga/wixl: replace QEMU_GA_MSI_MINGW_BIN_PATH with glib bindir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use more conventional variables to set the location of pre-built DLL/bin. Signed-off-by: Marc-André Lureau Reviewed-by: Konstantin Kostiuk Message-Id: <20220525144140.591926-15-marcandre.lureau@redhat.com> --- configure | 9 ++++++--- meson.build | 5 ++++- qga/installer/qemu-ga.wxs | 24 ++++++++++++------------ qga/meson.build | 2 +- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/configure b/configure index 180ee688dc..f2baf2f526 100755 --- a/configure +++ b/configure @@ -1495,6 +1495,11 @@ for i in $glib_modules; do fi done +glib_bindir="$($pkg_config --variable=bindir glib-2.0)" +if test -z "$glib_bindir" ; then + glib_bindir="$($pkg_config --variable=prefix glib-2.0)"/bin +fi + # This workaround is required due to a bug in pkg-config file for glib as it # doesn't define GLIB_STATIC_COMPILATION for pkg-config --static @@ -1860,8 +1865,6 @@ if test "$QEMU_GA_VERSION" = ""; then QEMU_GA_VERSION=$(cat $source_path/VERSION) fi -QEMU_GA_MSI_MINGW_BIN_PATH="$($pkg_config --variable=prefix glib-2.0)/bin" - # Mac OS X ships with a broken assembler roms= if { test "$cpu" = "i386" || test "$cpu" = "x86_64"; } && \ @@ -1948,7 +1951,6 @@ if test "$debug_tcg" = "yes" ; then fi if test "$mingw32" = "yes" ; then echo "CONFIG_WIN32=y" >> $config_host_mak - echo "QEMU_GA_MSI_MINGW_BIN_PATH=${QEMU_GA_MSI_MINGW_BIN_PATH}" >> $config_host_mak echo "QEMU_GA_MANUFACTURER=${QEMU_GA_MANUFACTURER}" >> $config_host_mak echo "QEMU_GA_DISTRO=${QEMU_GA_DISTRO}" >> $config_host_mak echo "QEMU_GA_VERSION=${QEMU_GA_VERSION}" >> $config_host_mak @@ -2020,6 +2022,7 @@ echo "QEMU_CXXFLAGS=$QEMU_CXXFLAGS" >> $config_host_mak echo "QEMU_OBJCFLAGS=$QEMU_OBJCFLAGS" >> $config_host_mak echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak echo "GLIB_LIBS=$glib_libs" >> $config_host_mak +echo "GLIB_BINDIR=$glib_bindir" >> $config_host_mak echo "GLIB_VERSION=$(pkg-config --modversion glib-2.0)" >> $config_host_mak echo "QEMU_LDFLAGS=$QEMU_LDFLAGS" >> $config_host_mak echo "LD_I386_EMULATION=$ld_i386_emulation" >> $config_host_mak diff --git a/meson.build b/meson.build index df7c34b076..bf318d9cbb 100644 --- a/meson.build +++ b/meson.build @@ -466,7 +466,10 @@ add_project_arguments(config_host['GLIB_CFLAGS'].split(), native: false, language: ['c', 'cpp', 'objc']) glib = declare_dependency(compile_args: config_host['GLIB_CFLAGS'].split(), link_args: config_host['GLIB_LIBS'].split(), - version: config_host['GLIB_VERSION']) + version: config_host['GLIB_VERSION'], + variables: { + 'bindir': config_host['GLIB_BINDIR'], + }) # override glib dep with the configure results (for subprojects) meson.override_dependency('glib-2.0', glib) diff --git a/qga/installer/qemu-ga.wxs b/qga/installer/qemu-ga.wxs index e5b0958e18..813d1c6ca6 100644 --- a/qga/installer/qemu-ga.wxs +++ b/qga/installer/qemu-ga.wxs @@ -58,7 +58,7 @@ - + @@ -69,40 +69,40 @@ - + - + - + - + - + - + - + - + - + - + - + Date: Wed, 25 May 2022 16:41:40 +0200 Subject: [PATCH 580/935] test/qga: use g_auto wherever sensible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Konstantin Kostiuk Message-Id: <20220525144140.591926-16-marcandre.lureau@redhat.com> --- tests/unit/test-qga.c | 121 +++++++++++++++--------------------------- 1 file changed, 43 insertions(+), 78 deletions(-) diff --git a/tests/unit/test-qga.c b/tests/unit/test-qga.c index ab0b12a2dd..530317044b 100644 --- a/tests/unit/test-qga.c +++ b/tests/unit/test-qga.c @@ -52,7 +52,10 @@ fixture_setup(TestFixture *fixture, gconstpointer data, gchar **envp) { const gchar *extra_arg = data; GError *error = NULL; - gchar *cwd, *path, *cmd, **argv = NULL; + g_autofree char *cwd = NULL; + g_autofree char *path = NULL; + g_autofree char *cmd = NULL; + g_auto(GStrv) argv = NULL; fixture->loop = g_main_loop_new(NULL, FALSE); @@ -78,17 +81,12 @@ fixture_setup(TestFixture *fixture, gconstpointer data, gchar **envp) fixture->fd = connect_qga(path); g_assert_cmpint(fixture->fd, !=, -1); - - g_strfreev(argv); - g_free(cmd); - g_free(cwd); - g_free(path); } static void fixture_tear_down(TestFixture *fixture, gconstpointer data) { - gchar *tmp; + g_autofree char *tmp = NULL; kill(fixture->pid, SIGTERM); @@ -107,7 +105,6 @@ fixture_tear_down(TestFixture *fixture, gconstpointer data) tmp = g_build_filename(fixture->test_dir, "sock", NULL); g_unlink(tmp); - g_free(tmp); g_rmdir(fixture->test_dir); g_free(fixture->test_dir); @@ -122,7 +119,7 @@ static void qmp_assertion_message_error(const char *domain, QDict *dict) { const char *class, *desc; - char *s; + g_autofree char *s = NULL; QDict *error; error = qdict_get_qdict(dict, "error"); @@ -131,7 +128,6 @@ static void qmp_assertion_message_error(const char *domain, s = g_strdup_printf("assertion failed %s: %s %s", expr, class, desc); g_assertion_message(domain, file, line, func, s); - g_free(s); } #define qmp_assert_no_error(err) do { \ @@ -146,7 +142,7 @@ static void test_qga_sync_delimited(gconstpointer fix) const TestFixture *fixture = fix; guint32 v, r = g_test_rand_int(); unsigned char c; - QDict *ret; + g_autoptr(QDict) ret = NULL; qmp_fd_send_raw(fixture->fd, "\xff"); qmp_fd_send(fixture->fd, @@ -180,15 +176,13 @@ static void test_qga_sync_delimited(gconstpointer fix) v = qdict_get_int(ret, "return"); g_assert_cmpint(r, ==, v); - - qobject_unref(ret); } static void test_qga_sync(gconstpointer fix) { const TestFixture *fixture = fix; guint32 v, r = g_test_rand_int(); - QDict *ret; + g_autoptr(QDict) ret = NULL; /* * TODO guest-sync is inherently limited: we cannot distinguish @@ -210,33 +204,27 @@ static void test_qga_sync(gconstpointer fix) v = qdict_get_int(ret, "return"); g_assert_cmpint(r, ==, v); - - qobject_unref(ret); } static void test_qga_ping(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret; + g_autoptr(QDict) ret = NULL; ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping'}"); g_assert_nonnull(ret); qmp_assert_no_error(ret); - - qobject_unref(ret); } static void test_qga_id(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret; + g_autoptr(QDict) ret = NULL; ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', 'id': 1}"); g_assert_nonnull(ret); qmp_assert_no_error(ret); g_assert_cmpint(qdict_get_int(ret, "id"), ==, 1); - - qobject_unref(ret); } static void test_qga_invalid_oob(gconstpointer fix) @@ -253,7 +241,8 @@ static void test_qga_invalid_oob(gconstpointer fix) static void test_qga_invalid_args(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret, *error; + g_autoptr(QDict) ret = NULL; + QDict *error; const gchar *class, *desc; ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', " @@ -266,14 +255,13 @@ static void test_qga_invalid_args(gconstpointer fix) g_assert_cmpstr(class, ==, "GenericError"); g_assert_cmpstr(desc, ==, "Parameter 'foo' is unexpected"); - - qobject_unref(ret); } static void test_qga_invalid_cmd(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret, *error; + g_autoptr(QDict) ret = NULL; + QDict *error; const gchar *class, *desc; ret = qmp_fd(fixture->fd, "{'execute': 'guest-invalid-cmd'}"); @@ -285,14 +273,13 @@ static void test_qga_invalid_cmd(gconstpointer fix) g_assert_cmpstr(class, ==, "CommandNotFound"); g_assert_cmpint(strlen(desc), >, 0); - - qobject_unref(ret); } static void test_qga_info(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret, *val; + g_autoptr(QDict) ret = NULL; + QDict *val; const gchar *version; ret = qmp_fd(fixture->fd, "{'execute': 'guest-info'}"); @@ -302,14 +289,12 @@ static void test_qga_info(gconstpointer fix) val = qdict_get_qdict(ret, "return"); version = qdict_get_try_str(val, "version"); g_assert_cmpstr(version, ==, QEMU_VERSION); - - qobject_unref(ret); } static void test_qga_get_vcpus(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret; + g_autoptr(QDict) ret = NULL; QList *list; const QListEntry *entry; @@ -322,14 +307,12 @@ static void test_qga_get_vcpus(gconstpointer fix) entry = qlist_first(list); g_assert(qdict_haskey(qobject_to(QDict, entry->value), "online")); g_assert(qdict_haskey(qobject_to(QDict, entry->value), "logical-id")); - - qobject_unref(ret); } static void test_qga_get_fsinfo(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret; + g_autoptr(QDict) ret = NULL; QList *list; const QListEntry *entry; @@ -346,14 +329,13 @@ static void test_qga_get_fsinfo(gconstpointer fix) g_assert(qdict_haskey(qobject_to(QDict, entry->value), "type")); g_assert(qdict_haskey(qobject_to(QDict, entry->value), "disk")); } - - qobject_unref(ret); } static void test_qga_get_memory_block_info(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret, *val; + g_autoptr(QDict) ret = NULL; + QDict *val; int64_t size; ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-block-info'}"); @@ -366,14 +348,12 @@ static void test_qga_get_memory_block_info(gconstpointer fix) size = qdict_get_int(val, "size"); g_assert_cmpint(size, >, 0); } - - qobject_unref(ret); } static void test_qga_get_memory_blocks(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret; + g_autoptr(QDict) ret = NULL; QList *list; const QListEntry *entry; @@ -391,14 +371,12 @@ static void test_qga_get_memory_blocks(gconstpointer fix) g_assert(qdict_haskey(qobject_to(QDict, entry->value), "online")); } } - - qobject_unref(ret); } static void test_qga_network_get_interfaces(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret; + g_autoptr(QDict) ret = NULL; QList *list; const QListEntry *entry; @@ -410,8 +388,6 @@ static void test_qga_network_get_interfaces(gconstpointer fix) list = qdict_get_qlist(ret, "return"); entry = qlist_first(list); g_assert(qdict_haskey(qobject_to(QDict, entry->value), "name")); - - qobject_unref(ret); } static void test_qga_file_ops(gconstpointer fix) @@ -642,7 +618,7 @@ static void test_qga_file_write_read(gconstpointer fix) static void test_qga_get_time(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret; + g_autoptr(QDict) ret = NULL; int64_t time; ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}"); @@ -651,8 +627,6 @@ static void test_qga_get_time(gconstpointer fix) time = qdict_get_int(ret, "return"); g_assert_cmpint(time, >, 0); - - qobject_unref(ret); } static void test_qga_blacklist(gconstpointer data) @@ -693,18 +667,22 @@ static void test_qga_blacklist(gconstpointer data) static void test_qga_config(gconstpointer data) { GError *error = NULL; - char *cwd, *cmd, *out, *err, *str, **strv, **argv = NULL; + g_autofree char *out = NULL; + g_autofree char *err = NULL; + g_autofree char *cwd = NULL; + g_autofree char *cmd = NULL; + g_auto(GStrv) argv = NULL; + g_auto(GStrv) strv = NULL; + g_autoptr(GKeyFile) kf = NULL; + char *str; char *env[2]; int status; gsize n; - GKeyFile *kf; cwd = g_get_current_dir(); cmd = g_strdup_printf("%s%cqga%cqemu-ga -D", cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR); - g_free(cwd); g_shell_parse_argv(cmd, NULL, &argv, &error); - g_free(cmd); g_assert_no_error(error); env[0] = g_strdup_printf("QGA_CONF=tests%cdata%ctest-qga-config", @@ -712,7 +690,6 @@ static void test_qga_config(gconstpointer data) env[1] = NULL; g_spawn_sync(NULL, argv, env, 0, NULL, NULL, &out, &err, &status, &error); - g_strfreev(argv); g_assert_no_error(error); g_assert_cmpstr(err, ==, ""); @@ -759,18 +736,14 @@ static void test_qga_config(gconstpointer data) g_assert_true(g_strv_contains((const char * const *)strv, "guest-get-time")); g_assert_no_error(error); - g_strfreev(strv); - g_free(out); - g_free(err); g_free(env[0]); - g_key_file_free(kf); } static void test_qga_fsfreeze_status(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret; + g_autoptr(QDict) ret = NULL; const gchar *status; ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}"); @@ -779,16 +752,15 @@ static void test_qga_fsfreeze_status(gconstpointer fix) status = qdict_get_try_str(ret, "return"); g_assert_cmpstr(status, ==, "thawed"); - - qobject_unref(ret); } static void test_qga_guest_exec(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret, *val; + g_autoptr(QDict) ret = NULL; + QDict *val; const gchar *out; - guchar *decoded; + g_autofree guchar *decoded = NULL; int64_t pid, now, exitcode; gsize len; bool exited; @@ -827,14 +799,13 @@ static void test_qga_guest_exec(gconstpointer fix) decoded = g_base64_decode(out, &len); g_assert_cmpint(len, ==, 12); g_assert_cmpstr((char *)decoded, ==, "\" test_str \""); - g_free(decoded); - qobject_unref(ret); } static void test_qga_guest_exec_invalid(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret, *error; + g_autoptr(QDict) ret = NULL; + QDict *error; const gchar *class, *desc; /* invalid command */ @@ -859,13 +830,13 @@ static void test_qga_guest_exec_invalid(gconstpointer fix) desc = qdict_get_str(error, "desc"); g_assert_cmpstr(class, ==, "GenericError"); g_assert_cmpint(strlen(desc), >, 0); - qobject_unref(ret); } static void test_qga_guest_get_host_name(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret, *val; + g_autoptr(QDict) ret = NULL; + QDict *val; ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-host-name'}"); g_assert_nonnull(ret); @@ -873,14 +844,13 @@ static void test_qga_guest_get_host_name(gconstpointer fix) val = qdict_get_qdict(ret, "return"); g_assert(qdict_haskey(val, "host-name")); - - qobject_unref(ret); } static void test_qga_guest_get_timezone(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret, *val; + g_autoptr(QDict) ret = NULL; + QDict *val; ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-timezone'}"); g_assert_nonnull(ret); @@ -889,14 +859,12 @@ static void test_qga_guest_get_timezone(gconstpointer fix) /* Make sure there's at least offset */ val = qdict_get_qdict(ret, "return"); g_assert(qdict_haskey(val, "offset")); - - qobject_unref(ret); } static void test_qga_guest_get_users(gconstpointer fix) { const TestFixture *fixture = fix; - QDict *ret; + g_autoptr(QDict) ret = NULL; QList *val; ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-users'}"); @@ -906,15 +874,13 @@ static void test_qga_guest_get_users(gconstpointer fix) /* There is not much to test here */ val = qdict_get_qlist(ret, "return"); g_assert_nonnull(val); - - qobject_unref(ret); } static void test_qga_guest_get_osinfo(gconstpointer data) { TestFixture fixture; const gchar *str; - QDict *ret = NULL; + g_autoptr(QDict) ret = NULL; char *env[2]; QDict *val; @@ -958,7 +924,6 @@ static void test_qga_guest_get_osinfo(gconstpointer data) g_assert_nonnull(str); g_assert_cmpstr(str, ==, "unit-test"); - qobject_unref(ret); g_free(env[0]); fixture_tear_down(&fixture, NULL); } From 4de43540644962687fcd2df2a2454c1e46c2f92a Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 28 May 2022 11:15:13 +0200 Subject: [PATCH 581/935] hppa: Sync contents of hppa_hardware.h header file with SeaBIOS-hppa The hppa_hardware.h header file holds many constants for addresses and offsets which are needed while building the firmware (SeaBIOS-hppa) and while setting up the virtual machine in QEMU. That's why this header file needs to be in sync between both source code repositories. This patch adds a comment mentioning this dependency at the top of this file and restores some DINO relevant offsets. Signed-off-by: Helge Deller Reviewed-by: Mark Cave-Ayland --- hw/hppa/hppa_hardware.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/hppa/hppa_hardware.h b/hw/hppa/hppa_hardware.h index 8b6b9222cb..3f7627b98f 100644 --- a/hw/hppa/hppa_hardware.h +++ b/hw/hppa/hppa_hardware.h @@ -1,4 +1,5 @@ /* HPPA cores and system support chips. */ +/* Be aware: QEMU and seabios-hppa repositories share this file as-is. */ #ifndef HW_HPPA_HPPA_HARDWARE_H #define HW_HPPA_HPPA_HARDWARE_H @@ -30,6 +31,11 @@ #define PCI_HPA DINO_HPA /* PCI bus */ #define IDE_HPA 0xf9000000 /* Boot disc controller */ +/* offsets to DINO HPA: */ +#define DINO_PCI_ADDR 0x064 +#define DINO_CONFIG_DATA 0x068 +#define DINO_IO_DATA 0x06c + #define PORT_PCI_CMD (PCI_HPA + DINO_PCI_ADDR) #define PORT_PCI_DATA (PCI_HPA + DINO_CONFIG_DATA) From 5079892df5f113c7f2b77f53bf7663f6c7bc6be9 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 28 May 2022 11:26:29 +0200 Subject: [PATCH 582/935] hppa: Fix serial port assignments and pass-through This fixes the serial ports in the emulation to behave as on original hardware. On the real hardware, the LASI UART is serial port #0 and the DINO UART is serial port #1. This is fixed in SeaBIOS-hppa firmware v6, which is why at least this firmware version is required. The serial port addresses in hppa/hppa_hardware.h have to be swapped, and when creating the virtual serial ports the correct port addresses are used. This patch now for example allows to specify on the qemu command line: -serial mon:stdio -serial /dev/ttyS4 to use the emulated ttyS0 in the guest for console output, and pass ttyS4 from the host to ttyS1 in the guest. Signed-off-by: Helge Deller Reviewed-by: Mark Cave-Ayland --- hw/hppa/hppa_hardware.h | 4 ++-- hw/hppa/machine.c | 22 ++++++++-------------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/hw/hppa/hppa_hardware.h b/hw/hppa/hppa_hardware.h index 3f7627b98f..a5ac3dd0fd 100644 --- a/hw/hppa/hppa_hardware.h +++ b/hw/hppa/hppa_hardware.h @@ -41,8 +41,8 @@ #define FW_CFG_IO_BASE 0xfffa0000 -#define PORT_SERIAL1 (DINO_UART_HPA + 0x800) -#define PORT_SERIAL2 (LASI_UART_HPA + 0x800) +#define PORT_SERIAL1 (LASI_UART_HPA + 0x800) +#define PORT_SERIAL2 (DINO_UART_HPA + 0x800) #define HPPA_MAX_CPUS 16 /* max. number of SMP CPUs */ #define CPU_CLOCK_MHZ 250 /* emulate a 250 MHz CPU */ diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index d1e174b1f4..63b9dd2396 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -32,7 +32,7 @@ #define MAX_IDE_BUS 2 -#define MIN_SEABIOS_HPPA_VERSION 1 /* require at least this fw version */ +#define MIN_SEABIOS_HPPA_VERSION 6 /* require at least this fw version */ #define HPA_POWER_BUTTON (FIRMWARE_END - 0x10) @@ -236,20 +236,14 @@ static void machine_hppa_init(MachineState *machine) /* Realtime clock, used by firmware for PDC_TOD call. */ mc146818_rtc_init(isa_bus, 2000, NULL); - /* Serial code setup. */ - if (serial_hd(0)) { - uint32_t addr = DINO_UART_HPA + 0x800; - serial_mm_init(addr_space, addr, 0, - qdev_get_gpio_in(dino_dev, DINO_IRQ_RS232INT), - 115200, serial_hd(0), DEVICE_BIG_ENDIAN); - } + /* Serial ports: Lasi and Dino use a 7.272727 MHz clock. */ + serial_mm_init(addr_space, LASI_UART_HPA + 0x800, 0, + qdev_get_gpio_in(lasi_dev, LASI_IRQ_UART_HPA), 7272727 / 16, + serial_hd(0), DEVICE_BIG_ENDIAN); - if (serial_hd(1)) { - /* Serial port */ - serial_mm_init(addr_space, LASI_UART_HPA + 0x800, 0, - qdev_get_gpio_in(lasi_dev, LASI_IRQ_UART_HPA), 8000000 / 16, - serial_hd(1), DEVICE_BIG_ENDIAN); - } + serial_mm_init(addr_space, DINO_UART_HPA + 0x800, 0, + qdev_get_gpio_in(dino_dev, DINO_IRQ_RS232INT), 7272727 / 16, + serial_hd(1), DEVICE_BIG_ENDIAN); /* Parallel port */ parallel_mm_init(addr_space, LASI_LPT_HPA + 0x800, 0, From 95d0f1d80eba918b6f1d7201994a468a38134ec1 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 May 2022 10:26:52 +0100 Subject: [PATCH 583/935] docs/system/arm: Add FEAT_HCX to list of emulated features In commit 5814d587fe861fe9 we added support for emulating FEAT_HCX (Support for the HCRX_EL2 register). However we forgot to add it to the list in emulated.rst. Correct the omission. Fixes: 5814d587fe861fe9 ("target/arm: Enable FEAT_HCX for -cpu max") Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220520084320.424166-1-peter.maydell@linaro.org --- docs/system/arm/emulation.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index 3e95bba0d2..49cc3e8340 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -29,6 +29,7 @@ the following architecture extensions: - FEAT_FRINTTS (Floating-point to integer instructions) - FEAT_FlagM (Flag manipulation instructions v2) - FEAT_FlagM2 (Enhancements to flag manipulation instructions) +- FEAT_HCX (Support for the HCRX_EL2 register) - FEAT_HPDS (Hierarchical permission disables) - FEAT_I8MM (AArch64 Int8 matrix multiplication instructions) - FEAT_IDST (ID space trap handling) From b5fb359cb5b9bf5d85932b869a707550a4e18ad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 25 May 2022 18:19:26 +0200 Subject: [PATCH 584/935] target/arm/hvf: Include missing "cpregs.h" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix when building HVF on macOS Aarch64: target/arm/hvf/hvf.c:586:15: error: unknown type name 'ARMCPRegInfo'; did you mean 'ARMCPUInfo'? const ARMCPRegInfo *ri; ^~~~~~~~~~~~ ARMCPUInfo target/arm/cpu-qom.h:38:3: note: 'ARMCPUInfo' declared here } ARMCPUInfo; ^ target/arm/hvf/hvf.c:589:14: error: implicit declaration of function 'get_arm_cp_reginfo' is invalid in C99 [-Werror,-Wimplicit-function-declaration] ri = get_arm_cp_reginfo(arm_cpu->cp_regs, key); ^ target/arm/hvf/hvf.c:589:12: warning: incompatible integer to pointer conversion assigning to 'const ARMCPUInfo *' (aka 'const struct ARMCPUInfo *') from 'int' [-Wint-conversion] ri = get_arm_cp_reginfo(arm_cpu->cp_regs, key); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ target/arm/hvf/hvf.c:591:26: error: no member named 'type' in 'struct ARMCPUInfo' assert(!(ri->type & ARM_CP_NO_RAW)); ~~ ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/assert.h:99:25: note: expanded from macro 'assert' (__builtin_expect(!(e), 0) ? __assert_rtn(__func__, __ASSERT_FILE_NAME, __LINE__, #e) : (void)0) ^ target/arm/hvf/hvf.c:591:33: error: use of undeclared identifier 'ARM_CP_NO_RAW' assert(!(ri->type & ARM_CP_NO_RAW)); ^ 1 warning and 4 errors generated. Fixes: cf7c6d1004 ("target/arm: Split out cpregs.h") Reported-by: Duncan Bayne Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20220525161926.34233-1-philmd@fungible.com Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1029 Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 86710509d2..1fdc5eef92 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -17,6 +17,7 @@ #include "sysemu/hvf_int.h" #include "sysemu/hw_accel.h" #include "hvf_arm.h" +#include "cpregs.h" #include From fd71f258bc0d245b2223bf3032c0ebc82f8a3463 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Fri, 20 May 2022 20:42:00 +0800 Subject: [PATCH 585/935] hw/sd/allwinner-sdhost: report FIFO water level as 1 when data ready U-Boot queries the FIFO water level to reduce checking status register when doing PIO SD card operation. Report a FIFO water level of 1 when data is ready, to prevent the code from trying to read 0 words from the FIFO each time. Signed-off-by: Icenowy Zheng Message-id: 20220520124200.2112699-1-uwu@icenowy.me Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/sd/allwinner-sdhost.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/sd/allwinner-sdhost.c b/hw/sd/allwinner-sdhost.c index 041e45c680..455d6eabf6 100644 --- a/hw/sd/allwinner-sdhost.c +++ b/hw/sd/allwinner-sdhost.c @@ -114,7 +114,9 @@ enum { }; enum { + SD_STAR_FIFO_EMPTY = (1 << 2), SD_STAR_CARD_PRESENT = (1 << 8), + SD_STAR_FIFO_LEVEL_1 = (1 << 17), }; enum { @@ -467,6 +469,11 @@ static uint64_t allwinner_sdhost_read(void *opaque, hwaddr offset, break; case REG_SD_STAR: /* Status */ res = s->status; + if (sdbus_data_ready(&s->sdbus)) { + res |= SD_STAR_FIFO_LEVEL_1; + } else { + res |= SD_STAR_FIFO_EMPTY; + } break; case REG_SD_FWLR: /* FIFO Water Level */ res = s->fifo_wlevel; From 05a546429f23841988c353d6ed7a1908cd209292 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:14 -0700 Subject: [PATCH 586/935] target/arm: Introduce TRANS, TRANS_FEAT Steal the idea for these leaf function expanders from PowerPC. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-2-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/target/arm/translate.h b/target/arm/translate.h index 6f0ebdc88e..9f0bb270c5 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -576,4 +576,15 @@ static inline MemOp finalize_memop(DisasContext *s, MemOp opc) */ uint64_t asimd_imm_const(uint32_t imm, int cmode, int op); +/* + * Helpers for implementing sets of trans_* functions. + * Defer the implementation of NAME to FUNC, with optional extra arguments. + */ +#define TRANS(NAME, FUNC, ...) \ + static bool trans_##NAME(DisasContext *s, arg_##NAME *a) \ + { return FUNC(s, __VA_ARGS__); } +#define TRANS_FEAT(NAME, FEAT, FUNC, ...) \ + static bool trans_##NAME(DisasContext *s, arg_##NAME *a) \ + { return dc_isar_feature(FEAT, s) && FUNC(s, __VA_ARGS__); } + #endif /* TARGET_ARM_TRANSLATE_H */ From c5edf07d33558ed71932de221906ed47a52f3bb2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:15 -0700 Subject: [PATCH 587/935] target/arm: Move null function and sve check into gen_gvec_ool_zz Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-3-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index dd4a5b23ab..903514cb6a 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -137,13 +137,19 @@ static int pred_gvec_reg_size(DisasContext *s) } /* Invoke an out-of-line helper on 2 Zregs. */ -static void gen_gvec_ool_zz(DisasContext *s, gen_helper_gvec_2 *fn, +static bool gen_gvec_ool_zz(DisasContext *s, gen_helper_gvec_2 *fn, int rd, int rn, int data) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_2_ool(vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - vsz, vsz, data, fn); + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_2_ool(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vsz, vsz, data, fn); + } + return true; } /* Invoke an out-of-line helper on 3 Zregs. */ @@ -1377,13 +1383,7 @@ static bool trans_FEXPA(DisasContext *s, arg_rr_esz *a) gen_helper_sve_fexpa_s, gen_helper_sve_fexpa_d, }; - if (a->esz == 0) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zz(s, fns[a->esz], a->rd, a->rn, 0); - } - return true; + return gen_gvec_ool_zz(s, fns[a->esz], a->rd, a->rn, 0); } static bool trans_FTSSEL(DisasContext *s, arg_rrr_esz *a) @@ -2424,11 +2424,7 @@ static bool trans_REV_v(DisasContext *s, arg_rr_esz *a) gen_helper_sve_rev_b, gen_helper_sve_rev_h, gen_helper_sve_rev_s, gen_helper_sve_rev_d }; - - if (sve_access_check(s)) { - gen_gvec_ool_zz(s, fns[a->esz], a->rd, a->rn, 0); - } - return true; + return gen_gvec_ool_zz(s, fns[a->esz], a->rd, a->rn, 0); } static bool trans_TBL(DisasContext *s, arg_rrr_esz *a) @@ -8385,10 +8381,8 @@ static bool trans_AESMC(DisasContext *s, arg_AESMC *a) if (!dc_isar_feature(aa64_sve2_aes, s)) { return false; } - if (sve_access_check(s)) { - gen_gvec_ool_zz(s, gen_helper_crypto_aesmc, a->rd, a->rd, a->decrypt); - } - return true; + return gen_gvec_ool_zz(s, gen_helper_crypto_aesmc, + a->rd, a->rd, a->decrypt); } static bool do_aese(DisasContext *s, arg_rrr_esz *a, bool decrypt) From 0ea3cdbf7fc0d4ff143b0af6dc5d45354eb942f2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:16 -0700 Subject: [PATCH 588/935] target/arm: Use TRANS_FEAT for gen_gvec_ool_zz Convert SVE translation functions using gen_gvec_ool_zz to TRANS_FEAT. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-4-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 39 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 903514cb6a..f7e7a569b7 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -1375,16 +1375,12 @@ static bool trans_ADR_u32(DisasContext *s, arg_rrri *a) *** SVE Integer Misc - Unpredicated Group */ -static bool trans_FEXPA(DisasContext *s, arg_rr_esz *a) -{ - static gen_helper_gvec_2 * const fns[4] = { - NULL, - gen_helper_sve_fexpa_h, - gen_helper_sve_fexpa_s, - gen_helper_sve_fexpa_d, - }; - return gen_gvec_ool_zz(s, fns[a->esz], a->rd, a->rn, 0); -} +static gen_helper_gvec_2 * const fexpa_fns[4] = { + NULL, gen_helper_sve_fexpa_h, + gen_helper_sve_fexpa_s, gen_helper_sve_fexpa_d, +}; +TRANS_FEAT(FEXPA, aa64_sve, gen_gvec_ool_zz, + fexpa_fns[a->esz], a->rd, a->rn, 0) static bool trans_FTSSEL(DisasContext *s, arg_rrr_esz *a) { @@ -2418,14 +2414,11 @@ static bool trans_INSR_r(DisasContext *s, arg_rrr_esz *a) return true; } -static bool trans_REV_v(DisasContext *s, arg_rr_esz *a) -{ - static gen_helper_gvec_2 * const fns[4] = { - gen_helper_sve_rev_b, gen_helper_sve_rev_h, - gen_helper_sve_rev_s, gen_helper_sve_rev_d - }; - return gen_gvec_ool_zz(s, fns[a->esz], a->rd, a->rn, 0); -} +static gen_helper_gvec_2 * const rev_fns[4] = { + gen_helper_sve_rev_b, gen_helper_sve_rev_h, + gen_helper_sve_rev_s, gen_helper_sve_rev_d +}; +TRANS_FEAT(REV_v, aa64_sve, gen_gvec_ool_zz, rev_fns[a->esz], a->rd, a->rn, 0) static bool trans_TBL(DisasContext *s, arg_rrr_esz *a) { @@ -8376,14 +8369,8 @@ static bool trans_USDOT_zzzz(DisasContext *s, arg_USDOT_zzzz *a) return true; } -static bool trans_AESMC(DisasContext *s, arg_AESMC *a) -{ - if (!dc_isar_feature(aa64_sve2_aes, s)) { - return false; - } - return gen_gvec_ool_zz(s, gen_helper_crypto_aesmc, - a->rd, a->rd, a->decrypt); -} +TRANS_FEAT(AESMC, aa64_sve2_aes, gen_gvec_ool_zz, + gen_helper_crypto_aesmc, a->rd, a->rd, a->decrypt) static bool do_aese(DisasContext *s, arg_rrr_esz *a, bool decrypt) { From 913a8a0023a480121d17cd3a0fa505688a1f3b0a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:17 -0700 Subject: [PATCH 589/935] target/arm: Move null function and sve check into gen_gvec_ool_zzz Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-5-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 74 ++++++++++++-------------------------- 1 file changed, 23 insertions(+), 51 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index f7e7a569b7..fd1d749c0e 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -153,14 +153,20 @@ static bool gen_gvec_ool_zz(DisasContext *s, gen_helper_gvec_2 *fn, } /* Invoke an out-of-line helper on 3 Zregs. */ -static void gen_gvec_ool_zzz(DisasContext *s, gen_helper_gvec_3 *fn, +static bool gen_gvec_ool_zzz(DisasContext *s, gen_helper_gvec_3 *fn, int rd, int rn, int rm, int data) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_3_ool(vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), - vsz, vsz, data, fn); + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_3_ool(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), + vsz, vsz, data, fn); + } + return true; } /* Invoke an out-of-line helper on 4 Zregs. */ @@ -1173,13 +1179,7 @@ static bool trans_LSL_zzi(DisasContext *s, arg_rri_esz *a) static bool do_zzw_ool(DisasContext *s, arg_rrr_esz *a, gen_helper_gvec_3 *fn) { - if (fn == NULL) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, 0); - } - return true; + return gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, 0); } #define DO_ZZW(NAME, name) \ @@ -1345,10 +1345,7 @@ static bool trans_RDVL(DisasContext *s, arg_RDVL *a) static bool do_adr(DisasContext *s, arg_rrri *a, gen_helper_gvec_3 *fn) { - if (sve_access_check(s)) { - gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, a->imm); - } - return true; + return gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, a->imm); } static bool trans_ADR_p32(DisasContext *s, arg_rrri *a) @@ -1390,13 +1387,7 @@ static bool trans_FTSSEL(DisasContext *s, arg_rrr_esz *a) gen_helper_sve_ftssel_s, gen_helper_sve_ftssel_d, }; - if (a->esz == 0) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzz(s, fns[a->esz], a->rd, a->rn, a->rm, 0); - } - return true; + return gen_gvec_ool_zzz(s, fns[a->esz], a->rd, a->rn, a->rm, 0); } /* @@ -2426,11 +2417,7 @@ static bool trans_TBL(DisasContext *s, arg_rrr_esz *a) gen_helper_sve_tbl_b, gen_helper_sve_tbl_h, gen_helper_sve_tbl_s, gen_helper_sve_tbl_d }; - - if (sve_access_check(s)) { - gen_gvec_ool_zzz(s, fns[a->esz], a->rd, a->rn, a->rm, 0); - } - return true; + return gen_gvec_ool_zzz(s, fns[a->esz], a->rd, a->rn, a->rm, 0); } static bool trans_TBL_sve2(DisasContext *s, arg_rrr_esz *a) @@ -2460,10 +2447,7 @@ static bool trans_TBX(DisasContext *s, arg_rrr_esz *a) if (!dc_isar_feature(aa64_sve2, s)) { return false; } - if (sve_access_check(s)) { - gen_gvec_ool_zzz(s, fns[a->esz], a->rd, a->rn, a->rm, 0); - } - return true; + return gen_gvec_ool_zzz(s, fns[a->esz], a->rd, a->rn, a->rm, 0); } static bool trans_UNPK(DisasContext *s, arg_UNPK *a) @@ -2618,10 +2602,7 @@ static bool do_zip(DisasContext *s, arg_rrr_esz *a, bool high) static bool do_zzz_data_ool(DisasContext *s, arg_rrr_esz *a, int data, gen_helper_gvec_3 *fn) { - if (sve_access_check(s)) { - gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, data); - } - return true; + return gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, data); } static bool trans_ZIP1_z(DisasContext *s, arg_rrr_esz *a) @@ -6693,13 +6674,10 @@ static bool trans_MUL_zzz(DisasContext *s, arg_rrr_esz *a) static bool do_sve2_zzz_ool(DisasContext *s, arg_rrr_esz *a, gen_helper_gvec_3 *fn) { - if (fn == NULL || !dc_isar_feature(aa64_sve2, s)) { + if (!dc_isar_feature(aa64_sve2, s)) { return false; } - if (sve_access_check(s)) { - gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, 0); - } - return true; + return gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, 0); } static bool trans_SMULH_zzz(DisasContext *s, arg_rrr_esz *a) @@ -8377,11 +8355,8 @@ static bool do_aese(DisasContext *s, arg_rrr_esz *a, bool decrypt) if (!dc_isar_feature(aa64_sve2_aes, s)) { return false; } - if (sve_access_check(s)) { - gen_gvec_ool_zzz(s, gen_helper_crypto_aese, - a->rd, a->rn, a->rm, decrypt); - } - return true; + return gen_gvec_ool_zzz(s, gen_helper_crypto_aese, + a->rd, a->rn, a->rm, decrypt); } static bool trans_AESE(DisasContext *s, arg_rrr_esz *a) @@ -8399,10 +8374,7 @@ static bool do_sm4(DisasContext *s, arg_rrr_esz *a, gen_helper_gvec_3 *fn) if (!dc_isar_feature(aa64_sve2_sm4, s)) { return false; } - if (sve_access_check(s)) { - gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, 0); - } - return true; + return gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, 0); } static bool trans_SM4E(DisasContext *s, arg_rrr_esz *a) From 84a272f565caa871a2762f74e718440bf9bbafc3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:18 -0700 Subject: [PATCH 590/935] target/arm: Introduce gen_gvec_ool_arg_zzz Use gen_gvec_ool_arg_zzz instead of gen_gvec_ool_zzz when the arguments come from arg_rrr_esz. Replaces do_zzw_ool and do_zzz_data_ool. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-6-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 48 +++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index fd1d749c0e..37343fb2f0 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -169,6 +169,12 @@ static bool gen_gvec_ool_zzz(DisasContext *s, gen_helper_gvec_3 *fn, return true; } +static bool gen_gvec_ool_arg_zzz(DisasContext *s, gen_helper_gvec_3 *fn, + arg_rrr_esz *a, int data) +{ + return gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, data); +} + /* Invoke an out-of-line helper on 4 Zregs. */ static void gen_gvec_ool_zzzz(DisasContext *s, gen_helper_gvec_4 *fn, int rd, int rn, int rm, int ra, int data) @@ -1177,11 +1183,6 @@ static bool trans_LSL_zzi(DisasContext *s, arg_rri_esz *a) return do_shift_imm(s, a, false, tcg_gen_gvec_shli); } -static bool do_zzw_ool(DisasContext *s, arg_rrr_esz *a, gen_helper_gvec_3 *fn) -{ - return gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, 0); -} - #define DO_ZZW(NAME, name) \ static bool trans_##NAME##_zzw(DisasContext *s, arg_rrr_esz *a) \ { \ @@ -1189,7 +1190,7 @@ static bool trans_##NAME##_zzw(DisasContext *s, arg_rrr_esz *a) \ gen_helper_sve_##name##_zzw_b, gen_helper_sve_##name##_zzw_h, \ gen_helper_sve_##name##_zzw_s, NULL \ }; \ - return do_zzw_ool(s, a, fns[a->esz]); \ + return gen_gvec_ool_arg_zzz(s, fns[a->esz], a, 0); \ } DO_ZZW(ASR, asr) @@ -1387,7 +1388,7 @@ static bool trans_FTSSEL(DisasContext *s, arg_rrr_esz *a) gen_helper_sve_ftssel_s, gen_helper_sve_ftssel_d, }; - return gen_gvec_ool_zzz(s, fns[a->esz], a->rd, a->rn, a->rm, 0); + return gen_gvec_ool_arg_zzz(s, fns[a->esz], a, 0); } /* @@ -2417,7 +2418,7 @@ static bool trans_TBL(DisasContext *s, arg_rrr_esz *a) gen_helper_sve_tbl_b, gen_helper_sve_tbl_h, gen_helper_sve_tbl_s, gen_helper_sve_tbl_d }; - return gen_gvec_ool_zzz(s, fns[a->esz], a->rd, a->rn, a->rm, 0); + return gen_gvec_ool_arg_zzz(s, fns[a->esz], a, 0); } static bool trans_TBL_sve2(DisasContext *s, arg_rrr_esz *a) @@ -2447,7 +2448,7 @@ static bool trans_TBX(DisasContext *s, arg_rrr_esz *a) if (!dc_isar_feature(aa64_sve2, s)) { return false; } - return gen_gvec_ool_zzz(s, fns[a->esz], a->rd, a->rn, a->rm, 0); + return gen_gvec_ool_arg_zzz(s, fns[a->esz], a, 0); } static bool trans_UNPK(DisasContext *s, arg_UNPK *a) @@ -2599,12 +2600,6 @@ static bool do_zip(DisasContext *s, arg_rrr_esz *a, bool high) return true; } -static bool do_zzz_data_ool(DisasContext *s, arg_rrr_esz *a, int data, - gen_helper_gvec_3 *fn) -{ - return gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, data); -} - static bool trans_ZIP1_z(DisasContext *s, arg_rrr_esz *a) { return do_zip(s, a, false); @@ -2648,12 +2643,12 @@ static gen_helper_gvec_3 * const uzp_fns[4] = { static bool trans_UZP1_z(DisasContext *s, arg_rrr_esz *a) { - return do_zzz_data_ool(s, a, 0, uzp_fns[a->esz]); + return gen_gvec_ool_arg_zzz(s, uzp_fns[a->esz], a, 0); } static bool trans_UZP2_z(DisasContext *s, arg_rrr_esz *a) { - return do_zzz_data_ool(s, a, 1 << a->esz, uzp_fns[a->esz]); + return gen_gvec_ool_arg_zzz(s, uzp_fns[a->esz], a, 1 << a->esz); } static bool trans_UZP1_q(DisasContext *s, arg_rrr_esz *a) @@ -2661,7 +2656,7 @@ static bool trans_UZP1_q(DisasContext *s, arg_rrr_esz *a) if (!dc_isar_feature(aa64_sve_f64mm, s)) { return false; } - return do_zzz_data_ool(s, a, 0, gen_helper_sve2_uzp_q); + return gen_gvec_ool_arg_zzz(s, gen_helper_sve2_uzp_q, a, 0); } static bool trans_UZP2_q(DisasContext *s, arg_rrr_esz *a) @@ -2669,7 +2664,7 @@ static bool trans_UZP2_q(DisasContext *s, arg_rrr_esz *a) if (!dc_isar_feature(aa64_sve_f64mm, s)) { return false; } - return do_zzz_data_ool(s, a, 16, gen_helper_sve2_uzp_q); + return gen_gvec_ool_arg_zzz(s, gen_helper_sve2_uzp_q, a, 16); } static gen_helper_gvec_3 * const trn_fns[4] = { @@ -2679,12 +2674,12 @@ static gen_helper_gvec_3 * const trn_fns[4] = { static bool trans_TRN1_z(DisasContext *s, arg_rrr_esz *a) { - return do_zzz_data_ool(s, a, 0, trn_fns[a->esz]); + return gen_gvec_ool_arg_zzz(s, trn_fns[a->esz], a, 0); } static bool trans_TRN2_z(DisasContext *s, arg_rrr_esz *a) { - return do_zzz_data_ool(s, a, 1 << a->esz, trn_fns[a->esz]); + return gen_gvec_ool_arg_zzz(s, trn_fns[a->esz], a, 1 << a->esz); } static bool trans_TRN1_q(DisasContext *s, arg_rrr_esz *a) @@ -2692,7 +2687,7 @@ static bool trans_TRN1_q(DisasContext *s, arg_rrr_esz *a) if (!dc_isar_feature(aa64_sve_f64mm, s)) { return false; } - return do_zzz_data_ool(s, a, 0, gen_helper_sve2_trn_q); + return gen_gvec_ool_arg_zzz(s, gen_helper_sve2_trn_q, a, 0); } static bool trans_TRN2_q(DisasContext *s, arg_rrr_esz *a) @@ -2700,7 +2695,7 @@ static bool trans_TRN2_q(DisasContext *s, arg_rrr_esz *a) if (!dc_isar_feature(aa64_sve_f64mm, s)) { return false; } - return do_zzz_data_ool(s, a, 16, gen_helper_sve2_trn_q); + return gen_gvec_ool_arg_zzz(s, gen_helper_sve2_trn_q, a, 16); } /* @@ -6677,7 +6672,7 @@ static bool do_sve2_zzz_ool(DisasContext *s, arg_rrr_esz *a, if (!dc_isar_feature(aa64_sve2, s)) { return false; } - return gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, 0); + return gen_gvec_ool_arg_zzz(s, fn, a, 0); } static bool trans_SMULH_zzz(DisasContext *s, arg_rrr_esz *a) @@ -8355,8 +8350,7 @@ static bool do_aese(DisasContext *s, arg_rrr_esz *a, bool decrypt) if (!dc_isar_feature(aa64_sve2_aes, s)) { return false; } - return gen_gvec_ool_zzz(s, gen_helper_crypto_aese, - a->rd, a->rn, a->rm, decrypt); + return gen_gvec_ool_arg_zzz(s, gen_helper_crypto_aese, a, decrypt); } static bool trans_AESE(DisasContext *s, arg_rrr_esz *a) @@ -8374,7 +8368,7 @@ static bool do_sm4(DisasContext *s, arg_rrr_esz *a, gen_helper_gvec_3 *fn) if (!dc_isar_feature(aa64_sve2_sm4, s)) { return false; } - return gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, 0); + return gen_gvec_ool_arg_zzz(s, fn, a, 0); } static bool trans_SM4E(DisasContext *s, arg_rrr_esz *a) From 32e2ad6589070d8b12209969514ac46ff9e435ab Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:19 -0700 Subject: [PATCH 591/935] target/arm: Use TRANS_FEAT for gen_gvec_ool_arg_zzz Convert SVE translation functions using gen_gvec_ool_arg_zzz to TRANS_FEAT. Remove trivial wrappers do_aese, do_sm4. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-7-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 165 ++++++++++--------------------------- 1 file changed, 45 insertions(+), 120 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 37343fb2f0..c89c25166c 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -1184,18 +1184,16 @@ static bool trans_LSL_zzi(DisasContext *s, arg_rri_esz *a) } #define DO_ZZW(NAME, name) \ -static bool trans_##NAME##_zzw(DisasContext *s, arg_rrr_esz *a) \ -{ \ - static gen_helper_gvec_3 * const fns[4] = { \ + static gen_helper_gvec_3 * const name##_zzw_fns[4] = { \ gen_helper_sve_##name##_zzw_b, gen_helper_sve_##name##_zzw_h, \ gen_helper_sve_##name##_zzw_s, NULL \ }; \ - return gen_gvec_ool_arg_zzz(s, fns[a->esz], a, 0); \ -} + TRANS_FEAT(NAME, aa64_sve, gen_gvec_ool_arg_zzz, \ + name##_zzw_fns[a->esz], a, 0) -DO_ZZW(ASR, asr) -DO_ZZW(LSR, lsr) -DO_ZZW(LSL, lsl) +DO_ZZW(ASR_zzw, asr) +DO_ZZW(LSR_zzw, lsr) +DO_ZZW(LSL_zzw, lsl) #undef DO_ZZW @@ -1380,16 +1378,11 @@ static gen_helper_gvec_2 * const fexpa_fns[4] = { TRANS_FEAT(FEXPA, aa64_sve, gen_gvec_ool_zz, fexpa_fns[a->esz], a->rd, a->rn, 0) -static bool trans_FTSSEL(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, - gen_helper_sve_ftssel_h, - gen_helper_sve_ftssel_s, - gen_helper_sve_ftssel_d, - }; - return gen_gvec_ool_arg_zzz(s, fns[a->esz], a, 0); -} +static gen_helper_gvec_3 * const ftssel_fns[4] = { + NULL, gen_helper_sve_ftssel_h, + gen_helper_sve_ftssel_s, gen_helper_sve_ftssel_d, +}; +TRANS_FEAT(FTSSEL, aa64_sve, gen_gvec_ool_arg_zzz, ftssel_fns[a->esz], a, 0) /* *** SVE Predicate Logical Operations Group @@ -2412,14 +2405,11 @@ static gen_helper_gvec_2 * const rev_fns[4] = { }; TRANS_FEAT(REV_v, aa64_sve, gen_gvec_ool_zz, rev_fns[a->esz], a->rd, a->rn, 0) -static bool trans_TBL(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve_tbl_b, gen_helper_sve_tbl_h, - gen_helper_sve_tbl_s, gen_helper_sve_tbl_d - }; - return gen_gvec_ool_arg_zzz(s, fns[a->esz], a, 0); -} +static gen_helper_gvec_3 * const sve_tbl_fns[4] = { + gen_helper_sve_tbl_b, gen_helper_sve_tbl_h, + gen_helper_sve_tbl_s, gen_helper_sve_tbl_d +}; +TRANS_FEAT(TBL, aa64_sve, gen_gvec_ool_arg_zzz, sve_tbl_fns[a->esz], a, 0) static bool trans_TBL_sve2(DisasContext *s, arg_rrr_esz *a) { @@ -2438,18 +2428,11 @@ static bool trans_TBL_sve2(DisasContext *s, arg_rrr_esz *a) return true; } -static bool trans_TBX(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_tbx_b, gen_helper_sve2_tbx_h, - gen_helper_sve2_tbx_s, gen_helper_sve2_tbx_d - }; - - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_ool_arg_zzz(s, fns[a->esz], a, 0); -} +static gen_helper_gvec_3 * const tbx_fns[4] = { + gen_helper_sve2_tbx_b, gen_helper_sve2_tbx_h, + gen_helper_sve2_tbx_s, gen_helper_sve2_tbx_d +}; +TRANS_FEAT(TBX, aa64_sve2, gen_gvec_ool_arg_zzz, tbx_fns[a->esz], a, 0) static bool trans_UNPK(DisasContext *s, arg_UNPK *a) { @@ -2641,62 +2624,30 @@ static gen_helper_gvec_3 * const uzp_fns[4] = { gen_helper_sve_uzp_s, gen_helper_sve_uzp_d, }; -static bool trans_UZP1_z(DisasContext *s, arg_rrr_esz *a) -{ - return gen_gvec_ool_arg_zzz(s, uzp_fns[a->esz], a, 0); -} +TRANS_FEAT(UZP1_z, aa64_sve, gen_gvec_ool_arg_zzz, + uzp_fns[a->esz], a, 0) +TRANS_FEAT(UZP2_z, aa64_sve, gen_gvec_ool_arg_zzz, + uzp_fns[a->esz], a, 1 << a->esz) -static bool trans_UZP2_z(DisasContext *s, arg_rrr_esz *a) -{ - return gen_gvec_ool_arg_zzz(s, uzp_fns[a->esz], a, 1 << a->esz); -} - -static bool trans_UZP1_q(DisasContext *s, arg_rrr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_f64mm, s)) { - return false; - } - return gen_gvec_ool_arg_zzz(s, gen_helper_sve2_uzp_q, a, 0); -} - -static bool trans_UZP2_q(DisasContext *s, arg_rrr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_f64mm, s)) { - return false; - } - return gen_gvec_ool_arg_zzz(s, gen_helper_sve2_uzp_q, a, 16); -} +TRANS_FEAT(UZP1_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz, + gen_helper_sve2_uzp_q, a, 0) +TRANS_FEAT(UZP2_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz, + gen_helper_sve2_uzp_q, a, 16) static gen_helper_gvec_3 * const trn_fns[4] = { gen_helper_sve_trn_b, gen_helper_sve_trn_h, gen_helper_sve_trn_s, gen_helper_sve_trn_d, }; -static bool trans_TRN1_z(DisasContext *s, arg_rrr_esz *a) -{ - return gen_gvec_ool_arg_zzz(s, trn_fns[a->esz], a, 0); -} +TRANS_FEAT(TRN1_z, aa64_sve, gen_gvec_ool_arg_zzz, + trn_fns[a->esz], a, 0) +TRANS_FEAT(TRN2_z, aa64_sve, gen_gvec_ool_arg_zzz, + trn_fns[a->esz], a, 1 << a->esz) -static bool trans_TRN2_z(DisasContext *s, arg_rrr_esz *a) -{ - return gen_gvec_ool_arg_zzz(s, trn_fns[a->esz], a, 1 << a->esz); -} - -static bool trans_TRN1_q(DisasContext *s, arg_rrr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_f64mm, s)) { - return false; - } - return gen_gvec_ool_arg_zzz(s, gen_helper_sve2_trn_q, a, 0); -} - -static bool trans_TRN2_q(DisasContext *s, arg_rrr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_f64mm, s)) { - return false; - } - return gen_gvec_ool_arg_zzz(s, gen_helper_sve2_trn_q, a, 16); -} +TRANS_FEAT(TRN1_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz, + gen_helper_sve2_trn_q, a, 0) +TRANS_FEAT(TRN2_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz, + gen_helper_sve2_trn_q, a, 16) /* *** SVE Permute Vector - Predicated Group @@ -8345,41 +8296,15 @@ static bool trans_USDOT_zzzz(DisasContext *s, arg_USDOT_zzzz *a) TRANS_FEAT(AESMC, aa64_sve2_aes, gen_gvec_ool_zz, gen_helper_crypto_aesmc, a->rd, a->rd, a->decrypt) -static bool do_aese(DisasContext *s, arg_rrr_esz *a, bool decrypt) -{ - if (!dc_isar_feature(aa64_sve2_aes, s)) { - return false; - } - return gen_gvec_ool_arg_zzz(s, gen_helper_crypto_aese, a, decrypt); -} +TRANS_FEAT(AESE, aa64_sve2_aes, gen_gvec_ool_arg_zzz, + gen_helper_crypto_aese, a, false) +TRANS_FEAT(AESD, aa64_sve2_aes, gen_gvec_ool_arg_zzz, + gen_helper_crypto_aese, a, true) -static bool trans_AESE(DisasContext *s, arg_rrr_esz *a) -{ - return do_aese(s, a, false); -} - -static bool trans_AESD(DisasContext *s, arg_rrr_esz *a) -{ - return do_aese(s, a, true); -} - -static bool do_sm4(DisasContext *s, arg_rrr_esz *a, gen_helper_gvec_3 *fn) -{ - if (!dc_isar_feature(aa64_sve2_sm4, s)) { - return false; - } - return gen_gvec_ool_arg_zzz(s, fn, a, 0); -} - -static bool trans_SM4E(DisasContext *s, arg_rrr_esz *a) -{ - return do_sm4(s, a, gen_helper_crypto_sm4e); -} - -static bool trans_SM4EKEY(DisasContext *s, arg_rrr_esz *a) -{ - return do_sm4(s, a, gen_helper_crypto_sm4ekey); -} +TRANS_FEAT(SM4E, aa64_sve2_sm4, gen_gvec_ool_arg_zzz, + gen_helper_crypto_sm4e, a, 0) +TRANS_FEAT(SM4EKEY, aa64_sve2_sm4, gen_gvec_ool_arg_zzz, + gen_helper_crypto_sm4ekey, a, 0) static bool trans_RAX1(DisasContext *s, arg_rrr_esz *a) { From bd394cf52f8201da609bca3dc31b48783ea69d1e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:20 -0700 Subject: [PATCH 592/935] target/arm: Use TRANS_FEAT for do_sve2_zzz_ool Convert SVE translation functions using do_sve2_zzz_ool to use TRANS_FEAT and gen_gvec_ool_arg_zzz. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-8-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 88 ++++++++++++++------------------------ 1 file changed, 31 insertions(+), 57 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index c89c25166c..6ec996e7f2 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -6617,55 +6617,36 @@ static bool trans_MUL_zzz(DisasContext *s, arg_rrr_esz *a) return true; } -static bool do_sve2_zzz_ool(DisasContext *s, arg_rrr_esz *a, - gen_helper_gvec_3 *fn) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_ool_arg_zzz(s, fn, a, 0); -} +static gen_helper_gvec_3 * const smulh_zzz_fns[4] = { + gen_helper_gvec_smulh_b, gen_helper_gvec_smulh_h, + gen_helper_gvec_smulh_s, gen_helper_gvec_smulh_d, +}; +TRANS_FEAT(SMULH_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + smulh_zzz_fns[a->esz], a, 0) -static bool trans_SMULH_zzz(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_gvec_smulh_b, gen_helper_gvec_smulh_h, - gen_helper_gvec_smulh_s, gen_helper_gvec_smulh_d, - }; - return do_sve2_zzz_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_3 * const umulh_zzz_fns[4] = { + gen_helper_gvec_umulh_b, gen_helper_gvec_umulh_h, + gen_helper_gvec_umulh_s, gen_helper_gvec_umulh_d, +}; +TRANS_FEAT(UMULH_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + umulh_zzz_fns[a->esz], a, 0) -static bool trans_UMULH_zzz(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_gvec_umulh_b, gen_helper_gvec_umulh_h, - gen_helper_gvec_umulh_s, gen_helper_gvec_umulh_d, - }; - return do_sve2_zzz_ool(s, a, fns[a->esz]); -} +TRANS_FEAT(PMUL_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + gen_helper_gvec_pmul_b, a, 0) -static bool trans_PMUL_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return do_sve2_zzz_ool(s, a, gen_helper_gvec_pmul_b); -} +static gen_helper_gvec_3 * const sqdmulh_zzz_fns[4] = { + gen_helper_sve2_sqdmulh_b, gen_helper_sve2_sqdmulh_h, + gen_helper_sve2_sqdmulh_s, gen_helper_sve2_sqdmulh_d, +}; +TRANS_FEAT(SQDMULH_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + sqdmulh_zzz_fns[a->esz], a, 0) -static bool trans_SQDMULH_zzz(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_sqdmulh_b, gen_helper_sve2_sqdmulh_h, - gen_helper_sve2_sqdmulh_s, gen_helper_sve2_sqdmulh_d, - }; - return do_sve2_zzz_ool(s, a, fns[a->esz]); -} - -static bool trans_SQRDMULH_zzz(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_sqrdmulh_b, gen_helper_sve2_sqrdmulh_h, - gen_helper_sve2_sqrdmulh_s, gen_helper_sve2_sqrdmulh_d, - }; - return do_sve2_zzz_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_3 * const sqrdmulh_zzz_fns[4] = { + gen_helper_sve2_sqrdmulh_b, gen_helper_sve2_sqrdmulh_h, + gen_helper_sve2_sqrdmulh_s, gen_helper_sve2_sqrdmulh_d, +}; +TRANS_FEAT(SQRDMULH_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + sqrdmulh_zzz_fns[a->esz], a, 0) /* * SVE2 Integer - Predicated @@ -7964,14 +7945,12 @@ static bool trans_UQRSHRNT(DisasContext *s, arg_rri_esz *a) } #define DO_SVE2_ZZZ_NARROW(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rrr_esz *a) \ -{ \ - static gen_helper_gvec_3 * const fns[4] = { \ + static gen_helper_gvec_3 * const name##_fns[4] = { \ NULL, gen_helper_sve2_##name##_h, \ gen_helper_sve2_##name##_s, gen_helper_sve2_##name##_d, \ }; \ - return do_sve2_zzz_ool(s, a, fns[a->esz]); \ -} + TRANS_FEAT(NAME, aa64_sve2, gen_gvec_ool_arg_zzz, \ + name##_fns[a->esz], a, 0) DO_SVE2_ZZZ_NARROW(ADDHNB, addhnb) DO_SVE2_ZZZ_NARROW(ADDHNT, addhnt) @@ -8016,13 +7995,8 @@ static bool trans_HISTCNT(DisasContext *s, arg_rprr_esz *a) return do_sve2_zpzz_ool(s, a, fns[a->esz - 2]); } -static bool trans_HISTSEG(DisasContext *s, arg_rrr_esz *a) -{ - if (a->esz != 0) { - return false; - } - return do_sve2_zzz_ool(s, a, gen_helper_sve2_histseg); -} +TRANS_FEAT(HISTSEG, aa64_sve2, gen_gvec_ool_arg_zzz, + a->esz == 0 ? gen_helper_sve2_histseg : NULL, a, 0) static bool do_sve2_zpzz_fp(DisasContext *s, arg_rprr_esz *a, gen_helper_gvec_4_ptr *fn) From 7ad416b143ff4a7d3eeb0ffbfeabaf0d25f76bdc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:21 -0700 Subject: [PATCH 593/935] target/arm: Move null function and sve check into gen_gvec_ool_zzzz Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-9-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 102 ++++++++++++++----------------------- 1 file changed, 38 insertions(+), 64 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 6ec996e7f2..5aaef5b18f 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -176,15 +176,21 @@ static bool gen_gvec_ool_arg_zzz(DisasContext *s, gen_helper_gvec_3 *fn, } /* Invoke an out-of-line helper on 4 Zregs. */ -static void gen_gvec_ool_zzzz(DisasContext *s, gen_helper_gvec_4 *fn, +static bool gen_gvec_ool_zzzz(DisasContext *s, gen_helper_gvec_4 *fn, int rd, int rn, int rm, int ra, int data) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_4_ool(vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), - vec_full_reg_offset(s, ra), - vsz, vsz, data, fn); + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_4_ool(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), + vec_full_reg_offset(s, ra), + vsz, vsz, data, fn); + } + return true; } /* Invoke an out-of-line helper on 2 Zregs and a predicate. */ @@ -2421,11 +2427,8 @@ static bool trans_TBL_sve2(DisasContext *s, arg_rrr_esz *a) if (!dc_isar_feature(aa64_sve2, s)) { return false; } - if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, fns[a->esz], a->rd, a->rn, - (a->rn + 1) % 32, a->rm, 0); - } - return true; + return gen_gvec_ool_zzzz(s, fns[a->esz], a->rd, a->rn, + (a->rn + 1) % 32, a->rm, 0); } static gen_helper_gvec_3 * const tbx_fns[4] = { @@ -3813,11 +3816,8 @@ static bool trans_DOT_zzzz(DisasContext *s, arg_DOT_zzzz *a) { gen_helper_gvec_sdot_b, gen_helper_gvec_sdot_h }, { gen_helper_gvec_udot_b, gen_helper_gvec_udot_h } }; - - if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, fns[a->u][a->sz], a->rd, a->rn, a->rm, a->ra, 0); - } - return true; + return gen_gvec_ool_zzzz(s, fns[a->u][a->sz], + a->rd, a->rn, a->rm, a->ra, 0); } /* @@ -3827,13 +3827,7 @@ static bool trans_DOT_zzzz(DisasContext *s, arg_DOT_zzzz *a) static bool do_zzxz_ool(DisasContext *s, arg_rrxr_esz *a, gen_helper_gvec_4 *fn) { - if (fn == NULL) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, a->index); - } - return true; + return gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, a->index); } #define DO_RRXR(NAME, FUNC) \ @@ -7122,13 +7116,10 @@ static bool trans_SQCADD_rot270(DisasContext *s, arg_rrr_esz *a) static bool do_sve2_zzzz_ool(DisasContext *s, arg_rrrr_esz *a, gen_helper_gvec_4 *fn, int data) { - if (fn == NULL || !dc_isar_feature(aa64_sve2, s)) { + if (!dc_isar_feature(aa64_sve2, s)) { return false; } - if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, data); - } - return true; + return gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, data); } static bool do_abal(DisasContext *s, arg_rrrr_esz *a, bool uns, bool sel) @@ -8215,24 +8206,21 @@ static bool trans_CMLA_zzzz(DisasContext *s, arg_CMLA_zzzz *a) if (!dc_isar_feature(aa64_sve2, s)) { return false; } - if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, fns[a->esz], a->rd, a->rn, a->rm, a->ra, a->rot); - } - return true; + return gen_gvec_ool_zzzz(s, fns[a->esz], a->rd, a->rn, + a->rm, a->ra, a->rot); } static bool trans_CDOT_zzzz(DisasContext *s, arg_CMLA_zzzz *a) { - if (!dc_isar_feature(aa64_sve2, s) || a->esz < MO_32) { + static gen_helper_gvec_4 * const fns[] = { + NULL, NULL, gen_helper_sve2_cdot_zzzz_s, gen_helper_sve2_cdot_zzzz_d + }; + + if (!dc_isar_feature(aa64_sve2, s)) { return false; } - if (sve_access_check(s)) { - gen_helper_gvec_4 *fn = (a->esz == MO_32 - ? gen_helper_sve2_cdot_zzzz_s - : gen_helper_sve2_cdot_zzzz_d); - gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, a->rot); - } - return true; + return gen_gvec_ool_zzzz(s, fns[a->esz], a->rd, a->rn, + a->rm, a->ra, a->rot); } static bool trans_SQRDCMLAH_zzzz(DisasContext *s, arg_SQRDCMLAH_zzzz *a) @@ -8245,10 +8233,8 @@ static bool trans_SQRDCMLAH_zzzz(DisasContext *s, arg_SQRDCMLAH_zzzz *a) if (!dc_isar_feature(aa64_sve2, s)) { return false; } - if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, fns[a->esz], a->rd, a->rn, a->rm, a->ra, a->rot); - } - return true; + return gen_gvec_ool_zzzz(s, fns[a->esz], a->rd, a->rn, + a->rm, a->ra, a->rot); } static bool trans_USDOT_zzzz(DisasContext *s, arg_USDOT_zzzz *a) @@ -8452,10 +8438,7 @@ static bool do_i8mm_zzzz_ool(DisasContext *s, arg_rrrr_esz *a, if (!dc_isar_feature(aa64_sve_i8mm, s)) { return false; } - if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, data); - } - return true; + return gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, data); } static bool trans_SMMLA(DisasContext *s, arg_rrrr_esz *a) @@ -8478,11 +8461,8 @@ static bool trans_BFDOT_zzzz(DisasContext *s, arg_rrrr_esz *a) if (!dc_isar_feature(aa64_sve_bf16, s)) { return false; } - if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, gen_helper_gvec_bfdot, - a->rd, a->rn, a->rm, a->ra, 0); - } - return true; + return gen_gvec_ool_zzzz(s, gen_helper_gvec_bfdot, + a->rd, a->rn, a->rm, a->ra, 0); } static bool trans_BFDOT_zzxz(DisasContext *s, arg_rrxr_esz *a) @@ -8490,11 +8470,8 @@ static bool trans_BFDOT_zzxz(DisasContext *s, arg_rrxr_esz *a) if (!dc_isar_feature(aa64_sve_bf16, s)) { return false; } - if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, gen_helper_gvec_bfdot_idx, - a->rd, a->rn, a->rm, a->ra, a->index); - } - return true; + return gen_gvec_ool_zzzz(s, gen_helper_gvec_bfdot_idx, + a->rd, a->rn, a->rm, a->ra, a->index); } static bool trans_BFMMLA(DisasContext *s, arg_rrrr_esz *a) @@ -8502,11 +8479,8 @@ static bool trans_BFMMLA(DisasContext *s, arg_rrrr_esz *a) if (!dc_isar_feature(aa64_sve_bf16, s)) { return false; } - if (sve_access_check(s)) { - gen_gvec_ool_zzzz(s, gen_helper_gvec_bfmmla, - a->rd, a->rn, a->rm, a->ra, 0); - } - return true; + return gen_gvec_ool_zzzz(s, gen_helper_gvec_bfmmla, + a->rd, a->rn, a->rm, a->ra, 0); } static bool do_BFMLAL_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sel) From 5f425b927b7578cbd5dfaed5d22b92ea331d1822 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:22 -0700 Subject: [PATCH 594/935] target/arm: Use TRANS_FEAT for gen_gvec_ool_zzzz Convert SVE translation functions directly using gen_gvec_ool_zzzz to TRANS_FEAT. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-10-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 89 +++++++++++++------------------------- 1 file changed, 29 insertions(+), 60 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 5aaef5b18f..823c1d0ae3 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -2417,19 +2417,12 @@ static gen_helper_gvec_3 * const sve_tbl_fns[4] = { }; TRANS_FEAT(TBL, aa64_sve, gen_gvec_ool_arg_zzz, sve_tbl_fns[a->esz], a, 0) -static bool trans_TBL_sve2(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_4 * const fns[4] = { - gen_helper_sve2_tbl_b, gen_helper_sve2_tbl_h, - gen_helper_sve2_tbl_s, gen_helper_sve2_tbl_d - }; - - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_ool_zzzz(s, fns[a->esz], a->rd, a->rn, - (a->rn + 1) % 32, a->rm, 0); -} +static gen_helper_gvec_4 * const sve2_tbl_fns[4] = { + gen_helper_sve2_tbl_b, gen_helper_sve2_tbl_h, + gen_helper_sve2_tbl_s, gen_helper_sve2_tbl_d +}; +TRANS_FEAT(TBL_sve2, aa64_sve2, gen_gvec_ool_zzzz, sve2_tbl_fns[a->esz], + a->rd, a->rn, (a->rn + 1) % 32, a->rm, 0) static gen_helper_gvec_3 * const tbx_fns[4] = { gen_helper_sve2_tbx_b, gen_helper_sve2_tbx_h, @@ -3810,15 +3803,12 @@ DO_ZZI(UMIN, umin) #undef DO_ZZI -static bool trans_DOT_zzzz(DisasContext *s, arg_DOT_zzzz *a) -{ - static gen_helper_gvec_4 * const fns[2][2] = { - { gen_helper_gvec_sdot_b, gen_helper_gvec_sdot_h }, - { gen_helper_gvec_udot_b, gen_helper_gvec_udot_h } - }; - return gen_gvec_ool_zzzz(s, fns[a->u][a->sz], - a->rd, a->rn, a->rm, a->ra, 0); -} +static gen_helper_gvec_4 * const dot_fns[2][2] = { + { gen_helper_gvec_sdot_b, gen_helper_gvec_sdot_h }, + { gen_helper_gvec_udot_b, gen_helper_gvec_udot_h } +}; +TRANS_FEAT(DOT_zzzz, aa64_sve, gen_gvec_ool_zzzz, + dot_fns[a->u][a->sz], a->rd, a->rn, a->rm, a->ra, 0) /* * SVE Multiply - Indexed @@ -8196,46 +8186,25 @@ static bool trans_UMLSLT_zzzw(DisasContext *s, arg_rrrr_esz *a) return do_umlsl_zzzw(s, a, true); } -static bool trans_CMLA_zzzz(DisasContext *s, arg_CMLA_zzzz *a) -{ - static gen_helper_gvec_4 * const fns[] = { - gen_helper_sve2_cmla_zzzz_b, gen_helper_sve2_cmla_zzzz_h, - gen_helper_sve2_cmla_zzzz_s, gen_helper_sve2_cmla_zzzz_d, - }; +static gen_helper_gvec_4 * const cmla_fns[] = { + gen_helper_sve2_cmla_zzzz_b, gen_helper_sve2_cmla_zzzz_h, + gen_helper_sve2_cmla_zzzz_s, gen_helper_sve2_cmla_zzzz_d, +}; +TRANS_FEAT(CMLA_zzzz, aa64_sve2, gen_gvec_ool_zzzz, + cmla_fns[a->esz], a->rd, a->rn, a->rm, a->ra, a->rot) - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_ool_zzzz(s, fns[a->esz], a->rd, a->rn, - a->rm, a->ra, a->rot); -} +static gen_helper_gvec_4 * const cdot_fns[] = { + NULL, NULL, gen_helper_sve2_cdot_zzzz_s, gen_helper_sve2_cdot_zzzz_d +}; +TRANS_FEAT(CDOT_zzzz, aa64_sve2, gen_gvec_ool_zzzz, + cdot_fns[a->esz], a->rd, a->rn, a->rm, a->ra, a->rot) -static bool trans_CDOT_zzzz(DisasContext *s, arg_CMLA_zzzz *a) -{ - static gen_helper_gvec_4 * const fns[] = { - NULL, NULL, gen_helper_sve2_cdot_zzzz_s, gen_helper_sve2_cdot_zzzz_d - }; - - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_ool_zzzz(s, fns[a->esz], a->rd, a->rn, - a->rm, a->ra, a->rot); -} - -static bool trans_SQRDCMLAH_zzzz(DisasContext *s, arg_SQRDCMLAH_zzzz *a) -{ - static gen_helper_gvec_4 * const fns[] = { - gen_helper_sve2_sqrdcmlah_zzzz_b, gen_helper_sve2_sqrdcmlah_zzzz_h, - gen_helper_sve2_sqrdcmlah_zzzz_s, gen_helper_sve2_sqrdcmlah_zzzz_d, - }; - - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_ool_zzzz(s, fns[a->esz], a->rd, a->rn, - a->rm, a->ra, a->rot); -} +static gen_helper_gvec_4 * const sqrdcmlah_fns[] = { + gen_helper_sve2_sqrdcmlah_zzzz_b, gen_helper_sve2_sqrdcmlah_zzzz_h, + gen_helper_sve2_sqrdcmlah_zzzz_s, gen_helper_sve2_sqrdcmlah_zzzz_d, +}; +TRANS_FEAT(SQRDCMLAH_zzzz, aa64_sve2, gen_gvec_ool_zzzz, + sqrdcmlah_fns[a->esz], a->rd, a->rn, a->rm, a->ra, a->rot) static bool trans_USDOT_zzzz(DisasContext *s, arg_USDOT_zzzz *a) { From cab79ac93459567a6b0a8f437d116cba4118c52e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:23 -0700 Subject: [PATCH 595/935] target/arm: Introduce gen_gvec_ool_arg_zzzz Use gen_gvec_ool_arg_zzzz instead of gen_gvec_ool_zzzz when the arguments come from arg_rrrr_esz. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-11-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 823c1d0ae3..e795baf6f9 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -193,6 +193,12 @@ static bool gen_gvec_ool_zzzz(DisasContext *s, gen_helper_gvec_4 *fn, return true; } +static bool gen_gvec_ool_arg_zzzz(DisasContext *s, gen_helper_gvec_4 *fn, + arg_rrrr_esz *a, int data) +{ + return gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, data); +} + /* Invoke an out-of-line helper on 2 Zregs and a predicate. */ static void gen_gvec_ool_zzp(DisasContext *s, gen_helper_gvec_3 *fn, int rd, int rn, int pg, int data) @@ -7109,7 +7115,7 @@ static bool do_sve2_zzzz_ool(DisasContext *s, arg_rrrr_esz *a, if (!dc_isar_feature(aa64_sve2, s)) { return false; } - return gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, data); + return gen_gvec_ool_arg_zzzz(s, fn, a, data); } static bool do_abal(DisasContext *s, arg_rrrr_esz *a, bool uns, bool sel) @@ -8407,7 +8413,7 @@ static bool do_i8mm_zzzz_ool(DisasContext *s, arg_rrrr_esz *a, if (!dc_isar_feature(aa64_sve_i8mm, s)) { return false; } - return gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, data); + return gen_gvec_ool_arg_zzzz(s, fn, a, data); } static bool trans_SMMLA(DisasContext *s, arg_rrrr_esz *a) @@ -8430,8 +8436,7 @@ static bool trans_BFDOT_zzzz(DisasContext *s, arg_rrrr_esz *a) if (!dc_isar_feature(aa64_sve_bf16, s)) { return false; } - return gen_gvec_ool_zzzz(s, gen_helper_gvec_bfdot, - a->rd, a->rn, a->rm, a->ra, 0); + return gen_gvec_ool_arg_zzzz(s, gen_helper_gvec_bfdot, a, 0); } static bool trans_BFDOT_zzxz(DisasContext *s, arg_rrxr_esz *a) @@ -8448,8 +8453,7 @@ static bool trans_BFMMLA(DisasContext *s, arg_rrrr_esz *a) if (!dc_isar_feature(aa64_sve_bf16, s)) { return false; } - return gen_gvec_ool_zzzz(s, gen_helper_gvec_bfmmla, - a->rd, a->rn, a->rm, a->ra, 0); + return gen_gvec_ool_arg_zzzz(s, gen_helper_gvec_bfmmla, a, 0); } static bool do_BFMLAL_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sel) From eeb4e84d384104a6872b06005a4636d60cb4f55e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:24 -0700 Subject: [PATCH 596/935] target/arm: Use TRANS_FEAT for do_sve2_zzzz_ool Convert SVE translation functions using do_sve2_zzzz_ool to use TRANS_FEAT and gen_gvec_ool_arg_zzzz. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-12-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 263 +++++++++++-------------------------- 1 file changed, 79 insertions(+), 184 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index e795baf6f9..cae6df705a 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -7109,45 +7109,19 @@ static bool trans_SQCADD_rot270(DisasContext *s, arg_rrr_esz *a) return do_cadd(s, a, true, true); } -static bool do_sve2_zzzz_ool(DisasContext *s, arg_rrrr_esz *a, - gen_helper_gvec_4 *fn, int data) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_ool_arg_zzzz(s, fn, a, data); -} +static gen_helper_gvec_4 * const sabal_fns[4] = { + NULL, gen_helper_sve2_sabal_h, + gen_helper_sve2_sabal_s, gen_helper_sve2_sabal_d, +}; +TRANS_FEAT(SABALB, aa64_sve2, gen_gvec_ool_arg_zzzz, sabal_fns[a->esz], a, 0) +TRANS_FEAT(SABALT, aa64_sve2, gen_gvec_ool_arg_zzzz, sabal_fns[a->esz], a, 1) -static bool do_abal(DisasContext *s, arg_rrrr_esz *a, bool uns, bool sel) -{ - static gen_helper_gvec_4 * const fns[2][4] = { - { NULL, gen_helper_sve2_sabal_h, - gen_helper_sve2_sabal_s, gen_helper_sve2_sabal_d }, - { NULL, gen_helper_sve2_uabal_h, - gen_helper_sve2_uabal_s, gen_helper_sve2_uabal_d }, - }; - return do_sve2_zzzz_ool(s, a, fns[uns][a->esz], sel); -} - -static bool trans_SABALB(DisasContext *s, arg_rrrr_esz *a) -{ - return do_abal(s, a, false, false); -} - -static bool trans_SABALT(DisasContext *s, arg_rrrr_esz *a) -{ - return do_abal(s, a, false, true); -} - -static bool trans_UABALB(DisasContext *s, arg_rrrr_esz *a) -{ - return do_abal(s, a, true, false); -} - -static bool trans_UABALT(DisasContext *s, arg_rrrr_esz *a) -{ - return do_abal(s, a, true, true); -} +static gen_helper_gvec_4 * const uabal_fns[4] = { + NULL, gen_helper_sve2_uabal_h, + gen_helper_sve2_uabal_s, gen_helper_sve2_uabal_d, +}; +TRANS_FEAT(UABALB, aa64_sve2, gen_gvec_ool_arg_zzzz, uabal_fns[a->esz], a, 0) +TRANS_FEAT(UABALT, aa64_sve2, gen_gvec_ool_arg_zzzz, uabal_fns[a->esz], a, 1) static bool do_adcl(DisasContext *s, arg_rrrr_esz *a, bool sel) { @@ -7159,18 +7133,11 @@ static bool do_adcl(DisasContext *s, arg_rrrr_esz *a, bool sel) * Note that in this case the ESZ field encodes both size and sign. * Split out 'subtract' into bit 1 of the data field for the helper. */ - return do_sve2_zzzz_ool(s, a, fns[a->esz & 1], (a->esz & 2) | sel); + return gen_gvec_ool_arg_zzzz(s, fns[a->esz & 1], a, (a->esz & 2) | sel); } -static bool trans_ADCLB(DisasContext *s, arg_rrrr_esz *a) -{ - return do_adcl(s, a, false); -} - -static bool trans_ADCLT(DisasContext *s, arg_rrrr_esz *a) -{ - return do_adcl(s, a, true); -} +TRANS_FEAT(ADCLB, aa64_sve2, do_adcl, a, false) +TRANS_FEAT(ADCLT, aa64_sve2, do_adcl, a, true) static bool do_sve2_fn2i(DisasContext *s, arg_rri_esz *a, GVecGen2iFn *fn) { @@ -8048,149 +8015,77 @@ static bool trans_FMMLA(DisasContext *s, arg_rrrr_esz *a) return true; } -static bool do_sqdmlal_zzzw(DisasContext *s, arg_rrrr_esz *a, - bool sel1, bool sel2) -{ - static gen_helper_gvec_4 * const fns[] = { - NULL, gen_helper_sve2_sqdmlal_zzzw_h, - gen_helper_sve2_sqdmlal_zzzw_s, gen_helper_sve2_sqdmlal_zzzw_d, - }; - return do_sve2_zzzz_ool(s, a, fns[a->esz], (sel2 << 1) | sel1); -} +static gen_helper_gvec_4 * const sqdmlal_zzzw_fns[] = { + NULL, gen_helper_sve2_sqdmlal_zzzw_h, + gen_helper_sve2_sqdmlal_zzzw_s, gen_helper_sve2_sqdmlal_zzzw_d, +}; +TRANS_FEAT(SQDMLALB_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + sqdmlal_zzzw_fns[a->esz], a, 0) +TRANS_FEAT(SQDMLALT_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + sqdmlal_zzzw_fns[a->esz], a, 3) +TRANS_FEAT(SQDMLALBT, aa64_sve2, gen_gvec_ool_arg_zzzz, + sqdmlal_zzzw_fns[a->esz], a, 2) -static bool do_sqdmlsl_zzzw(DisasContext *s, arg_rrrr_esz *a, - bool sel1, bool sel2) -{ - static gen_helper_gvec_4 * const fns[] = { - NULL, gen_helper_sve2_sqdmlsl_zzzw_h, - gen_helper_sve2_sqdmlsl_zzzw_s, gen_helper_sve2_sqdmlsl_zzzw_d, - }; - return do_sve2_zzzz_ool(s, a, fns[a->esz], (sel2 << 1) | sel1); -} +static gen_helper_gvec_4 * const sqdmlsl_zzzw_fns[] = { + NULL, gen_helper_sve2_sqdmlsl_zzzw_h, + gen_helper_sve2_sqdmlsl_zzzw_s, gen_helper_sve2_sqdmlsl_zzzw_d, +}; +TRANS_FEAT(SQDMLSLB_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + sqdmlsl_zzzw_fns[a->esz], a, 0) +TRANS_FEAT(SQDMLSLT_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + sqdmlsl_zzzw_fns[a->esz], a, 3) +TRANS_FEAT(SQDMLSLBT, aa64_sve2, gen_gvec_ool_arg_zzzz, + sqdmlsl_zzzw_fns[a->esz], a, 2) -static bool trans_SQDMLALB_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sqdmlal_zzzw(s, a, false, false); -} +static gen_helper_gvec_4 * const sqrdmlah_fns[] = { + gen_helper_sve2_sqrdmlah_b, gen_helper_sve2_sqrdmlah_h, + gen_helper_sve2_sqrdmlah_s, gen_helper_sve2_sqrdmlah_d, +}; +TRANS_FEAT(SQRDMLAH_zzzz, aa64_sve2, gen_gvec_ool_arg_zzzz, + sqrdmlah_fns[a->esz], a, 0) -static bool trans_SQDMLALT_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sqdmlal_zzzw(s, a, true, true); -} +static gen_helper_gvec_4 * const sqrdmlsh_fns[] = { + gen_helper_sve2_sqrdmlsh_b, gen_helper_sve2_sqrdmlsh_h, + gen_helper_sve2_sqrdmlsh_s, gen_helper_sve2_sqrdmlsh_d, +}; +TRANS_FEAT(SQRDMLSH_zzzz, aa64_sve2, gen_gvec_ool_arg_zzzz, + sqrdmlsh_fns[a->esz], a, 0) -static bool trans_SQDMLALBT(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sqdmlal_zzzw(s, a, false, true); -} +static gen_helper_gvec_4 * const smlal_zzzw_fns[] = { + NULL, gen_helper_sve2_smlal_zzzw_h, + gen_helper_sve2_smlal_zzzw_s, gen_helper_sve2_smlal_zzzw_d, +}; +TRANS_FEAT(SMLALB_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + smlal_zzzw_fns[a->esz], a, 0) +TRANS_FEAT(SMLALT_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + smlal_zzzw_fns[a->esz], a, 1) -static bool trans_SQDMLSLB_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sqdmlsl_zzzw(s, a, false, false); -} +static gen_helper_gvec_4 * const umlal_zzzw_fns[] = { + NULL, gen_helper_sve2_umlal_zzzw_h, + gen_helper_sve2_umlal_zzzw_s, gen_helper_sve2_umlal_zzzw_d, +}; +TRANS_FEAT(UMLALB_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + umlal_zzzw_fns[a->esz], a, 0) +TRANS_FEAT(UMLALT_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + umlal_zzzw_fns[a->esz], a, 1) -static bool trans_SQDMLSLT_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sqdmlsl_zzzw(s, a, true, true); -} +static gen_helper_gvec_4 * const smlsl_zzzw_fns[] = { + NULL, gen_helper_sve2_smlsl_zzzw_h, + gen_helper_sve2_smlsl_zzzw_s, gen_helper_sve2_smlsl_zzzw_d, +}; +TRANS_FEAT(SMLSLB_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + smlsl_zzzw_fns[a->esz], a, 0) +TRANS_FEAT(SMLSLT_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + smlsl_zzzw_fns[a->esz], a, 1) -static bool trans_SQDMLSLBT(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sqdmlsl_zzzw(s, a, false, true); -} - -static bool trans_SQRDMLAH_zzzz(DisasContext *s, arg_rrrr_esz *a) -{ - static gen_helper_gvec_4 * const fns[] = { - gen_helper_sve2_sqrdmlah_b, gen_helper_sve2_sqrdmlah_h, - gen_helper_sve2_sqrdmlah_s, gen_helper_sve2_sqrdmlah_d, - }; - return do_sve2_zzzz_ool(s, a, fns[a->esz], 0); -} - -static bool trans_SQRDMLSH_zzzz(DisasContext *s, arg_rrrr_esz *a) -{ - static gen_helper_gvec_4 * const fns[] = { - gen_helper_sve2_sqrdmlsh_b, gen_helper_sve2_sqrdmlsh_h, - gen_helper_sve2_sqrdmlsh_s, gen_helper_sve2_sqrdmlsh_d, - }; - return do_sve2_zzzz_ool(s, a, fns[a->esz], 0); -} - -static bool do_smlal_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sel) -{ - static gen_helper_gvec_4 * const fns[] = { - NULL, gen_helper_sve2_smlal_zzzw_h, - gen_helper_sve2_smlal_zzzw_s, gen_helper_sve2_smlal_zzzw_d, - }; - return do_sve2_zzzz_ool(s, a, fns[a->esz], sel); -} - -static bool trans_SMLALB_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_smlal_zzzw(s, a, false); -} - -static bool trans_SMLALT_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_smlal_zzzw(s, a, true); -} - -static bool do_umlal_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sel) -{ - static gen_helper_gvec_4 * const fns[] = { - NULL, gen_helper_sve2_umlal_zzzw_h, - gen_helper_sve2_umlal_zzzw_s, gen_helper_sve2_umlal_zzzw_d, - }; - return do_sve2_zzzz_ool(s, a, fns[a->esz], sel); -} - -static bool trans_UMLALB_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_umlal_zzzw(s, a, false); -} - -static bool trans_UMLALT_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_umlal_zzzw(s, a, true); -} - -static bool do_smlsl_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sel) -{ - static gen_helper_gvec_4 * const fns[] = { - NULL, gen_helper_sve2_smlsl_zzzw_h, - gen_helper_sve2_smlsl_zzzw_s, gen_helper_sve2_smlsl_zzzw_d, - }; - return do_sve2_zzzz_ool(s, a, fns[a->esz], sel); -} - -static bool trans_SMLSLB_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_smlsl_zzzw(s, a, false); -} - -static bool trans_SMLSLT_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_smlsl_zzzw(s, a, true); -} - -static bool do_umlsl_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sel) -{ - static gen_helper_gvec_4 * const fns[] = { - NULL, gen_helper_sve2_umlsl_zzzw_h, - gen_helper_sve2_umlsl_zzzw_s, gen_helper_sve2_umlsl_zzzw_d, - }; - return do_sve2_zzzz_ool(s, a, fns[a->esz], sel); -} - -static bool trans_UMLSLB_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_umlsl_zzzw(s, a, false); -} - -static bool trans_UMLSLT_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_umlsl_zzzw(s, a, true); -} +static gen_helper_gvec_4 * const umlsl_zzzw_fns[] = { + NULL, gen_helper_sve2_umlsl_zzzw_h, + gen_helper_sve2_umlsl_zzzw_s, gen_helper_sve2_umlsl_zzzw_d, +}; +TRANS_FEAT(UMLSLB_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + umlsl_zzzw_fns[a->esz], a, 0) +TRANS_FEAT(UMLSLT_zzzw, aa64_sve2, gen_gvec_ool_arg_zzzz, + umlsl_zzzw_fns[a->esz], a, 1) static gen_helper_gvec_4 * const cmla_fns[] = { gen_helper_sve2_cmla_zzzz_b, gen_helper_sve2_cmla_zzzz_h, From eec05e4e1766713a29821e6205feddc88496eea6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:25 -0700 Subject: [PATCH 597/935] target/arm: Use TRANS_FEAT for gen_gvec_ool_arg_zzzz Convert SVE translation functions directly using gen_gvec_ool_arg_zzzz to TRANS_FEAT. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-13-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 47 ++++++++------------------------------ 1 file changed, 10 insertions(+), 37 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index cae6df705a..f7367a4f62 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -8302,37 +8302,15 @@ static bool trans_FMLSLT_zzxw(DisasContext *s, arg_rrxr_esz *a) return do_FMLAL_zzxw(s, a, true, true); } -static bool do_i8mm_zzzz_ool(DisasContext *s, arg_rrrr_esz *a, - gen_helper_gvec_4 *fn, int data) -{ - if (!dc_isar_feature(aa64_sve_i8mm, s)) { - return false; - } - return gen_gvec_ool_arg_zzzz(s, fn, a, data); -} +TRANS_FEAT(SMMLA, aa64_sve_i8mm, gen_gvec_ool_arg_zzzz, + gen_helper_gvec_smmla_b, a, 0) +TRANS_FEAT(USMMLA, aa64_sve_i8mm, gen_gvec_ool_arg_zzzz, + gen_helper_gvec_usmmla_b, a, 0) +TRANS_FEAT(UMMLA, aa64_sve_i8mm, gen_gvec_ool_arg_zzzz, + gen_helper_gvec_ummla_b, a, 0) -static bool trans_SMMLA(DisasContext *s, arg_rrrr_esz *a) -{ - return do_i8mm_zzzz_ool(s, a, gen_helper_gvec_smmla_b, 0); -} - -static bool trans_USMMLA(DisasContext *s, arg_rrrr_esz *a) -{ - return do_i8mm_zzzz_ool(s, a, gen_helper_gvec_usmmla_b, 0); -} - -static bool trans_UMMLA(DisasContext *s, arg_rrrr_esz *a) -{ - return do_i8mm_zzzz_ool(s, a, gen_helper_gvec_ummla_b, 0); -} - -static bool trans_BFDOT_zzzz(DisasContext *s, arg_rrrr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_bf16, s)) { - return false; - } - return gen_gvec_ool_arg_zzzz(s, gen_helper_gvec_bfdot, a, 0); -} +TRANS_FEAT(BFDOT_zzzz, aa64_sve_bf16, gen_gvec_ool_arg_zzzz, + gen_helper_gvec_bfdot, a, 0) static bool trans_BFDOT_zzxz(DisasContext *s, arg_rrxr_esz *a) { @@ -8343,13 +8321,8 @@ static bool trans_BFDOT_zzxz(DisasContext *s, arg_rrxr_esz *a) a->rd, a->rn, a->rm, a->ra, a->index); } -static bool trans_BFMMLA(DisasContext *s, arg_rrrr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_bf16, s)) { - return false; - } - return gen_gvec_ool_arg_zzzz(s, gen_helper_gvec_bfmmla, a, 0); -} +TRANS_FEAT(BFMMLA, aa64_sve_bf16, gen_gvec_ool_arg_zzzz, + gen_helper_gvec_bfmmla, a, 0) static bool do_BFMLAL_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sel) { From e82d3536cd1af0c5bde907269f3dc394bdf3912b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:26 -0700 Subject: [PATCH 598/935] target/arm: Rename do_zzxz_ool to gen_gvec_ool_arg_zzxz Rename the function to match gen_gvec_ool_arg_zzzz, and move to be adjacent. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-14-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index f7367a4f62..b42df76c69 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -199,6 +199,12 @@ static bool gen_gvec_ool_arg_zzzz(DisasContext *s, gen_helper_gvec_4 *fn, return gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, data); } +static bool gen_gvec_ool_arg_zzxz(DisasContext *s, gen_helper_gvec_4 *fn, + arg_rrxr_esz *a) +{ + return gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, a->index); +} + /* Invoke an out-of-line helper on 2 Zregs and a predicate. */ static void gen_gvec_ool_zzp(DisasContext *s, gen_helper_gvec_3 *fn, int rd, int rn, int pg, int data) @@ -3820,15 +3826,9 @@ TRANS_FEAT(DOT_zzzz, aa64_sve, gen_gvec_ool_zzzz, * SVE Multiply - Indexed */ -static bool do_zzxz_ool(DisasContext *s, arg_rrxr_esz *a, - gen_helper_gvec_4 *fn) -{ - return gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, a->index); -} - #define DO_RRXR(NAME, FUNC) \ static bool NAME(DisasContext *s, arg_rrxr_esz *a) \ - { return do_zzxz_ool(s, a, FUNC); } + { return gen_gvec_ool_arg_zzxz(s, FUNC, a); } DO_RRXR(trans_SDOT_zzxw_s, gen_helper_gvec_sdot_idx_b) DO_RRXR(trans_SDOT_zzxw_d, gen_helper_gvec_sdot_idx_h) @@ -3840,7 +3840,7 @@ static bool trans_SUDOT_zzxw_s(DisasContext *s, arg_rrxr_esz *a) if (!dc_isar_feature(aa64_sve_i8mm, s)) { return false; } - return do_zzxz_ool(s, a, gen_helper_gvec_sudot_idx_b); + return gen_gvec_ool_arg_zzxz(s, gen_helper_gvec_sudot_idx_b, a); } static bool trans_USDOT_zzxw_s(DisasContext *s, arg_rrxr_esz *a) @@ -3848,7 +3848,7 @@ static bool trans_USDOT_zzxw_s(DisasContext *s, arg_rrxr_esz *a) if (!dc_isar_feature(aa64_sve_i8mm, s)) { return false; } - return do_zzxz_ool(s, a, gen_helper_gvec_usdot_idx_b); + return gen_gvec_ool_arg_zzxz(s, gen_helper_gvec_usdot_idx_b, a); } #undef DO_RRXR From f3500a25fd12218fb74a09e9a6813108c10bf83c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:27 -0700 Subject: [PATCH 599/935] target/arm: Use TRANS_FEAT for gen_gvec_ool_arg_zzxz Convert SVE translation functions directly using gen_gvec_ool_arg_zzxz to TRANS_FEAT. Also include BFDOT_zzxz, which was using gen_gvec_ool_zzzz. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-15-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 48 +++++++++++--------------------------- 1 file changed, 14 insertions(+), 34 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index b42df76c69..b097b44d9f 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3826,32 +3826,19 @@ TRANS_FEAT(DOT_zzzz, aa64_sve, gen_gvec_ool_zzzz, * SVE Multiply - Indexed */ -#define DO_RRXR(NAME, FUNC) \ - static bool NAME(DisasContext *s, arg_rrxr_esz *a) \ - { return gen_gvec_ool_arg_zzxz(s, FUNC, a); } +TRANS_FEAT(SDOT_zzxw_s, aa64_sve, gen_gvec_ool_arg_zzxz, + gen_helper_gvec_sdot_idx_b, a) +TRANS_FEAT(SDOT_zzxw_d, aa64_sve, gen_gvec_ool_arg_zzxz, + gen_helper_gvec_sdot_idx_h, a) +TRANS_FEAT(UDOT_zzxw_s, aa64_sve, gen_gvec_ool_arg_zzxz, + gen_helper_gvec_udot_idx_b, a) +TRANS_FEAT(UDOT_zzxw_d, aa64_sve, gen_gvec_ool_arg_zzxz, + gen_helper_gvec_udot_idx_h, a) -DO_RRXR(trans_SDOT_zzxw_s, gen_helper_gvec_sdot_idx_b) -DO_RRXR(trans_SDOT_zzxw_d, gen_helper_gvec_sdot_idx_h) -DO_RRXR(trans_UDOT_zzxw_s, gen_helper_gvec_udot_idx_b) -DO_RRXR(trans_UDOT_zzxw_d, gen_helper_gvec_udot_idx_h) - -static bool trans_SUDOT_zzxw_s(DisasContext *s, arg_rrxr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_i8mm, s)) { - return false; - } - return gen_gvec_ool_arg_zzxz(s, gen_helper_gvec_sudot_idx_b, a); -} - -static bool trans_USDOT_zzxw_s(DisasContext *s, arg_rrxr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_i8mm, s)) { - return false; - } - return gen_gvec_ool_arg_zzxz(s, gen_helper_gvec_usdot_idx_b, a); -} - -#undef DO_RRXR +TRANS_FEAT(SUDOT_zzxw_s, aa64_sve_i8mm, gen_gvec_ool_arg_zzxz, + gen_helper_gvec_sudot_idx_b, a) +TRANS_FEAT(USDOT_zzxw_s, aa64_sve_i8mm, gen_gvec_ool_arg_zzxz, + gen_helper_gvec_usdot_idx_b, a) static bool do_sve2_zzz_data(DisasContext *s, int rd, int rn, int rm, int data, gen_helper_gvec_3 *fn) @@ -8311,15 +8298,8 @@ TRANS_FEAT(UMMLA, aa64_sve_i8mm, gen_gvec_ool_arg_zzzz, TRANS_FEAT(BFDOT_zzzz, aa64_sve_bf16, gen_gvec_ool_arg_zzzz, gen_helper_gvec_bfdot, a, 0) - -static bool trans_BFDOT_zzxz(DisasContext *s, arg_rrxr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_bf16, s)) { - return false; - } - return gen_gvec_ool_zzzz(s, gen_helper_gvec_bfdot_idx, - a->rd, a->rn, a->rm, a->ra, a->index); -} +TRANS_FEAT(BFDOT_zzxz, aa64_sve_bf16, gen_gvec_ool_arg_zzxz, + gen_helper_gvec_bfdot_idx, a) TRANS_FEAT(BFMMLA, aa64_sve_bf16, gen_gvec_ool_arg_zzzz, gen_helper_gvec_bfmmla, a, 0) From af031f64287f95590bdc12a673e3571d8d4696ee Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:28 -0700 Subject: [PATCH 600/935] target/arm: Use TRANS_FEAT for do_sve2_zzz_data Convert SVE translation functions using do_sve2_zzz_data to use TRANS_FEAT and gen_gvec_ool_zzz. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-16-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 69 ++++++++++++++------------------------ 1 file changed, 25 insertions(+), 44 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index b097b44d9f..ac76705da6 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3840,61 +3840,42 @@ TRANS_FEAT(SUDOT_zzxw_s, aa64_sve_i8mm, gen_gvec_ool_arg_zzxz, TRANS_FEAT(USDOT_zzxw_s, aa64_sve_i8mm, gen_gvec_ool_arg_zzxz, gen_helper_gvec_usdot_idx_b, a) -static bool do_sve2_zzz_data(DisasContext *s, int rd, int rn, int rm, int data, - gen_helper_gvec_3 *fn) -{ - if (fn == NULL || !dc_isar_feature(aa64_sve2, s)) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_3_ool(vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), - vsz, vsz, data, fn); - } - return true; -} - #define DO_SVE2_RRX(NAME, FUNC) \ - static bool NAME(DisasContext *s, arg_rrx_esz *a) \ - { return do_sve2_zzz_data(s, a->rd, a->rn, a->rm, a->index, FUNC); } + TRANS_FEAT(NAME, aa64_sve, gen_gvec_ool_zzz, FUNC, \ + a->rd, a->rn, a->rm, a->index) -DO_SVE2_RRX(trans_MUL_zzx_h, gen_helper_gvec_mul_idx_h) -DO_SVE2_RRX(trans_MUL_zzx_s, gen_helper_gvec_mul_idx_s) -DO_SVE2_RRX(trans_MUL_zzx_d, gen_helper_gvec_mul_idx_d) +DO_SVE2_RRX(MUL_zzx_h, gen_helper_gvec_mul_idx_h) +DO_SVE2_RRX(MUL_zzx_s, gen_helper_gvec_mul_idx_s) +DO_SVE2_RRX(MUL_zzx_d, gen_helper_gvec_mul_idx_d) -DO_SVE2_RRX(trans_SQDMULH_zzx_h, gen_helper_sve2_sqdmulh_idx_h) -DO_SVE2_RRX(trans_SQDMULH_zzx_s, gen_helper_sve2_sqdmulh_idx_s) -DO_SVE2_RRX(trans_SQDMULH_zzx_d, gen_helper_sve2_sqdmulh_idx_d) +DO_SVE2_RRX(SQDMULH_zzx_h, gen_helper_sve2_sqdmulh_idx_h) +DO_SVE2_RRX(SQDMULH_zzx_s, gen_helper_sve2_sqdmulh_idx_s) +DO_SVE2_RRX(SQDMULH_zzx_d, gen_helper_sve2_sqdmulh_idx_d) -DO_SVE2_RRX(trans_SQRDMULH_zzx_h, gen_helper_sve2_sqrdmulh_idx_h) -DO_SVE2_RRX(trans_SQRDMULH_zzx_s, gen_helper_sve2_sqrdmulh_idx_s) -DO_SVE2_RRX(trans_SQRDMULH_zzx_d, gen_helper_sve2_sqrdmulh_idx_d) +DO_SVE2_RRX(SQRDMULH_zzx_h, gen_helper_sve2_sqrdmulh_idx_h) +DO_SVE2_RRX(SQRDMULH_zzx_s, gen_helper_sve2_sqrdmulh_idx_s) +DO_SVE2_RRX(SQRDMULH_zzx_d, gen_helper_sve2_sqrdmulh_idx_d) #undef DO_SVE2_RRX #define DO_SVE2_RRX_TB(NAME, FUNC, TOP) \ - static bool NAME(DisasContext *s, arg_rrx_esz *a) \ - { \ - return do_sve2_zzz_data(s, a->rd, a->rn, a->rm, \ - (a->index << 1) | TOP, FUNC); \ - } + TRANS_FEAT(NAME, aa64_sve, gen_gvec_ool_zzz, FUNC, \ + a->rd, a->rn, a->rm, (a->index << 1) | TOP) -DO_SVE2_RRX_TB(trans_SQDMULLB_zzx_s, gen_helper_sve2_sqdmull_idx_s, false) -DO_SVE2_RRX_TB(trans_SQDMULLB_zzx_d, gen_helper_sve2_sqdmull_idx_d, false) -DO_SVE2_RRX_TB(trans_SQDMULLT_zzx_s, gen_helper_sve2_sqdmull_idx_s, true) -DO_SVE2_RRX_TB(trans_SQDMULLT_zzx_d, gen_helper_sve2_sqdmull_idx_d, true) +DO_SVE2_RRX_TB(SQDMULLB_zzx_s, gen_helper_sve2_sqdmull_idx_s, false) +DO_SVE2_RRX_TB(SQDMULLB_zzx_d, gen_helper_sve2_sqdmull_idx_d, false) +DO_SVE2_RRX_TB(SQDMULLT_zzx_s, gen_helper_sve2_sqdmull_idx_s, true) +DO_SVE2_RRX_TB(SQDMULLT_zzx_d, gen_helper_sve2_sqdmull_idx_d, true) -DO_SVE2_RRX_TB(trans_SMULLB_zzx_s, gen_helper_sve2_smull_idx_s, false) -DO_SVE2_RRX_TB(trans_SMULLB_zzx_d, gen_helper_sve2_smull_idx_d, false) -DO_SVE2_RRX_TB(trans_SMULLT_zzx_s, gen_helper_sve2_smull_idx_s, true) -DO_SVE2_RRX_TB(trans_SMULLT_zzx_d, gen_helper_sve2_smull_idx_d, true) +DO_SVE2_RRX_TB(SMULLB_zzx_s, gen_helper_sve2_smull_idx_s, false) +DO_SVE2_RRX_TB(SMULLB_zzx_d, gen_helper_sve2_smull_idx_d, false) +DO_SVE2_RRX_TB(SMULLT_zzx_s, gen_helper_sve2_smull_idx_s, true) +DO_SVE2_RRX_TB(SMULLT_zzx_d, gen_helper_sve2_smull_idx_d, true) -DO_SVE2_RRX_TB(trans_UMULLB_zzx_s, gen_helper_sve2_umull_idx_s, false) -DO_SVE2_RRX_TB(trans_UMULLB_zzx_d, gen_helper_sve2_umull_idx_d, false) -DO_SVE2_RRX_TB(trans_UMULLT_zzx_s, gen_helper_sve2_umull_idx_s, true) -DO_SVE2_RRX_TB(trans_UMULLT_zzx_d, gen_helper_sve2_umull_idx_d, true) +DO_SVE2_RRX_TB(UMULLB_zzx_s, gen_helper_sve2_umull_idx_s, false) +DO_SVE2_RRX_TB(UMULLB_zzx_d, gen_helper_sve2_umull_idx_d, false) +DO_SVE2_RRX_TB(UMULLT_zzx_s, gen_helper_sve2_umull_idx_s, true) +DO_SVE2_RRX_TB(UMULLT_zzx_d, gen_helper_sve2_umull_idx_d, true) #undef DO_SVE2_RRX_TB From 8681eb76224c959eaf9c9e290c9d598f712dd566 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:29 -0700 Subject: [PATCH 601/935] target/arm: Use TRANS_FEAT for do_sve2_zzzz_data Convert SVE translation functions using do_sve2_zzzz_data to use TRANS_FEAT and gen_gvec_ool_{zzzz,zzxz}. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-17-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 106 ++++++++++++++----------------------- 1 file changed, 41 insertions(+), 65 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index ac76705da6..c345399ace 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3879,90 +3879,66 @@ DO_SVE2_RRX_TB(UMULLT_zzx_d, gen_helper_sve2_umull_idx_d, true) #undef DO_SVE2_RRX_TB -static bool do_sve2_zzzz_data(DisasContext *s, int rd, int rn, int rm, int ra, - int data, gen_helper_gvec_4 *fn) -{ - if (fn == NULL || !dc_isar_feature(aa64_sve2, s)) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_4_ool(vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), - vec_full_reg_offset(s, ra), - vsz, vsz, data, fn); - } - return true; -} - #define DO_SVE2_RRXR(NAME, FUNC) \ - static bool NAME(DisasContext *s, arg_rrxr_esz *a) \ - { return do_sve2_zzzz_data(s, a->rd, a->rn, a->rm, a->ra, a->index, FUNC); } + TRANS_FEAT(NAME, aa64_sve2, gen_gvec_ool_arg_zzxz, FUNC, a) -DO_SVE2_RRXR(trans_MLA_zzxz_h, gen_helper_gvec_mla_idx_h) -DO_SVE2_RRXR(trans_MLA_zzxz_s, gen_helper_gvec_mla_idx_s) -DO_SVE2_RRXR(trans_MLA_zzxz_d, gen_helper_gvec_mla_idx_d) +DO_SVE2_RRXR(MLA_zzxz_h, gen_helper_gvec_mla_idx_h) +DO_SVE2_RRXR(MLA_zzxz_s, gen_helper_gvec_mla_idx_s) +DO_SVE2_RRXR(MLA_zzxz_d, gen_helper_gvec_mla_idx_d) -DO_SVE2_RRXR(trans_MLS_zzxz_h, gen_helper_gvec_mls_idx_h) -DO_SVE2_RRXR(trans_MLS_zzxz_s, gen_helper_gvec_mls_idx_s) -DO_SVE2_RRXR(trans_MLS_zzxz_d, gen_helper_gvec_mls_idx_d) +DO_SVE2_RRXR(MLS_zzxz_h, gen_helper_gvec_mls_idx_h) +DO_SVE2_RRXR(MLS_zzxz_s, gen_helper_gvec_mls_idx_s) +DO_SVE2_RRXR(MLS_zzxz_d, gen_helper_gvec_mls_idx_d) -DO_SVE2_RRXR(trans_SQRDMLAH_zzxz_h, gen_helper_sve2_sqrdmlah_idx_h) -DO_SVE2_RRXR(trans_SQRDMLAH_zzxz_s, gen_helper_sve2_sqrdmlah_idx_s) -DO_SVE2_RRXR(trans_SQRDMLAH_zzxz_d, gen_helper_sve2_sqrdmlah_idx_d) +DO_SVE2_RRXR(SQRDMLAH_zzxz_h, gen_helper_sve2_sqrdmlah_idx_h) +DO_SVE2_RRXR(SQRDMLAH_zzxz_s, gen_helper_sve2_sqrdmlah_idx_s) +DO_SVE2_RRXR(SQRDMLAH_zzxz_d, gen_helper_sve2_sqrdmlah_idx_d) -DO_SVE2_RRXR(trans_SQRDMLSH_zzxz_h, gen_helper_sve2_sqrdmlsh_idx_h) -DO_SVE2_RRXR(trans_SQRDMLSH_zzxz_s, gen_helper_sve2_sqrdmlsh_idx_s) -DO_SVE2_RRXR(trans_SQRDMLSH_zzxz_d, gen_helper_sve2_sqrdmlsh_idx_d) +DO_SVE2_RRXR(SQRDMLSH_zzxz_h, gen_helper_sve2_sqrdmlsh_idx_h) +DO_SVE2_RRXR(SQRDMLSH_zzxz_s, gen_helper_sve2_sqrdmlsh_idx_s) +DO_SVE2_RRXR(SQRDMLSH_zzxz_d, gen_helper_sve2_sqrdmlsh_idx_d) #undef DO_SVE2_RRXR #define DO_SVE2_RRXR_TB(NAME, FUNC, TOP) \ - static bool NAME(DisasContext *s, arg_rrxr_esz *a) \ - { \ - return do_sve2_zzzz_data(s, a->rd, a->rn, a->rm, a->rd, \ - (a->index << 1) | TOP, FUNC); \ - } + TRANS_FEAT(NAME, aa64_sve2, gen_gvec_ool_zzzz, FUNC, \ + a->rd, a->rn, a->rm, a->ra, (a->index << 1) | TOP) -DO_SVE2_RRXR_TB(trans_SQDMLALB_zzxw_s, gen_helper_sve2_sqdmlal_idx_s, false) -DO_SVE2_RRXR_TB(trans_SQDMLALB_zzxw_d, gen_helper_sve2_sqdmlal_idx_d, false) -DO_SVE2_RRXR_TB(trans_SQDMLALT_zzxw_s, gen_helper_sve2_sqdmlal_idx_s, true) -DO_SVE2_RRXR_TB(trans_SQDMLALT_zzxw_d, gen_helper_sve2_sqdmlal_idx_d, true) +DO_SVE2_RRXR_TB(SQDMLALB_zzxw_s, gen_helper_sve2_sqdmlal_idx_s, false) +DO_SVE2_RRXR_TB(SQDMLALB_zzxw_d, gen_helper_sve2_sqdmlal_idx_d, false) +DO_SVE2_RRXR_TB(SQDMLALT_zzxw_s, gen_helper_sve2_sqdmlal_idx_s, true) +DO_SVE2_RRXR_TB(SQDMLALT_zzxw_d, gen_helper_sve2_sqdmlal_idx_d, true) -DO_SVE2_RRXR_TB(trans_SQDMLSLB_zzxw_s, gen_helper_sve2_sqdmlsl_idx_s, false) -DO_SVE2_RRXR_TB(trans_SQDMLSLB_zzxw_d, gen_helper_sve2_sqdmlsl_idx_d, false) -DO_SVE2_RRXR_TB(trans_SQDMLSLT_zzxw_s, gen_helper_sve2_sqdmlsl_idx_s, true) -DO_SVE2_RRXR_TB(trans_SQDMLSLT_zzxw_d, gen_helper_sve2_sqdmlsl_idx_d, true) +DO_SVE2_RRXR_TB(SQDMLSLB_zzxw_s, gen_helper_sve2_sqdmlsl_idx_s, false) +DO_SVE2_RRXR_TB(SQDMLSLB_zzxw_d, gen_helper_sve2_sqdmlsl_idx_d, false) +DO_SVE2_RRXR_TB(SQDMLSLT_zzxw_s, gen_helper_sve2_sqdmlsl_idx_s, true) +DO_SVE2_RRXR_TB(SQDMLSLT_zzxw_d, gen_helper_sve2_sqdmlsl_idx_d, true) -DO_SVE2_RRXR_TB(trans_SMLALB_zzxw_s, gen_helper_sve2_smlal_idx_s, false) -DO_SVE2_RRXR_TB(trans_SMLALB_zzxw_d, gen_helper_sve2_smlal_idx_d, false) -DO_SVE2_RRXR_TB(trans_SMLALT_zzxw_s, gen_helper_sve2_smlal_idx_s, true) -DO_SVE2_RRXR_TB(trans_SMLALT_zzxw_d, gen_helper_sve2_smlal_idx_d, true) +DO_SVE2_RRXR_TB(SMLALB_zzxw_s, gen_helper_sve2_smlal_idx_s, false) +DO_SVE2_RRXR_TB(SMLALB_zzxw_d, gen_helper_sve2_smlal_idx_d, false) +DO_SVE2_RRXR_TB(SMLALT_zzxw_s, gen_helper_sve2_smlal_idx_s, true) +DO_SVE2_RRXR_TB(SMLALT_zzxw_d, gen_helper_sve2_smlal_idx_d, true) -DO_SVE2_RRXR_TB(trans_UMLALB_zzxw_s, gen_helper_sve2_umlal_idx_s, false) -DO_SVE2_RRXR_TB(trans_UMLALB_zzxw_d, gen_helper_sve2_umlal_idx_d, false) -DO_SVE2_RRXR_TB(trans_UMLALT_zzxw_s, gen_helper_sve2_umlal_idx_s, true) -DO_SVE2_RRXR_TB(trans_UMLALT_zzxw_d, gen_helper_sve2_umlal_idx_d, true) +DO_SVE2_RRXR_TB(UMLALB_zzxw_s, gen_helper_sve2_umlal_idx_s, false) +DO_SVE2_RRXR_TB(UMLALB_zzxw_d, gen_helper_sve2_umlal_idx_d, false) +DO_SVE2_RRXR_TB(UMLALT_zzxw_s, gen_helper_sve2_umlal_idx_s, true) +DO_SVE2_RRXR_TB(UMLALT_zzxw_d, gen_helper_sve2_umlal_idx_d, true) -DO_SVE2_RRXR_TB(trans_SMLSLB_zzxw_s, gen_helper_sve2_smlsl_idx_s, false) -DO_SVE2_RRXR_TB(trans_SMLSLB_zzxw_d, gen_helper_sve2_smlsl_idx_d, false) -DO_SVE2_RRXR_TB(trans_SMLSLT_zzxw_s, gen_helper_sve2_smlsl_idx_s, true) -DO_SVE2_RRXR_TB(trans_SMLSLT_zzxw_d, gen_helper_sve2_smlsl_idx_d, true) +DO_SVE2_RRXR_TB(SMLSLB_zzxw_s, gen_helper_sve2_smlsl_idx_s, false) +DO_SVE2_RRXR_TB(SMLSLB_zzxw_d, gen_helper_sve2_smlsl_idx_d, false) +DO_SVE2_RRXR_TB(SMLSLT_zzxw_s, gen_helper_sve2_smlsl_idx_s, true) +DO_SVE2_RRXR_TB(SMLSLT_zzxw_d, gen_helper_sve2_smlsl_idx_d, true) -DO_SVE2_RRXR_TB(trans_UMLSLB_zzxw_s, gen_helper_sve2_umlsl_idx_s, false) -DO_SVE2_RRXR_TB(trans_UMLSLB_zzxw_d, gen_helper_sve2_umlsl_idx_d, false) -DO_SVE2_RRXR_TB(trans_UMLSLT_zzxw_s, gen_helper_sve2_umlsl_idx_s, true) -DO_SVE2_RRXR_TB(trans_UMLSLT_zzxw_d, gen_helper_sve2_umlsl_idx_d, true) +DO_SVE2_RRXR_TB(UMLSLB_zzxw_s, gen_helper_sve2_umlsl_idx_s, false) +DO_SVE2_RRXR_TB(UMLSLB_zzxw_d, gen_helper_sve2_umlsl_idx_d, false) +DO_SVE2_RRXR_TB(UMLSLT_zzxw_s, gen_helper_sve2_umlsl_idx_s, true) +DO_SVE2_RRXR_TB(UMLSLT_zzxw_d, gen_helper_sve2_umlsl_idx_d, true) #undef DO_SVE2_RRXR_TB #define DO_SVE2_RRXR_ROT(NAME, FUNC) \ - static bool trans_##NAME(DisasContext *s, arg_##NAME *a) \ - { \ - return do_sve2_zzzz_data(s, a->rd, a->rn, a->rm, a->ra, \ - (a->index << 2) | a->rot, FUNC); \ - } + TRANS_FEAT(NAME, aa64_sve2, gen_gvec_ool_zzzz, FUNC, \ + a->rd, a->rn, a->rm, a->ra, (a->index << 2) | a->rot) DO_SVE2_RRXR_ROT(CMLA_zzxz_h, gen_helper_sve2_cmla_idx_h) DO_SVE2_RRXR_ROT(CMLA_zzxz_s, gen_helper_sve2_cmla_idx_s) From 615f19fefb24318e6c37860bf370a6dc39628b37 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:30 -0700 Subject: [PATCH 602/935] target/arm: Use TRANS_FEAT for do_sve2_zzw_data Convert SVE translation functions using do_sve2_zzw_data to use TRANS_FEAT and gen_gvec_ool_arg_zzz. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-18-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 297 ++++++++++++++++++------------------- 1 file changed, 145 insertions(+), 152 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index c345399ace..2347b60d8e 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -6711,79 +6711,99 @@ DO_SVE2_ZPZZ(USQADD, usqadd) * SVE2 Widening Integer Arithmetic */ -static bool do_sve2_zzw_ool(DisasContext *s, arg_rrr_esz *a, - gen_helper_gvec_3 *fn, int data) -{ - if (fn == NULL || !dc_isar_feature(aa64_sve2, s)) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_3_ool(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vsz, vsz, data, fn); - } - return true; -} +static gen_helper_gvec_3 * const saddl_fns[4] = { + NULL, gen_helper_sve2_saddl_h, + gen_helper_sve2_saddl_s, gen_helper_sve2_saddl_d, +}; +TRANS_FEAT(SADDLB, aa64_sve2, gen_gvec_ool_arg_zzz, + saddl_fns[a->esz], a, 0) +TRANS_FEAT(SADDLT, aa64_sve2, gen_gvec_ool_arg_zzz, + saddl_fns[a->esz], a, 3) +TRANS_FEAT(SADDLBT, aa64_sve2, gen_gvec_ool_arg_zzz, + saddl_fns[a->esz], a, 2) -#define DO_SVE2_ZZZ_TB(NAME, name, SEL1, SEL2) \ -static bool trans_##NAME(DisasContext *s, arg_rrr_esz *a) \ -{ \ - static gen_helper_gvec_3 * const fns[4] = { \ - NULL, gen_helper_sve2_##name##_h, \ - gen_helper_sve2_##name##_s, gen_helper_sve2_##name##_d, \ - }; \ - return do_sve2_zzw_ool(s, a, fns[a->esz], (SEL2 << 1) | SEL1); \ -} +static gen_helper_gvec_3 * const ssubl_fns[4] = { + NULL, gen_helper_sve2_ssubl_h, + gen_helper_sve2_ssubl_s, gen_helper_sve2_ssubl_d, +}; +TRANS_FEAT(SSUBLB, aa64_sve2, gen_gvec_ool_arg_zzz, + ssubl_fns[a->esz], a, 0) +TRANS_FEAT(SSUBLT, aa64_sve2, gen_gvec_ool_arg_zzz, + ssubl_fns[a->esz], a, 3) +TRANS_FEAT(SSUBLBT, aa64_sve2, gen_gvec_ool_arg_zzz, + ssubl_fns[a->esz], a, 2) +TRANS_FEAT(SSUBLTB, aa64_sve2, gen_gvec_ool_arg_zzz, + ssubl_fns[a->esz], a, 1) -DO_SVE2_ZZZ_TB(SADDLB, saddl, false, false) -DO_SVE2_ZZZ_TB(SSUBLB, ssubl, false, false) -DO_SVE2_ZZZ_TB(SABDLB, sabdl, false, false) +static gen_helper_gvec_3 * const sabdl_fns[4] = { + NULL, gen_helper_sve2_sabdl_h, + gen_helper_sve2_sabdl_s, gen_helper_sve2_sabdl_d, +}; +TRANS_FEAT(SABDLB, aa64_sve2, gen_gvec_ool_arg_zzz, + sabdl_fns[a->esz], a, 0) +TRANS_FEAT(SABDLT, aa64_sve2, gen_gvec_ool_arg_zzz, + sabdl_fns[a->esz], a, 3) -DO_SVE2_ZZZ_TB(UADDLB, uaddl, false, false) -DO_SVE2_ZZZ_TB(USUBLB, usubl, false, false) -DO_SVE2_ZZZ_TB(UABDLB, uabdl, false, false) +static gen_helper_gvec_3 * const uaddl_fns[4] = { + NULL, gen_helper_sve2_uaddl_h, + gen_helper_sve2_uaddl_s, gen_helper_sve2_uaddl_d, +}; +TRANS_FEAT(UADDLB, aa64_sve2, gen_gvec_ool_arg_zzz, + uaddl_fns[a->esz], a, 0) +TRANS_FEAT(UADDLT, aa64_sve2, gen_gvec_ool_arg_zzz, + uaddl_fns[a->esz], a, 3) -DO_SVE2_ZZZ_TB(SADDLT, saddl, true, true) -DO_SVE2_ZZZ_TB(SSUBLT, ssubl, true, true) -DO_SVE2_ZZZ_TB(SABDLT, sabdl, true, true) +static gen_helper_gvec_3 * const usubl_fns[4] = { + NULL, gen_helper_sve2_usubl_h, + gen_helper_sve2_usubl_s, gen_helper_sve2_usubl_d, +}; +TRANS_FEAT(USUBLB, aa64_sve2, gen_gvec_ool_arg_zzz, + usubl_fns[a->esz], a, 0) +TRANS_FEAT(USUBLT, aa64_sve2, gen_gvec_ool_arg_zzz, + usubl_fns[a->esz], a, 3) -DO_SVE2_ZZZ_TB(UADDLT, uaddl, true, true) -DO_SVE2_ZZZ_TB(USUBLT, usubl, true, true) -DO_SVE2_ZZZ_TB(UABDLT, uabdl, true, true) +static gen_helper_gvec_3 * const uabdl_fns[4] = { + NULL, gen_helper_sve2_uabdl_h, + gen_helper_sve2_uabdl_s, gen_helper_sve2_uabdl_d, +}; +TRANS_FEAT(UABDLB, aa64_sve2, gen_gvec_ool_arg_zzz, + uabdl_fns[a->esz], a, 0) +TRANS_FEAT(UABDLT, aa64_sve2, gen_gvec_ool_arg_zzz, + uabdl_fns[a->esz], a, 3) -DO_SVE2_ZZZ_TB(SADDLBT, saddl, false, true) -DO_SVE2_ZZZ_TB(SSUBLBT, ssubl, false, true) -DO_SVE2_ZZZ_TB(SSUBLTB, ssubl, true, false) +static gen_helper_gvec_3 * const sqdmull_fns[4] = { + NULL, gen_helper_sve2_sqdmull_zzz_h, + gen_helper_sve2_sqdmull_zzz_s, gen_helper_sve2_sqdmull_zzz_d, +}; +TRANS_FEAT(SQDMULLB_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + sqdmull_fns[a->esz], a, 0) +TRANS_FEAT(SQDMULLT_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + sqdmull_fns[a->esz], a, 3) -DO_SVE2_ZZZ_TB(SQDMULLB_zzz, sqdmull_zzz, false, false) -DO_SVE2_ZZZ_TB(SQDMULLT_zzz, sqdmull_zzz, true, true) +static gen_helper_gvec_3 * const smull_fns[4] = { + NULL, gen_helper_sve2_smull_zzz_h, + gen_helper_sve2_smull_zzz_s, gen_helper_sve2_smull_zzz_d, +}; +TRANS_FEAT(SMULLB_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + smull_fns[a->esz], a, 0) +TRANS_FEAT(SMULLT_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + smull_fns[a->esz], a, 3) -DO_SVE2_ZZZ_TB(SMULLB_zzz, smull_zzz, false, false) -DO_SVE2_ZZZ_TB(SMULLT_zzz, smull_zzz, true, true) +static gen_helper_gvec_3 * const umull_fns[4] = { + NULL, gen_helper_sve2_umull_zzz_h, + gen_helper_sve2_umull_zzz_s, gen_helper_sve2_umull_zzz_d, +}; +TRANS_FEAT(UMULLB_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + umull_fns[a->esz], a, 0) +TRANS_FEAT(UMULLT_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, + umull_fns[a->esz], a, 3) -DO_SVE2_ZZZ_TB(UMULLB_zzz, umull_zzz, false, false) -DO_SVE2_ZZZ_TB(UMULLT_zzz, umull_zzz, true, true) - -static bool do_eor_tb(DisasContext *s, arg_rrr_esz *a, bool sel1) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_eoril_b, gen_helper_sve2_eoril_h, - gen_helper_sve2_eoril_s, gen_helper_sve2_eoril_d, - }; - return do_sve2_zzw_ool(s, a, fns[a->esz], (!sel1 << 1) | sel1); -} - -static bool trans_EORBT(DisasContext *s, arg_rrr_esz *a) -{ - return do_eor_tb(s, a, false); -} - -static bool trans_EORTB(DisasContext *s, arg_rrr_esz *a) -{ - return do_eor_tb(s, a, true); -} +static gen_helper_gvec_3 * const eoril_fns[4] = { + gen_helper_sve2_eoril_b, gen_helper_sve2_eoril_h, + gen_helper_sve2_eoril_s, gen_helper_sve2_eoril_d, +}; +TRANS_FEAT(EORBT, aa64_sve2, gen_gvec_ool_arg_zzz, eoril_fns[a->esz], a, 2) +TRANS_FEAT(EORTB, aa64_sve2, gen_gvec_ool_arg_zzz, eoril_fns[a->esz], a, 1) static bool do_trans_pmull(DisasContext *s, arg_rrr_esz *a, bool sel) { @@ -6794,38 +6814,39 @@ static bool do_trans_pmull(DisasContext *s, arg_rrr_esz *a, bool sel) if (a->esz == 0 && !dc_isar_feature(aa64_sve2_pmull128, s)) { return false; } - return do_sve2_zzw_ool(s, a, fns[a->esz], sel); + return gen_gvec_ool_arg_zzz(s, fns[a->esz], a, sel); } -static bool trans_PMULLB(DisasContext *s, arg_rrr_esz *a) -{ - return do_trans_pmull(s, a, false); -} +TRANS_FEAT(PMULLB, aa64_sve2, do_trans_pmull, a, false) +TRANS_FEAT(PMULLT, aa64_sve2, do_trans_pmull, a, true) -static bool trans_PMULLT(DisasContext *s, arg_rrr_esz *a) -{ - return do_trans_pmull(s, a, true); -} +static gen_helper_gvec_3 * const saddw_fns[4] = { + NULL, gen_helper_sve2_saddw_h, + gen_helper_sve2_saddw_s, gen_helper_sve2_saddw_d, +}; +TRANS_FEAT(SADDWB, aa64_sve2, gen_gvec_ool_arg_zzz, saddw_fns[a->esz], a, 0) +TRANS_FEAT(SADDWT, aa64_sve2, gen_gvec_ool_arg_zzz, saddw_fns[a->esz], a, 1) -#define DO_SVE2_ZZZ_WTB(NAME, name, SEL2) \ -static bool trans_##NAME(DisasContext *s, arg_rrr_esz *a) \ -{ \ - static gen_helper_gvec_3 * const fns[4] = { \ - NULL, gen_helper_sve2_##name##_h, \ - gen_helper_sve2_##name##_s, gen_helper_sve2_##name##_d, \ - }; \ - return do_sve2_zzw_ool(s, a, fns[a->esz], SEL2); \ -} +static gen_helper_gvec_3 * const ssubw_fns[4] = { + NULL, gen_helper_sve2_ssubw_h, + gen_helper_sve2_ssubw_s, gen_helper_sve2_ssubw_d, +}; +TRANS_FEAT(SSUBWB, aa64_sve2, gen_gvec_ool_arg_zzz, ssubw_fns[a->esz], a, 0) +TRANS_FEAT(SSUBWT, aa64_sve2, gen_gvec_ool_arg_zzz, ssubw_fns[a->esz], a, 1) -DO_SVE2_ZZZ_WTB(SADDWB, saddw, false) -DO_SVE2_ZZZ_WTB(SADDWT, saddw, true) -DO_SVE2_ZZZ_WTB(SSUBWB, ssubw, false) -DO_SVE2_ZZZ_WTB(SSUBWT, ssubw, true) +static gen_helper_gvec_3 * const uaddw_fns[4] = { + NULL, gen_helper_sve2_uaddw_h, + gen_helper_sve2_uaddw_s, gen_helper_sve2_uaddw_d, +}; +TRANS_FEAT(UADDWB, aa64_sve2, gen_gvec_ool_arg_zzz, uaddw_fns[a->esz], a, 0) +TRANS_FEAT(UADDWT, aa64_sve2, gen_gvec_ool_arg_zzz, uaddw_fns[a->esz], a, 1) -DO_SVE2_ZZZ_WTB(UADDWB, uaddw, false) -DO_SVE2_ZZZ_WTB(UADDWT, uaddw, true) -DO_SVE2_ZZZ_WTB(USUBWB, usubw, false) -DO_SVE2_ZZZ_WTB(USUBWT, usubw, true) +static gen_helper_gvec_3 * const usubw_fns[4] = { + NULL, gen_helper_sve2_usubw_h, + gen_helper_sve2_usubw_s, gen_helper_sve2_usubw_d, +}; +TRANS_FEAT(USUBWB, aa64_sve2, gen_gvec_ool_arg_zzz, usubw_fns[a->esz], a, 0) +TRANS_FEAT(USUBWT, aa64_sve2, gen_gvec_ool_arg_zzz, usubw_fns[a->esz], a, 1) static void gen_sshll_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t imm) { @@ -6986,72 +7007,44 @@ static bool trans_USHLLT(DisasContext *s, arg_rri_esz *a) return do_sve2_shll_tb(s, a, true, true); } -static bool trans_BEXT(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_bext_b, gen_helper_sve2_bext_h, - gen_helper_sve2_bext_s, gen_helper_sve2_bext_d, - }; - if (!dc_isar_feature(aa64_sve2_bitperm, s)) { - return false; - } - return do_sve2_zzw_ool(s, a, fns[a->esz], 0); -} +static gen_helper_gvec_3 * const bext_fns[4] = { + gen_helper_sve2_bext_b, gen_helper_sve2_bext_h, + gen_helper_sve2_bext_s, gen_helper_sve2_bext_d, +}; +TRANS_FEAT(BEXT, aa64_sve2_bitperm, gen_gvec_ool_arg_zzz, + bext_fns[a->esz], a, 0) -static bool trans_BDEP(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_bdep_b, gen_helper_sve2_bdep_h, - gen_helper_sve2_bdep_s, gen_helper_sve2_bdep_d, - }; - if (!dc_isar_feature(aa64_sve2_bitperm, s)) { - return false; - } - return do_sve2_zzw_ool(s, a, fns[a->esz], 0); -} +static gen_helper_gvec_3 * const bdep_fns[4] = { + gen_helper_sve2_bdep_b, gen_helper_sve2_bdep_h, + gen_helper_sve2_bdep_s, gen_helper_sve2_bdep_d, +}; +TRANS_FEAT(BDEP, aa64_sve2_bitperm, gen_gvec_ool_arg_zzz, + bdep_fns[a->esz], a, 0) -static bool trans_BGRP(DisasContext *s, arg_rrr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_bgrp_b, gen_helper_sve2_bgrp_h, - gen_helper_sve2_bgrp_s, gen_helper_sve2_bgrp_d, - }; - if (!dc_isar_feature(aa64_sve2_bitperm, s)) { - return false; - } - return do_sve2_zzw_ool(s, a, fns[a->esz], 0); -} +static gen_helper_gvec_3 * const bgrp_fns[4] = { + gen_helper_sve2_bgrp_b, gen_helper_sve2_bgrp_h, + gen_helper_sve2_bgrp_s, gen_helper_sve2_bgrp_d, +}; +TRANS_FEAT(BGRP, aa64_sve2_bitperm, gen_gvec_ool_arg_zzz, + bgrp_fns[a->esz], a, 0) -static bool do_cadd(DisasContext *s, arg_rrr_esz *a, bool sq, bool rot) -{ - static gen_helper_gvec_3 * const fns[2][4] = { - { gen_helper_sve2_cadd_b, gen_helper_sve2_cadd_h, - gen_helper_sve2_cadd_s, gen_helper_sve2_cadd_d }, - { gen_helper_sve2_sqcadd_b, gen_helper_sve2_sqcadd_h, - gen_helper_sve2_sqcadd_s, gen_helper_sve2_sqcadd_d }, - }; - return do_sve2_zzw_ool(s, a, fns[sq][a->esz], rot); -} +static gen_helper_gvec_3 * const cadd_fns[4] = { + gen_helper_sve2_cadd_b, gen_helper_sve2_cadd_h, + gen_helper_sve2_cadd_s, gen_helper_sve2_cadd_d, +}; +TRANS_FEAT(CADD_rot90, aa64_sve2, gen_gvec_ool_arg_zzz, + cadd_fns[a->esz], a, 0) +TRANS_FEAT(CADD_rot270, aa64_sve2, gen_gvec_ool_arg_zzz, + cadd_fns[a->esz], a, 1) -static bool trans_CADD_rot90(DisasContext *s, arg_rrr_esz *a) -{ - return do_cadd(s, a, false, false); -} - -static bool trans_CADD_rot270(DisasContext *s, arg_rrr_esz *a) -{ - return do_cadd(s, a, false, true); -} - -static bool trans_SQCADD_rot90(DisasContext *s, arg_rrr_esz *a) -{ - return do_cadd(s, a, true, false); -} - -static bool trans_SQCADD_rot270(DisasContext *s, arg_rrr_esz *a) -{ - return do_cadd(s, a, true, true); -} +static gen_helper_gvec_3 * const sqcadd_fns[4] = { + gen_helper_sve2_sqcadd_b, gen_helper_sve2_sqcadd_h, + gen_helper_sve2_sqcadd_s, gen_helper_sve2_sqcadd_d, +}; +TRANS_FEAT(SQCADD_rot90, aa64_sve2, gen_gvec_ool_arg_zzz, + sqcadd_fns[a->esz], a, 0) +TRANS_FEAT(SQCADD_rot270, aa64_sve2, gen_gvec_ool_arg_zzz, + sqcadd_fns[a->esz], a, 1) static gen_helper_gvec_4 * const sabal_fns[4] = { NULL, gen_helper_sve2_sabal_h, From 8740d69416f556d68832d6f2b46c9972d574e94b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:31 -0700 Subject: [PATCH 603/935] target/arm: Use TRANS_FEAT for USDOT_zzzz This is the last direct user of tcg_gen_gvec_4_ool. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-19-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 2347b60d8e..b4307f062c 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -8044,21 +8044,8 @@ static gen_helper_gvec_4 * const sqrdcmlah_fns[] = { TRANS_FEAT(SQRDCMLAH_zzzz, aa64_sve2, gen_gvec_ool_zzzz, sqrdcmlah_fns[a->esz], a->rd, a->rn, a->rm, a->ra, a->rot) -static bool trans_USDOT_zzzz(DisasContext *s, arg_USDOT_zzzz *a) -{ - if (a->esz != 2 || !dc_isar_feature(aa64_sve_i8mm, s)) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_4_ool(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - vsz, vsz, 0, gen_helper_gvec_usdot_b); - } - return true; -} +TRANS_FEAT(USDOT_zzzz, aa64_sve_i8mm, gen_gvec_ool_arg_zzzz, + a->esz == 2 ? gen_helper_gvec_usdot_b : NULL, a, 0) TRANS_FEAT(AESMC, aa64_sve2_aes, gen_gvec_ool_zz, gen_helper_crypto_aesmc, a->rd, a->rd, a->decrypt) From 8fb27a21b1a0b29ad60e155de838e199cdf4ee38 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:32 -0700 Subject: [PATCH 604/935] target/arm: Move null function and sve check into gen_gvec_ool_zzp Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-20-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index b4307f062c..e81c2de37f 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -206,14 +206,20 @@ static bool gen_gvec_ool_arg_zzxz(DisasContext *s, gen_helper_gvec_4 *fn, } /* Invoke an out-of-line helper on 2 Zregs and a predicate. */ -static void gen_gvec_ool_zzp(DisasContext *s, gen_helper_gvec_3 *fn, +static bool gen_gvec_ool_zzp(DisasContext *s, gen_helper_gvec_3 *fn, int rd, int rn, int pg, int data) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_3_ool(vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - pred_full_reg_offset(s, pg), - vsz, vsz, data, fn); + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_3_ool(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + pred_full_reg_offset(s, pg), + vsz, vsz, data, fn); + } + return true; } /* Invoke an out-of-line helper on 3 Zregs and a predicate. */ @@ -801,13 +807,7 @@ static bool trans_SEL_zpzz(DisasContext *s, arg_rprr_esz *a) static bool do_zpz_ool(DisasContext *s, arg_rpr_esz *a, gen_helper_gvec_3 *fn) { - if (fn == NULL) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzp(s, fn, a->rd, a->rn, a->pg, 0); - } - return true; + return gen_gvec_ool_zzp(s, fn, a->rd, a->rn, a->pg, 0); } #define DO_ZPZ(NAME, name) \ @@ -986,20 +986,13 @@ static bool do_movz_zpz(DisasContext *s, int rd, int rn, int pg, gen_helper_sve_movz_b, gen_helper_sve_movz_h, gen_helper_sve_movz_s, gen_helper_sve_movz_d, }; - - if (sve_access_check(s)) { - gen_gvec_ool_zzp(s, fns[esz], rd, rn, pg, invert); - } - return true; + return gen_gvec_ool_zzp(s, fns[esz], rd, rn, pg, invert); } static bool do_zpzi_ool(DisasContext *s, arg_rpri_esz *a, gen_helper_gvec_3 *fn) { - if (sve_access_check(s)) { - gen_gvec_ool_zzp(s, fn, a->rd, a->rn, a->pg, a->imm); - } - return true; + return gen_gvec_ool_zzp(s, fn, a->rd, a->rn, a->pg, a->imm); } static bool trans_ASR_zpzi(DisasContext *s, arg_rpri_esz *a) From b051809adf08dc75869f5adc229d981f2a7f6070 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:33 -0700 Subject: [PATCH 605/935] target/arm: Introduce gen_gvec_ool_arg_zpz Use gen_gvec_ool_arg_zpz instead of gen_gvec_ool_zzp when the arguments come from arg_rpr_esz. Replaces do_zpz_ool. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-21-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 45 +++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index e81c2de37f..be426db6a9 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -222,6 +222,13 @@ static bool gen_gvec_ool_zzp(DisasContext *s, gen_helper_gvec_3 *fn, return true; } +static bool gen_gvec_ool_arg_zpz(DisasContext *s, gen_helper_gvec_3 *fn, + arg_rpr_esz *a, int data) +{ + return gen_gvec_ool_zzp(s, fn, a->rd, a->rn, a->pg, data); +} + + /* Invoke an out-of-line helper on 3 Zregs and a predicate. */ static void gen_gvec_ool_zzzp(DisasContext *s, gen_helper_gvec_4 *fn, int rd, int rn, int rm, int pg, int data) @@ -805,11 +812,6 @@ static bool trans_SEL_zpzz(DisasContext *s, arg_rprr_esz *a) *** SVE Integer Arithmetic - Unary Predicated Group */ -static bool do_zpz_ool(DisasContext *s, arg_rpr_esz *a, gen_helper_gvec_3 *fn) -{ - return gen_gvec_ool_zzp(s, fn, a->rd, a->rn, a->pg, 0); -} - #define DO_ZPZ(NAME, name) \ static bool trans_##NAME(DisasContext *s, arg_rpr_esz *a) \ { \ @@ -817,7 +819,7 @@ static bool trans_##NAME(DisasContext *s, arg_rpr_esz *a) \ gen_helper_sve_##name##_b, gen_helper_sve_##name##_h, \ gen_helper_sve_##name##_s, gen_helper_sve_##name##_d, \ }; \ - return do_zpz_ool(s, a, fns[a->esz]); \ + return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); \ } DO_ZPZ(CLS, cls) @@ -836,7 +838,7 @@ static bool trans_FABS(DisasContext *s, arg_rpr_esz *a) gen_helper_sve_fabs_s, gen_helper_sve_fabs_d }; - return do_zpz_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); } static bool trans_FNEG(DisasContext *s, arg_rpr_esz *a) @@ -847,7 +849,7 @@ static bool trans_FNEG(DisasContext *s, arg_rpr_esz *a) gen_helper_sve_fneg_s, gen_helper_sve_fneg_d }; - return do_zpz_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); } static bool trans_SXTB(DisasContext *s, arg_rpr_esz *a) @@ -858,7 +860,7 @@ static bool trans_SXTB(DisasContext *s, arg_rpr_esz *a) gen_helper_sve_sxtb_s, gen_helper_sve_sxtb_d }; - return do_zpz_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); } static bool trans_UXTB(DisasContext *s, arg_rpr_esz *a) @@ -869,7 +871,7 @@ static bool trans_UXTB(DisasContext *s, arg_rpr_esz *a) gen_helper_sve_uxtb_s, gen_helper_sve_uxtb_d }; - return do_zpz_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); } static bool trans_SXTH(DisasContext *s, arg_rpr_esz *a) @@ -879,7 +881,7 @@ static bool trans_SXTH(DisasContext *s, arg_rpr_esz *a) gen_helper_sve_sxth_s, gen_helper_sve_sxth_d }; - return do_zpz_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); } static bool trans_UXTH(DisasContext *s, arg_rpr_esz *a) @@ -889,17 +891,19 @@ static bool trans_UXTH(DisasContext *s, arg_rpr_esz *a) gen_helper_sve_uxth_s, gen_helper_sve_uxth_d }; - return do_zpz_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); } static bool trans_SXTW(DisasContext *s, arg_rpr_esz *a) { - return do_zpz_ool(s, a, a->esz == 3 ? gen_helper_sve_sxtw_d : NULL); + return gen_gvec_ool_arg_zpz(s, a->esz == 3 ? gen_helper_sve_sxtw_d + : NULL, a, 0); } static bool trans_UXTW(DisasContext *s, arg_rpr_esz *a) { - return do_zpz_ool(s, a, a->esz == 3 ? gen_helper_sve_uxtw_d : NULL); + return gen_gvec_ool_arg_zpz(s, a->esz == 3 ? gen_helper_sve_uxtw_d + : NULL, a, 0); } #undef DO_ZPZ @@ -2659,7 +2663,7 @@ static bool trans_COMPACT(DisasContext *s, arg_rpr_esz *a) static gen_helper_gvec_3 * const fns[4] = { NULL, NULL, gen_helper_sve_compact_s, gen_helper_sve_compact_d }; - return do_zpz_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); } /* Call the helper that computes the ARM LastActiveElement pseudocode @@ -3008,7 +3012,7 @@ static bool trans_REVB(DisasContext *s, arg_rpr_esz *a) gen_helper_sve_revb_s, gen_helper_sve_revb_d, }; - return do_zpz_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); } static bool trans_REVH(DisasContext *s, arg_rpr_esz *a) @@ -3019,12 +3023,13 @@ static bool trans_REVH(DisasContext *s, arg_rpr_esz *a) gen_helper_sve_revh_s, gen_helper_sve_revh_d, }; - return do_zpz_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); } static bool trans_REVW(DisasContext *s, arg_rpr_esz *a) { - return do_zpz_ool(s, a, a->esz == 3 ? gen_helper_sve_revw_d : NULL); + return gen_gvec_ool_arg_zpz(s, a->esz == 3 ? gen_helper_sve_revw_d + : NULL, a, 0); } static bool trans_RBIT(DisasContext *s, arg_rpr_esz *a) @@ -3035,7 +3040,7 @@ static bool trans_RBIT(DisasContext *s, arg_rpr_esz *a) gen_helper_sve_rbit_s, gen_helper_sve_rbit_d, }; - return do_zpz_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); } static bool trans_SPLICE(DisasContext *s, arg_rprr_esz *a) @@ -6624,7 +6629,7 @@ static bool do_sve2_zpz_ool(DisasContext *s, arg_rpr_esz *a, if (!dc_isar_feature(aa64_sve2, s)) { return false; } - return do_zpz_ool(s, a, fn); + return gen_gvec_ool_arg_zpz(s, fn, a, 0); } static bool trans_URECPE(DisasContext *s, arg_rpr_esz *a) From 817bd5c98e2cfe7a3477248e01aa316450769ce0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:34 -0700 Subject: [PATCH 606/935] target/arm: Use TRANS_FEAT for gen_gvec_ool_arg_zpz Convert SVE translation functions directly using gen_gvec_ool_arg_zpz to TRANS_FEAT. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-22-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 189 ++++++++++++------------------------- 1 file changed, 60 insertions(+), 129 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index be426db6a9..d5a09a60af 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -812,101 +812,60 @@ static bool trans_SEL_zpzz(DisasContext *s, arg_rprr_esz *a) *** SVE Integer Arithmetic - Unary Predicated Group */ -#define DO_ZPZ(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rpr_esz *a) \ -{ \ - static gen_helper_gvec_3 * const fns[4] = { \ - gen_helper_sve_##name##_b, gen_helper_sve_##name##_h, \ - gen_helper_sve_##name##_s, gen_helper_sve_##name##_d, \ +#define DO_ZPZ(NAME, FEAT, name) \ + static gen_helper_gvec_3 * const name##_fns[4] = { \ + gen_helper_##name##_b, gen_helper_##name##_h, \ + gen_helper_##name##_s, gen_helper_##name##_d, \ }; \ - return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); \ -} + TRANS_FEAT(NAME, FEAT, gen_gvec_ool_arg_zpz, name##_fns[a->esz], a, 0) -DO_ZPZ(CLS, cls) -DO_ZPZ(CLZ, clz) -DO_ZPZ(CNT_zpz, cnt_zpz) -DO_ZPZ(CNOT, cnot) -DO_ZPZ(NOT_zpz, not_zpz) -DO_ZPZ(ABS, abs) -DO_ZPZ(NEG, neg) +DO_ZPZ(CLS, aa64_sve, sve_cls) +DO_ZPZ(CLZ, aa64_sve, sve_clz) +DO_ZPZ(CNT_zpz, aa64_sve, sve_cnt_zpz) +DO_ZPZ(CNOT, aa64_sve, sve_cnot) +DO_ZPZ(NOT_zpz, aa64_sve, sve_not_zpz) +DO_ZPZ(ABS, aa64_sve, sve_abs) +DO_ZPZ(NEG, aa64_sve, sve_neg) +DO_ZPZ(RBIT, aa64_sve, sve_rbit) -static bool trans_FABS(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, - gen_helper_sve_fabs_h, - gen_helper_sve_fabs_s, - gen_helper_sve_fabs_d - }; - return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); -} +static gen_helper_gvec_3 * const fabs_fns[4] = { + NULL, gen_helper_sve_fabs_h, + gen_helper_sve_fabs_s, gen_helper_sve_fabs_d, +}; +TRANS_FEAT(FABS, aa64_sve, gen_gvec_ool_arg_zpz, fabs_fns[a->esz], a, 0) -static bool trans_FNEG(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, - gen_helper_sve_fneg_h, - gen_helper_sve_fneg_s, - gen_helper_sve_fneg_d - }; - return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); -} +static gen_helper_gvec_3 * const fneg_fns[4] = { + NULL, gen_helper_sve_fneg_h, + gen_helper_sve_fneg_s, gen_helper_sve_fneg_d, +}; +TRANS_FEAT(FNEG, aa64_sve, gen_gvec_ool_arg_zpz, fneg_fns[a->esz], a, 0) -static bool trans_SXTB(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, - gen_helper_sve_sxtb_h, - gen_helper_sve_sxtb_s, - gen_helper_sve_sxtb_d - }; - return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); -} +static gen_helper_gvec_3 * const sxtb_fns[4] = { + NULL, gen_helper_sve_sxtb_h, + gen_helper_sve_sxtb_s, gen_helper_sve_sxtb_d, +}; +TRANS_FEAT(SXTB, aa64_sve, gen_gvec_ool_arg_zpz, sxtb_fns[a->esz], a, 0) -static bool trans_UXTB(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, - gen_helper_sve_uxtb_h, - gen_helper_sve_uxtb_s, - gen_helper_sve_uxtb_d - }; - return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); -} +static gen_helper_gvec_3 * const uxtb_fns[4] = { + NULL, gen_helper_sve_uxtb_h, + gen_helper_sve_uxtb_s, gen_helper_sve_uxtb_d, +}; +TRANS_FEAT(UXTB, aa64_sve, gen_gvec_ool_arg_zpz, uxtb_fns[a->esz], a, 0) -static bool trans_SXTH(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, NULL, - gen_helper_sve_sxth_s, - gen_helper_sve_sxth_d - }; - return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); -} +static gen_helper_gvec_3 * const sxth_fns[4] = { + NULL, NULL, gen_helper_sve_sxth_s, gen_helper_sve_sxth_d +}; +TRANS_FEAT(SXTH, aa64_sve, gen_gvec_ool_arg_zpz, sxth_fns[a->esz], a, 0) -static bool trans_UXTH(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, NULL, - gen_helper_sve_uxth_s, - gen_helper_sve_uxth_d - }; - return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); -} +static gen_helper_gvec_3 * const uxth_fns[4] = { + NULL, NULL, gen_helper_sve_uxth_s, gen_helper_sve_uxth_d +}; +TRANS_FEAT(UXTH, aa64_sve, gen_gvec_ool_arg_zpz, uxth_fns[a->esz], a, 0) -static bool trans_SXTW(DisasContext *s, arg_rpr_esz *a) -{ - return gen_gvec_ool_arg_zpz(s, a->esz == 3 ? gen_helper_sve_sxtw_d - : NULL, a, 0); -} - -static bool trans_UXTW(DisasContext *s, arg_rpr_esz *a) -{ - return gen_gvec_ool_arg_zpz(s, a->esz == 3 ? gen_helper_sve_uxtw_d - : NULL, a, 0); -} - -#undef DO_ZPZ +TRANS_FEAT(SXTW, aa64_sve, gen_gvec_ool_arg_zpz, + a->esz == 3 ? gen_helper_sve_sxtw_d : NULL, a, 0) +TRANS_FEAT(UXTW, aa64_sve, gen_gvec_ool_arg_zpz, + a->esz == 3 ? gen_helper_sve_uxtw_d : NULL, a, 0) /* *** SVE Integer Reduction Group @@ -2658,13 +2617,10 @@ TRANS_FEAT(TRN2_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz, *** SVE Permute Vector - Predicated Group */ -static bool trans_COMPACT(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, NULL, gen_helper_sve_compact_s, gen_helper_sve_compact_d - }; - return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); -} +static gen_helper_gvec_3 * const compact_fns[4] = { + NULL, NULL, gen_helper_sve_compact_s, gen_helper_sve_compact_d +}; +TRANS_FEAT(COMPACT, aa64_sve, gen_gvec_ool_arg_zpz, compact_fns[a->esz], a, 0) /* Call the helper that computes the ARM LastActiveElement pseudocode * function, scaled by the element size. This includes the not found @@ -3004,44 +2960,19 @@ static bool trans_CPY_m_v(DisasContext *s, arg_rpr_esz *a) return true; } -static bool trans_REVB(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, - gen_helper_sve_revb_h, - gen_helper_sve_revb_s, - gen_helper_sve_revb_d, - }; - return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); -} +static gen_helper_gvec_3 * const revb_fns[4] = { + NULL, gen_helper_sve_revb_h, + gen_helper_sve_revb_s, gen_helper_sve_revb_d, +}; +TRANS_FEAT(REVB, aa64_sve, gen_gvec_ool_arg_zpz, revb_fns[a->esz], a, 0) -static bool trans_REVH(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - NULL, - NULL, - gen_helper_sve_revh_s, - gen_helper_sve_revh_d, - }; - return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); -} +static gen_helper_gvec_3 * const revh_fns[4] = { + NULL, NULL, gen_helper_sve_revh_s, gen_helper_sve_revh_d, +}; +TRANS_FEAT(REVH, aa64_sve, gen_gvec_ool_arg_zpz, revh_fns[a->esz], a, 0) -static bool trans_REVW(DisasContext *s, arg_rpr_esz *a) -{ - return gen_gvec_ool_arg_zpz(s, a->esz == 3 ? gen_helper_sve_revw_d - : NULL, a, 0); -} - -static bool trans_RBIT(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve_rbit_b, - gen_helper_sve_rbit_h, - gen_helper_sve_rbit_s, - gen_helper_sve_rbit_d, - }; - return gen_gvec_ool_arg_zpz(s, fns[a->esz], a, 0); -} +TRANS_FEAT(REVW, aa64_sve, gen_gvec_ool_arg_zpz, + a->esz == 3 ? gen_helper_sve_revw_d : NULL, a, 0) static bool trans_SPLICE(DisasContext *s, arg_rprr_esz *a) { From b2c0096119836008b61c21e1714ec1d90d4a0ec2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:35 -0700 Subject: [PATCH 607/935] target/arm: Use TRANS_FEAT for do_sve2_zpz_data Convert SVE translation functions using do_sve2_zpz_data to use TRANS_FEAT and gen_gvec_ool_arg_zpz. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-23-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 53 ++++++++++---------------------------- 1 file changed, 14 insertions(+), 39 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index d5a09a60af..fe11cfed6b 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -6554,48 +6554,23 @@ static bool trans_UADALP_zpzz(DisasContext *s, arg_rprr_esz *a) * SVE2 integer unary operations (predicated) */ -static bool do_sve2_zpz_ool(DisasContext *s, arg_rpr_esz *a, - gen_helper_gvec_3 *fn) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_ool_arg_zpz(s, fn, a, 0); -} +TRANS_FEAT(URECPE, aa64_sve2, gen_gvec_ool_arg_zpz, + a->esz == 2 ? gen_helper_sve2_urecpe_s : NULL, a, 0) -static bool trans_URECPE(DisasContext *s, arg_rpr_esz *a) -{ - if (a->esz != 2) { - return false; - } - return do_sve2_zpz_ool(s, a, gen_helper_sve2_urecpe_s); -} +TRANS_FEAT(URSQRTE, aa64_sve2, gen_gvec_ool_arg_zpz, + a->esz == 2 ? gen_helper_sve2_ursqrte_s : NULL, a, 0) -static bool trans_URSQRTE(DisasContext *s, arg_rpr_esz *a) -{ - if (a->esz != 2) { - return false; - } - return do_sve2_zpz_ool(s, a, gen_helper_sve2_ursqrte_s); -} +static gen_helper_gvec_3 * const sqabs_fns[4] = { + gen_helper_sve2_sqabs_b, gen_helper_sve2_sqabs_h, + gen_helper_sve2_sqabs_s, gen_helper_sve2_sqabs_d, +}; +TRANS_FEAT(SQABS, aa64_sve2, gen_gvec_ool_arg_zpz, sqabs_fns[a->esz], a, 0) -static bool trans_SQABS(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_sqabs_b, gen_helper_sve2_sqabs_h, - gen_helper_sve2_sqabs_s, gen_helper_sve2_sqabs_d, - }; - return do_sve2_zpz_ool(s, a, fns[a->esz]); -} - -static bool trans_SQNEG(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_sqneg_b, gen_helper_sve2_sqneg_h, - gen_helper_sve2_sqneg_s, gen_helper_sve2_sqneg_d, - }; - return do_sve2_zpz_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_3 * const sqneg_fns[4] = { + gen_helper_sve2_sqneg_b, gen_helper_sve2_sqneg_h, + gen_helper_sve2_sqneg_s, gen_helper_sve2_sqneg_d, +}; +TRANS_FEAT(SQNEG, aa64_sve2, gen_gvec_ool_arg_zpz, sqneg_fns[a->esz], a, 0) #define DO_SVE2_ZPZZ(NAME, name) \ static bool trans_##NAME(DisasContext *s, arg_rprr_esz *a) \ From afa2529c263502c1a0fbe0e9fa23a80c174392d1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:36 -0700 Subject: [PATCH 608/935] target/arm: Rename do_zpzi_ool to gen_gvec_ool_arg_zpzi Rename the function to match gen_gvec_ool_arg_zpz, and move to be adjacent. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-24-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index fe11cfed6b..86e87a2078 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -228,6 +228,11 @@ static bool gen_gvec_ool_arg_zpz(DisasContext *s, gen_helper_gvec_3 *fn, return gen_gvec_ool_zzp(s, fn, a->rd, a->rn, a->pg, data); } +static bool gen_gvec_ool_arg_zpzi(DisasContext *s, gen_helper_gvec_3 *fn, + arg_rpri_esz *a) +{ + return gen_gvec_ool_zzp(s, fn, a->rd, a->rn, a->pg, a->imm); +} /* Invoke an out-of-line helper on 3 Zregs and a predicate. */ static void gen_gvec_ool_zzzp(DisasContext *s, gen_helper_gvec_4 *fn, @@ -952,12 +957,6 @@ static bool do_movz_zpz(DisasContext *s, int rd, int rn, int pg, return gen_gvec_ool_zzp(s, fns[esz], rd, rn, pg, invert); } -static bool do_zpzi_ool(DisasContext *s, arg_rpri_esz *a, - gen_helper_gvec_3 *fn) -{ - return gen_gvec_ool_zzp(s, fn, a->rd, a->rn, a->pg, a->imm); -} - static bool trans_ASR_zpzi(DisasContext *s, arg_rpri_esz *a) { static gen_helper_gvec_3 * const fns[4] = { @@ -971,7 +970,7 @@ static bool trans_ASR_zpzi(DisasContext *s, arg_rpri_esz *a) /* Shift by element size is architecturally valid. For arithmetic right-shift, it's the same as by one less. */ a->imm = MIN(a->imm, (8 << a->esz) - 1); - return do_zpzi_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); } static bool trans_LSR_zpzi(DisasContext *s, arg_rpri_esz *a) @@ -988,7 +987,7 @@ static bool trans_LSR_zpzi(DisasContext *s, arg_rpri_esz *a) if (a->imm >= (8 << a->esz)) { return do_movz_zpz(s, a->rd, a->rd, a->pg, a->esz, true); } else { - return do_zpzi_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); } } @@ -1006,7 +1005,7 @@ static bool trans_LSL_zpzi(DisasContext *s, arg_rpri_esz *a) if (a->imm >= (8 << a->esz)) { return do_movz_zpz(s, a->rd, a->rd, a->pg, a->esz, true); } else { - return do_zpzi_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); } } @@ -1024,7 +1023,7 @@ static bool trans_ASRD(DisasContext *s, arg_rpri_esz *a) if (a->imm >= (8 << a->esz)) { return do_movz_zpz(s, a->rd, a->rd, a->pg, a->esz, true); } else { - return do_zpzi_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); } } @@ -1037,7 +1036,7 @@ static bool trans_SQSHL_zpzi(DisasContext *s, arg_rpri_esz *a) if (a->esz < 0 || !dc_isar_feature(aa64_sve2, s)) { return false; } - return do_zpzi_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); } static bool trans_UQSHL_zpzi(DisasContext *s, arg_rpri_esz *a) @@ -1049,7 +1048,7 @@ static bool trans_UQSHL_zpzi(DisasContext *s, arg_rpri_esz *a) if (a->esz < 0 || !dc_isar_feature(aa64_sve2, s)) { return false; } - return do_zpzi_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); } static bool trans_SRSHR(DisasContext *s, arg_rpri_esz *a) @@ -1061,7 +1060,7 @@ static bool trans_SRSHR(DisasContext *s, arg_rpri_esz *a) if (a->esz < 0 || !dc_isar_feature(aa64_sve2, s)) { return false; } - return do_zpzi_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); } static bool trans_URSHR(DisasContext *s, arg_rpri_esz *a) @@ -1073,7 +1072,7 @@ static bool trans_URSHR(DisasContext *s, arg_rpri_esz *a) if (a->esz < 0 || !dc_isar_feature(aa64_sve2, s)) { return false; } - return do_zpzi_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); } static bool trans_SQSHLU(DisasContext *s, arg_rpri_esz *a) @@ -1085,7 +1084,7 @@ static bool trans_SQSHLU(DisasContext *s, arg_rpri_esz *a) if (a->esz < 0 || !dc_isar_feature(aa64_sve2, s)) { return false; } - return do_zpzi_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); } /* From 4df37e414d812a4beb757fbb3f9db107b5451f7f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:37 -0700 Subject: [PATCH 609/935] target/arm: Use TRANS_FEAT for gen_gvec_ool_arg_zpzi Convert some SVE translation functions using gen_gvec_ool_arg_zpzi to TRANS_FEAT. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-25-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 85 ++++++++++++++------------------------ 1 file changed, 30 insertions(+), 55 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 86e87a2078..10614bf915 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -1027,65 +1027,40 @@ static bool trans_ASRD(DisasContext *s, arg_rpri_esz *a) } } -static bool trans_SQSHL_zpzi(DisasContext *s, arg_rpri_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_sqshl_zpzi_b, gen_helper_sve2_sqshl_zpzi_h, - gen_helper_sve2_sqshl_zpzi_s, gen_helper_sve2_sqshl_zpzi_d, - }; - if (a->esz < 0 || !dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); -} +static gen_helper_gvec_3 * const sqshl_zpzi_fns[4] = { + gen_helper_sve2_sqshl_zpzi_b, gen_helper_sve2_sqshl_zpzi_h, + gen_helper_sve2_sqshl_zpzi_s, gen_helper_sve2_sqshl_zpzi_d, +}; +TRANS_FEAT(SQSHL_zpzi, aa64_sve2, gen_gvec_ool_arg_zpzi, + a->esz < 0 ? NULL : sqshl_zpzi_fns[a->esz], a) -static bool trans_UQSHL_zpzi(DisasContext *s, arg_rpri_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_uqshl_zpzi_b, gen_helper_sve2_uqshl_zpzi_h, - gen_helper_sve2_uqshl_zpzi_s, gen_helper_sve2_uqshl_zpzi_d, - }; - if (a->esz < 0 || !dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); -} +static gen_helper_gvec_3 * const uqshl_zpzi_fns[4] = { + gen_helper_sve2_uqshl_zpzi_b, gen_helper_sve2_uqshl_zpzi_h, + gen_helper_sve2_uqshl_zpzi_s, gen_helper_sve2_uqshl_zpzi_d, +}; +TRANS_FEAT(UQSHL_zpzi, aa64_sve2, gen_gvec_ool_arg_zpzi, + a->esz < 0 ? NULL : uqshl_zpzi_fns[a->esz], a) -static bool trans_SRSHR(DisasContext *s, arg_rpri_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_srshr_b, gen_helper_sve2_srshr_h, - gen_helper_sve2_srshr_s, gen_helper_sve2_srshr_d, - }; - if (a->esz < 0 || !dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); -} +static gen_helper_gvec_3 * const srshr_fns[4] = { + gen_helper_sve2_srshr_b, gen_helper_sve2_srshr_h, + gen_helper_sve2_srshr_s, gen_helper_sve2_srshr_d, +}; +TRANS_FEAT(SRSHR, aa64_sve2, gen_gvec_ool_arg_zpzi, + a->esz < 0 ? NULL : srshr_fns[a->esz], a) -static bool trans_URSHR(DisasContext *s, arg_rpri_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_urshr_b, gen_helper_sve2_urshr_h, - gen_helper_sve2_urshr_s, gen_helper_sve2_urshr_d, - }; - if (a->esz < 0 || !dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); -} +static gen_helper_gvec_3 * const urshr_fns[4] = { + gen_helper_sve2_urshr_b, gen_helper_sve2_urshr_h, + gen_helper_sve2_urshr_s, gen_helper_sve2_urshr_d, +}; +TRANS_FEAT(URSHR, aa64_sve2, gen_gvec_ool_arg_zpzi, + a->esz < 0 ? NULL : urshr_fns[a->esz], a) -static bool trans_SQSHLU(DisasContext *s, arg_rpri_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve2_sqshlu_b, gen_helper_sve2_sqshlu_h, - gen_helper_sve2_sqshlu_s, gen_helper_sve2_sqshlu_d, - }; - if (a->esz < 0 || !dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); -} +static gen_helper_gvec_3 * const sqshlu_fns[4] = { + gen_helper_sve2_sqshlu_b, gen_helper_sve2_sqshlu_h, + gen_helper_sve2_sqshlu_s, gen_helper_sve2_sqshlu_d, +}; +TRANS_FEAT(SQSHLU, aa64_sve2, gen_gvec_ool_arg_zpzi, + a->esz < 0 ? NULL : sqshlu_fns[a->esz], a) /* *** SVE Bitwise Shift - Predicated Group From 2a753d1e1dd65c093440e3ecd079da624ebd64b3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:38 -0700 Subject: [PATCH 610/935] target/arm: Move null function and sve check into gen_gvec_ool_zzzp Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-26-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 42 ++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 10614bf915..fea7164d72 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -235,15 +235,21 @@ static bool gen_gvec_ool_arg_zpzi(DisasContext *s, gen_helper_gvec_3 *fn, } /* Invoke an out-of-line helper on 3 Zregs and a predicate. */ -static void gen_gvec_ool_zzzp(DisasContext *s, gen_helper_gvec_4 *fn, +static bool gen_gvec_ool_zzzp(DisasContext *s, gen_helper_gvec_4 *fn, int rd, int rn, int rm, int pg, int data) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_4_ool(vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), - pred_full_reg_offset(s, pg), - vsz, vsz, data, fn); + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_4_ool(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), + pred_full_reg_offset(s, pg), + vsz, vsz, data, fn); + } + return true; } /* Invoke a vector expander on two Zregs. */ @@ -733,13 +739,7 @@ static bool trans_UQSUB_zzz(DisasContext *s, arg_rrr_esz *a) static bool do_zpzz_ool(DisasContext *s, arg_rprr_esz *a, gen_helper_gvec_4 *fn) { - if (fn == NULL) { - return false; - } - if (sve_access_check(s)) { - gen_gvec_ool_zzzp(s, fn, a->rd, a->rn, a->rm, a->pg, 0); - } - return true; + return gen_gvec_ool_zzzp(s, fn, a->rd, a->rn, a->rm, a->pg, 0); } /* Select active elememnts from Zn and inactive elements from Zm, @@ -2950,11 +2950,8 @@ TRANS_FEAT(REVW, aa64_sve, gen_gvec_ool_arg_zpz, static bool trans_SPLICE(DisasContext *s, arg_rprr_esz *a) { - if (sve_access_check(s)) { - gen_gvec_ool_zzzp(s, gen_helper_sve_splice, - a->rd, a->rn, a->rm, a->pg, a->esz); - } - return true; + return gen_gvec_ool_zzzp(s, gen_helper_sve_splice, + a->rd, a->rn, a->rm, a->pg, a->esz); } static bool trans_SPLICE_sve2(DisasContext *s, arg_rpr_esz *a) @@ -2962,11 +2959,8 @@ static bool trans_SPLICE_sve2(DisasContext *s, arg_rpr_esz *a) if (!dc_isar_feature(aa64_sve2, s)) { return false; } - if (sve_access_check(s)) { - gen_gvec_ool_zzzp(s, gen_helper_sve_splice, - a->rd, a->rn, (a->rn + 1) % 32, a->pg, a->esz); - } - return true; + return gen_gvec_ool_zzzp(s, gen_helper_sve_splice, + a->rd, a->rn, (a->rn + 1) % 32, a->pg, a->esz); } /* From 312016c96a914aa6440f7d9f0fca146426619eca Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:39 -0700 Subject: [PATCH 611/935] target/arm: Introduce gen_gvec_ool_arg_zpzz Use gen_gvec_ool_arg_zpzz instead of gen_gvec_ool_zzzp when the arguments come from arg_rprr_esz. Replaces do_zpzz_ool. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-27-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index fea7164d72..d63099c5b7 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -252,6 +252,12 @@ static bool gen_gvec_ool_zzzp(DisasContext *s, gen_helper_gvec_4 *fn, return true; } +static bool gen_gvec_ool_arg_zpzz(DisasContext *s, gen_helper_gvec_4 *fn, + arg_rprr_esz *a, int data) +{ + return gen_gvec_ool_zzzp(s, fn, a->rd, a->rn, a->rm, a->pg, data); +} + /* Invoke a vector expander on two Zregs. */ static void gen_gvec_fn_zz(DisasContext *s, GVecGen2Fn *gvec_fn, int esz, int rd, int rn) @@ -737,11 +743,6 @@ static bool trans_UQSUB_zzz(DisasContext *s, arg_rrr_esz *a) *** SVE Integer Arithmetic - Binary Predicated Group */ -static bool do_zpzz_ool(DisasContext *s, arg_rprr_esz *a, gen_helper_gvec_4 *fn) -{ - return gen_gvec_ool_zzzp(s, fn, a->rd, a->rn, a->rm, a->pg, 0); -} - /* Select active elememnts from Zn and inactive elements from Zm, * storing the result in Zd. */ @@ -761,7 +762,7 @@ static bool trans_##NAME##_zpzz(DisasContext *s, arg_rprr_esz *a) \ gen_helper_sve_##name##_zpzz_b, gen_helper_sve_##name##_zpzz_h, \ gen_helper_sve_##name##_zpzz_s, gen_helper_sve_##name##_zpzz_d, \ }; \ - return do_zpzz_ool(s, a, fns[a->esz]); \ + return gen_gvec_ool_arg_zpzz(s, fns[a->esz], a, 0); \ } DO_ZPZZ(AND, and) @@ -792,7 +793,7 @@ static bool trans_SDIV_zpzz(DisasContext *s, arg_rprr_esz *a) static gen_helper_gvec_4 * const fns[4] = { NULL, NULL, gen_helper_sve_sdiv_zpzz_s, gen_helper_sve_sdiv_zpzz_d }; - return do_zpzz_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpzz(s, fns[a->esz], a, 0); } static bool trans_UDIV_zpzz(DisasContext *s, arg_rprr_esz *a) @@ -800,7 +801,7 @@ static bool trans_UDIV_zpzz(DisasContext *s, arg_rprr_esz *a) static gen_helper_gvec_4 * const fns[4] = { NULL, NULL, gen_helper_sve_udiv_zpzz_s, gen_helper_sve_udiv_zpzz_d }; - return do_zpzz_ool(s, a, fns[a->esz]); + return gen_gvec_ool_arg_zpzz(s, fns[a->esz], a, 0); } static bool trans_SEL_zpzz(DisasContext *s, arg_rprr_esz *a) @@ -1076,7 +1077,7 @@ static bool trans_##NAME##_zpzw(DisasContext *s, arg_rprr_esz *a) \ if (a->esz < 0 || a->esz >= 3) { \ return false; \ } \ - return do_zpzz_ool(s, a, fns[a->esz]); \ + return gen_gvec_ool_arg_zpzz(s, fns[a->esz], a, 0); \ } DO_ZPZW(ASR, asr) @@ -6489,7 +6490,7 @@ static bool do_sve2_zpzz_ool(DisasContext *s, arg_rprr_esz *a, if (!dc_isar_feature(aa64_sve2, s)) { return false; } - return do_zpzz_ool(s, a, fn); + return gen_gvec_ool_arg_zpzz(s, fn, a, 0); } static bool trans_SADALP_zpzz(DisasContext *s, arg_rprr_esz *a) From 8e7acb2443031d6395c18de09406803e9d3f3ac4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:40 -0700 Subject: [PATCH 612/935] target/arm: Use TRANS_FEAT for gen_gvec_ool_arg_zpzz Convert SVE translation functions directly using gen_gvec_ool_arg_zpzz to TRANS_FEAT. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-28-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 85 ++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 49 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index d63099c5b7..f8277eeb7c 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -755,54 +755,46 @@ static void do_sel_z(DisasContext *s, int rd, int rn, int rm, int pg, int esz) gen_gvec_ool_zzzp(s, fns[esz], rd, rn, rm, pg, 0); } -#define DO_ZPZZ(NAME, name) \ -static bool trans_##NAME##_zpzz(DisasContext *s, arg_rprr_esz *a) \ -{ \ - static gen_helper_gvec_4 * const fns[4] = { \ - gen_helper_sve_##name##_zpzz_b, gen_helper_sve_##name##_zpzz_h, \ - gen_helper_sve_##name##_zpzz_s, gen_helper_sve_##name##_zpzz_d, \ +#define DO_ZPZZ(NAME, FEAT, name) \ + static gen_helper_gvec_4 * const name##_zpzz_fns[4] = { \ + gen_helper_##name##_zpzz_b, gen_helper_##name##_zpzz_h, \ + gen_helper_##name##_zpzz_s, gen_helper_##name##_zpzz_d, \ }; \ - return gen_gvec_ool_arg_zpzz(s, fns[a->esz], a, 0); \ -} + TRANS_FEAT(NAME, FEAT, gen_gvec_ool_arg_zpzz, \ + name##_zpzz_fns[a->esz], a, 0) -DO_ZPZZ(AND, and) -DO_ZPZZ(EOR, eor) -DO_ZPZZ(ORR, orr) -DO_ZPZZ(BIC, bic) +DO_ZPZZ(AND_zpzz, aa64_sve, sve_and) +DO_ZPZZ(EOR_zpzz, aa64_sve, sve_eor) +DO_ZPZZ(ORR_zpzz, aa64_sve, sve_orr) +DO_ZPZZ(BIC_zpzz, aa64_sve, sve_bic) -DO_ZPZZ(ADD, add) -DO_ZPZZ(SUB, sub) +DO_ZPZZ(ADD_zpzz, aa64_sve, sve_add) +DO_ZPZZ(SUB_zpzz, aa64_sve, sve_sub) -DO_ZPZZ(SMAX, smax) -DO_ZPZZ(UMAX, umax) -DO_ZPZZ(SMIN, smin) -DO_ZPZZ(UMIN, umin) -DO_ZPZZ(SABD, sabd) -DO_ZPZZ(UABD, uabd) +DO_ZPZZ(SMAX_zpzz, aa64_sve, sve_smax) +DO_ZPZZ(UMAX_zpzz, aa64_sve, sve_umax) +DO_ZPZZ(SMIN_zpzz, aa64_sve, sve_smin) +DO_ZPZZ(UMIN_zpzz, aa64_sve, sve_umin) +DO_ZPZZ(SABD_zpzz, aa64_sve, sve_sabd) +DO_ZPZZ(UABD_zpzz, aa64_sve, sve_uabd) -DO_ZPZZ(MUL, mul) -DO_ZPZZ(SMULH, smulh) -DO_ZPZZ(UMULH, umulh) +DO_ZPZZ(MUL_zpzz, aa64_sve, sve_mul) +DO_ZPZZ(SMULH_zpzz, aa64_sve, sve_smulh) +DO_ZPZZ(UMULH_zpzz, aa64_sve, sve_umulh) -DO_ZPZZ(ASR, asr) -DO_ZPZZ(LSR, lsr) -DO_ZPZZ(LSL, lsl) +DO_ZPZZ(ASR_zpzz, aa64_sve, sve_asr) +DO_ZPZZ(LSR_zpzz, aa64_sve, sve_lsr) +DO_ZPZZ(LSL_zpzz, aa64_sve, sve_lsl) -static bool trans_SDIV_zpzz(DisasContext *s, arg_rprr_esz *a) -{ - static gen_helper_gvec_4 * const fns[4] = { - NULL, NULL, gen_helper_sve_sdiv_zpzz_s, gen_helper_sve_sdiv_zpzz_d - }; - return gen_gvec_ool_arg_zpzz(s, fns[a->esz], a, 0); -} +static gen_helper_gvec_4 * const sdiv_fns[4] = { + NULL, NULL, gen_helper_sve_sdiv_zpzz_s, gen_helper_sve_sdiv_zpzz_d +}; +TRANS_FEAT(SDIV_zpzz, aa64_sve, gen_gvec_ool_arg_zpzz, sdiv_fns[a->esz], a, 0) -static bool trans_UDIV_zpzz(DisasContext *s, arg_rprr_esz *a) -{ - static gen_helper_gvec_4 * const fns[4] = { - NULL, NULL, gen_helper_sve_udiv_zpzz_s, gen_helper_sve_udiv_zpzz_d - }; - return gen_gvec_ool_arg_zpzz(s, fns[a->esz], a, 0); -} +static gen_helper_gvec_4 * const udiv_fns[4] = { + NULL, NULL, gen_helper_sve_udiv_zpzz_s, gen_helper_sve_udiv_zpzz_d +}; +TRANS_FEAT(UDIV_zpzz, aa64_sve, gen_gvec_ool_arg_zpzz, udiv_fns[a->esz], a, 0) static bool trans_SEL_zpzz(DisasContext *s, arg_rprr_esz *a) { @@ -1068,17 +1060,12 @@ TRANS_FEAT(SQSHLU, aa64_sve2, gen_gvec_ool_arg_zpzi, */ #define DO_ZPZW(NAME, name) \ -static bool trans_##NAME##_zpzw(DisasContext *s, arg_rprr_esz *a) \ -{ \ - static gen_helper_gvec_4 * const fns[3] = { \ + static gen_helper_gvec_4 * const name##_zpzw_fns[4] = { \ gen_helper_sve_##name##_zpzw_b, gen_helper_sve_##name##_zpzw_h, \ - gen_helper_sve_##name##_zpzw_s, \ + gen_helper_sve_##name##_zpzw_s, NULL \ }; \ - if (a->esz < 0 || a->esz >= 3) { \ - return false; \ - } \ - return gen_gvec_ool_arg_zpzz(s, fns[a->esz], a, 0); \ -} + TRANS_FEAT(NAME##_zpzw, aa64_sve, gen_gvec_ool_arg_zpzz, \ + a->esz < 0 ? NULL : name##_zpzw_fns[a->esz], a, 0) DO_ZPZW(ASR, asr) DO_ZPZW(LSR, lsr) From 5880bdc03e4ee90b08c1e8242254920d1fac7512 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:41 -0700 Subject: [PATCH 613/935] target/arm: Use TRANS_FEAT for do_sve2_zpzz_ool Convert SVE translation functions using do_sve2_zpzz_ool to use TRANS_FEAT and gen_gvec_ool_arg_zpzz. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-29-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 118 +++++++++++++------------------------ 1 file changed, 40 insertions(+), 78 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index f8277eeb7c..0a69a1ef65 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -804,8 +804,6 @@ static bool trans_SEL_zpzz(DisasContext *s, arg_rprr_esz *a) return true; } -#undef DO_ZPZZ - /* *** SVE Integer Arithmetic - Unary Predicated Group */ @@ -6471,40 +6469,19 @@ TRANS_FEAT(SQRDMULH_zzz, aa64_sve2, gen_gvec_ool_arg_zzz, * SVE2 Integer - Predicated */ -static bool do_sve2_zpzz_ool(DisasContext *s, arg_rprr_esz *a, - gen_helper_gvec_4 *fn) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_ool_arg_zpzz(s, fn, a, 0); -} +static gen_helper_gvec_4 * const sadlp_fns[4] = { + NULL, gen_helper_sve2_sadalp_zpzz_h, + gen_helper_sve2_sadalp_zpzz_s, gen_helper_sve2_sadalp_zpzz_d, +}; +TRANS_FEAT(SADALP_zpzz, aa64_sve2, gen_gvec_ool_arg_zpzz, + sadlp_fns[a->esz], a, 0) -static bool trans_SADALP_zpzz(DisasContext *s, arg_rprr_esz *a) -{ - static gen_helper_gvec_4 * const fns[3] = { - gen_helper_sve2_sadalp_zpzz_h, - gen_helper_sve2_sadalp_zpzz_s, - gen_helper_sve2_sadalp_zpzz_d, - }; - if (a->esz == 0) { - return false; - } - return do_sve2_zpzz_ool(s, a, fns[a->esz - 1]); -} - -static bool trans_UADALP_zpzz(DisasContext *s, arg_rprr_esz *a) -{ - static gen_helper_gvec_4 * const fns[3] = { - gen_helper_sve2_uadalp_zpzz_h, - gen_helper_sve2_uadalp_zpzz_s, - gen_helper_sve2_uadalp_zpzz_d, - }; - if (a->esz == 0) { - return false; - } - return do_sve2_zpzz_ool(s, a, fns[a->esz - 1]); -} +static gen_helper_gvec_4 * const uadlp_fns[4] = { + NULL, gen_helper_sve2_uadalp_zpzz_h, + gen_helper_sve2_uadalp_zpzz_s, gen_helper_sve2_uadalp_zpzz_d, +}; +TRANS_FEAT(UADALP_zpzz, aa64_sve2, gen_gvec_ool_arg_zpzz, + uadlp_fns[a->esz], a, 0) /* * SVE2 integer unary operations (predicated) @@ -6528,44 +6505,34 @@ static gen_helper_gvec_3 * const sqneg_fns[4] = { }; TRANS_FEAT(SQNEG, aa64_sve2, gen_gvec_ool_arg_zpz, sqneg_fns[a->esz], a, 0) -#define DO_SVE2_ZPZZ(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rprr_esz *a) \ -{ \ - static gen_helper_gvec_4 * const fns[4] = { \ - gen_helper_sve2_##name##_zpzz_b, gen_helper_sve2_##name##_zpzz_h, \ - gen_helper_sve2_##name##_zpzz_s, gen_helper_sve2_##name##_zpzz_d, \ - }; \ - return do_sve2_zpzz_ool(s, a, fns[a->esz]); \ -} +DO_ZPZZ(SQSHL, aa64_sve2, sve2_sqshl) +DO_ZPZZ(SQRSHL, aa64_sve2, sve2_sqrshl) +DO_ZPZZ(SRSHL, aa64_sve2, sve2_srshl) -DO_SVE2_ZPZZ(SQSHL, sqshl) -DO_SVE2_ZPZZ(SQRSHL, sqrshl) -DO_SVE2_ZPZZ(SRSHL, srshl) +DO_ZPZZ(UQSHL, aa64_sve2, sve2_uqshl) +DO_ZPZZ(UQRSHL, aa64_sve2, sve2_uqrshl) +DO_ZPZZ(URSHL, aa64_sve2, sve2_urshl) -DO_SVE2_ZPZZ(UQSHL, uqshl) -DO_SVE2_ZPZZ(UQRSHL, uqrshl) -DO_SVE2_ZPZZ(URSHL, urshl) +DO_ZPZZ(SHADD, aa64_sve2, sve2_shadd) +DO_ZPZZ(SRHADD, aa64_sve2, sve2_srhadd) +DO_ZPZZ(SHSUB, aa64_sve2, sve2_shsub) -DO_SVE2_ZPZZ(SHADD, shadd) -DO_SVE2_ZPZZ(SRHADD, srhadd) -DO_SVE2_ZPZZ(SHSUB, shsub) +DO_ZPZZ(UHADD, aa64_sve2, sve2_uhadd) +DO_ZPZZ(URHADD, aa64_sve2, sve2_urhadd) +DO_ZPZZ(UHSUB, aa64_sve2, sve2_uhsub) -DO_SVE2_ZPZZ(UHADD, uhadd) -DO_SVE2_ZPZZ(URHADD, urhadd) -DO_SVE2_ZPZZ(UHSUB, uhsub) +DO_ZPZZ(ADDP, aa64_sve2, sve2_addp) +DO_ZPZZ(SMAXP, aa64_sve2, sve2_smaxp) +DO_ZPZZ(UMAXP, aa64_sve2, sve2_umaxp) +DO_ZPZZ(SMINP, aa64_sve2, sve2_sminp) +DO_ZPZZ(UMINP, aa64_sve2, sve2_uminp) -DO_SVE2_ZPZZ(ADDP, addp) -DO_SVE2_ZPZZ(SMAXP, smaxp) -DO_SVE2_ZPZZ(UMAXP, umaxp) -DO_SVE2_ZPZZ(SMINP, sminp) -DO_SVE2_ZPZZ(UMINP, uminp) - -DO_SVE2_ZPZZ(SQADD_zpzz, sqadd) -DO_SVE2_ZPZZ(UQADD_zpzz, uqadd) -DO_SVE2_ZPZZ(SQSUB_zpzz, sqsub) -DO_SVE2_ZPZZ(UQSUB_zpzz, uqsub) -DO_SVE2_ZPZZ(SUQADD, suqadd) -DO_SVE2_ZPZZ(USQADD, usqadd) +DO_ZPZZ(SQADD_zpzz, aa64_sve2, sve2_sqadd) +DO_ZPZZ(UQADD_zpzz, aa64_sve2, sve2_uqadd) +DO_ZPZZ(SQSUB_zpzz, aa64_sve2, sve2_sqsub) +DO_ZPZZ(UQSUB_zpzz, aa64_sve2, sve2_uqsub) +DO_ZPZZ(SUQADD, aa64_sve2, sve2_suqadd) +DO_ZPZZ(USQADD, aa64_sve2, sve2_usqadd) /* * SVE2 Widening Integer Arithmetic @@ -7735,16 +7702,11 @@ static bool trans_##NAME(DisasContext *s, arg_rprr_esz *a) \ DO_SVE2_PPZZ_MATCH(MATCH, match) DO_SVE2_PPZZ_MATCH(NMATCH, nmatch) -static bool trans_HISTCNT(DisasContext *s, arg_rprr_esz *a) -{ - static gen_helper_gvec_4 * const fns[2] = { - gen_helper_sve2_histcnt_s, gen_helper_sve2_histcnt_d - }; - if (a->esz < 2) { - return false; - } - return do_sve2_zpzz_ool(s, a, fns[a->esz - 2]); -} +static gen_helper_gvec_4 * const histcnt_fns[4] = { + NULL, NULL, gen_helper_sve2_histcnt_s, gen_helper_sve2_histcnt_d +}; +TRANS_FEAT(HISTCNT, aa64_sve2, gen_gvec_ool_arg_zpzz, + histcnt_fns[a->esz], a, 0) TRANS_FEAT(HISTSEG, aa64_sve2, gen_gvec_ool_arg_zzz, a->esz == 0 ? gen_helper_sve2_histseg : NULL, a, 0) From 5f730621ea285cc1f45c03baac8adb86632e0904 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:42 -0700 Subject: [PATCH 614/935] target/arm: Merge gen_gvec_fn_zz into do_mov_z There is only one caller for gen_gvec_fn_zz; inline it. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-30-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 0a69a1ef65..5ab9de46a7 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -258,15 +258,6 @@ static bool gen_gvec_ool_arg_zpzz(DisasContext *s, gen_helper_gvec_4 *fn, return gen_gvec_ool_zzzp(s, fn, a->rd, a->rn, a->rm, a->pg, data); } -/* Invoke a vector expander on two Zregs. */ -static void gen_gvec_fn_zz(DisasContext *s, GVecGen2Fn *gvec_fn, - int esz, int rd, int rn) -{ - unsigned vsz = vec_full_reg_size(s); - gvec_fn(esz, vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), vsz, vsz); -} - /* Invoke a vector expander on three Zregs. */ static void gen_gvec_fn_zzz(DisasContext *s, GVecGen3Fn *gvec_fn, int esz, int rd, int rn, int rm) @@ -292,7 +283,9 @@ static void gen_gvec_fn_zzzz(DisasContext *s, GVecGen4Fn *gvec_fn, static bool do_mov_z(DisasContext *s, int rd, int rn) { if (sve_access_check(s)) { - gen_gvec_fn_zz(s, tcg_gen_gvec_mov, MO_8, rd, rn); + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_mov(MO_8, vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), vsz, vsz); } return true; } From 50f6db5f23e2a837a98a97cc388de9afc46fae2f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:43 -0700 Subject: [PATCH 615/935] target/arm: Move null function and sve check into gen_gvec_fn_zzz Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-31-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 5ab9de46a7..3af4626e58 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -259,13 +259,19 @@ static bool gen_gvec_ool_arg_zpzz(DisasContext *s, gen_helper_gvec_4 *fn, } /* Invoke a vector expander on three Zregs. */ -static void gen_gvec_fn_zzz(DisasContext *s, GVecGen3Fn *gvec_fn, +static bool gen_gvec_fn_zzz(DisasContext *s, GVecGen3Fn *gvec_fn, int esz, int rd, int rn, int rm) { - unsigned vsz = vec_full_reg_size(s); - gvec_fn(esz, vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), vsz, vsz); + if (gvec_fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + gvec_fn(esz, vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), vsz, vsz); + } + return true; } /* Invoke a vector expander on four Zregs. */ @@ -366,10 +372,7 @@ const uint64_t pred_esz_masks[4] = { static bool do_zzz_fn(DisasContext *s, arg_rrr_esz *a, GVecGen3Fn *gvec_fn) { - if (sve_access_check(s)) { - gen_gvec_fn_zzz(s, gvec_fn, a->esz, a->rd, a->rn, a->rm); - } - return true; + return gen_gvec_fn_zzz(s, gvec_fn, a->esz, a->rd, a->rn, a->rm); } static bool trans_AND_zzz(DisasContext *s, arg_rrr_esz *a) @@ -6421,10 +6424,7 @@ static bool trans_MUL_zzz(DisasContext *s, arg_rrr_esz *a) if (!dc_isar_feature(aa64_sve2, s)) { return false; } - if (sve_access_check(s)) { - gen_gvec_fn_zzz(s, tcg_gen_gvec_mul, a->esz, a->rd, a->rn, a->rm); - } - return true; + return gen_gvec_fn_zzz(s, tcg_gen_gvec_mul, a->esz, a->rd, a->rn, a->rm); } static gen_helper_gvec_3 * const smulh_zzz_fns[4] = { @@ -6945,10 +6945,7 @@ static bool do_sve2_fn_zzz(DisasContext *s, arg_rrr_esz *a, GVecGen3Fn *fn) if (!dc_isar_feature(aa64_sve2, s)) { return false; } - if (sve_access_check(s)) { - gen_gvec_fn_zzz(s, fn, a->esz, a->rd, a->rn, a->rm); - } - return true; + return gen_gvec_fn_zzz(s, fn, a->esz, a->rd, a->rn, a->rm); } static bool trans_SABA(DisasContext *s, arg_rrr_esz *a) @@ -7880,10 +7877,7 @@ static bool trans_RAX1(DisasContext *s, arg_rrr_esz *a) if (!dc_isar_feature(aa64_sve2_sha3, s)) { return false; } - if (sve_access_check(s)) { - gen_gvec_fn_zzz(s, gen_gvec_rax1, MO_64, a->rd, a->rn, a->rm); - } - return true; + return gen_gvec_fn_zzz(s, gen_gvec_rax1, MO_64, a->rd, a->rn, a->rm); } static bool trans_FCVTNT_sh(DisasContext *s, arg_rpr_esz *a) From cd54bbe66288a75073fbb67d12d1300876390b02 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:44 -0700 Subject: [PATCH 616/935] target/arm: Rename do_zzz_fn to gen_gvec_fn_arg_zzz Rename the function to match gen_gvec_fn_zzz, and move to be adjacent. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-32-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 3af4626e58..1b3afcc24c 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -274,6 +274,12 @@ static bool gen_gvec_fn_zzz(DisasContext *s, GVecGen3Fn *gvec_fn, return true; } +static bool gen_gvec_fn_arg_zzz(DisasContext *s, GVecGen3Fn *fn, + arg_rrr_esz *a) +{ + return gen_gvec_fn_zzz(s, fn, a->esz, a->rd, a->rn, a->rm); +} + /* Invoke a vector expander on four Zregs. */ static void gen_gvec_fn_zzzz(DisasContext *s, GVecGen4Fn *gvec_fn, int esz, int rd, int rn, int rm, int ra) @@ -370,29 +376,24 @@ const uint64_t pred_esz_masks[4] = { *** SVE Logical - Unpredicated Group */ -static bool do_zzz_fn(DisasContext *s, arg_rrr_esz *a, GVecGen3Fn *gvec_fn) -{ - return gen_gvec_fn_zzz(s, gvec_fn, a->esz, a->rd, a->rn, a->rm); -} - static bool trans_AND_zzz(DisasContext *s, arg_rrr_esz *a) { - return do_zzz_fn(s, a, tcg_gen_gvec_and); + return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_and, a); } static bool trans_ORR_zzz(DisasContext *s, arg_rrr_esz *a) { - return do_zzz_fn(s, a, tcg_gen_gvec_or); + return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_or, a); } static bool trans_EOR_zzz(DisasContext *s, arg_rrr_esz *a) { - return do_zzz_fn(s, a, tcg_gen_gvec_xor); + return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_xor, a); } static bool trans_BIC_zzz(DisasContext *s, arg_rrr_esz *a) { - return do_zzz_fn(s, a, tcg_gen_gvec_andc); + return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_andc, a); } static void gen_xar8_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, int64_t sh) @@ -707,32 +708,32 @@ static bool trans_NBSL(DisasContext *s, arg_rrrr_esz *a) static bool trans_ADD_zzz(DisasContext *s, arg_rrr_esz *a) { - return do_zzz_fn(s, a, tcg_gen_gvec_add); + return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_add, a); } static bool trans_SUB_zzz(DisasContext *s, arg_rrr_esz *a) { - return do_zzz_fn(s, a, tcg_gen_gvec_sub); + return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_sub, a); } static bool trans_SQADD_zzz(DisasContext *s, arg_rrr_esz *a) { - return do_zzz_fn(s, a, tcg_gen_gvec_ssadd); + return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_ssadd, a); } static bool trans_SQSUB_zzz(DisasContext *s, arg_rrr_esz *a) { - return do_zzz_fn(s, a, tcg_gen_gvec_sssub); + return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_sssub, a); } static bool trans_UQADD_zzz(DisasContext *s, arg_rrr_esz *a) { - return do_zzz_fn(s, a, tcg_gen_gvec_usadd); + return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_usadd, a); } static bool trans_UQSUB_zzz(DisasContext *s, arg_rrr_esz *a) { - return do_zzz_fn(s, a, tcg_gen_gvec_ussub); + return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_ussub, a); } /* From f96aae7649cca25b427b80d6cc9e67a617af6795 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:45 -0700 Subject: [PATCH 617/935] target/arm: More use of gen_gvec_fn_arg_zzz Two uses of gen_gvec_fn_zzz can pass on arg_rrr_esz instead. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-33-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 1b3afcc24c..2dbf296128 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -6425,7 +6425,7 @@ static bool trans_MUL_zzz(DisasContext *s, arg_rrr_esz *a) if (!dc_isar_feature(aa64_sve2, s)) { return false; } - return gen_gvec_fn_zzz(s, tcg_gen_gvec_mul, a->esz, a->rd, a->rn, a->rm); + return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_mul, a); } static gen_helper_gvec_3 * const smulh_zzz_fns[4] = { @@ -6946,7 +6946,7 @@ static bool do_sve2_fn_zzz(DisasContext *s, arg_rrr_esz *a, GVecGen3Fn *fn) if (!dc_isar_feature(aa64_sve2, s)) { return false; } - return gen_gvec_fn_zzz(s, fn, a->esz, a->rd, a->rn, a->rm); + return gen_gvec_fn_arg_zzz(s, fn, a); } static bool trans_SABA(DisasContext *s, arg_rrr_esz *a) From b262215bf3eb90e06101c94c886691cc4f7776a0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:46 -0700 Subject: [PATCH 618/935] target/arm: Use TRANS_FEAT for gen_gvec_fn_arg_zzz Convert SVE translation functions directly using gen_gvec_fn_arg_zzz to TRANS_FEAT. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-34-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 66 +++++++------------------------------- 1 file changed, 11 insertions(+), 55 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 2dbf296128..ddb34cad8e 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -376,25 +376,10 @@ const uint64_t pred_esz_masks[4] = { *** SVE Logical - Unpredicated Group */ -static bool trans_AND_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_and, a); -} - -static bool trans_ORR_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_or, a); -} - -static bool trans_EOR_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_xor, a); -} - -static bool trans_BIC_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_andc, a); -} +TRANS_FEAT(AND_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_and, a) +TRANS_FEAT(ORR_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_or, a) +TRANS_FEAT(EOR_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_xor, a) +TRANS_FEAT(BIC_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_andc, a) static void gen_xar8_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, int64_t sh) { @@ -706,35 +691,12 @@ static bool trans_NBSL(DisasContext *s, arg_rrrr_esz *a) *** SVE Integer Arithmetic - Unpredicated Group */ -static bool trans_ADD_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_add, a); -} - -static bool trans_SUB_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_sub, a); -} - -static bool trans_SQADD_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_ssadd, a); -} - -static bool trans_SQSUB_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_sssub, a); -} - -static bool trans_UQADD_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_usadd, a); -} - -static bool trans_UQSUB_zzz(DisasContext *s, arg_rrr_esz *a) -{ - return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_ussub, a); -} +TRANS_FEAT(ADD_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_add, a) +TRANS_FEAT(SUB_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_sub, a) +TRANS_FEAT(SQADD_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_ssadd, a) +TRANS_FEAT(SQSUB_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_sssub, a) +TRANS_FEAT(UQADD_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_usadd, a) +TRANS_FEAT(UQSUB_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_ussub, a) /* *** SVE Integer Arithmetic - Binary Predicated Group @@ -6420,13 +6382,7 @@ static bool trans_MOVPRFX_z(DisasContext *s, arg_rpr_esz *a) * SVE2 Integer Multiply - Unpredicated */ -static bool trans_MUL_zzz(DisasContext *s, arg_rrr_esz *a) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_fn_arg_zzz(s, tcg_gen_gvec_mul, a); -} +TRANS_FEAT(MUL_zzz, aa64_sve2, gen_gvec_fn_arg_zzz, tcg_gen_gvec_mul, a) static gen_helper_gvec_3 * const smulh_zzz_fns[4] = { gen_helper_gvec_smulh_b, gen_helper_gvec_smulh_h, From 79828dcbf5a497e83d350a2f8f8e61429fc60c89 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:47 -0700 Subject: [PATCH 619/935] target/arm: Use TRANS_FEAT for do_sve2_fn_zzz Convert SVE translation functions using do_sve2_fn_zzz to use TRANS_FEAT and gen_gvec_fn_arg_zzz. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-35-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index ddb34cad8e..e92fef2304 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -6897,23 +6897,8 @@ static bool trans_SLI(DisasContext *s, arg_rri_esz *a) return do_sve2_fn2i(s, a, gen_gvec_sli); } -static bool do_sve2_fn_zzz(DisasContext *s, arg_rrr_esz *a, GVecGen3Fn *fn) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_fn_arg_zzz(s, fn, a); -} - -static bool trans_SABA(DisasContext *s, arg_rrr_esz *a) -{ - return do_sve2_fn_zzz(s, a, gen_gvec_saba); -} - -static bool trans_UABA(DisasContext *s, arg_rrr_esz *a) -{ - return do_sve2_fn_zzz(s, a, gen_gvec_uaba); -} +TRANS_FEAT(SABA, aa64_sve2, gen_gvec_fn_arg_zzz, gen_gvec_saba, a) +TRANS_FEAT(UABA, aa64_sve2, gen_gvec_fn_arg_zzz, gen_gvec_uaba, a) static bool do_sve2_narrow_extract(DisasContext *s, arg_rri_esz *a, const GVecGen2 ops[3]) From 2aa469ff5fde3f1c59b14ddf48d58018e2f03982 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:48 -0700 Subject: [PATCH 620/935] target/arm: Use TRANS_FEAT for RAX1 The decode for RAX1 sets esz to MO_8, because that's what we use by default for "no esz present". We changed that to MO_64 during translation because it is more logical for the operation. However, the esz argument to gen_gvec_rax1 is unused and forces MO_64 within that function, so there is no need to do it here as well. Simplify to use gen_gvec_fn_arg_zzz and TRANS_FEAT. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-36-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index e92fef2304..36d739d7b2 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -7814,13 +7814,7 @@ TRANS_FEAT(SM4E, aa64_sve2_sm4, gen_gvec_ool_arg_zzz, TRANS_FEAT(SM4EKEY, aa64_sve2_sm4, gen_gvec_ool_arg_zzz, gen_helper_crypto_sm4ekey, a, 0) -static bool trans_RAX1(DisasContext *s, arg_rrr_esz *a) -{ - if (!dc_isar_feature(aa64_sve2_sha3, s)) { - return false; - } - return gen_gvec_fn_zzz(s, gen_gvec_rax1, MO_64, a->rd, a->rn, a->rm); -} +TRANS_FEAT(RAX1, aa64_sve2_sha3, gen_gvec_fn_arg_zzz, gen_gvec_rax1, a) static bool trans_FCVTNT_sh(DisasContext *s, arg_rpr_esz *a) { From 189876af9cf33fff1de5ad16d0537ed2417ead97 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:49 -0700 Subject: [PATCH 621/935] target/arm: Introduce gen_gvec_fn_arg_zzzz Merge gen_gvec_fn_zzzz with the sve access check and the dereference of arg_rrrr_esz. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-37-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 36d739d7b2..e0b083f861 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -281,14 +281,20 @@ static bool gen_gvec_fn_arg_zzz(DisasContext *s, GVecGen3Fn *fn, } /* Invoke a vector expander on four Zregs. */ -static void gen_gvec_fn_zzzz(DisasContext *s, GVecGen4Fn *gvec_fn, - int esz, int rd, int rn, int rm, int ra) +static bool gen_gvec_fn_arg_zzzz(DisasContext *s, GVecGen4Fn *gvec_fn, + arg_rrrr_esz *a) { - unsigned vsz = vec_full_reg_size(s); - gvec_fn(esz, vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), - vec_full_reg_offset(s, ra), vsz, vsz); + if (gvec_fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + gvec_fn(a->esz, vec_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + vec_full_reg_offset(s, a->rm), + vec_full_reg_offset(s, a->ra), vsz, vsz); + } + return true; } /* Invoke a vector move on two Zregs. */ @@ -490,10 +496,7 @@ static bool do_sve2_zzzz_fn(DisasContext *s, arg_rrrr_esz *a, GVecGen4Fn *fn) if (!dc_isar_feature(aa64_sve2, s)) { return false; } - if (sve_access_check(s)) { - gen_gvec_fn_zzzz(s, fn, a->esz, a->rd, a->rn, a->rm, a->ra); - } - return true; + return gen_gvec_fn_arg_zzzz(s, fn, a); } static void gen_eor3_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, TCGv_i64 k) From b773a5c8080f67faeace1169f6a4770eb45646c3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:50 -0700 Subject: [PATCH 622/935] target/arm: Use TRANS_FEAT for do_sve2_zzzz_fn Convert SVE translation functions using do_sve2_zzzz_fn to use TRANS_FEAT and gen_gvec_fn_arg_zzzz. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-38-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 38 ++++++-------------------------------- 1 file changed, 6 insertions(+), 32 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index e0b083f861..f89c78a23e 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -491,14 +491,6 @@ static bool trans_XAR(DisasContext *s, arg_rrri_esz *a) return true; } -static bool do_sve2_zzzz_fn(DisasContext *s, arg_rrrr_esz *a, GVecGen4Fn *fn) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_fn_arg_zzzz(s, fn, a); -} - static void gen_eor3_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, TCGv_i64 k) { tcg_gen_xor_i64(d, n, m); @@ -525,10 +517,7 @@ static void gen_eor3(unsigned vece, uint32_t d, uint32_t n, uint32_t m, tcg_gen_gvec_4(d, n, m, a, oprsz, maxsz, &op); } -static bool trans_EOR3(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sve2_zzzz_fn(s, a, gen_eor3); -} +TRANS_FEAT(EOR3, aa64_sve2, gen_gvec_fn_arg_zzzz, gen_eor3, a) static void gen_bcax_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, TCGv_i64 k) { @@ -556,10 +545,7 @@ static void gen_bcax(unsigned vece, uint32_t d, uint32_t n, uint32_t m, tcg_gen_gvec_4(d, n, m, a, oprsz, maxsz, &op); } -static bool trans_BCAX(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sve2_zzzz_fn(s, a, gen_bcax); -} +TRANS_FEAT(BCAX, aa64_sve2, gen_gvec_fn_arg_zzzz, gen_bcax, a) static void gen_bsl(unsigned vece, uint32_t d, uint32_t n, uint32_t m, uint32_t a, uint32_t oprsz, uint32_t maxsz) @@ -568,10 +554,7 @@ static void gen_bsl(unsigned vece, uint32_t d, uint32_t n, uint32_t m, tcg_gen_gvec_bitsel(vece, d, a, n, m, oprsz, maxsz); } -static bool trans_BSL(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sve2_zzzz_fn(s, a, gen_bsl); -} +TRANS_FEAT(BSL, aa64_sve2, gen_gvec_fn_arg_zzzz, gen_bsl, a) static void gen_bsl1n_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, TCGv_i64 k) { @@ -606,10 +589,7 @@ static void gen_bsl1n(unsigned vece, uint32_t d, uint32_t n, uint32_t m, tcg_gen_gvec_4(d, n, m, a, oprsz, maxsz, &op); } -static bool trans_BSL1N(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sve2_zzzz_fn(s, a, gen_bsl1n); -} +TRANS_FEAT(BSL1N, aa64_sve2, gen_gvec_fn_arg_zzzz, gen_bsl1n, a) static void gen_bsl2n_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, TCGv_i64 k) { @@ -653,10 +633,7 @@ static void gen_bsl2n(unsigned vece, uint32_t d, uint32_t n, uint32_t m, tcg_gen_gvec_4(d, n, m, a, oprsz, maxsz, &op); } -static bool trans_BSL2N(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sve2_zzzz_fn(s, a, gen_bsl2n); -} +TRANS_FEAT(BSL2N, aa64_sve2, gen_gvec_fn_arg_zzzz, gen_bsl2n, a) static void gen_nbsl_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, TCGv_i64 k) { @@ -685,10 +662,7 @@ static void gen_nbsl(unsigned vece, uint32_t d, uint32_t n, uint32_t m, tcg_gen_gvec_4(d, n, m, a, oprsz, maxsz, &op); } -static bool trans_NBSL(DisasContext *s, arg_rrrr_esz *a) -{ - return do_sve2_zzzz_fn(s, a, gen_nbsl); -} +TRANS_FEAT(NBSL, aa64_sve2, gen_gvec_fn_arg_zzzz, gen_nbsl, a) /* *** SVE Integer Arithmetic - Unpredicated Group From faf915e2a162bb679b4054d931ce3b464459be79 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:51 -0700 Subject: [PATCH 623/935] target/arm: Introduce gen_gvec_fn_zzi We have two places that perform this particular operation. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-39-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index f89c78a23e..7938c5393e 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -258,6 +258,21 @@ static bool gen_gvec_ool_arg_zpzz(DisasContext *s, gen_helper_gvec_4 *fn, return gen_gvec_ool_zzzp(s, fn, a->rd, a->rn, a->rm, a->pg, data); } +/* Invoke a vector expander on two Zregs and an immediate. */ +static bool gen_gvec_fn_zzi(DisasContext *s, GVecGen2iFn *gvec_fn, + int esz, int rd, int rn, uint64_t imm) +{ + if (gvec_fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + gvec_fn(esz, vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), imm, vsz, vsz); + } + return true; +} + /* Invoke a vector expander on three Zregs. */ static bool gen_gvec_fn_zzz(DisasContext *s, GVecGen3Fn *gvec_fn, int esz, int rd, int rn, int rm) @@ -2028,12 +2043,7 @@ static bool do_zz_dbm(DisasContext *s, arg_rr_dbm *a, GVecGen2iFn *gvec_fn) extract32(a->dbm, 6, 6))) { return false; } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - gvec_fn(MO_64, vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), imm, vsz, vsz); - } - return true; + return gen_gvec_fn_zzi(s, gvec_fn, MO_64, a->rd, a->rn, imm); } static bool trans_AND_zzi(DisasContext *s, arg_rr_dbm *a) @@ -6835,13 +6845,7 @@ static bool do_sve2_fn2i(DisasContext *s, arg_rri_esz *a, GVecGen2iFn *fn) if (a->esz < 0 || !dc_isar_feature(aa64_sve2, s)) { return false; } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - unsigned rd_ofs = vec_full_reg_offset(s, a->rd); - unsigned rn_ofs = vec_full_reg_offset(s, a->rn); - fn(a->esz, rd_ofs, rn_ofs, a->imm, vsz, vsz); - } - return true; + return gen_gvec_fn_zzi(s, fn, a->esz, a->rd, a->rn, a->imm); } static bool trans_SSRA(DisasContext *s, arg_rri_esz *a) From 15a314dad5898eef560456d084c245881290e8e2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:52 -0700 Subject: [PATCH 624/935] target/arm: Use TRANS_FEAT for do_zz_dbm Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-40-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 7938c5393e..6fa721eca6 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -2046,20 +2046,9 @@ static bool do_zz_dbm(DisasContext *s, arg_rr_dbm *a, GVecGen2iFn *gvec_fn) return gen_gvec_fn_zzi(s, gvec_fn, MO_64, a->rd, a->rn, imm); } -static bool trans_AND_zzi(DisasContext *s, arg_rr_dbm *a) -{ - return do_zz_dbm(s, a, tcg_gen_gvec_andi); -} - -static bool trans_ORR_zzi(DisasContext *s, arg_rr_dbm *a) -{ - return do_zz_dbm(s, a, tcg_gen_gvec_ori); -} - -static bool trans_EOR_zzi(DisasContext *s, arg_rr_dbm *a) -{ - return do_zz_dbm(s, a, tcg_gen_gvec_xori); -} +TRANS_FEAT(AND_zzi, aa64_sve, do_zz_dbm, a, tcg_gen_gvec_andi) +TRANS_FEAT(ORR_zzi, aa64_sve, do_zz_dbm, a, tcg_gen_gvec_ori) +TRANS_FEAT(EOR_zzi, aa64_sve, do_zz_dbm, a, tcg_gen_gvec_xori) static bool trans_DUPM(DisasContext *s, arg_DUPM *a) { From 68cc4ee3f98bbc13224582e13f87db04e4be016a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:53 -0700 Subject: [PATCH 625/935] target/arm: Hoist sve access check through do_sel_z The check is already done in gen_gvec_ool_zzzp, which is called by do_sel_z; remove from callers. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-41-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 6fa721eca6..62bfc6fe7c 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -697,13 +697,13 @@ TRANS_FEAT(UQSUB_zzz, aa64_sve, gen_gvec_fn_arg_zzz, tcg_gen_gvec_ussub, a) /* Select active elememnts from Zn and inactive elements from Zm, * storing the result in Zd. */ -static void do_sel_z(DisasContext *s, int rd, int rn, int rm, int pg, int esz) +static bool do_sel_z(DisasContext *s, int rd, int rn, int rm, int pg, int esz) { static gen_helper_gvec_4 * const fns[4] = { gen_helper_sve_sel_zpzz_b, gen_helper_sve_sel_zpzz_h, gen_helper_sve_sel_zpzz_s, gen_helper_sve_sel_zpzz_d }; - gen_gvec_ool_zzzp(s, fns[esz], rd, rn, rm, pg, 0); + return gen_gvec_ool_zzzp(s, fns[esz], rd, rn, rm, pg, 0); } #define DO_ZPZZ(NAME, FEAT, name) \ @@ -749,10 +749,7 @@ TRANS_FEAT(UDIV_zpzz, aa64_sve, gen_gvec_ool_arg_zpzz, udiv_fns[a->esz], a, 0) static bool trans_SEL_zpzz(DisasContext *s, arg_rprr_esz *a) { - if (sve_access_check(s)) { - do_sel_z(s, a->rd, a->rn, a->rm, a->pg, a->esz); - } - return true; + return do_sel_z(s, a->rd, a->rn, a->rm, a->pg, a->esz); } /* @@ -6343,10 +6340,7 @@ static bool trans_MOVPRFX(DisasContext *s, arg_MOVPRFX *a) static bool trans_MOVPRFX_m(DisasContext *s, arg_rpr_esz *a) { - if (sve_access_check(s)) { - do_sel_z(s, a->rd, a->rn, a->rd, a->pg, a->esz); - } - return true; + return do_sel_z(s, a->rd, a->rn, a->rd, a->pg, a->esz); } static bool trans_MOVPRFX_z(DisasContext *s, arg_rpr_esz *a) From ada378f042edbad9430f0e7c0cfb0f4946ecb370 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:54 -0700 Subject: [PATCH 626/935] target/arm: Introduce gen_gvec_fn_arg_zzi We have two places that perform this particular operation. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-42-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 62bfc6fe7c..7a3b5f137a 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -273,6 +273,16 @@ static bool gen_gvec_fn_zzi(DisasContext *s, GVecGen2iFn *gvec_fn, return true; } +static bool gen_gvec_fn_arg_zzi(DisasContext *s, GVecGen2iFn *gvec_fn, + arg_rri_esz *a) +{ + if (a->esz < 0) { + /* Invalid tsz encoding -- see tszimm_esz. */ + return false; + } + return gen_gvec_fn_zzi(s, gvec_fn, a->esz, a->rd, a->rn, a->imm); +} + /* Invoke a vector expander on three Zregs. */ static bool gen_gvec_fn_zzz(DisasContext *s, GVecGen3Fn *gvec_fn, int esz, int rd, int rn, int rm) @@ -3503,12 +3513,7 @@ static bool trans_ADD_zzi(DisasContext *s, arg_rri_esz *a) if (a->esz == 0 && extract32(s->insn, 13, 1)) { return false; } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_addi(a->esz, vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), a->imm, vsz, vsz); - } - return true; + return gen_gvec_fn_arg_zzi(s, tcg_gen_gvec_addi, a); } static bool trans_SUB_zzi(DisasContext *s, arg_rri_esz *a) @@ -6825,10 +6830,10 @@ TRANS_FEAT(ADCLT, aa64_sve2, do_adcl, a, true) static bool do_sve2_fn2i(DisasContext *s, arg_rri_esz *a, GVecGen2iFn *fn) { - if (a->esz < 0 || !dc_isar_feature(aa64_sve2, s)) { + if (!dc_isar_feature(aa64_sve2, s)) { return false; } - return gen_gvec_fn_zzi(s, fn, a->esz, a->rd, a->rn, a->imm); + return gen_gvec_fn_arg_zzi(s, fn, a); } static bool trans_SSRA(DisasContext *s, arg_rri_esz *a) From f2be26a5fe7b419ac7bdc38e82a1362000ad84c7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:55 -0700 Subject: [PATCH 627/935] target/arm: Use TRANS_FEAT for do_sve2_fn2i Convert SVE translation functions using do_sve2_fn2i to use TRANS_FEAT and gen_gvec_fn_arg_zzi. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-43-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 43 ++++++-------------------------------- 1 file changed, 6 insertions(+), 37 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 7a3b5f137a..911d2e28bf 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -6828,43 +6828,12 @@ static bool do_adcl(DisasContext *s, arg_rrrr_esz *a, bool sel) TRANS_FEAT(ADCLB, aa64_sve2, do_adcl, a, false) TRANS_FEAT(ADCLT, aa64_sve2, do_adcl, a, true) -static bool do_sve2_fn2i(DisasContext *s, arg_rri_esz *a, GVecGen2iFn *fn) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_fn_arg_zzi(s, fn, a); -} - -static bool trans_SSRA(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_fn2i(s, a, gen_gvec_ssra); -} - -static bool trans_USRA(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_fn2i(s, a, gen_gvec_usra); -} - -static bool trans_SRSRA(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_fn2i(s, a, gen_gvec_srsra); -} - -static bool trans_URSRA(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_fn2i(s, a, gen_gvec_ursra); -} - -static bool trans_SRI(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_fn2i(s, a, gen_gvec_sri); -} - -static bool trans_SLI(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_fn2i(s, a, gen_gvec_sli); -} +TRANS_FEAT(SSRA, aa64_sve2, gen_gvec_fn_arg_zzi, gen_gvec_ssra, a) +TRANS_FEAT(USRA, aa64_sve2, gen_gvec_fn_arg_zzi, gen_gvec_usra, a) +TRANS_FEAT(SRSRA, aa64_sve2, gen_gvec_fn_arg_zzi, gen_gvec_srsra, a) +TRANS_FEAT(URSRA, aa64_sve2, gen_gvec_fn_arg_zzi, gen_gvec_ursra, a) +TRANS_FEAT(SRI, aa64_sve2, gen_gvec_fn_arg_zzi, gen_gvec_sri, a) +TRANS_FEAT(SLI, aa64_sve2, gen_gvec_fn_arg_zzi, gen_gvec_sli, a) TRANS_FEAT(SABA, aa64_sve2, gen_gvec_fn_arg_zzz, gen_gvec_saba, a) TRANS_FEAT(UABA, aa64_sve2, gen_gvec_fn_arg_zzz, gen_gvec_uaba, a) From 9ac24f1f350eebb7f3b58bf3365fc9f39c802f43 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:56 -0700 Subject: [PATCH 628/935] target/arm: Use TRANS_FEAT for do_vpz_ool Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-44-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 911d2e28bf..6103bd7f1d 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -858,14 +858,11 @@ static bool do_vpz_ool(DisasContext *s, arg_rpr_esz *a, } #define DO_VPZ(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rpr_esz *a) \ -{ \ - static gen_helper_gvec_reduc * const fns[4] = { \ + static gen_helper_gvec_reduc * const name##_fns[4] = { \ gen_helper_sve_##name##_b, gen_helper_sve_##name##_h, \ gen_helper_sve_##name##_s, gen_helper_sve_##name##_d, \ }; \ - return do_vpz_ool(s, a, fns[a->esz]); \ -} + TRANS_FEAT(NAME, aa64_sve, do_vpz_ool, a, name##_fns[a->esz]) DO_VPZ(ORV, orv) DO_VPZ(ANDV, andv) @@ -877,14 +874,11 @@ DO_VPZ(UMAXV, umaxv) DO_VPZ(SMINV, sminv) DO_VPZ(UMINV, uminv) -static bool trans_SADDV(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_reduc * const fns[4] = { - gen_helper_sve_saddv_b, gen_helper_sve_saddv_h, - gen_helper_sve_saddv_s, NULL - }; - return do_vpz_ool(s, a, fns[a->esz]); -} +static gen_helper_gvec_reduc * const saddv_fns[4] = { + gen_helper_sve_saddv_b, gen_helper_sve_saddv_h, + gen_helper_sve_saddv_s, NULL +}; +TRANS_FEAT(SADDV, aa64_sve, do_vpz_ool, a, saddv_fns[a->esz]) #undef DO_VPZ From 5e612f807303d216e51c9a84b3764f72965f546e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:57 -0700 Subject: [PATCH 629/935] target/arm: Use TRANS_FEAT for do_shift_imm Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-45-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 6103bd7f1d..f15e9a30b3 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -1054,20 +1054,9 @@ static bool do_shift_imm(DisasContext *s, arg_rri_esz *a, bool asr, return true; } -static bool trans_ASR_zzi(DisasContext *s, arg_rri_esz *a) -{ - return do_shift_imm(s, a, true, tcg_gen_gvec_sari); -} - -static bool trans_LSR_zzi(DisasContext *s, arg_rri_esz *a) -{ - return do_shift_imm(s, a, false, tcg_gen_gvec_shri); -} - -static bool trans_LSL_zzi(DisasContext *s, arg_rri_esz *a) -{ - return do_shift_imm(s, a, false, tcg_gen_gvec_shli); -} +TRANS_FEAT(ASR_zzi, aa64_sve, do_shift_imm, a, true, tcg_gen_gvec_sari) +TRANS_FEAT(LSR_zzi, aa64_sve, do_shift_imm, a, false, tcg_gen_gvec_shri) +TRANS_FEAT(LSL_zzi, aa64_sve, do_shift_imm, a, false, tcg_gen_gvec_shli) #define DO_ZZW(NAME, name) \ static gen_helper_gvec_3 * const name##_zzw_fns[4] = { \ From 73c558a85d57782aedf5a184702742861fcd53c7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:58 -0700 Subject: [PATCH 630/935] target/arm: Introduce do_shift_zpzi Share code between the various shifts using arg_rpri_esz. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-46-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 68 +++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 38 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index f15e9a30b3..c7c16863c0 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -900,20 +900,39 @@ static bool do_movz_zpz(DisasContext *s, int rd, int rn, int pg, return gen_gvec_ool_zzp(s, fns[esz], rd, rn, pg, invert); } +static bool do_shift_zpzi(DisasContext *s, arg_rpri_esz *a, bool asr, + gen_helper_gvec_3 * const fns[4]) +{ + int max; + + if (a->esz < 0) { + /* Invalid tsz encoding -- see tszimm_esz. */ + return false; + } + + /* + * Shift by element size is architecturally valid. + * For arithmetic right-shift, it's the same as by one less. + * For logical shifts and ASRD, it is a zeroing operation. + */ + max = 8 << a->esz; + if (a->imm >= max) { + if (asr) { + a->imm = max - 1; + } else { + return do_movz_zpz(s, a->rd, a->rd, a->pg, a->esz, true); + } + } + return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); +} + static bool trans_ASR_zpzi(DisasContext *s, arg_rpri_esz *a) { static gen_helper_gvec_3 * const fns[4] = { gen_helper_sve_asr_zpzi_b, gen_helper_sve_asr_zpzi_h, gen_helper_sve_asr_zpzi_s, gen_helper_sve_asr_zpzi_d, }; - if (a->esz < 0) { - /* Invalid tsz encoding -- see tszimm_esz. */ - return false; - } - /* Shift by element size is architecturally valid. For - arithmetic right-shift, it's the same as by one less. */ - a->imm = MIN(a->imm, (8 << a->esz) - 1); - return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); + return do_shift_zpzi(s, a, true, fns); } static bool trans_LSR_zpzi(DisasContext *s, arg_rpri_esz *a) @@ -922,16 +941,7 @@ static bool trans_LSR_zpzi(DisasContext *s, arg_rpri_esz *a) gen_helper_sve_lsr_zpzi_b, gen_helper_sve_lsr_zpzi_h, gen_helper_sve_lsr_zpzi_s, gen_helper_sve_lsr_zpzi_d, }; - if (a->esz < 0) { - return false; - } - /* Shift by element size is architecturally valid. - For logical shifts, it is a zeroing operation. */ - if (a->imm >= (8 << a->esz)) { - return do_movz_zpz(s, a->rd, a->rd, a->pg, a->esz, true); - } else { - return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); - } + return do_shift_zpzi(s, a, false, fns); } static bool trans_LSL_zpzi(DisasContext *s, arg_rpri_esz *a) @@ -940,16 +950,7 @@ static bool trans_LSL_zpzi(DisasContext *s, arg_rpri_esz *a) gen_helper_sve_lsl_zpzi_b, gen_helper_sve_lsl_zpzi_h, gen_helper_sve_lsl_zpzi_s, gen_helper_sve_lsl_zpzi_d, }; - if (a->esz < 0) { - return false; - } - /* Shift by element size is architecturally valid. - For logical shifts, it is a zeroing operation. */ - if (a->imm >= (8 << a->esz)) { - return do_movz_zpz(s, a->rd, a->rd, a->pg, a->esz, true); - } else { - return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); - } + return do_shift_zpzi(s, a, false, fns); } static bool trans_ASRD(DisasContext *s, arg_rpri_esz *a) @@ -958,16 +959,7 @@ static bool trans_ASRD(DisasContext *s, arg_rpri_esz *a) gen_helper_sve_asrd_b, gen_helper_sve_asrd_h, gen_helper_sve_asrd_s, gen_helper_sve_asrd_d, }; - if (a->esz < 0) { - return false; - } - /* Shift by element size is architecturally valid. For arithmetic - right shift for division, it is a zeroing operation. */ - if (a->imm >= (8 << a->esz)) { - return do_movz_zpz(s, a->rd, a->rd, a->pg, a->esz, true); - } else { - return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); - } + return do_shift_zpzi(s, a, false, fns); } static gen_helper_gvec_3 * const sqshl_zpzi_fns[4] = { From 5cccd1f182bc7e066908bc4f5a9a992360f11248 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:17:59 -0700 Subject: [PATCH 631/935] target/arm: Use TRANS_FEAT for do_shift_zpzi Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-47-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 52 +++++++++++++++----------------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index c7c16863c0..98f9cfa86c 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -926,41 +926,29 @@ static bool do_shift_zpzi(DisasContext *s, arg_rpri_esz *a, bool asr, return gen_gvec_ool_arg_zpzi(s, fns[a->esz], a); } -static bool trans_ASR_zpzi(DisasContext *s, arg_rpri_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve_asr_zpzi_b, gen_helper_sve_asr_zpzi_h, - gen_helper_sve_asr_zpzi_s, gen_helper_sve_asr_zpzi_d, - }; - return do_shift_zpzi(s, a, true, fns); -} +static gen_helper_gvec_3 * const asr_zpzi_fns[4] = { + gen_helper_sve_asr_zpzi_b, gen_helper_sve_asr_zpzi_h, + gen_helper_sve_asr_zpzi_s, gen_helper_sve_asr_zpzi_d, +}; +TRANS_FEAT(ASR_zpzi, aa64_sve, do_shift_zpzi, a, true, asr_zpzi_fns) -static bool trans_LSR_zpzi(DisasContext *s, arg_rpri_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve_lsr_zpzi_b, gen_helper_sve_lsr_zpzi_h, - gen_helper_sve_lsr_zpzi_s, gen_helper_sve_lsr_zpzi_d, - }; - return do_shift_zpzi(s, a, false, fns); -} +static gen_helper_gvec_3 * const lsr_zpzi_fns[4] = { + gen_helper_sve_lsr_zpzi_b, gen_helper_sve_lsr_zpzi_h, + gen_helper_sve_lsr_zpzi_s, gen_helper_sve_lsr_zpzi_d, +}; +TRANS_FEAT(LSR_zpzi, aa64_sve, do_shift_zpzi, a, false, lsr_zpzi_fns) -static bool trans_LSL_zpzi(DisasContext *s, arg_rpri_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve_lsl_zpzi_b, gen_helper_sve_lsl_zpzi_h, - gen_helper_sve_lsl_zpzi_s, gen_helper_sve_lsl_zpzi_d, - }; - return do_shift_zpzi(s, a, false, fns); -} +static gen_helper_gvec_3 * const lsl_zpzi_fns[4] = { + gen_helper_sve_lsl_zpzi_b, gen_helper_sve_lsl_zpzi_h, + gen_helper_sve_lsl_zpzi_s, gen_helper_sve_lsl_zpzi_d, +}; +TRANS_FEAT(LSL_zpzi, aa64_sve, do_shift_zpzi, a, false, lsl_zpzi_fns) -static bool trans_ASRD(DisasContext *s, arg_rpri_esz *a) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve_asrd_b, gen_helper_sve_asrd_h, - gen_helper_sve_asrd_s, gen_helper_sve_asrd_d, - }; - return do_shift_zpzi(s, a, false, fns); -} +static gen_helper_gvec_3 * const asrd_fns[4] = { + gen_helper_sve_asrd_b, gen_helper_sve_asrd_h, + gen_helper_sve_asrd_s, gen_helper_sve_asrd_d, +}; +TRANS_FEAT(ASRD, aa64_sve, do_shift_zpzi, a, false, asrd_fns) static gen_helper_gvec_3 * const sqshl_zpzi_fns[4] = { gen_helper_sve2_sqshl_zpzi_b, gen_helper_sve2_sqshl_zpzi_h, From dc67e645fb27ef86b48a29de972628edaffe9946 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:00 -0700 Subject: [PATCH 632/935] target/arm: Use TRANS_FEAT for do_zpzzz_ool Remove the DO_ZPZZZ macro, as it had just the two uses. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-48-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 98f9cfa86c..52bbd1a4fa 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -1071,20 +1071,17 @@ static bool do_zpzzz_ool(DisasContext *s, arg_rprrr_esz *a, return true; } -#define DO_ZPZZZ(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rprrr_esz *a) \ -{ \ - static gen_helper_gvec_5 * const fns[4] = { \ - gen_helper_sve_##name##_b, gen_helper_sve_##name##_h, \ - gen_helper_sve_##name##_s, gen_helper_sve_##name##_d, \ - }; \ - return do_zpzzz_ool(s, a, fns[a->esz]); \ -} +static gen_helper_gvec_5 * const mla_fns[4] = { + gen_helper_sve_mla_b, gen_helper_sve_mla_h, + gen_helper_sve_mla_s, gen_helper_sve_mla_d, +}; +TRANS_FEAT(MLA, aa64_sve, do_zpzzz_ool, a, mla_fns[a->esz]) -DO_ZPZZZ(MLA, mla) -DO_ZPZZZ(MLS, mls) - -#undef DO_ZPZZZ +static gen_helper_gvec_5 * const mls_fns[4] = { + gen_helper_sve_mls_b, gen_helper_sve_mls_h, + gen_helper_sve_mls_s, gen_helper_sve_mls_d, +}; +TRANS_FEAT(MLS, aa64_sve, do_zpzzz_ool, a, mls_fns[a->esz]) /* *** SVE Index Generation Group From 6687d05dc318aed9dbd1fc724bcfcbea1a48809a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:01 -0700 Subject: [PATCH 633/935] target/arm: Move sve check into do_index Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-49-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 53 ++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 52bbd1a4fa..44c2342923 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -1087,12 +1087,20 @@ TRANS_FEAT(MLS, aa64_sve, do_zpzzz_ool, a, mls_fns[a->esz]) *** SVE Index Generation Group */ -static void do_index(DisasContext *s, int esz, int rd, +static bool do_index(DisasContext *s, int esz, int rd, TCGv_i64 start, TCGv_i64 incr) { - unsigned vsz = vec_full_reg_size(s); - TCGv_i32 desc = tcg_constant_i32(simd_desc(vsz, vsz, 0)); - TCGv_ptr t_zd = tcg_temp_new_ptr(); + unsigned vsz; + TCGv_i32 desc; + TCGv_ptr t_zd; + + if (!sve_access_check(s)) { + return true; + } + + vsz = vec_full_reg_size(s); + desc = tcg_constant_i32(simd_desc(vsz, vsz, 0)); + t_zd = tcg_temp_new_ptr(); tcg_gen_addi_ptr(t_zd, cpu_env, vec_full_reg_offset(s, rd)); if (esz == 3) { @@ -1115,46 +1123,35 @@ static void do_index(DisasContext *s, int esz, int rd, tcg_temp_free_i32(i32); } tcg_temp_free_ptr(t_zd); + return true; } static bool trans_INDEX_ii(DisasContext *s, arg_INDEX_ii *a) { - if (sve_access_check(s)) { - TCGv_i64 start = tcg_constant_i64(a->imm1); - TCGv_i64 incr = tcg_constant_i64(a->imm2); - do_index(s, a->esz, a->rd, start, incr); - } - return true; + TCGv_i64 start = tcg_constant_i64(a->imm1); + TCGv_i64 incr = tcg_constant_i64(a->imm2); + return do_index(s, a->esz, a->rd, start, incr); } static bool trans_INDEX_ir(DisasContext *s, arg_INDEX_ir *a) { - if (sve_access_check(s)) { - TCGv_i64 start = tcg_constant_i64(a->imm); - TCGv_i64 incr = cpu_reg(s, a->rm); - do_index(s, a->esz, a->rd, start, incr); - } - return true; + TCGv_i64 start = tcg_constant_i64(a->imm); + TCGv_i64 incr = cpu_reg(s, a->rm); + return do_index(s, a->esz, a->rd, start, incr); } static bool trans_INDEX_ri(DisasContext *s, arg_INDEX_ri *a) { - if (sve_access_check(s)) { - TCGv_i64 start = cpu_reg(s, a->rn); - TCGv_i64 incr = tcg_constant_i64(a->imm); - do_index(s, a->esz, a->rd, start, incr); - } - return true; + TCGv_i64 start = cpu_reg(s, a->rn); + TCGv_i64 incr = tcg_constant_i64(a->imm); + return do_index(s, a->esz, a->rd, start, incr); } static bool trans_INDEX_rr(DisasContext *s, arg_INDEX_rr *a) { - if (sve_access_check(s)) { - TCGv_i64 start = cpu_reg(s, a->rn); - TCGv_i64 incr = cpu_reg(s, a->rm); - do_index(s, a->esz, a->rd, start, incr); - } - return true; + TCGv_i64 start = cpu_reg(s, a->rn); + TCGv_i64 incr = cpu_reg(s, a->rm); + return do_index(s, a->esz, a->rd, start, incr); } /* From 9aa60c83ea424036469076cfb2989fe85969673e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:02 -0700 Subject: [PATCH 634/935] target/arm: Use TRANS_FEAT for do_index Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-50-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 35 ++++++++--------------------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 44c2342923..dac29749ce 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -1126,33 +1126,14 @@ static bool do_index(DisasContext *s, int esz, int rd, return true; } -static bool trans_INDEX_ii(DisasContext *s, arg_INDEX_ii *a) -{ - TCGv_i64 start = tcg_constant_i64(a->imm1); - TCGv_i64 incr = tcg_constant_i64(a->imm2); - return do_index(s, a->esz, a->rd, start, incr); -} - -static bool trans_INDEX_ir(DisasContext *s, arg_INDEX_ir *a) -{ - TCGv_i64 start = tcg_constant_i64(a->imm); - TCGv_i64 incr = cpu_reg(s, a->rm); - return do_index(s, a->esz, a->rd, start, incr); -} - -static bool trans_INDEX_ri(DisasContext *s, arg_INDEX_ri *a) -{ - TCGv_i64 start = cpu_reg(s, a->rn); - TCGv_i64 incr = tcg_constant_i64(a->imm); - return do_index(s, a->esz, a->rd, start, incr); -} - -static bool trans_INDEX_rr(DisasContext *s, arg_INDEX_rr *a) -{ - TCGv_i64 start = cpu_reg(s, a->rn); - TCGv_i64 incr = cpu_reg(s, a->rm); - return do_index(s, a->esz, a->rd, start, incr); -} +TRANS_FEAT(INDEX_ii, aa64_sve, do_index, a->esz, a->rd, + tcg_constant_i64(a->imm1), tcg_constant_i64(a->imm2)) +TRANS_FEAT(INDEX_ir, aa64_sve, do_index, a->esz, a->rd, + tcg_constant_i64(a->imm), cpu_reg(s, a->rm)) +TRANS_FEAT(INDEX_ri, aa64_sve, do_index, a->esz, a->rd, + cpu_reg(s, a->rn), tcg_constant_i64(a->imm)) +TRANS_FEAT(INDEX_rr, aa64_sve, do_index, a->esz, a->rd, + cpu_reg(s, a->rn), cpu_reg(s, a->rm)) /* *** SVE Stack Allocation Group From dcba3d6741f721c5e3b66aac641ebcbc4e104839 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:03 -0700 Subject: [PATCH 635/935] target/arm: Use TRANS_FEAT for do_adr Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-51-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index dac29749ce..c8eb2c684b 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -1177,25 +1177,10 @@ static bool do_adr(DisasContext *s, arg_rrri *a, gen_helper_gvec_3 *fn) return gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, a->imm); } -static bool trans_ADR_p32(DisasContext *s, arg_rrri *a) -{ - return do_adr(s, a, gen_helper_sve_adr_p32); -} - -static bool trans_ADR_p64(DisasContext *s, arg_rrri *a) -{ - return do_adr(s, a, gen_helper_sve_adr_p64); -} - -static bool trans_ADR_s32(DisasContext *s, arg_rrri *a) -{ - return do_adr(s, a, gen_helper_sve_adr_s32); -} - -static bool trans_ADR_u32(DisasContext *s, arg_rrri *a) -{ - return do_adr(s, a, gen_helper_sve_adr_u32); -} +TRANS_FEAT(ADR_p32, aa64_sve, do_adr, a, gen_helper_sve_adr_p32) +TRANS_FEAT(ADR_p64, aa64_sve, do_adr, a, gen_helper_sve_adr_p64) +TRANS_FEAT(ADR_s32, aa64_sve, do_adr, a, gen_helper_sve_adr_s32) +TRANS_FEAT(ADR_u32, aa64_sve, do_adr, a, gen_helper_sve_adr_u32) /* *** SVE Integer Misc - Unpredicated Group From b03a85010f7b3ba828dbb49c0ce39b18156d16f1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:04 -0700 Subject: [PATCH 636/935] target/arm: Use TRANS_FEAT for do_predset Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-52-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index c8eb2c684b..ce6e000f6f 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -1616,22 +1616,13 @@ static bool do_predset(DisasContext *s, int esz, int rd, int pat, bool setflag) return true; } -static bool trans_PTRUE(DisasContext *s, arg_PTRUE *a) -{ - return do_predset(s, a->esz, a->rd, a->pat, a->s); -} +TRANS_FEAT(PTRUE, aa64_sve, do_predset, a->esz, a->rd, a->pat, a->s) -static bool trans_SETFFR(DisasContext *s, arg_SETFFR *a) -{ - /* Note pat == 31 is #all, to set all elements. */ - return do_predset(s, 0, FFR_PRED_NUM, 31, false); -} +/* Note pat == 31 is #all, to set all elements. */ +TRANS_FEAT(SETFFR, aa64_sve, do_predset, 0, FFR_PRED_NUM, 31, false) -static bool trans_PFALSE(DisasContext *s, arg_PFALSE *a) -{ - /* Note pat == 32 is #unimp, to set no elements. */ - return do_predset(s, 0, a->rd, 32, false); -} +/* Note pat == 32 is #unimp, to set no elements. */ +TRANS_FEAT(PFALSE, aa64_sve, do_predset, 0, a->rd, 32, false) static bool trans_RDFFR_p(DisasContext *s, arg_RDFFR_p *a) { From ff502658566ecc58a768a68fefc062366e74a65b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:05 -0700 Subject: [PATCH 637/935] target/arm: Use TRANS_FEAT for RDFFR, WRFFR Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-53-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index ce6e000f6f..6fd9a42ef9 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -1636,15 +1636,8 @@ static bool trans_RDFFR_p(DisasContext *s, arg_RDFFR_p *a) return trans_AND_pppp(s, &alt_a); } -static bool trans_RDFFR(DisasContext *s, arg_RDFFR *a) -{ - return do_mov_p(s, a->rd, FFR_PRED_NUM); -} - -static bool trans_WRFFR(DisasContext *s, arg_WRFFR *a) -{ - return do_mov_p(s, FFR_PRED_NUM, a->rn); -} +TRANS_FEAT(RDFFR, aa64_sve, do_mov_p, a->rd, FFR_PRED_NUM) +TRANS_FEAT(WRFFR, aa64_sve, do_mov_p, FFR_PRED_NUM, a->rn) static bool do_pfirst_pnext(DisasContext *s, arg_rr_esz *a, void (*gen_fn)(TCGv_i32, TCGv_ptr, From d95040e3df45537fc7ed76b1d9928fa18f1829ad Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:06 -0700 Subject: [PATCH 638/935] target/arm: Use TRANS_FEAT for do_pfirst_pnext Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-54-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 6fd9a42ef9..abb5433ee5 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -1668,15 +1668,8 @@ static bool do_pfirst_pnext(DisasContext *s, arg_rr_esz *a, return true; } -static bool trans_PFIRST(DisasContext *s, arg_rr_esz *a) -{ - return do_pfirst_pnext(s, a, gen_helper_sve_pfirst); -} - -static bool trans_PNEXT(DisasContext *s, arg_rr_esz *a) -{ - return do_pfirst_pnext(s, a, gen_helper_sve_pnext); -} +TRANS_FEAT(PFIRST, aa64_sve, do_pfirst_pnext, a, gen_helper_sve_pfirst) +TRANS_FEAT(PNEXT, aa64_sve, do_pfirst_pnext, a, gen_helper_sve_pnext) /* *** SVE Element Count Group From c799c115dbf55dad6ee909fd94b362ec760ffa11 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:07 -0700 Subject: [PATCH 639/935] target/arm: Use TRANS_FEAT for do_EXT Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-55-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index abb5433ee5..7139e6c0b0 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -2081,18 +2081,8 @@ static bool do_EXT(DisasContext *s, int rd, int rn, int rm, int imm) return true; } -static bool trans_EXT(DisasContext *s, arg_EXT *a) -{ - return do_EXT(s, a->rd, a->rn, a->rm, a->imm); -} - -static bool trans_EXT_sve2(DisasContext *s, arg_rri *a) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_EXT(s, a->rd, a->rn, (a->rn + 1) % 32, a->imm); -} +TRANS_FEAT(EXT, aa64_sve, do_EXT, a->rd, a->rn, a->rm, a->imm) +TRANS_FEAT(EXT_sve2, aa64_sve2, do_EXT, a->rd, a->rn, (a->rn + 1) % 32, a->imm) /* *** SVE Permute - Unpredicated Group From bdb349f5dcea97512e183f335ff037270170e794 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:08 -0700 Subject: [PATCH 640/935] target/arm: Use TRANS_FEAT for do_perm_pred3 Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-56-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 35 ++++++----------------------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 7139e6c0b0..413e89b19c 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -2272,35 +2272,12 @@ static bool do_perm_pred2(DisasContext *s, arg_rr_esz *a, bool high_odd, return true; } -static bool trans_ZIP1_p(DisasContext *s, arg_rrr_esz *a) -{ - return do_perm_pred3(s, a, 0, gen_helper_sve_zip_p); -} - -static bool trans_ZIP2_p(DisasContext *s, arg_rrr_esz *a) -{ - return do_perm_pred3(s, a, 1, gen_helper_sve_zip_p); -} - -static bool trans_UZP1_p(DisasContext *s, arg_rrr_esz *a) -{ - return do_perm_pred3(s, a, 0, gen_helper_sve_uzp_p); -} - -static bool trans_UZP2_p(DisasContext *s, arg_rrr_esz *a) -{ - return do_perm_pred3(s, a, 1, gen_helper_sve_uzp_p); -} - -static bool trans_TRN1_p(DisasContext *s, arg_rrr_esz *a) -{ - return do_perm_pred3(s, a, 0, gen_helper_sve_trn_p); -} - -static bool trans_TRN2_p(DisasContext *s, arg_rrr_esz *a) -{ - return do_perm_pred3(s, a, 1, gen_helper_sve_trn_p); -} +TRANS_FEAT(ZIP1_p, aa64_sve, do_perm_pred3, a, 0, gen_helper_sve_zip_p) +TRANS_FEAT(ZIP2_p, aa64_sve, do_perm_pred3, a, 1, gen_helper_sve_zip_p) +TRANS_FEAT(UZP1_p, aa64_sve, do_perm_pred3, a, 0, gen_helper_sve_uzp_p) +TRANS_FEAT(UZP2_p, aa64_sve, do_perm_pred3, a, 1, gen_helper_sve_uzp_p) +TRANS_FEAT(TRN1_p, aa64_sve, do_perm_pred3, a, 0, gen_helper_sve_trn_p) +TRANS_FEAT(TRN2_p, aa64_sve, do_perm_pred3, a, 1, gen_helper_sve_trn_p) static bool trans_REV_p(DisasContext *s, arg_rr_esz *a) { From 1d0fce4bd0c6ceff32f14f8bab118351c4366a6c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:09 -0700 Subject: [PATCH 641/935] target/arm: Use TRANS_FEAT for do_perm_pred2 Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-57-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 413e89b19c..1e6bcedb9d 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -2279,20 +2279,9 @@ TRANS_FEAT(UZP2_p, aa64_sve, do_perm_pred3, a, 1, gen_helper_sve_uzp_p) TRANS_FEAT(TRN1_p, aa64_sve, do_perm_pred3, a, 0, gen_helper_sve_trn_p) TRANS_FEAT(TRN2_p, aa64_sve, do_perm_pred3, a, 1, gen_helper_sve_trn_p) -static bool trans_REV_p(DisasContext *s, arg_rr_esz *a) -{ - return do_perm_pred2(s, a, 0, gen_helper_sve_rev_p); -} - -static bool trans_PUNPKLO(DisasContext *s, arg_PUNPKLO *a) -{ - return do_perm_pred2(s, a, 0, gen_helper_sve_punpk_p); -} - -static bool trans_PUNPKHI(DisasContext *s, arg_PUNPKHI *a) -{ - return do_perm_pred2(s, a, 1, gen_helper_sve_punpk_p); -} +TRANS_FEAT(REV_p, aa64_sve, do_perm_pred2, a, 0, gen_helper_sve_rev_p) +TRANS_FEAT(PUNPKLO, aa64_sve, do_perm_pred2, a, 0, gen_helper_sve_punpk_p) +TRANS_FEAT(PUNPKHI, aa64_sve, do_perm_pred2, a, 1, gen_helper_sve_punpk_p) /* *** SVE Permute - Interleaving Group From 09eb6d7025d14bc01293a1bd6ecfcde985dec4d9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:10 -0700 Subject: [PATCH 642/935] target/arm: Move sve zip high_ofs into simd_data This is in line with how we treat uzp, and will eliminate the special case code during translation. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-58-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/sve_helper.c | 6 ++++-- target/arm/translate-sve.c | 12 ++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index e0f9aa9983..3bdcd4ce9d 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -3382,6 +3382,7 @@ void HELPER(sve_punpk_p)(void *vd, void *vn, uint32_t pred_desc) void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \ { \ intptr_t oprsz = simd_oprsz(desc); \ + intptr_t odd_ofs = simd_data(desc); \ intptr_t i, oprsz_2 = oprsz / 2; \ ARMVectorReg tmp_n, tmp_m; \ /* We produce output faster than we consume input. \ @@ -3393,8 +3394,9 @@ void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \ vm = memcpy(&tmp_m, vm, oprsz_2); \ } \ for (i = 0; i < oprsz_2; i += sizeof(TYPE)) { \ - *(TYPE *)(vd + H(2 * i + 0)) = *(TYPE *)(vn + H(i)); \ - *(TYPE *)(vd + H(2 * i + sizeof(TYPE))) = *(TYPE *)(vm + H(i)); \ + *(TYPE *)(vd + H(2 * i + 0)) = *(TYPE *)(vn + odd_ofs + H(i)); \ + *(TYPE *)(vd + H(2 * i + sizeof(TYPE))) = \ + *(TYPE *)(vm + odd_ofs + H(i)); \ } \ if (sizeof(TYPE) == 16 && unlikely(oprsz & 16)) { \ memset(vd + oprsz - 16, 0, 16); \ diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 1e6bcedb9d..c2ced3e2bb 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -2298,9 +2298,9 @@ static bool do_zip(DisasContext *s, arg_rrr_esz *a, bool high) unsigned vsz = vec_full_reg_size(s); unsigned high_ofs = high ? vsz / 2 : 0; tcg_gen_gvec_3_ool(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn) + high_ofs, - vec_full_reg_offset(s, a->rm) + high_ofs, - vsz, vsz, 0, fns[a->esz]); + vec_full_reg_offset(s, a->rn), + vec_full_reg_offset(s, a->rm), + vsz, vsz, high_ofs, fns[a->esz]); } return true; } @@ -2324,9 +2324,9 @@ static bool do_zip_q(DisasContext *s, arg_rrr_esz *a, bool high) unsigned vsz = vec_full_reg_size(s); unsigned high_ofs = high ? QEMU_ALIGN_DOWN(vsz, 32) / 2 : 0; tcg_gen_gvec_3_ool(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn) + high_ofs, - vec_full_reg_offset(s, a->rm) + high_ofs, - vsz, vsz, 0, gen_helper_sve2_zip_q); + vec_full_reg_offset(s, a->rn), + vec_full_reg_offset(s, a->rm), + vsz, vsz, high_ofs, gen_helper_sve2_zip_q); } return true; } From c9e0bd5f964efec6f1119c3aa622e712370789dd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:11 -0700 Subject: [PATCH 643/935] target/arm: Use gen_gvec_ool_arg_zzz for do_zip, do_zip_q Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-59-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index c2ced3e2bb..75c52d8ce1 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -2293,16 +2293,10 @@ static bool do_zip(DisasContext *s, arg_rrr_esz *a, bool high) gen_helper_sve_zip_b, gen_helper_sve_zip_h, gen_helper_sve_zip_s, gen_helper_sve_zip_d, }; + unsigned vsz = vec_full_reg_size(s); + unsigned high_ofs = high ? vsz / 2 : 0; - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - unsigned high_ofs = high ? vsz / 2 : 0; - tcg_gen_gvec_3_ool(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vsz, vsz, high_ofs, fns[a->esz]); - } - return true; + return gen_gvec_ool_arg_zzz(s, fns[a->esz], a, high_ofs); } static bool trans_ZIP1_z(DisasContext *s, arg_rrr_esz *a) @@ -2317,18 +2311,13 @@ static bool trans_ZIP2_z(DisasContext *s, arg_rrr_esz *a) static bool do_zip_q(DisasContext *s, arg_rrr_esz *a, bool high) { + unsigned vsz = vec_full_reg_size(s); + unsigned high_ofs = high ? QEMU_ALIGN_DOWN(vsz, 32) / 2 : 0; + if (!dc_isar_feature(aa64_sve_f64mm, s)) { return false; } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - unsigned high_ofs = high ? QEMU_ALIGN_DOWN(vsz, 32) / 2 : 0; - tcg_gen_gvec_3_ool(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vsz, vsz, high_ofs, gen_helper_sve2_zip_q); - } - return true; + return gen_gvec_ool_arg_zzz(s, gen_helper_sve2_zip_q, a, high_ofs); } static bool trans_ZIP1_q(DisasContext *s, arg_rrr_esz *a) From a95b9618b0312b23e297b8f4631f530618c809f8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:12 -0700 Subject: [PATCH 644/935] target/arm: Use TRANS_FEAT for do_zip, do_zip_q Convert SVE translation functions using do_zip* to use TRANS_FEAT and gen_gvec_ool_arg_zzz. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-60-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 54 +++++++++----------------------------- 1 file changed, 13 insertions(+), 41 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 75c52d8ce1..7c9deb267f 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -2287,48 +2287,20 @@ TRANS_FEAT(PUNPKHI, aa64_sve, do_perm_pred2, a, 1, gen_helper_sve_punpk_p) *** SVE Permute - Interleaving Group */ -static bool do_zip(DisasContext *s, arg_rrr_esz *a, bool high) -{ - static gen_helper_gvec_3 * const fns[4] = { - gen_helper_sve_zip_b, gen_helper_sve_zip_h, - gen_helper_sve_zip_s, gen_helper_sve_zip_d, - }; - unsigned vsz = vec_full_reg_size(s); - unsigned high_ofs = high ? vsz / 2 : 0; +static gen_helper_gvec_3 * const zip_fns[4] = { + gen_helper_sve_zip_b, gen_helper_sve_zip_h, + gen_helper_sve_zip_s, gen_helper_sve_zip_d, +}; +TRANS_FEAT(ZIP1_z, aa64_sve, gen_gvec_ool_arg_zzz, + zip_fns[a->esz], a, 0) +TRANS_FEAT(ZIP2_z, aa64_sve, gen_gvec_ool_arg_zzz, + zip_fns[a->esz], a, vec_full_reg_size(s) / 2) - return gen_gvec_ool_arg_zzz(s, fns[a->esz], a, high_ofs); -} - -static bool trans_ZIP1_z(DisasContext *s, arg_rrr_esz *a) -{ - return do_zip(s, a, false); -} - -static bool trans_ZIP2_z(DisasContext *s, arg_rrr_esz *a) -{ - return do_zip(s, a, true); -} - -static bool do_zip_q(DisasContext *s, arg_rrr_esz *a, bool high) -{ - unsigned vsz = vec_full_reg_size(s); - unsigned high_ofs = high ? QEMU_ALIGN_DOWN(vsz, 32) / 2 : 0; - - if (!dc_isar_feature(aa64_sve_f64mm, s)) { - return false; - } - return gen_gvec_ool_arg_zzz(s, gen_helper_sve2_zip_q, a, high_ofs); -} - -static bool trans_ZIP1_q(DisasContext *s, arg_rrr_esz *a) -{ - return do_zip_q(s, a, false); -} - -static bool trans_ZIP2_q(DisasContext *s, arg_rrr_esz *a) -{ - return do_zip_q(s, a, true); -} +TRANS_FEAT(ZIP1_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz, + gen_helper_sve2_zip_q, a, 0) +TRANS_FEAT(ZIP2_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz, + gen_helper_sve2_zip_q, a, + QEMU_ALIGN_DOWN(vec_full_reg_size(s), 32) / 2) static gen_helper_gvec_3 * const uzp_fns[4] = { gen_helper_sve_uzp_b, gen_helper_sve_uzp_h, From db7fa5d82156985f978da7d6985b4e8b5f451455 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:13 -0700 Subject: [PATCH 645/935] target/arm: Use TRANS_FEAT for do_clast_vector Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-61-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 7c9deb267f..5135866798 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -2492,15 +2492,8 @@ static bool do_clast_vector(DisasContext *s, arg_rprr_esz *a, bool before) return true; } -static bool trans_CLASTA_z(DisasContext *s, arg_rprr_esz *a) -{ - return do_clast_vector(s, a, false); -} - -static bool trans_CLASTB_z(DisasContext *s, arg_rprr_esz *a) -{ - return do_clast_vector(s, a, true); -} +TRANS_FEAT(CLASTA_z, aa64_sve, do_clast_vector, a, false) +TRANS_FEAT(CLASTB_z, aa64_sve, do_clast_vector, a, true) /* Compute CLAST for a scalar. */ static void do_clast_scalar(DisasContext *s, int esz, int pg, int rm, From ac4fb247fb288d6a2bdeb6a4b6cbf68cf3f7b150 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:14 -0700 Subject: [PATCH 646/935] target/arm: Use TRANS_FEAT for do_clast_fp Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-62-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 5135866798..21c2bd099d 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -2542,15 +2542,8 @@ static bool do_clast_fp(DisasContext *s, arg_rpr_esz *a, bool before) return true; } -static bool trans_CLASTA_v(DisasContext *s, arg_rpr_esz *a) -{ - return do_clast_fp(s, a, false); -} - -static bool trans_CLASTB_v(DisasContext *s, arg_rpr_esz *a) -{ - return do_clast_fp(s, a, true); -} +TRANS_FEAT(CLASTA_v, aa64_sve, do_clast_fp, a, false) +TRANS_FEAT(CLASTB_v, aa64_sve, do_clast_fp, a, true) /* Compute CLAST for a Xreg. */ static bool do_clast_general(DisasContext *s, arg_rpr_esz *a, bool before) From c673404a6371a03833bab46a28ed1f7f835eb086 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:15 -0700 Subject: [PATCH 647/935] target/arm: Use TRANS_FEAT for do_clast_general Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-63-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 21c2bd099d..f5453e99e1 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -2575,15 +2575,8 @@ static bool do_clast_general(DisasContext *s, arg_rpr_esz *a, bool before) return true; } -static bool trans_CLASTA_r(DisasContext *s, arg_rpr_esz *a) -{ - return do_clast_general(s, a, false); -} - -static bool trans_CLASTB_r(DisasContext *s, arg_rpr_esz *a) -{ - return do_clast_general(s, a, true); -} +TRANS_FEAT(CLASTA_r, aa64_sve, do_clast_general, a, false) +TRANS_FEAT(CLASTB_r, aa64_sve, do_clast_general, a, true) /* Compute LAST for a scalar. */ static TCGv_i64 do_last_scalar(DisasContext *s, int esz, From 75de9fd4d240d5b74a4176b392f49ac3c8fe4675 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:16 -0700 Subject: [PATCH 648/935] target/arm: Use TRANS_FEAT for do_last_fp Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-64-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index f5453e99e1..841c1b5644 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -2608,15 +2608,8 @@ static bool do_last_fp(DisasContext *s, arg_rpr_esz *a, bool before) return true; } -static bool trans_LASTA_v(DisasContext *s, arg_rpr_esz *a) -{ - return do_last_fp(s, a, false); -} - -static bool trans_LASTB_v(DisasContext *s, arg_rpr_esz *a) -{ - return do_last_fp(s, a, true); -} +TRANS_FEAT(LASTA_v, aa64_sve, do_last_fp, a, false) +TRANS_FEAT(LASTB_v, aa64_sve, do_last_fp, a, true) /* Compute LAST for a Xreg. */ static bool do_last_general(DisasContext *s, arg_rpr_esz *a, bool before) From 884c5a802e784c508840395586dc45f9e014b2ee Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:17 -0700 Subject: [PATCH 649/935] target/arm: Use TRANS_FEAT for do_last_general Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-65-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 841c1b5644..caa587506c 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -2622,15 +2622,8 @@ static bool do_last_general(DisasContext *s, arg_rpr_esz *a, bool before) return true; } -static bool trans_LASTA_r(DisasContext *s, arg_rpr_esz *a) -{ - return do_last_general(s, a, false); -} - -static bool trans_LASTB_r(DisasContext *s, arg_rpr_esz *a) -{ - return do_last_general(s, a, true); -} +TRANS_FEAT(LASTA_r, aa64_sve, do_last_general, a, false) +TRANS_FEAT(LASTB_r, aa64_sve, do_last_general, a, true) static bool trans_CPY_m_r(DisasContext *s, arg_rpr_esz *a) { From 897ebd70742faa8d2f1e139813f37bc560950202 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:18 -0700 Subject: [PATCH 650/935] target/arm: Use TRANS_FEAT for SPLICE Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-66-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index caa587506c..8eb70fd56f 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -2658,20 +2658,11 @@ TRANS_FEAT(REVH, aa64_sve, gen_gvec_ool_arg_zpz, revh_fns[a->esz], a, 0) TRANS_FEAT(REVW, aa64_sve, gen_gvec_ool_arg_zpz, a->esz == 3 ? gen_helper_sve_revw_d : NULL, a, 0) -static bool trans_SPLICE(DisasContext *s, arg_rprr_esz *a) -{ - return gen_gvec_ool_zzzp(s, gen_helper_sve_splice, - a->rd, a->rn, a->rm, a->pg, a->esz); -} +TRANS_FEAT(SPLICE, aa64_sve, gen_gvec_ool_arg_zpzz, + gen_helper_sve_splice, a, a->esz) -static bool trans_SPLICE_sve2(DisasContext *s, arg_rpr_esz *a) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_ool_zzzp(s, gen_helper_sve_splice, - a->rd, a->rn, (a->rn + 1) % 32, a->pg, a->esz); -} +TRANS_FEAT(SPLICE_sve2, aa64_sve2, gen_gvec_ool_zzzp, gen_helper_sve_splice, + a->rd, a->rn, (a->rn + 1) % 32, a->pg, a->esz) /* *** SVE Integer Compare - Vectors Group From 671bdb2e1ffc8ed4e7e61264abcf6193494665c7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:19 -0700 Subject: [PATCH 651/935] target/arm: Use TRANS_FEAT for do_ppzz_flags Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-67-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 8eb70fd56f..73b5b67c25 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -2708,14 +2708,12 @@ static bool do_ppzz_flags(DisasContext *s, arg_rprr_esz *a, } #define DO_PPZZ(NAME, name) \ -static bool trans_##NAME##_ppzz(DisasContext *s, arg_rprr_esz *a) \ -{ \ - static gen_helper_gvec_flags_4 * const fns[4] = { \ - gen_helper_sve_##name##_ppzz_b, gen_helper_sve_##name##_ppzz_h, \ - gen_helper_sve_##name##_ppzz_s, gen_helper_sve_##name##_ppzz_d, \ - }; \ - return do_ppzz_flags(s, a, fns[a->esz]); \ -} + static gen_helper_gvec_flags_4 * const name##_ppzz_fns[4] = { \ + gen_helper_sve_##name##_ppzz_b, gen_helper_sve_##name##_ppzz_h, \ + gen_helper_sve_##name##_ppzz_s, gen_helper_sve_##name##_ppzz_d, \ + }; \ + TRANS_FEAT(NAME##_ppzz, aa64_sve, do_ppzz_flags, \ + a, name##_ppzz_fns[a->esz]) DO_PPZZ(CMPEQ, cmpeq) DO_PPZZ(CMPNE, cmpne) @@ -2727,14 +2725,12 @@ DO_PPZZ(CMPHS, cmphs) #undef DO_PPZZ #define DO_PPZW(NAME, name) \ -static bool trans_##NAME##_ppzw(DisasContext *s, arg_rprr_esz *a) \ -{ \ - static gen_helper_gvec_flags_4 * const fns[4] = { \ - gen_helper_sve_##name##_ppzw_b, gen_helper_sve_##name##_ppzw_h, \ - gen_helper_sve_##name##_ppzw_s, NULL \ - }; \ - return do_ppzz_flags(s, a, fns[a->esz]); \ -} + static gen_helper_gvec_flags_4 * const name##_ppzw_fns[4] = { \ + gen_helper_sve_##name##_ppzw_b, gen_helper_sve_##name##_ppzw_h, \ + gen_helper_sve_##name##_ppzw_s, NULL \ + }; \ + TRANS_FEAT(NAME##_ppzw, aa64_sve, do_ppzz_flags, \ + a, name##_ppzw_fns[a->esz]) DO_PPZW(CMPEQ, cmpeq) DO_PPZW(CMPNE, cmpne) From ef75309be9b4619b29963df2a2b0b068c43bd5b2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:20 -0700 Subject: [PATCH 652/935] target/arm: Use TRANS_FEAT for do_sve2_ppzz_flags Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-68-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 73b5b67c25..22acd5ead0 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -7319,27 +7319,15 @@ DO_SVE2_ZZZ_NARROW(SUBHNT, subhnt) DO_SVE2_ZZZ_NARROW(RSUBHNB, rsubhnb) DO_SVE2_ZZZ_NARROW(RSUBHNT, rsubhnt) -static bool do_sve2_ppzz_flags(DisasContext *s, arg_rprr_esz *a, - gen_helper_gvec_flags_4 *fn) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_ppzz_flags(s, a, fn); -} +static gen_helper_gvec_flags_4 * const match_fns[4] = { + gen_helper_sve2_match_ppzz_b, gen_helper_sve2_match_ppzz_h, NULL, NULL +}; +TRANS_FEAT(MATCH, aa64_sve2, do_ppzz_flags, a, match_fns[a->esz]) -#define DO_SVE2_PPZZ_MATCH(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rprr_esz *a) \ -{ \ - static gen_helper_gvec_flags_4 * const fns[4] = { \ - gen_helper_sve2_##name##_ppzz_b, gen_helper_sve2_##name##_ppzz_h, \ - NULL, NULL \ - }; \ - return do_sve2_ppzz_flags(s, a, fns[a->esz]); \ -} - -DO_SVE2_PPZZ_MATCH(MATCH, match) -DO_SVE2_PPZZ_MATCH(NMATCH, nmatch) +static gen_helper_gvec_flags_4 * const nmatch_fns[4] = { + gen_helper_sve2_nmatch_ppzz_b, gen_helper_sve2_nmatch_ppzz_h, NULL, NULL +}; +TRANS_FEAT(NMATCH, aa64_sve2, do_ppzz_flags, a, nmatch_fns[a->esz]) static gen_helper_gvec_4 * const histcnt_fns[4] = { NULL, NULL, gen_helper_sve2_histcnt_s, gen_helper_sve2_histcnt_d From 9c545be60d0f04e65769117ac744bd372dc35ed4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:21 -0700 Subject: [PATCH 653/935] target/arm: Use TRANS_FEAT for do_ppzi_flags Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-69-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 22acd5ead0..03b2eddd8b 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -2786,14 +2786,12 @@ static bool do_ppzi_flags(DisasContext *s, arg_rpri_esz *a, } #define DO_PPZI(NAME, name) \ -static bool trans_##NAME##_ppzi(DisasContext *s, arg_rpri_esz *a) \ -{ \ - static gen_helper_gvec_flags_3 * const fns[4] = { \ + static gen_helper_gvec_flags_3 * const name##_ppzi_fns[4] = { \ gen_helper_sve_##name##_ppzi_b, gen_helper_sve_##name##_ppzi_h, \ gen_helper_sve_##name##_ppzi_s, gen_helper_sve_##name##_ppzi_d, \ }; \ - return do_ppzi_flags(s, a, fns[a->esz]); \ -} + TRANS_FEAT(NAME##_ppzi, aa64_sve, do_ppzi_flags, a, \ + name##_ppzi_fns[a->esz]) DO_PPZI(CMPEQ, cmpeq) DO_PPZI(CMPNE, cmpne) From 2224d24d037b78d0c4ce7a34ee640c99b6c74dcf Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:22 -0700 Subject: [PATCH 654/935] target/arm: Use TRANS_FEAT for do_brk2, do_brk3 Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-70-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 45 ++++++++++++-------------------------- 1 file changed, 14 insertions(+), 31 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 03b2eddd8b..d44b24e988 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -2879,40 +2879,23 @@ static bool do_brk2(DisasContext *s, arg_rpr_s *a, return true; } -static bool trans_BRKPA(DisasContext *s, arg_rprr_s *a) -{ - return do_brk3(s, a, gen_helper_sve_brkpa, gen_helper_sve_brkpas); -} +TRANS_FEAT(BRKPA, aa64_sve, do_brk3, a, + gen_helper_sve_brkpa, gen_helper_sve_brkpas) +TRANS_FEAT(BRKPB, aa64_sve, do_brk3, a, + gen_helper_sve_brkpb, gen_helper_sve_brkpbs) -static bool trans_BRKPB(DisasContext *s, arg_rprr_s *a) -{ - return do_brk3(s, a, gen_helper_sve_brkpb, gen_helper_sve_brkpbs); -} +TRANS_FEAT(BRKA_m, aa64_sve, do_brk2, a, + gen_helper_sve_brka_m, gen_helper_sve_brkas_m) +TRANS_FEAT(BRKB_m, aa64_sve, do_brk2, a, + gen_helper_sve_brkb_m, gen_helper_sve_brkbs_m) -static bool trans_BRKA_m(DisasContext *s, arg_rpr_s *a) -{ - return do_brk2(s, a, gen_helper_sve_brka_m, gen_helper_sve_brkas_m); -} +TRANS_FEAT(BRKA_z, aa64_sve, do_brk2, a, + gen_helper_sve_brka_z, gen_helper_sve_brkas_z) +TRANS_FEAT(BRKB_z, aa64_sve, do_brk2, a, + gen_helper_sve_brkb_z, gen_helper_sve_brkbs_z) -static bool trans_BRKB_m(DisasContext *s, arg_rpr_s *a) -{ - return do_brk2(s, a, gen_helper_sve_brkb_m, gen_helper_sve_brkbs_m); -} - -static bool trans_BRKA_z(DisasContext *s, arg_rpr_s *a) -{ - return do_brk2(s, a, gen_helper_sve_brka_z, gen_helper_sve_brkas_z); -} - -static bool trans_BRKB_z(DisasContext *s, arg_rpr_s *a) -{ - return do_brk2(s, a, gen_helper_sve_brkb_z, gen_helper_sve_brkbs_z); -} - -static bool trans_BRKN(DisasContext *s, arg_rpr_s *a) -{ - return do_brk2(s, a, gen_helper_sve_brkn, gen_helper_sve_brkns); -} +TRANS_FEAT(BRKN, aa64_sve, do_brk2, a, + gen_helper_sve_brkn, gen_helper_sve_brkns) /* *** SVE Predicate Count Group From fa4bd72cc19e7309038f656c91caf1f1d4a00cee Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:23 -0700 Subject: [PATCH 655/935] target/arm: Use TRANS_FEAT for MUL_zzi Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-71-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index d44b24e988..c0781ecf60 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3315,15 +3315,7 @@ static bool trans_SUBR_zzi(DisasContext *s, arg_rri_esz *a) return true; } -static bool trans_MUL_zzi(DisasContext *s, arg_rri_esz *a) -{ - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_muli(a->esz, vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), a->imm, vsz, vsz); - } - return true; -} +TRANS_FEAT(MUL_zzi, aa64_sve, gen_gvec_fn_arg_zzi, tcg_gen_gvec_muli, a) static bool do_zzi_sat(DisasContext *s, arg_rri_esz *a, bool u, bool d) { From c437c59ba1842dc8488316412cb071d57d8231d8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:24 -0700 Subject: [PATCH 656/935] target/arm: Reject dup_i w/ shifted byte early Remove the unparsed extraction in trans_DUP_i, which is intended to reject an 8-bit shift of an 8-bit constant for 8-bit element. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-72-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/sve.decode | 5 ++++- target/arm/translate-sve.c | 10 ++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/target/arm/sve.decode b/target/arm/sve.decode index 0388cce3bd..c02da0a082 100644 --- a/target/arm/sve.decode +++ b/target/arm/sve.decode @@ -787,7 +787,10 @@ WHILE_ptr 00100101 esz:2 1 rm:5 001 100 rn:5 rw:1 rd:4 FDUP 00100101 esz:2 111 00 1110 imm:8 rd:5 # SVE broadcast integer immediate (unpredicated) -DUP_i 00100101 esz:2 111 00 011 . ........ rd:5 imm=%sh8_i8s +{ + INVALID 00100101 00 111 00 011 1 -------- ----- + DUP_i 00100101 esz:2 111 00 011 . ........ rd:5 imm=%sh8_i8s +} # SVE integer add/subtract immediate (unpredicated) ADD_zzi 00100101 .. 100 000 11 . ........ ..... @rdn_sh_i8u diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index c0781ecf60..14faef0564 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -403,6 +403,12 @@ const uint64_t pred_esz_masks[4] = { 0x1111111111111111ull, 0x0101010101010101ull }; +static bool trans_INVALID(DisasContext *s, arg_INVALID *a) +{ + unallocated_encoding(s); + return true; +} + /* *** SVE Logical - Unpredicated Group */ @@ -3246,13 +3252,9 @@ static bool trans_FDUP(DisasContext *s, arg_FDUP *a) static bool trans_DUP_i(DisasContext *s, arg_DUP_i *a) { - if (a->esz == 0 && extract32(s->insn, 13, 1)) { - return false; - } if (sve_access_check(s)) { unsigned vsz = vec_full_reg_size(s); int dofs = vec_full_reg_offset(s, a->rd); - tcg_gen_gvec_dup_imm(a->esz, dofs, vsz, vsz, a->imm); } return true; From 3a40518079ff295b560b9ee193768e57a25007e2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:25 -0700 Subject: [PATCH 657/935] target/arm: Reject add/sub w/ shifted byte early Remove the unparsed extractions in trans_ADD_zzi, trans_SUBR_zzi, and do_zzi_sat which are intended to reject an 8-bit shift of an 8-bit constant for 8-bit element. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-73-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/sve.decode | 35 ++++++++++++++++++++++++++++------- target/arm/translate-sve.c | 9 --------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/target/arm/sve.decode b/target/arm/sve.decode index c02da0a082..8cff63cf25 100644 --- a/target/arm/sve.decode +++ b/target/arm/sve.decode @@ -793,13 +793,34 @@ FDUP 00100101 esz:2 111 00 1110 imm:8 rd:5 } # SVE integer add/subtract immediate (unpredicated) -ADD_zzi 00100101 .. 100 000 11 . ........ ..... @rdn_sh_i8u -SUB_zzi 00100101 .. 100 001 11 . ........ ..... @rdn_sh_i8u -SUBR_zzi 00100101 .. 100 011 11 . ........ ..... @rdn_sh_i8u -SQADD_zzi 00100101 .. 100 100 11 . ........ ..... @rdn_sh_i8u -UQADD_zzi 00100101 .. 100 101 11 . ........ ..... @rdn_sh_i8u -SQSUB_zzi 00100101 .. 100 110 11 . ........ ..... @rdn_sh_i8u -UQSUB_zzi 00100101 .. 100 111 11 . ........ ..... @rdn_sh_i8u +{ + INVALID 00100101 00 100 000 11 1 -------- ----- + ADD_zzi 00100101 .. 100 000 11 . ........ ..... @rdn_sh_i8u +} +{ + INVALID 00100101 00 100 001 11 1 -------- ----- + SUB_zzi 00100101 .. 100 001 11 . ........ ..... @rdn_sh_i8u +} +{ + INVALID 00100101 00 100 011 11 1 -------- ----- + SUBR_zzi 00100101 .. 100 011 11 . ........ ..... @rdn_sh_i8u +} +{ + INVALID 00100101 00 100 100 11 1 -------- ----- + SQADD_zzi 00100101 .. 100 100 11 . ........ ..... @rdn_sh_i8u +} +{ + INVALID 00100101 00 100 101 11 1 -------- ----- + UQADD_zzi 00100101 .. 100 101 11 . ........ ..... @rdn_sh_i8u +} +{ + INVALID 00100101 00 100 110 11 1 -------- ----- + SQSUB_zzi 00100101 .. 100 110 11 . ........ ..... @rdn_sh_i8u +} +{ + INVALID 00100101 00 100 111 11 1 -------- ----- + UQSUB_zzi 00100101 .. 100 111 11 . ........ ..... @rdn_sh_i8u +} # SVE integer min/max immediate (unpredicated) SMAX_zzi 00100101 .. 101 000 110 ........ ..... @rdn_i8s diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 14faef0564..bf988cab3e 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3262,9 +3262,6 @@ static bool trans_DUP_i(DisasContext *s, arg_DUP_i *a) static bool trans_ADD_zzi(DisasContext *s, arg_rri_esz *a) { - if (a->esz == 0 && extract32(s->insn, 13, 1)) { - return false; - } return gen_gvec_fn_arg_zzi(s, tcg_gen_gvec_addi, a); } @@ -3305,9 +3302,6 @@ static bool trans_SUBR_zzi(DisasContext *s, arg_rri_esz *a) .scalar_first = true } }; - if (a->esz == 0 && extract32(s->insn, 13, 1)) { - return false; - } if (sve_access_check(s)) { unsigned vsz = vec_full_reg_size(s); tcg_gen_gvec_2s(vec_full_reg_offset(s, a->rd), @@ -3321,9 +3315,6 @@ TRANS_FEAT(MUL_zzi, aa64_sve, gen_gvec_fn_arg_zzi, tcg_gen_gvec_muli, a) static bool do_zzi_sat(DisasContext *s, arg_rri_esz *a, bool u, bool d) { - if (a->esz == 0 && extract32(s->insn, 13, 1)) { - return false; - } if (sve_access_check(s)) { do_sat_addsub_vec(s, a->esz, a->rd, a->rn, tcg_constant_i64(a->imm), u, d); From 7836c9414f51257d673b794abd562c770590e4fd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:26 -0700 Subject: [PATCH 658/935] target/arm: Reject copy w/ shifted byte early Remove the unparsed extractions in trans_CPY_{m,z}_i which are intended to reject an 8-bit shift of an 8-bit constant for 8-bit element. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-74-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/sve.decode | 10 ++++++++-- target/arm/translate-sve.c | 6 ------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/target/arm/sve.decode b/target/arm/sve.decode index 8cff63cf25..7e79198f5b 100644 --- a/target/arm/sve.decode +++ b/target/arm/sve.decode @@ -528,8 +528,14 @@ DUPM 00000101 11 0000 dbm:13 rd:5 FCPY 00000101 .. 01 .... 110 imm:8 ..... @rdn_pg4 # SVE copy integer immediate (predicated) -CPY_m_i 00000101 .. 01 .... 01 . ........ ..... @rdn_pg4 imm=%sh8_i8s -CPY_z_i 00000101 .. 01 .... 00 . ........ ..... @rdn_pg4 imm=%sh8_i8s +{ + INVALID 00000101 00 01 ---- 01 1 -------- ----- + CPY_m_i 00000101 .. 01 .... 01 . ........ ..... @rdn_pg4 imm=%sh8_i8s +} +{ + INVALID 00000101 00 01 ---- 00 1 -------- ----- + CPY_z_i 00000101 .. 01 .... 00 . ........ ..... @rdn_pg4 imm=%sh8_i8s +} ### SVE Permute - Extract Group diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index bf988cab3e..83980f5ee6 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -2024,9 +2024,6 @@ static bool trans_FCPY(DisasContext *s, arg_FCPY *a) static bool trans_CPY_m_i(DisasContext *s, arg_rpri_esz *a) { - if (a->esz == 0 && extract32(s->insn, 13, 1)) { - return false; - } if (sve_access_check(s)) { do_cpy_m(s, a->esz, a->rd, a->rn, a->pg, tcg_constant_i64(a->imm)); } @@ -2040,9 +2037,6 @@ static bool trans_CPY_z_i(DisasContext *s, arg_CPY_z_i *a) gen_helper_sve_cpy_z_s, gen_helper_sve_cpy_z_d, }; - if (a->esz == 0 && extract32(s->insn, 13, 1)) { - return false; - } if (sve_access_check(s)) { unsigned vsz = vec_full_reg_size(s); tcg_gen_gvec_2i_ool(vec_full_reg_offset(s, a->rd), From 48ca613df5c914b898f9bcb32b8711db5b2e8f0c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:27 -0700 Subject: [PATCH 659/935] target/arm: Use TRANS_FEAT for ADD_zzi Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-75-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 83980f5ee6..6b2f235e4a 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3254,10 +3254,7 @@ static bool trans_DUP_i(DisasContext *s, arg_DUP_i *a) return true; } -static bool trans_ADD_zzi(DisasContext *s, arg_rri_esz *a) -{ - return gen_gvec_fn_arg_zzi(s, tcg_gen_gvec_addi, a); -} +TRANS_FEAT(ADD_zzi, aa64_sve, gen_gvec_fn_arg_zzi, tcg_gen_gvec_addi, a) static bool trans_SUB_zzi(DisasContext *s, arg_rri_esz *a) { From 17b54d1c7877577e1e7fd568be0b281bad83a7c5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:28 -0700 Subject: [PATCH 660/935] target/arm: Use TRANS_FEAT for do_zzi_sat Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-76-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 6b2f235e4a..e6434589f4 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3313,25 +3313,10 @@ static bool do_zzi_sat(DisasContext *s, arg_rri_esz *a, bool u, bool d) return true; } -static bool trans_SQADD_zzi(DisasContext *s, arg_rri_esz *a) -{ - return do_zzi_sat(s, a, false, false); -} - -static bool trans_UQADD_zzi(DisasContext *s, arg_rri_esz *a) -{ - return do_zzi_sat(s, a, true, false); -} - -static bool trans_SQSUB_zzi(DisasContext *s, arg_rri_esz *a) -{ - return do_zzi_sat(s, a, false, true); -} - -static bool trans_UQSUB_zzi(DisasContext *s, arg_rri_esz *a) -{ - return do_zzi_sat(s, a, true, true); -} +TRANS_FEAT(SQADD_zzi, aa64_sve, do_zzi_sat, a, false, false) +TRANS_FEAT(UQADD_zzi, aa64_sve, do_zzi_sat, a, true, false) +TRANS_FEAT(SQSUB_zzi, aa64_sve, do_zzi_sat, a, false, true) +TRANS_FEAT(UQSUB_zzi, aa64_sve, do_zzi_sat, a, true, true) static bool do_zzi_ool(DisasContext *s, arg_rri_esz *a, gen_helper_gvec_2i *fn) { From ef4a3958633e0ca9e0e656d5fbef002c23329aac Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:29 -0700 Subject: [PATCH 661/935] target/arm: Use TRANS_FEAT for do_zzi_ool Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-77-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index e6434589f4..b8bd1047b0 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3330,14 +3330,11 @@ static bool do_zzi_ool(DisasContext *s, arg_rri_esz *a, gen_helper_gvec_2i *fn) } #define DO_ZZI(NAME, name) \ -static bool trans_##NAME##_zzi(DisasContext *s, arg_rri_esz *a) \ -{ \ - static gen_helper_gvec_2i * const fns[4] = { \ + static gen_helper_gvec_2i * const name##i_fns[4] = { \ gen_helper_sve_##name##i_b, gen_helper_sve_##name##i_h, \ gen_helper_sve_##name##i_s, gen_helper_sve_##name##i_d, \ }; \ - return do_zzi_ool(s, a, fns[a->esz]); \ -} + TRANS_FEAT(NAME##_zzi, aa64_sve, do_zzi_ool, a, name##i_fns[a->esz]) DO_ZZI(SMAX, smax) DO_ZZI(UMAX, umax) From 41bf9b679953e54331cbf703dbd1ef6a7a779ea1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:30 -0700 Subject: [PATCH 662/935] target/arm: Introduce gen_gvec_{ptr,fpst}_zzzz Use these for the several varieties of floating-point multiply-add instructions. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-78-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 140 ++++++++++++++----------------------- 1 file changed, 53 insertions(+), 87 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index b8bd1047b0..a799ce3110 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -205,6 +205,35 @@ static bool gen_gvec_ool_arg_zzxz(DisasContext *s, gen_helper_gvec_4 *fn, return gen_gvec_ool_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, a->index); } +/* Invoke an out-of-line helper on 4 Zregs, plus a pointer. */ +static bool gen_gvec_ptr_zzzz(DisasContext *s, gen_helper_gvec_4_ptr *fn, + int rd, int rn, int rm, int ra, + int data, TCGv_ptr ptr) +{ + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), + vec_full_reg_offset(s, ra), + ptr, vsz, vsz, data, fn); + } + return true; +} + +static bool gen_gvec_fpst_zzzz(DisasContext *s, gen_helper_gvec_4_ptr *fn, + int rd, int rn, int rm, int ra, + int data, ARMFPStatusFlavour flavour) +{ + TCGv_ptr status = fpstatus_ptr(flavour); + bool ret = gen_gvec_ptr_zzzz(s, fn, rd, rn, rm, ra, data, status); + tcg_temp_free_ptr(status); + return ret; +} + /* Invoke an out-of-line helper on 2 Zregs and a predicate. */ static bool gen_gvec_ool_zzp(DisasContext *s, gen_helper_gvec_3 *fn, int rd, int rn, int pg, int data) @@ -3485,24 +3514,15 @@ DO_SVE2_RRXR_ROT(CDOT_zzxw_d, gen_helper_sve2_cdot_idx_d) static bool do_FMLA_zzxz(DisasContext *s, arg_rrxr_esz *a, bool sub) { - static gen_helper_gvec_4_ptr * const fns[3] = { + static gen_helper_gvec_4_ptr * const fns[4] = { + NULL, gen_helper_gvec_fmla_idx_h, gen_helper_gvec_fmla_idx_s, gen_helper_gvec_fmla_idx_d, }; - - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - status, vsz, vsz, (a->index << 1) | sub, - fns[a->esz - 1]); - tcg_temp_free_ptr(status); - } - return true; + return gen_gvec_fpst_zzzz(s, fns[a->esz], a->rd, a->rn, a->rm, a->ra, + (a->index << 1) | sub, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); } static bool trans_FMLA_zzxz(DisasContext *s, arg_FMLA_zzxz *a) @@ -4040,26 +4060,18 @@ static bool trans_FCMLA_zpzzz(DisasContext *s, arg_FCMLA_zpzzz *a) static bool trans_FCMLA_zzxz(DisasContext *s, arg_FCMLA_zzxz *a) { - static gen_helper_gvec_4_ptr * const fns[2] = { + static gen_helper_gvec_4_ptr * const fns[4] = { + NULL, gen_helper_gvec_fcmlah_idx, gen_helper_gvec_fcmlas_idx, + NULL, }; - tcg_debug_assert(a->esz == 1 || a->esz == 2); tcg_debug_assert(a->rd == a->ra); - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - status, vsz, vsz, - a->index * 4 + a->rot, - fns[a->esz - 1]); - tcg_temp_free_ptr(status); - } - return true; + + return gen_gvec_fpst_zzzz(s, fns[a->esz], a->rd, a->rn, a->rm, a->ra, + a->index * 4 + a->rot, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); } /* @@ -7327,17 +7339,7 @@ static bool trans_FMMLA(DisasContext *s, arg_rrrr_esz *a) return false; } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(FPST_FPCR); - tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - status, vsz, vsz, 0, fn); - tcg_temp_free_ptr(status); - } - return true; + return gen_gvec_fpst_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, 0, FPST_FPCR); } static gen_helper_gvec_4 * const sqdmlal_zzzw_fns[] = { @@ -7535,16 +7537,9 @@ static bool do_FMLAL_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sub, bool sel) if (!dc_isar_feature(aa64_sve2, s)) { return false; } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - cpu_env, vsz, vsz, (sel << 1) | sub, - gen_helper_sve2_fmlal_zzzw_s); - } - return true; + return gen_gvec_ptr_zzzz(s, gen_helper_sve2_fmlal_zzzw_s, + a->rd, a->rn, a->rm, a->ra, + (sel << 1) | sub, cpu_env); } static bool trans_FMLALB_zzzw(DisasContext *s, arg_rrrr_esz *a) @@ -7572,17 +7567,9 @@ static bool do_FMLAL_zzxw(DisasContext *s, arg_rrxr_esz *a, bool sub, bool sel) if (!dc_isar_feature(aa64_sve2, s)) { return false; } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - cpu_env, vsz, vsz, - (a->index << 2) | (sel << 1) | sub, - gen_helper_sve2_fmlal_zzxw_s); - } - return true; + return gen_gvec_ptr_zzzz(s, gen_helper_sve2_fmlal_zzxw_s, + a->rd, a->rn, a->rm, a->ra, + (a->index << 2) | (sel << 1) | sub, cpu_env); } static bool trans_FMLALB_zzxw(DisasContext *s, arg_rrxr_esz *a) @@ -7625,19 +7612,8 @@ static bool do_BFMLAL_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sel) if (!dc_isar_feature(aa64_sve_bf16, s)) { return false; } - if (sve_access_check(s)) { - TCGv_ptr status = fpstatus_ptr(FPST_FPCR); - unsigned vsz = vec_full_reg_size(s); - - tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - status, vsz, vsz, sel, - gen_helper_gvec_bfmlal); - tcg_temp_free_ptr(status); - } - return true; + return gen_gvec_fpst_zzzz(s, gen_helper_gvec_bfmlal, + a->rd, a->rn, a->rm, a->ra, sel, FPST_FPCR); } static bool trans_BFMLALB_zzzw(DisasContext *s, arg_rrrr_esz *a) @@ -7655,19 +7631,9 @@ static bool do_BFMLAL_zzxw(DisasContext *s, arg_rrxr_esz *a, bool sel) if (!dc_isar_feature(aa64_sve_bf16, s)) { return false; } - if (sve_access_check(s)) { - TCGv_ptr status = fpstatus_ptr(FPST_FPCR); - unsigned vsz = vec_full_reg_size(s); - - tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - status, vsz, vsz, (a->index << 1) | sel, - gen_helper_gvec_bfmlal_idx); - tcg_temp_free_ptr(status); - } - return true; + return gen_gvec_fpst_zzzz(s, gen_helper_gvec_bfmlal_idx, + a->rd, a->rn, a->rm, a->ra, + (a->index << 1) | sel, FPST_FPCR); } static bool trans_BFMLALB_zzxw(DisasContext *s, arg_rrxr_esz *a) From 25aee7cc3bd0c9a1b273ec2ead99ddde42f5c04a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:31 -0700 Subject: [PATCH 663/935] target/arm: Use TRANS_FEAT for FMMLA Being able to specify the feature predicate in TRANS_FEAT makes it easier to split trans_FMMLA by element size, which also happens to simplify the decode. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-79-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/sve.decode | 7 +++---- target/arm/translate-sve.c | 27 ++++----------------------- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/target/arm/sve.decode b/target/arm/sve.decode index 7e79198f5b..a54feb2f61 100644 --- a/target/arm/sve.decode +++ b/target/arm/sve.decode @@ -1598,10 +1598,9 @@ SQRDCMLAH_zzzz 01000100 esz:2 0 rm:5 0011 rot:2 rn:5 rd:5 ra=%reg_movprfx USDOT_zzzz 01000100 .. 0 ..... 011 110 ..... ..... @rda_rn_rm ### SVE2 floating point matrix multiply accumulate -{ - BFMMLA 01100100 01 1 ..... 111 001 ..... ..... @rda_rn_rm_e0 - FMMLA 01100100 .. 1 ..... 111 001 ..... ..... @rda_rn_rm -} +BFMMLA 01100100 01 1 ..... 111 001 ..... ..... @rda_rn_rm_e0 +FMMLA_s 01100100 10 1 ..... 111 001 ..... ..... @rda_rn_rm_e0 +FMMLA_d 01100100 11 1 ..... 111 001 ..... ..... @rda_rn_rm_e0 ### SVE2 Memory Gather Load Group diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index a799ce3110..364e419f3e 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -7318,29 +7318,10 @@ DO_SVE2_ZPZZ_FP(FMINP, fminp) * SVE Integer Multiply-Add (unpredicated) */ -static bool trans_FMMLA(DisasContext *s, arg_rrrr_esz *a) -{ - gen_helper_gvec_4_ptr *fn; - - switch (a->esz) { - case MO_32: - if (!dc_isar_feature(aa64_sve_f32mm, s)) { - return false; - } - fn = gen_helper_fmmla_s; - break; - case MO_64: - if (!dc_isar_feature(aa64_sve_f64mm, s)) { - return false; - } - fn = gen_helper_fmmla_d; - break; - default: - return false; - } - - return gen_gvec_fpst_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, 0, FPST_FPCR); -} +TRANS_FEAT(FMMLA_s, aa64_sve_f32mm, gen_gvec_fpst_zzzz, gen_helper_fmmla_s, + a->rd, a->rn, a->rm, a->ra, 0, FPST_FPCR) +TRANS_FEAT(FMMLA_d, aa64_sve_f64mm, gen_gvec_fpst_zzzz, gen_helper_fmmla_d, + a->rd, a->rn, a->rm, a->ra, 0, FPST_FPCR) static gen_helper_gvec_4 * const sqdmlal_zzzw_fns[] = { NULL, gen_helper_sve2_sqdmlal_zzzw_h, From 23e5fa5f90a6073f270ec89418085e4cb341a4ea Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:32 -0700 Subject: [PATCH 664/935] target/arm: Move sve check into gen_gvec_fn_ppp Combined with the check already present in gen_mov_p, we can simplify some special cases in trans_AND_pppp and trans_BIC_pppp. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-80-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 364e419f3e..f33bc9d480 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -370,13 +370,16 @@ static void do_dupi_z(DisasContext *s, int rd, uint64_t word) } /* Invoke a vector expander on three Pregs. */ -static void gen_gvec_fn_ppp(DisasContext *s, GVecGen3Fn *gvec_fn, +static bool gen_gvec_fn_ppp(DisasContext *s, GVecGen3Fn *gvec_fn, int rd, int rn, int rm) { - unsigned psz = pred_gvec_reg_size(s); - gvec_fn(MO_64, pred_full_reg_offset(s, rd), - pred_full_reg_offset(s, rn), - pred_full_reg_offset(s, rm), psz, psz); + if (sve_access_check(s)) { + unsigned psz = pred_gvec_reg_size(s); + gvec_fn(MO_64, pred_full_reg_offset(s, rd), + pred_full_reg_offset(s, rn), + pred_full_reg_offset(s, rm), psz, psz); + } + return true; } /* Invoke a vector move on two Pregs. */ @@ -1317,19 +1320,13 @@ static bool trans_AND_pppp(DisasContext *s, arg_rprr_s *a) }; if (!a->s) { - if (!sve_access_check(s)) { - return true; - } if (a->rn == a->rm) { if (a->pg == a->rn) { - do_mov_p(s, a->rd, a->rn); - } else { - gen_gvec_fn_ppp(s, tcg_gen_gvec_and, a->rd, a->rn, a->pg); + return do_mov_p(s, a->rd, a->rn); } - return true; + return gen_gvec_fn_ppp(s, tcg_gen_gvec_and, a->rd, a->rn, a->pg); } else if (a->pg == a->rn || a->pg == a->rm) { - gen_gvec_fn_ppp(s, tcg_gen_gvec_and, a->rd, a->rn, a->rm); - return true; + return gen_gvec_fn_ppp(s, tcg_gen_gvec_and, a->rd, a->rn, a->rm); } } return do_pppp_flags(s, a, &op); @@ -1358,10 +1355,7 @@ static bool trans_BIC_pppp(DisasContext *s, arg_rprr_s *a) }; if (!a->s && a->pg == a->rn) { - if (sve_access_check(s)) { - gen_gvec_fn_ppp(s, tcg_gen_gvec_andc, a->rd, a->rn, a->rm); - } - return true; + return gen_gvec_fn_ppp(s, tcg_gen_gvec_andc, a->rd, a->rn, a->rm); } return do_pppp_flags(s, a, &op); } From 738b679cc961bd086f14d7d7e3f4be116a719810 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:33 -0700 Subject: [PATCH 665/935] target/arm: Implement NOT (prediates) alias This alias is defined on EOR (prediates). While the same operation could be performed with NAND or NOR, only bother with the official alias. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-81-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index f33bc9d480..b6b5980e2d 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -1381,6 +1381,11 @@ static bool trans_EOR_pppp(DisasContext *s, arg_rprr_s *a) .fno = gen_helper_sve_eor_pppp, .prefer_i64 = TCG_TARGET_REG_BITS == 64, }; + + /* Alias NOT (predicate) is EOR Pd.B, Pg/Z, Pn.B, Pg.B */ + if (!a->s && a->pg == a->rm) { + return gen_gvec_fn_ppp(s, tcg_gen_gvec_andc, a->rd, a->pg, a->rn); + } return do_pppp_flags(s, a, &op); } From 29693f5f97c716718f05e601ea2b954b4a1236de Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:34 -0700 Subject: [PATCH 666/935] target/arm: Use TRANS_FEAT for SEL_zpzz Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-82-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index b6b5980e2d..a040d694ea 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -795,10 +795,7 @@ static gen_helper_gvec_4 * const udiv_fns[4] = { }; TRANS_FEAT(UDIV_zpzz, aa64_sve, gen_gvec_ool_arg_zpzz, udiv_fns[a->esz], a, 0) -static bool trans_SEL_zpzz(DisasContext *s, arg_rprr_esz *a) -{ - return do_sel_z(s, a->rd, a->rn, a->rm, a->pg, a->esz); -} +TRANS_FEAT(SEL_zpzz, aa64_sve, do_sel_z, a->rd, a->rn, a->rm, a->pg, a->esz) /* *** SVE Integer Arithmetic - Unary Predicated Group From 4b0b37e900700889f7cecd812bd05005fb2fbd57 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:35 -0700 Subject: [PATCH 667/935] target/arm: Use TRANS_FEAT for MOVPRFX Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-83-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index a040d694ea..6e8d8d54bf 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -6054,20 +6054,9 @@ static bool trans_PRF_rr(DisasContext *s, arg_PRF_rr *a) * In the meantime, just emit the moves. */ -static bool trans_MOVPRFX(DisasContext *s, arg_MOVPRFX *a) -{ - return do_mov_z(s, a->rd, a->rn); -} - -static bool trans_MOVPRFX_m(DisasContext *s, arg_rpr_esz *a) -{ - return do_sel_z(s, a->rd, a->rn, a->rd, a->pg, a->esz); -} - -static bool trans_MOVPRFX_z(DisasContext *s, arg_rpr_esz *a) -{ - return do_movz_zpz(s, a->rd, a->rn, a->pg, a->esz, false); -} +TRANS_FEAT(MOVPRFX, aa64_sve, do_mov_z, a->rd, a->rn) +TRANS_FEAT(MOVPRFX_m, aa64_sve, do_sel_z, a->rd, a->rn, a->rd, a->pg, a->esz) +TRANS_FEAT(MOVPRFX_z, aa64_sve, do_movz_zpz, a->rd, a->rn, a->pg, a->esz, false) /* * SVE2 Integer Multiply - Unpredicated From 3b879c28826e3d731e2bea427d0ca09aadd19c29 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:36 -0700 Subject: [PATCH 668/935] target/arm: Use TRANS_FEAT for FMLA Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-84-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 6e8d8d54bf..5aa3e477cf 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3521,15 +3521,8 @@ static bool do_FMLA_zzxz(DisasContext *s, arg_rrxr_esz *a, bool sub) a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); } -static bool trans_FMLA_zzxz(DisasContext *s, arg_FMLA_zzxz *a) -{ - return do_FMLA_zzxz(s, a, false); -} - -static bool trans_FMLS_zzxz(DisasContext *s, arg_FMLA_zzxz *a) -{ - return do_FMLA_zzxz(s, a, true); -} +TRANS_FEAT(FMLA_zzxz, aa64_sve, do_FMLA_zzxz, a, false) +TRANS_FEAT(FMLS_zzxz, aa64_sve, do_FMLA_zzxz, a, true) /* *** SVE Floating Point Multiply Indexed Group From 698ddb9d02aea308631a538fefb243547b884fe1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:37 -0700 Subject: [PATCH 669/935] target/arm: Use TRANS_FEAT for BFMLA Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-85-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 5aa3e477cf..f2939fbeb9 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -7568,39 +7568,19 @@ TRANS_FEAT(BFMMLA, aa64_sve_bf16, gen_gvec_ool_arg_zzzz, static bool do_BFMLAL_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sel) { - if (!dc_isar_feature(aa64_sve_bf16, s)) { - return false; - } return gen_gvec_fpst_zzzz(s, gen_helper_gvec_bfmlal, a->rd, a->rn, a->rm, a->ra, sel, FPST_FPCR); } -static bool trans_BFMLALB_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_BFMLAL_zzzw(s, a, false); -} - -static bool trans_BFMLALT_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_BFMLAL_zzzw(s, a, true); -} +TRANS_FEAT(BFMLALB_zzzw, aa64_sve_bf16, do_BFMLAL_zzzw, a, false) +TRANS_FEAT(BFMLALT_zzzw, aa64_sve_bf16, do_BFMLAL_zzzw, a, true) static bool do_BFMLAL_zzxw(DisasContext *s, arg_rrxr_esz *a, bool sel) { - if (!dc_isar_feature(aa64_sve_bf16, s)) { - return false; - } return gen_gvec_fpst_zzzz(s, gen_helper_gvec_bfmlal_idx, a->rd, a->rn, a->rm, a->ra, (a->index << 1) | sel, FPST_FPCR); } -static bool trans_BFMLALB_zzxw(DisasContext *s, arg_rrxr_esz *a) -{ - return do_BFMLAL_zzxw(s, a, false); -} - -static bool trans_BFMLALT_zzxw(DisasContext *s, arg_rrxr_esz *a) -{ - return do_BFMLAL_zzxw(s, a, true); -} +TRANS_FEAT(BFMLALB_zzxw, aa64_sve_bf16, do_BFMLAL_zzxw, a, false) +TRANS_FEAT(BFMLALT_zzxw, aa64_sve_bf16, do_BFMLAL_zzxw, a, true) From 532724e439fb8911644d3592b21c0e7e0bffc5d1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:38 -0700 Subject: [PATCH 670/935] target/arm: Rename do_zzz_fp to gen_gvec_ool_fpst_arg_zzz Rename the function to match gen_gvec_ool_arg_zzz, and move to be adjacent. Split out gen_gvec_fpst_zzz as a helper while we're at it. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-86-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 50 +++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index f2939fbeb9..61bf5f5757 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -175,6 +175,35 @@ static bool gen_gvec_ool_arg_zzz(DisasContext *s, gen_helper_gvec_3 *fn, return gen_gvec_ool_zzz(s, fn, a->rd, a->rn, a->rm, data); } +/* Invoke an out-of-line helper on 3 Zregs, plus float_status. */ +static bool gen_gvec_fpst_zzz(DisasContext *s, gen_helper_gvec_3_ptr *fn, + int rd, int rn, int rm, + int data, ARMFPStatusFlavour flavour) +{ + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + TCGv_ptr status = fpstatus_ptr(flavour); + + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), + status, vsz, vsz, data, fn); + + tcg_temp_free_ptr(status); + } + return true; +} + +static bool gen_gvec_fpst_arg_zzz(DisasContext *s, gen_helper_gvec_3_ptr *fn, + arg_rrr_esz *a, int data) +{ + return gen_gvec_fpst_zzz(s, fn, a->rd, a->rn, a->rm, data, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); +} + /* Invoke an out-of-line helper on 4 Zregs. */ static bool gen_gvec_ool_zzzz(DisasContext *s, gen_helper_gvec_4 *fn, int rd, int rn, int rm, int ra, int data) @@ -3769,25 +3798,6 @@ static bool trans_FADDA(DisasContext *s, arg_rprr_esz *a) *** SVE Floating Point Arithmetic - Unpredicated Group */ -static bool do_zzz_fp(DisasContext *s, arg_rrr_esz *a, - gen_helper_gvec_3_ptr *fn) -{ - if (fn == NULL) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - status, vsz, vsz, 0, fn); - tcg_temp_free_ptr(status); - } - return true; -} - - #define DO_FP3(NAME, name) \ static bool trans_##NAME(DisasContext *s, arg_rrr_esz *a) \ { \ @@ -3795,7 +3805,7 @@ static bool trans_##NAME(DisasContext *s, arg_rrr_esz *a) \ NULL, gen_helper_gvec_##name##_h, \ gen_helper_gvec_##name##_s, gen_helper_gvec_##name##_d \ }; \ - return do_zzz_fp(s, a, fns[a->esz]); \ + return gen_gvec_fpst_arg_zzz(s, fns[a->esz], a, 0); \ } DO_FP3(FADD_zzz, fadd) From bdd4ce0d0e4f1e767bb1fa0462d7a8542e1af04b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:39 -0700 Subject: [PATCH 671/935] target/arm: Use TRANS_FEAT for DO_FP3 Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-87-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 61bf5f5757..d596e7a027 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3799,14 +3799,11 @@ static bool trans_FADDA(DisasContext *s, arg_rprr_esz *a) */ #define DO_FP3(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rrr_esz *a) \ -{ \ - static gen_helper_gvec_3_ptr * const fns[4] = { \ + static gen_helper_gvec_3_ptr * const name##_fns[4] = { \ NULL, gen_helper_gvec_##name##_h, \ gen_helper_gvec_##name##_s, gen_helper_gvec_##name##_d \ }; \ - return gen_gvec_fpst_arg_zzz(s, fns[a->esz], a, 0); \ -} + TRANS_FEAT(NAME, aa64_sve, gen_gvec_fpst_arg_zzz, name##_fns[a->esz], a, 0) DO_FP3(FADD_zzz, fadd) DO_FP3(FSUB_zzz, fsub) From 9c99ef66770d03e077535cca64c7ac827de308fb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:40 -0700 Subject: [PATCH 672/935] target/arm: Use TRANS_FEAT for FMUL_zzx Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-88-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index d596e7a027..29fcc8b014 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3557,25 +3557,13 @@ TRANS_FEAT(FMLS_zzxz, aa64_sve, do_FMLA_zzxz, a, true) *** SVE Floating Point Multiply Indexed Group */ -static bool trans_FMUL_zzx(DisasContext *s, arg_FMUL_zzx *a) -{ - static gen_helper_gvec_3_ptr * const fns[3] = { - gen_helper_gvec_fmul_idx_h, - gen_helper_gvec_fmul_idx_s, - gen_helper_gvec_fmul_idx_d, - }; - - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - status, vsz, vsz, a->index, fns[a->esz - 1]); - tcg_temp_free_ptr(status); - } - return true; -} +static gen_helper_gvec_3_ptr * const fmul_idx_fns[4] = { + NULL, gen_helper_gvec_fmul_idx_h, + gen_helper_gvec_fmul_idx_s, gen_helper_gvec_fmul_idx_d, +}; +TRANS_FEAT(FMUL_zzx, aa64_sve, gen_gvec_fpst_zzz, + fmul_idx_fns[a->esz], a->rd, a->rn, a->rm, a->index, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) /* *** SVE Floating Point Fast Reduction Group From cdd85923370bc232472c79bdd8f0336f547add1d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:41 -0700 Subject: [PATCH 673/935] target/arm: Use TRANS_FEAT for FTMAD Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-89-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 29fcc8b014..11e4b4e1e4 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3715,28 +3715,13 @@ DO_PPZ(FCMNE_ppz0, fcmne0) *** SVE floating-point trig multiply-add coefficient */ -static bool trans_FTMAD(DisasContext *s, arg_FTMAD *a) -{ - static gen_helper_gvec_3_ptr * const fns[3] = { - gen_helper_sve_ftmad_h, - gen_helper_sve_ftmad_s, - gen_helper_sve_ftmad_d, - }; - - if (a->esz == 0) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - status, vsz, vsz, a->imm, fns[a->esz - 1]); - tcg_temp_free_ptr(status); - } - return true; -} +static gen_helper_gvec_3_ptr * const ftmad_fns[4] = { + NULL, gen_helper_sve_ftmad_h, + gen_helper_sve_ftmad_s, gen_helper_sve_ftmad_d, +}; +TRANS_FEAT(FTMAD, aa64_sve, gen_gvec_fpst_zzz, + ftmad_fns[a->esz], a->rd, a->rn, a->rm, a->imm, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) /* *** SVE Floating Point Accumulating Reduction Group From 5ce18efe306b9eb1f74074df3eab8dac96a8fe51 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:42 -0700 Subject: [PATCH 674/935] target/arm: Move null function and sve check into do_reduce Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-90-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 11e4b4e1e4..0d71072f83 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3572,15 +3572,24 @@ TRANS_FEAT(FMUL_zzx, aa64_sve, gen_gvec_fpst_zzz, typedef void gen_helper_fp_reduce(TCGv_i64, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32); -static void do_reduce(DisasContext *s, arg_rpr_esz *a, +static bool do_reduce(DisasContext *s, arg_rpr_esz *a, gen_helper_fp_reduce *fn) { - unsigned vsz = vec_full_reg_size(s); - unsigned p2vsz = pow2ceil(vsz); - TCGv_i32 t_desc = tcg_constant_i32(simd_desc(vsz, vsz, p2vsz)); + unsigned vsz, p2vsz; + TCGv_i32 t_desc; TCGv_ptr t_zn, t_pg, status; TCGv_i64 temp; + if (fn == NULL) { + return false; + } + if (!sve_access_check(s)) { + return true; + } + + vsz = vec_full_reg_size(s); + p2vsz = pow2ceil(vsz); + t_desc = tcg_constant_i32(simd_desc(vsz, vsz, p2vsz)); temp = tcg_temp_new_i64(); t_zn = tcg_temp_new_ptr(); t_pg = tcg_temp_new_ptr(); @@ -3596,23 +3605,18 @@ static void do_reduce(DisasContext *s, arg_rpr_esz *a, write_fp_dreg(s, a->rd, temp); tcg_temp_free_i64(temp); + return true; } #define DO_VPZ(NAME, name) \ static bool trans_##NAME(DisasContext *s, arg_rpr_esz *a) \ { \ - static gen_helper_fp_reduce * const fns[3] = { \ - gen_helper_sve_##name##_h, \ + static gen_helper_fp_reduce * const fns[4] = { \ + NULL, gen_helper_sve_##name##_h, \ gen_helper_sve_##name##_s, \ gen_helper_sve_##name##_d, \ }; \ - if (a->esz == 0) { \ - return false; \ - } \ - if (sve_access_check(s)) { \ - do_reduce(s, a, fns[a->esz - 1]); \ - } \ - return true; \ + return do_reduce(s, a, fns[a->esz]); \ } DO_VPZ(FADDV, faddv) From 8003e7cf15fa00496fe2c4d0208d88aa6802d4f6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:43 -0700 Subject: [PATCH 675/935] target/arm: Use TRANS_FEAT for do_reduce Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-91-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 0d71072f83..4a9ecd5e72 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3609,15 +3609,11 @@ static bool do_reduce(DisasContext *s, arg_rpr_esz *a, } #define DO_VPZ(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rpr_esz *a) \ -{ \ - static gen_helper_fp_reduce * const fns[4] = { \ - NULL, gen_helper_sve_##name##_h, \ - gen_helper_sve_##name##_s, \ - gen_helper_sve_##name##_d, \ + static gen_helper_fp_reduce * const name##_fns[4] = { \ + NULL, gen_helper_sve_##name##_h, \ + gen_helper_sve_##name##_s, gen_helper_sve_##name##_d, \ }; \ - return do_reduce(s, a, fns[a->esz]); \ -} + TRANS_FEAT(NAME, aa64_sve, do_reduce, a, name##_fns[a->esz]) DO_VPZ(FADDV, faddv) DO_VPZ(FMINNMV, fminnmv) @@ -3625,6 +3621,8 @@ DO_VPZ(FMAXNMV, fmaxnmv) DO_VPZ(FMINV, fminv) DO_VPZ(FMAXV, fmaxv) +#undef DO_VPZ + /* *** SVE Floating Point Unary Operations - Unpredicated Group */ From de58c6b09fcea732edac2a90dc4eb49ab448bf8b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:44 -0700 Subject: [PATCH 676/935] target/arm: Use TRANS_FEAT for FRECPE, FRSQRTE Rename do_zz_fp to gen_gvec_fpst_arg_zz, and move up. Split out gen_gvec_fpst_zz as a helper while we're at it. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-92-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 77 ++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 4a9ecd5e72..2f7651249a 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -152,6 +152,32 @@ static bool gen_gvec_ool_zz(DisasContext *s, gen_helper_gvec_2 *fn, return true; } +static bool gen_gvec_fpst_zz(DisasContext *s, gen_helper_gvec_2_ptr *fn, + int rd, int rn, int data, + ARMFPStatusFlavour flavour) +{ + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + TCGv_ptr status = fpstatus_ptr(flavour); + + tcg_gen_gvec_2_ptr(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + status, vsz, vsz, data, fn); + tcg_temp_free_ptr(status); + } + return true; +} + +static bool gen_gvec_fpst_arg_zz(DisasContext *s, gen_helper_gvec_2_ptr *fn, + arg_rr_esz *a, int data) +{ + return gen_gvec_fpst_zz(s, fn, a->rd, a->rn, data, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); +} + /* Invoke an out-of-line helper on 3 Zregs. */ static bool gen_gvec_ool_zzz(DisasContext *s, gen_helper_gvec_3 *fn, int rd, int rn, int rm, int data) @@ -3627,48 +3653,17 @@ DO_VPZ(FMAXV, fmaxv) *** SVE Floating Point Unary Operations - Unpredicated Group */ -static void do_zz_fp(DisasContext *s, arg_rr_esz *a, gen_helper_gvec_2_ptr *fn) -{ - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); +static gen_helper_gvec_2_ptr * const frecpe_fns[] = { + NULL, gen_helper_gvec_frecpe_h, + gen_helper_gvec_frecpe_s, gen_helper_gvec_frecpe_d, +}; +TRANS_FEAT(FRECPE, aa64_sve, gen_gvec_fpst_arg_zz, frecpe_fns[a->esz], a, 0) - tcg_gen_gvec_2_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - status, vsz, vsz, 0, fn); - tcg_temp_free_ptr(status); -} - -static bool trans_FRECPE(DisasContext *s, arg_rr_esz *a) -{ - static gen_helper_gvec_2_ptr * const fns[3] = { - gen_helper_gvec_frecpe_h, - gen_helper_gvec_frecpe_s, - gen_helper_gvec_frecpe_d, - }; - if (a->esz == 0) { - return false; - } - if (sve_access_check(s)) { - do_zz_fp(s, a, fns[a->esz - 1]); - } - return true; -} - -static bool trans_FRSQRTE(DisasContext *s, arg_rr_esz *a) -{ - static gen_helper_gvec_2_ptr * const fns[3] = { - gen_helper_gvec_frsqrte_h, - gen_helper_gvec_frsqrte_s, - gen_helper_gvec_frsqrte_d, - }; - if (a->esz == 0) { - return false; - } - if (sve_access_check(s)) { - do_zz_fp(s, a, fns[a->esz - 1]); - } - return true; -} +static gen_helper_gvec_2_ptr * const frsqrte_fns[] = { + NULL, gen_helper_gvec_frsqrte_h, + gen_helper_gvec_frsqrte_s, gen_helper_gvec_frsqrte_d, +}; +TRANS_FEAT(FRSQRTE, aa64_sve, gen_gvec_fpst_arg_zz, frsqrte_fns[a->esz], a, 0) /* *** SVE Floating Point Compare with Zero Group From ed6bb6b4d2817e5edc04a6214912f55b5e54c2c8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:45 -0700 Subject: [PATCH 677/935] target/arm: Expand frint_fns for MO_8 Simplify indexing of this array. This will allow folding of the illegal esz == 0 into the normal fn == NULL check. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-93-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 2f7651249a..99e5d89645 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -4167,7 +4167,8 @@ static bool trans_FCVTZU_dd(DisasContext *s, arg_rpr_esz *a) return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvtzu_dd); } -static gen_helper_gvec_3_ptr * const frint_fns[3] = { +static gen_helper_gvec_3_ptr * const frint_fns[] = { + NULL, gen_helper_sve_frint_h, gen_helper_sve_frint_s, gen_helper_sve_frint_d @@ -4179,7 +4180,7 @@ static bool trans_FRINTI(DisasContext *s, arg_rpr_esz *a) return false; } return do_zpz_ptr(s, a->rd, a->rn, a->pg, a->esz == MO_16, - frint_fns[a->esz - 1]); + frint_fns[a->esz]); } static bool trans_FRINTX(DisasContext *s, arg_rpr_esz *a) @@ -4222,7 +4223,7 @@ static bool trans_FRINTN(DisasContext *s, arg_rpr_esz *a) if (a->esz == 0) { return false; } - return do_frint_mode(s, a, float_round_nearest_even, frint_fns[a->esz - 1]); + return do_frint_mode(s, a, float_round_nearest_even, frint_fns[a->esz]); } static bool trans_FRINTP(DisasContext *s, arg_rpr_esz *a) @@ -4230,7 +4231,7 @@ static bool trans_FRINTP(DisasContext *s, arg_rpr_esz *a) if (a->esz == 0) { return false; } - return do_frint_mode(s, a, float_round_up, frint_fns[a->esz - 1]); + return do_frint_mode(s, a, float_round_up, frint_fns[a->esz]); } static bool trans_FRINTM(DisasContext *s, arg_rpr_esz *a) @@ -4238,7 +4239,7 @@ static bool trans_FRINTM(DisasContext *s, arg_rpr_esz *a) if (a->esz == 0) { return false; } - return do_frint_mode(s, a, float_round_down, frint_fns[a->esz - 1]); + return do_frint_mode(s, a, float_round_down, frint_fns[a->esz]); } static bool trans_FRINTZ(DisasContext *s, arg_rpr_esz *a) @@ -4246,7 +4247,7 @@ static bool trans_FRINTZ(DisasContext *s, arg_rpr_esz *a) if (a->esz == 0) { return false; } - return do_frint_mode(s, a, float_round_to_zero, frint_fns[a->esz - 1]); + return do_frint_mode(s, a, float_round_to_zero, frint_fns[a->esz]); } static bool trans_FRINTA(DisasContext *s, arg_rpr_esz *a) @@ -4254,7 +4255,7 @@ static bool trans_FRINTA(DisasContext *s, arg_rpr_esz *a) if (a->esz == 0) { return false; } - return do_frint_mode(s, a, float_round_ties_away, frint_fns[a->esz - 1]); + return do_frint_mode(s, a, float_round_ties_away, frint_fns[a->esz]); } static bool trans_FRECPX(DisasContext *s, arg_rpr_esz *a) From 0360730c467397c32be9b1bc4dcb31b62ab7baac Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:46 -0700 Subject: [PATCH 678/935] target/arm: Rename do_zpz_ptr to gen_gvec_ool_fpst_arg_zpz Rename the function to match other expansion function and move to be adjacent. Split out gen_gvec_fpst_zzp as a helper while we're at it. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-94-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 392 ++++++++++++------------------------- 1 file changed, 129 insertions(+), 263 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 99e5d89645..2a5fbec2d6 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -318,6 +318,33 @@ static bool gen_gvec_ool_arg_zpzi(DisasContext *s, gen_helper_gvec_3 *fn, return gen_gvec_ool_zzp(s, fn, a->rd, a->rn, a->pg, a->imm); } +static bool gen_gvec_fpst_zzp(DisasContext *s, gen_helper_gvec_3_ptr *fn, + int rd, int rn, int pg, int data, + ARMFPStatusFlavour flavour) +{ + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + TCGv_ptr status = fpstatus_ptr(flavour); + + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + pred_full_reg_offset(s, pg), + status, vsz, vsz, data, fn); + tcg_temp_free_ptr(status); + } + return true; +} + +static bool gen_gvec_fpst_arg_zpz(DisasContext *s, gen_helper_gvec_3_ptr *fn, + arg_rpr_esz *a, int data, + ARMFPStatusFlavour flavour) +{ + return gen_gvec_fpst_zzp(s, fn, a->rd, a->rn, a->pg, data, flavour); +} + /* Invoke an out-of-line helper on 3 Zregs and a predicate. */ static bool gen_gvec_ool_zzzp(DisasContext *s, gen_helper_gvec_4 *fn, int rd, int rn, int rm, int pg, int data) @@ -4044,128 +4071,53 @@ static bool trans_FCMLA_zzxz(DisasContext *s, arg_FCMLA_zzxz *a) *** SVE Floating Point Unary Operations Predicated Group */ -static bool do_zpz_ptr(DisasContext *s, int rd, int rn, int pg, - bool is_fp16, gen_helper_gvec_3_ptr *fn) -{ - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(is_fp16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - pred_full_reg_offset(s, pg), - status, vsz, vsz, 0, fn); - tcg_temp_free_ptr(status); - } - return true; -} +TRANS_FEAT(FCVT_sh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvt_sh, a, 0, FPST_FPCR) +TRANS_FEAT(FCVT_hs, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvt_hs, a, 0, FPST_FPCR) -static bool trans_FCVT_sh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvt_sh); -} +TRANS_FEAT(BFCVT, aa64_sve_bf16, gen_gvec_fpst_arg_zpz, + gen_helper_sve_bfcvt, a, 0, FPST_FPCR) -static bool trans_FCVT_hs(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvt_hs); -} +TRANS_FEAT(FCVT_dh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvt_dh, a, 0, FPST_FPCR) +TRANS_FEAT(FCVT_hd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvt_hd, a, 0, FPST_FPCR) +TRANS_FEAT(FCVT_ds, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvt_ds, a, 0, FPST_FPCR) +TRANS_FEAT(FCVT_sd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvt_sd, a, 0, FPST_FPCR) -static bool trans_BFCVT(DisasContext *s, arg_rpr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_bf16, s)) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_bfcvt); -} +TRANS_FEAT(FCVTZS_hh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzs_hh, a, 0, FPST_FPCR_F16) +TRANS_FEAT(FCVTZU_hh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzu_hh, a, 0, FPST_FPCR_F16) +TRANS_FEAT(FCVTZS_hs, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzs_hs, a, 0, FPST_FPCR_F16) +TRANS_FEAT(FCVTZU_hs, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzu_hs, a, 0, FPST_FPCR_F16) +TRANS_FEAT(FCVTZS_hd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzs_hd, a, 0, FPST_FPCR_F16) +TRANS_FEAT(FCVTZU_hd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzu_hd, a, 0, FPST_FPCR_F16) -static bool trans_FCVT_dh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvt_dh); -} +TRANS_FEAT(FCVTZS_ss, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzs_ss, a, 0, FPST_FPCR) +TRANS_FEAT(FCVTZU_ss, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzu_ss, a, 0, FPST_FPCR) +TRANS_FEAT(FCVTZS_sd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzs_sd, a, 0, FPST_FPCR) +TRANS_FEAT(FCVTZU_sd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzu_sd, a, 0, FPST_FPCR) +TRANS_FEAT(FCVTZS_ds, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzs_ds, a, 0, FPST_FPCR) +TRANS_FEAT(FCVTZU_ds, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzu_ds, a, 0, FPST_FPCR) -static bool trans_FCVT_hd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvt_hd); -} - -static bool trans_FCVT_ds(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvt_ds); -} - -static bool trans_FCVT_sd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvt_sd); -} - -static bool trans_FCVTZS_hh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_fcvtzs_hh); -} - -static bool trans_FCVTZU_hh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_fcvtzu_hh); -} - -static bool trans_FCVTZS_hs(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_fcvtzs_hs); -} - -static bool trans_FCVTZU_hs(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_fcvtzu_hs); -} - -static bool trans_FCVTZS_hd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_fcvtzs_hd); -} - -static bool trans_FCVTZU_hd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_fcvtzu_hd); -} - -static bool trans_FCVTZS_ss(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvtzs_ss); -} - -static bool trans_FCVTZU_ss(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvtzu_ss); -} - -static bool trans_FCVTZS_sd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvtzs_sd); -} - -static bool trans_FCVTZU_sd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvtzu_sd); -} - -static bool trans_FCVTZS_ds(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvtzs_ds); -} - -static bool trans_FCVTZU_ds(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvtzu_ds); -} - -static bool trans_FCVTZS_dd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvtzs_dd); -} - -static bool trans_FCVTZU_dd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_fcvtzu_dd); -} +TRANS_FEAT(FCVTZS_dd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzs_dd, a, 0, FPST_FPCR) +TRANS_FEAT(FCVTZU_dd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_fcvtzu_dd, a, 0, FPST_FPCR) static gen_helper_gvec_3_ptr * const frint_fns[] = { NULL, @@ -4173,28 +4125,17 @@ static gen_helper_gvec_3_ptr * const frint_fns[] = { gen_helper_sve_frint_s, gen_helper_sve_frint_d }; +TRANS_FEAT(FRINTI, aa64_sve, gen_gvec_fpst_arg_zpz, frint_fns[a->esz], + a, 0, a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) -static bool trans_FRINTI(DisasContext *s, arg_rpr_esz *a) -{ - if (a->esz == 0) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, a->esz == MO_16, - frint_fns[a->esz]); -} - -static bool trans_FRINTX(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3_ptr * const fns[3] = { - gen_helper_sve_frintx_h, - gen_helper_sve_frintx_s, - gen_helper_sve_frintx_d - }; - if (a->esz == 0) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, a->esz == MO_16, fns[a->esz - 1]); -} +static gen_helper_gvec_3_ptr * const frintx_fns[] = { + NULL, + gen_helper_sve_frintx_h, + gen_helper_sve_frintx_s, + gen_helper_sve_frintx_d +}; +TRANS_FEAT(FRINTX, aa64_sve, gen_gvec_fpst_arg_zpz, frintx_fns[a->esz], + a, 0, a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); static bool do_frint_mode(DisasContext *s, arg_rpr_esz *a, int mode, gen_helper_gvec_3_ptr *fn) @@ -4258,101 +4199,53 @@ static bool trans_FRINTA(DisasContext *s, arg_rpr_esz *a) return do_frint_mode(s, a, float_round_ties_away, frint_fns[a->esz]); } -static bool trans_FRECPX(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3_ptr * const fns[3] = { - gen_helper_sve_frecpx_h, - gen_helper_sve_frecpx_s, - gen_helper_sve_frecpx_d - }; - if (a->esz == 0) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, a->esz == MO_16, fns[a->esz - 1]); -} +static gen_helper_gvec_3_ptr * const frecpx_fns[] = { + NULL, gen_helper_sve_frecpx_h, + gen_helper_sve_frecpx_s, gen_helper_sve_frecpx_d, +}; +TRANS_FEAT(FRECPX, aa64_sve, gen_gvec_fpst_arg_zpz, frecpx_fns[a->esz], + a, 0, a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) -static bool trans_FSQRT(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3_ptr * const fns[3] = { - gen_helper_sve_fsqrt_h, - gen_helper_sve_fsqrt_s, - gen_helper_sve_fsqrt_d - }; - if (a->esz == 0) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, a->esz == MO_16, fns[a->esz - 1]); -} +static gen_helper_gvec_3_ptr * const fsqrt_fns[] = { + NULL, gen_helper_sve_fsqrt_h, + gen_helper_sve_fsqrt_s, gen_helper_sve_fsqrt_d, +}; +TRANS_FEAT(FSQRT, aa64_sve, gen_gvec_fpst_arg_zpz, fsqrt_fns[a->esz], + a, 0, a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) -static bool trans_SCVTF_hh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_scvt_hh); -} +TRANS_FEAT(SCVTF_hh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_scvt_hh, a, 0, FPST_FPCR_F16) +TRANS_FEAT(SCVTF_sh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_scvt_sh, a, 0, FPST_FPCR_F16) +TRANS_FEAT(SCVTF_dh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_scvt_dh, a, 0, FPST_FPCR_F16) -static bool trans_SCVTF_sh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_scvt_sh); -} +TRANS_FEAT(SCVTF_ss, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_scvt_ss, a, 0, FPST_FPCR) +TRANS_FEAT(SCVTF_ds, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_scvt_ds, a, 0, FPST_FPCR) -static bool trans_SCVTF_dh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_scvt_dh); -} +TRANS_FEAT(SCVTF_sd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_scvt_sd, a, 0, FPST_FPCR) +TRANS_FEAT(SCVTF_dd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_scvt_dd, a, 0, FPST_FPCR) -static bool trans_SCVTF_ss(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_scvt_ss); -} +TRANS_FEAT(UCVTF_hh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_ucvt_hh, a, 0, FPST_FPCR_F16) +TRANS_FEAT(UCVTF_sh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_ucvt_sh, a, 0, FPST_FPCR_F16) +TRANS_FEAT(UCVTF_dh, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_ucvt_dh, a, 0, FPST_FPCR_F16) -static bool trans_SCVTF_ds(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_scvt_ds); -} +TRANS_FEAT(UCVTF_ss, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_ucvt_ss, a, 0, FPST_FPCR) +TRANS_FEAT(UCVTF_ds, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_ucvt_ds, a, 0, FPST_FPCR) +TRANS_FEAT(UCVTF_sd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_ucvt_sd, a, 0, FPST_FPCR) -static bool trans_SCVTF_sd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_scvt_sd); -} - -static bool trans_SCVTF_dd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_scvt_dd); -} - -static bool trans_UCVTF_hh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_ucvt_hh); -} - -static bool trans_UCVTF_sh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_ucvt_sh); -} - -static bool trans_UCVTF_dh(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, true, gen_helper_sve_ucvt_dh); -} - -static bool trans_UCVTF_ss(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_ucvt_ss); -} - -static bool trans_UCVTF_ds(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_ucvt_ds); -} - -static bool trans_UCVTF_sd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_ucvt_sd); -} - -static bool trans_UCVTF_dd(DisasContext *s, arg_rpr_esz *a) -{ - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_ucvt_dd); -} +TRANS_FEAT(UCVTF_dd, aa64_sve, gen_gvec_fpst_arg_zpz, + gen_helper_sve_ucvt_dd, a, 0, FPST_FPCR) /* *** SVE Memory - 32-bit Gather and Unsized Contiguous Group @@ -7389,45 +7282,18 @@ TRANS_FEAT(SM4EKEY, aa64_sve2_sm4, gen_gvec_ool_arg_zzz, TRANS_FEAT(RAX1, aa64_sve2_sha3, gen_gvec_fn_arg_zzz, gen_gvec_rax1, a) -static bool trans_FCVTNT_sh(DisasContext *s, arg_rpr_esz *a) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve2_fcvtnt_sh); -} +TRANS_FEAT(FCVTNT_sh, aa64_sve2, gen_gvec_fpst_arg_zpz, + gen_helper_sve2_fcvtnt_sh, a, 0, FPST_FPCR) +TRANS_FEAT(FCVTNT_ds, aa64_sve2, gen_gvec_fpst_arg_zpz, + gen_helper_sve2_fcvtnt_ds, a, 0, FPST_FPCR) -static bool trans_BFCVTNT(DisasContext *s, arg_rpr_esz *a) -{ - if (!dc_isar_feature(aa64_sve_bf16, s)) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve_bfcvtnt); -} +TRANS_FEAT(BFCVTNT, aa64_sve_bf16, gen_gvec_fpst_arg_zpz, + gen_helper_sve_bfcvtnt, a, 0, FPST_FPCR) -static bool trans_FCVTNT_ds(DisasContext *s, arg_rpr_esz *a) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve2_fcvtnt_ds); -} - -static bool trans_FCVTLT_hs(DisasContext *s, arg_rpr_esz *a) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve2_fcvtlt_hs); -} - -static bool trans_FCVTLT_sd(DisasContext *s, arg_rpr_esz *a) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_zpz_ptr(s, a->rd, a->rn, a->pg, false, gen_helper_sve2_fcvtlt_sd); -} +TRANS_FEAT(FCVTLT_hs, aa64_sve2, gen_gvec_fpst_arg_zpz, + gen_helper_sve2_fcvtlt_hs, a, 0, FPST_FPCR) +TRANS_FEAT(FCVTLT_sd, aa64_sve2, gen_gvec_fpst_arg_zpz, + gen_helper_sve2_fcvtlt_sd, a, 0, FPST_FPCR) static bool trans_FCVTX_ds(DisasContext *s, arg_rpr_esz *a) { From 13c0dd173952b22a8705017e234373f2ba3b0d25 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:47 -0700 Subject: [PATCH 679/935] target/arm: Move null function and sve check into do_frint_mode Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-95-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 52 +++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 2a5fbec2d6..43cfd2818e 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -4140,62 +4140,56 @@ TRANS_FEAT(FRINTX, aa64_sve, gen_gvec_fpst_arg_zpz, frintx_fns[a->esz], static bool do_frint_mode(DisasContext *s, arg_rpr_esz *a, int mode, gen_helper_gvec_3_ptr *fn) { - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_i32 tmode = tcg_const_i32(mode); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); + unsigned vsz; + TCGv_i32 tmode; + TCGv_ptr status; - gen_helper_set_rmode(tmode, tmode, status); - - tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - pred_full_reg_offset(s, a->pg), - status, vsz, vsz, 0, fn); - - gen_helper_set_rmode(tmode, tmode, status); - tcg_temp_free_i32(tmode); - tcg_temp_free_ptr(status); + if (fn == NULL) { + return false; } + if (!sve_access_check(s)) { + return true; + } + + vsz = vec_full_reg_size(s); + tmode = tcg_const_i32(mode); + status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); + + gen_helper_set_rmode(tmode, tmode, status); + + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + pred_full_reg_offset(s, a->pg), + status, vsz, vsz, 0, fn); + + gen_helper_set_rmode(tmode, tmode, status); + tcg_temp_free_i32(tmode); + tcg_temp_free_ptr(status); return true; } static bool trans_FRINTN(DisasContext *s, arg_rpr_esz *a) { - if (a->esz == 0) { - return false; - } return do_frint_mode(s, a, float_round_nearest_even, frint_fns[a->esz]); } static bool trans_FRINTP(DisasContext *s, arg_rpr_esz *a) { - if (a->esz == 0) { - return false; - } return do_frint_mode(s, a, float_round_up, frint_fns[a->esz]); } static bool trans_FRINTM(DisasContext *s, arg_rpr_esz *a) { - if (a->esz == 0) { - return false; - } return do_frint_mode(s, a, float_round_down, frint_fns[a->esz]); } static bool trans_FRINTZ(DisasContext *s, arg_rpr_esz *a) { - if (a->esz == 0) { - return false; - } return do_frint_mode(s, a, float_round_to_zero, frint_fns[a->esz]); } static bool trans_FRINTA(DisasContext *s, arg_rpr_esz *a) { - if (a->esz == 0) { - return false; - } return do_frint_mode(s, a, float_round_ties_away, frint_fns[a->esz]); } From 27645836952081775138f8c9a118de63e327f7fb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:48 -0700 Subject: [PATCH 680/935] target/arm: Use TRANS_FEAT for do_frint_mode Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-96-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 53 ++++++++++---------------------------- 1 file changed, 14 insertions(+), 39 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 43cfd2818e..552a551fef 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -4168,30 +4168,16 @@ static bool do_frint_mode(DisasContext *s, arg_rpr_esz *a, return true; } -static bool trans_FRINTN(DisasContext *s, arg_rpr_esz *a) -{ - return do_frint_mode(s, a, float_round_nearest_even, frint_fns[a->esz]); -} - -static bool trans_FRINTP(DisasContext *s, arg_rpr_esz *a) -{ - return do_frint_mode(s, a, float_round_up, frint_fns[a->esz]); -} - -static bool trans_FRINTM(DisasContext *s, arg_rpr_esz *a) -{ - return do_frint_mode(s, a, float_round_down, frint_fns[a->esz]); -} - -static bool trans_FRINTZ(DisasContext *s, arg_rpr_esz *a) -{ - return do_frint_mode(s, a, float_round_to_zero, frint_fns[a->esz]); -} - -static bool trans_FRINTA(DisasContext *s, arg_rpr_esz *a) -{ - return do_frint_mode(s, a, float_round_ties_away, frint_fns[a->esz]); -} +TRANS_FEAT(FRINTN, aa64_sve, do_frint_mode, a, + float_round_nearest_even, frint_fns[a->esz]) +TRANS_FEAT(FRINTP, aa64_sve, do_frint_mode, a, + float_round_up, frint_fns[a->esz]) +TRANS_FEAT(FRINTM, aa64_sve, do_frint_mode, a, + float_round_down, frint_fns[a->esz]) +TRANS_FEAT(FRINTZ, aa64_sve, do_frint_mode, a, + float_round_to_zero, frint_fns[a->esz]) +TRANS_FEAT(FRINTA, aa64_sve, do_frint_mode, a, + float_round_ties_away, frint_fns[a->esz]) static gen_helper_gvec_3_ptr * const frecpx_fns[] = { NULL, gen_helper_sve_frecpx_h, @@ -7289,21 +7275,10 @@ TRANS_FEAT(FCVTLT_hs, aa64_sve2, gen_gvec_fpst_arg_zpz, TRANS_FEAT(FCVTLT_sd, aa64_sve2, gen_gvec_fpst_arg_zpz, gen_helper_sve2_fcvtlt_sd, a, 0, FPST_FPCR) -static bool trans_FCVTX_ds(DisasContext *s, arg_rpr_esz *a) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_frint_mode(s, a, float_round_to_odd, gen_helper_sve_fcvt_ds); -} - -static bool trans_FCVTXNT_ds(DisasContext *s, arg_rpr_esz *a) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return do_frint_mode(s, a, float_round_to_odd, gen_helper_sve2_fcvtnt_ds); -} +TRANS_FEAT(FCVTX_ds, aa64_sve2, do_frint_mode, a, + float_round_to_odd, gen_helper_sve_fcvt_ds) +TRANS_FEAT(FCVTXNT_ds, aa64_sve2, do_frint_mode, a, + float_round_to_odd, gen_helper_sve2_fcvtnt_ds) static bool trans_FLOGB(DisasContext *s, arg_rpr_esz *a) { From 7b9dfcfec889ba10cda7f2426de253f73226f129 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:49 -0700 Subject: [PATCH 681/935] target/arm: Use TRANS_FEAT for FLOGB Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-97-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 552a551fef..2f96f52293 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -7280,29 +7280,12 @@ TRANS_FEAT(FCVTX_ds, aa64_sve2, do_frint_mode, a, TRANS_FEAT(FCVTXNT_ds, aa64_sve2, do_frint_mode, a, float_round_to_odd, gen_helper_sve2_fcvtnt_ds) -static bool trans_FLOGB(DisasContext *s, arg_rpr_esz *a) -{ - static gen_helper_gvec_3_ptr * const fns[] = { - NULL, gen_helper_flogb_h, - gen_helper_flogb_s, gen_helper_flogb_d - }; - - if (!dc_isar_feature(aa64_sve2, s) || fns[a->esz] == NULL) { - return false; - } - if (sve_access_check(s)) { - TCGv_ptr status = - fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - unsigned vsz = vec_full_reg_size(s); - - tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - pred_full_reg_offset(s, a->pg), - status, vsz, vsz, 0, fns[a->esz]); - tcg_temp_free_ptr(status); - } - return true; -} +static gen_helper_gvec_3_ptr * const flogb_fns[] = { + NULL, gen_helper_flogb_h, + gen_helper_flogb_s, gen_helper_flogb_d +}; +TRANS_FEAT(FLOGB, aa64_sve2, gen_gvec_fpst_arg_zpz, flogb_fns[a->esz], + a, 0, a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) static bool do_FMLAL_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sub, bool sel) { From 63d6aef86c137765ce3d0b884cf2d54a14bbaa3b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:50 -0700 Subject: [PATCH 682/935] target/arm: Use TRANS_FEAT for do_ppz_fp Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-98-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 41 ++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 2f96f52293..2ee48186ba 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3696,35 +3696,32 @@ TRANS_FEAT(FRSQRTE, aa64_sve, gen_gvec_fpst_arg_zz, frsqrte_fns[a->esz], a, 0) *** SVE Floating Point Compare with Zero Group */ -static void do_ppz_fp(DisasContext *s, arg_rpr_esz *a, +static bool do_ppz_fp(DisasContext *s, arg_rpr_esz *a, gen_helper_gvec_3_ptr *fn) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + TCGv_ptr status = + fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_3_ptr(pred_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - pred_full_reg_offset(s, a->pg), - status, vsz, vsz, 0, fn); - tcg_temp_free_ptr(status); + tcg_gen_gvec_3_ptr(pred_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + pred_full_reg_offset(s, a->pg), + status, vsz, vsz, 0, fn); + tcg_temp_free_ptr(status); + } + return true; } #define DO_PPZ(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rpr_esz *a) \ -{ \ - static gen_helper_gvec_3_ptr * const fns[3] = { \ - gen_helper_sve_##name##_h, \ - gen_helper_sve_##name##_s, \ - gen_helper_sve_##name##_d, \ + static gen_helper_gvec_3_ptr * const name##_fns[] = { \ + NULL, gen_helper_sve_##name##_h, \ + gen_helper_sve_##name##_s, gen_helper_sve_##name##_d, \ }; \ - if (a->esz == 0) { \ - return false; \ - } \ - if (sve_access_check(s)) { \ - do_ppz_fp(s, a, fns[a->esz - 1]); \ - } \ - return true; \ -} + TRANS_FEAT(NAME, aa64_sve, do_ppz_fp, a, name##_fns[a->esz]) DO_PPZ(FCMGE_ppz0, fcmge0) DO_PPZ(FCMGT_ppz0, fcmgt0) From 7e2d07ff87f43e892335fad7fccae6497afa6ebc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:51 -0700 Subject: [PATCH 683/935] target/arm: Rename do_zpzz_ptr to gen_gvec_fpst_arg_zpzz Rename the function to match other expansion functions and move to be adjacent. Split out gen_gvec_fpst_zzzp as a helper while we're at it. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-99-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 52 +++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 2ee48186ba..f0f2db351e 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -369,6 +369,35 @@ static bool gen_gvec_ool_arg_zpzz(DisasContext *s, gen_helper_gvec_4 *fn, return gen_gvec_ool_zzzp(s, fn, a->rd, a->rn, a->rm, a->pg, data); } +/* Invoke an out-of-line helper on 3 Zregs and a predicate. */ +static bool gen_gvec_fpst_zzzp(DisasContext *s, gen_helper_gvec_4_ptr *fn, + int rd, int rn, int rm, int pg, int data, + ARMFPStatusFlavour flavour) +{ + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + TCGv_ptr status = fpstatus_ptr(flavour); + + tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), + pred_full_reg_offset(s, pg), + status, vsz, vsz, data, fn); + tcg_temp_free_ptr(status); + } + return true; +} + +static bool gen_gvec_fpst_arg_zpzz(DisasContext *s, gen_helper_gvec_4_ptr *fn, + arg_rprr_esz *a) +{ + return gen_gvec_fpst_zzzp(s, fn, a->rd, a->rn, a->rm, a->pg, 0, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); +} + /* Invoke a vector expander on two Zregs and an immediate. */ static bool gen_gvec_fn_zzi(DisasContext *s, GVecGen2iFn *gvec_fn, int esz, int rd, int rn, uint64_t imm) @@ -3812,25 +3841,6 @@ DO_FP3(FRSQRTS, rsqrts) *** SVE Floating Point Arithmetic - Predicated Group */ -static bool do_zpzz_fp(DisasContext *s, arg_rprr_esz *a, - gen_helper_gvec_4_ptr *fn) -{ - if (fn == NULL) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - pred_full_reg_offset(s, a->pg), - status, vsz, vsz, 0, fn); - tcg_temp_free_ptr(status); - } - return true; -} - #define DO_FP3(NAME, name) \ static bool trans_##NAME(DisasContext *s, arg_rprr_esz *a) \ { \ @@ -3838,7 +3848,7 @@ static bool trans_##NAME(DisasContext *s, arg_rprr_esz *a) \ NULL, gen_helper_sve_##name##_h, \ gen_helper_sve_##name##_s, gen_helper_sve_##name##_d \ }; \ - return do_zpzz_fp(s, a, fns[a->esz]); \ + return gen_gvec_fpst_arg_zpzz(s, fns[a->esz], a); \ } DO_FP3(FADD_zpzz, fadd) @@ -7121,7 +7131,7 @@ static bool do_sve2_zpzz_fp(DisasContext *s, arg_rprr_esz *a, if (!dc_isar_feature(aa64_sve2, s)) { return false; } - return do_zpzz_fp(s, a, fn); + return gen_gvec_fpst_arg_zpzz(s, fn, a); } #define DO_SVE2_ZPZZ_FP(NAME, name) \ From 7de2617b7ae54536f291dc8df1b5a50863badae0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:52 -0700 Subject: [PATCH 684/935] target/arm: Use TRANS_FEAT for gen_gvec_fpst_arg_zpzz Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-100-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 68 ++++++++++++-------------------------- 1 file changed, 22 insertions(+), 46 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index f0f2db351e..1108494919 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3841,29 +3841,24 @@ DO_FP3(FRSQRTS, rsqrts) *** SVE Floating Point Arithmetic - Predicated Group */ -#define DO_FP3(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rprr_esz *a) \ -{ \ - static gen_helper_gvec_4_ptr * const fns[4] = { \ - NULL, gen_helper_sve_##name##_h, \ - gen_helper_sve_##name##_s, gen_helper_sve_##name##_d \ - }; \ - return gen_gvec_fpst_arg_zpzz(s, fns[a->esz], a); \ -} +#define DO_ZPZZ_FP(NAME, FEAT, name) \ + static gen_helper_gvec_4_ptr * const name##_zpzz_fns[4] = { \ + NULL, gen_helper_##name##_h, \ + gen_helper_##name##_s, gen_helper_##name##_d \ + }; \ + TRANS_FEAT(NAME, FEAT, gen_gvec_fpst_arg_zpzz, name##_zpzz_fns[a->esz], a) -DO_FP3(FADD_zpzz, fadd) -DO_FP3(FSUB_zpzz, fsub) -DO_FP3(FMUL_zpzz, fmul) -DO_FP3(FMIN_zpzz, fmin) -DO_FP3(FMAX_zpzz, fmax) -DO_FP3(FMINNM_zpzz, fminnum) -DO_FP3(FMAXNM_zpzz, fmaxnum) -DO_FP3(FABD, fabd) -DO_FP3(FSCALE, fscalbn) -DO_FP3(FDIV, fdiv) -DO_FP3(FMULX, fmulx) - -#undef DO_FP3 +DO_ZPZZ_FP(FADD_zpzz, aa64_sve, sve_fadd) +DO_ZPZZ_FP(FSUB_zpzz, aa64_sve, sve_fsub) +DO_ZPZZ_FP(FMUL_zpzz, aa64_sve, sve_fmul) +DO_ZPZZ_FP(FMIN_zpzz, aa64_sve, sve_fmin) +DO_ZPZZ_FP(FMAX_zpzz, aa64_sve, sve_fmax) +DO_ZPZZ_FP(FMINNM_zpzz, aa64_sve, sve_fminnum) +DO_ZPZZ_FP(FMAXNM_zpzz, aa64_sve, sve_fmaxnum) +DO_ZPZZ_FP(FABD, aa64_sve, sve_fabd) +DO_ZPZZ_FP(FSCALE, aa64_sve, sve_fscalbn) +DO_ZPZZ_FP(FDIV, aa64_sve, sve_fdiv) +DO_ZPZZ_FP(FMULX, aa64_sve, sve_fmulx) typedef void gen_helper_sve_fp2scalar(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr, TCGv_i32); @@ -7125,30 +7120,11 @@ TRANS_FEAT(HISTCNT, aa64_sve2, gen_gvec_ool_arg_zpzz, TRANS_FEAT(HISTSEG, aa64_sve2, gen_gvec_ool_arg_zzz, a->esz == 0 ? gen_helper_sve2_histseg : NULL, a, 0) -static bool do_sve2_zpzz_fp(DisasContext *s, arg_rprr_esz *a, - gen_helper_gvec_4_ptr *fn) -{ - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } - return gen_gvec_fpst_arg_zpzz(s, fn, a); -} - -#define DO_SVE2_ZPZZ_FP(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rprr_esz *a) \ -{ \ - static gen_helper_gvec_4_ptr * const fns[4] = { \ - NULL, gen_helper_sve2_##name##_zpzz_h, \ - gen_helper_sve2_##name##_zpzz_s, gen_helper_sve2_##name##_zpzz_d \ - }; \ - return do_sve2_zpzz_fp(s, a, fns[a->esz]); \ -} - -DO_SVE2_ZPZZ_FP(FADDP, faddp) -DO_SVE2_ZPZZ_FP(FMAXNMP, fmaxnmp) -DO_SVE2_ZPZZ_FP(FMINNMP, fminnmp) -DO_SVE2_ZPZZ_FP(FMAXP, fmaxp) -DO_SVE2_ZPZZ_FP(FMINP, fminp) +DO_ZPZZ_FP(FADDP, aa64_sve2, sve2_faddp_zpzz) +DO_ZPZZ_FP(FMAXNMP, aa64_sve2, sve2_fmaxnmp_zpzz) +DO_ZPZZ_FP(FMINNMP, aa64_sve2, sve2_fminnmp_zpzz) +DO_ZPZZ_FP(FMAXP, aa64_sve2, sve2_fmaxp_zpzz) +DO_ZPZZ_FP(FMINP, aa64_sve2, sve2_fminp_zpzz) /* * SVE Integer Multiply-Add (unpredicated) From 6f5cd67008ec3fc3e270ac41bbd80f3b510613a5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:53 -0700 Subject: [PATCH 685/935] target/arm: Use TRANS_FEAT for FCADD Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-101-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 1108494919..e323b2d6d5 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3966,29 +3966,13 @@ DO_FPCMP(FACGT, facgt) #undef DO_FPCMP -static bool trans_FCADD(DisasContext *s, arg_FCADD *a) -{ - static gen_helper_gvec_4_ptr * const fns[3] = { - gen_helper_sve_fcadd_h, - gen_helper_sve_fcadd_s, - gen_helper_sve_fcadd_d - }; - - if (a->esz == 0) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - pred_full_reg_offset(s, a->pg), - status, vsz, vsz, a->rot, fns[a->esz - 1]); - tcg_temp_free_ptr(status); - } - return true; -} +static gen_helper_gvec_4_ptr * const fcadd_fns[] = { + NULL, gen_helper_sve_fcadd_h, + gen_helper_sve_fcadd_s, gen_helper_sve_fcadd_d, +}; +TRANS_FEAT(FCADD, aa64_sve, gen_gvec_fpst_zzzp, fcadd_fns[a->esz], + a->rd, a->rn, a->rm, a->pg, a->rot, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) static bool do_fmla(DisasContext *s, arg_rprrr_esz *a, gen_helper_gvec_5_ptr *fn) From e14da11035e165798e611bcd6479ab0e54516de8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:54 -0700 Subject: [PATCH 686/935] target/arm: Introduce gen_gvec_fpst_zzzzp Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-102-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 59 +++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index e323b2d6d5..8f50956d3b 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -289,6 +289,30 @@ static bool gen_gvec_fpst_zzzz(DisasContext *s, gen_helper_gvec_4_ptr *fn, return ret; } +/* Invoke an out-of-line helper on 4 Zregs, 1 Preg, plus fpst. */ +static bool gen_gvec_fpst_zzzzp(DisasContext *s, gen_helper_gvec_5_ptr *fn, + int rd, int rn, int rm, int ra, int pg, + int data, ARMFPStatusFlavour flavour) +{ + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + TCGv_ptr status = fpstatus_ptr(flavour); + + tcg_gen_gvec_5_ptr(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), + vec_full_reg_offset(s, ra), + pred_full_reg_offset(s, pg), + status, vsz, vsz, data, fn); + + tcg_temp_free_ptr(status); + } + return true; +} + /* Invoke an out-of-line helper on 2 Zregs and a predicate. */ static bool gen_gvec_ool_zzp(DisasContext *s, gen_helper_gvec_3 *fn, int rd, int rn, int pg, int data) @@ -3977,21 +4001,8 @@ TRANS_FEAT(FCADD, aa64_sve, gen_gvec_fpst_zzzp, fcadd_fns[a->esz], static bool do_fmla(DisasContext *s, arg_rprrr_esz *a, gen_helper_gvec_5_ptr *fn) { - if (a->esz == 0) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_5_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - pred_full_reg_offset(s, a->pg), - status, vsz, vsz, 0, fn); - tcg_temp_free_ptr(status); - } - return true; + return gen_gvec_fpst_zzzzp(s, fn, a->rd, a->rn, a->rm, a->ra, a->pg, 0, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); } #define DO_FMLA(NAME, name) \ @@ -4020,21 +4031,9 @@ static bool trans_FCMLA_zpzzz(DisasContext *s, arg_FCMLA_zpzzz *a) gen_helper_sve_fcmla_zpzzz_d, }; - if (a->esz == 0) { - return false; - } - if (sve_access_check(s)) { - unsigned vsz = vec_full_reg_size(s); - TCGv_ptr status = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - tcg_gen_gvec_5_ptr(vec_full_reg_offset(s, a->rd), - vec_full_reg_offset(s, a->rn), - vec_full_reg_offset(s, a->rm), - vec_full_reg_offset(s, a->ra), - pred_full_reg_offset(s, a->pg), - status, vsz, vsz, a->rot, fns[a->esz]); - tcg_temp_free_ptr(status); - } - return true; + return gen_gvec_fpst_zzzzp(s, fns[a->esz], a->rd, a->rn, a->rm, + a->ra, a->pg, a->rot, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); } static bool trans_FCMLA_zzxz(DisasContext *s, arg_FCMLA_zzxz *a) From 498be5b87d61f377b38701b31e460eed7a104c0d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:55 -0700 Subject: [PATCH 687/935] target/arm: Use TRANS_FEAT for gen_gvec_fpst_zzzzp Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-103-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 42 +++++++++++++------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 8f50956d3b..75854a7c6c 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3998,22 +3998,14 @@ TRANS_FEAT(FCADD, aa64_sve, gen_gvec_fpst_zzzp, fcadd_fns[a->esz], a->rd, a->rn, a->rm, a->pg, a->rot, a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) -static bool do_fmla(DisasContext *s, arg_rprrr_esz *a, - gen_helper_gvec_5_ptr *fn) -{ - return gen_gvec_fpst_zzzzp(s, fn, a->rd, a->rn, a->rm, a->ra, a->pg, 0, - a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); -} - #define DO_FMLA(NAME, name) \ -static bool trans_##NAME(DisasContext *s, arg_rprrr_esz *a) \ -{ \ - static gen_helper_gvec_5_ptr * const fns[4] = { \ - NULL, gen_helper_sve_##name##_h, \ - gen_helper_sve_##name##_s, gen_helper_sve_##name##_d \ - }; \ - return do_fmla(s, a, fns[a->esz]); \ -} + static gen_helper_gvec_5_ptr * const name##_fns[4] = { \ + NULL, gen_helper_sve_##name##_h, \ + gen_helper_sve_##name##_s, gen_helper_sve_##name##_d \ + }; \ + TRANS_FEAT(NAME, aa64_sve, gen_gvec_fpst_zzzzp, name##_fns[a->esz], \ + a->rd, a->rn, a->rm, a->ra, a->pg, 0, \ + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) DO_FMLA(FMLA_zpzzz, fmla_zpzzz) DO_FMLA(FMLS_zpzzz, fmls_zpzzz) @@ -4022,19 +4014,13 @@ DO_FMLA(FNMLS_zpzzz, fnmls_zpzzz) #undef DO_FMLA -static bool trans_FCMLA_zpzzz(DisasContext *s, arg_FCMLA_zpzzz *a) -{ - static gen_helper_gvec_5_ptr * const fns[4] = { - NULL, - gen_helper_sve_fcmla_zpzzz_h, - gen_helper_sve_fcmla_zpzzz_s, - gen_helper_sve_fcmla_zpzzz_d, - }; - - return gen_gvec_fpst_zzzzp(s, fns[a->esz], a->rd, a->rn, a->rm, - a->ra, a->pg, a->rot, - a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); -} +static gen_helper_gvec_5_ptr * const fcmla_fns[4] = { + NULL, gen_helper_sve_fcmla_zpzzz_h, + gen_helper_sve_fcmla_zpzzz_s, gen_helper_sve_fcmla_zpzzz_d, +}; +TRANS_FEAT(FCMLA_zpzzz, aa64_sve, gen_gvec_fpst_zzzzp, fcmla_fns[a->esz], + a->rd, a->rn, a->rm, a->ra, a->pg, a->rot, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) static bool trans_FCMLA_zzxz(DisasContext *s, arg_FCMLA_zzxz *a) { From 413ee8e41a42571179482511313904f418331232 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:56 -0700 Subject: [PATCH 688/935] target/arm: Move null function and sve check into do_fp_imm Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-104-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 75854a7c6c..b47d5d7f21 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3911,33 +3911,34 @@ static void do_fp_scalar(DisasContext *s, int zd, int zn, int pg, bool is_fp16, tcg_temp_free_ptr(t_zd); } -static void do_fp_imm(DisasContext *s, arg_rpri_esz *a, uint64_t imm, +static bool do_fp_imm(DisasContext *s, arg_rpri_esz *a, uint64_t imm, gen_helper_sve_fp2scalar *fn) { - do_fp_scalar(s, a->rd, a->rn, a->pg, a->esz == MO_16, - tcg_constant_i64(imm), fn); + if (fn == NULL) { + return false; + } + if (sve_access_check(s)) { + do_fp_scalar(s, a->rd, a->rn, a->pg, a->esz == MO_16, + tcg_constant_i64(imm), fn); + } + return true; } #define DO_FP_IMM(NAME, name, const0, const1) \ static bool trans_##NAME##_zpzi(DisasContext *s, arg_rpri_esz *a) \ { \ - static gen_helper_sve_fp2scalar * const fns[3] = { \ - gen_helper_sve_##name##_h, \ + static gen_helper_sve_fp2scalar * const fns[4] = { \ + NULL, gen_helper_sve_##name##_h, \ gen_helper_sve_##name##_s, \ gen_helper_sve_##name##_d \ }; \ - static uint64_t const val[3][2] = { \ + static uint64_t const val[4][2] = { \ + { -1, -1 }, \ { float16_##const0, float16_##const1 }, \ { float32_##const0, float32_##const1 }, \ { float64_##const0, float64_##const1 }, \ }; \ - if (a->esz == 0) { \ - return false; \ - } \ - if (sve_access_check(s)) { \ - do_fp_imm(s, a, val[a->esz - 1][a->imm], fns[a->esz - 1]); \ - } \ - return true; \ + return do_fp_imm(s, a, val[a->esz][a->imm], fns[a->esz]); \ } DO_FP_IMM(FADD, fadds, half, one) From 98c37459c346f84ec032747bc7cd692877a0bc9e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:57 -0700 Subject: [PATCH 689/935] target/arm: Use TRANS_FEAT for DO_FP_IMM Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-105-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index b47d5d7f21..e2ae387d62 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3924,22 +3924,20 @@ static bool do_fp_imm(DisasContext *s, arg_rpri_esz *a, uint64_t imm, return true; } -#define DO_FP_IMM(NAME, name, const0, const1) \ -static bool trans_##NAME##_zpzi(DisasContext *s, arg_rpri_esz *a) \ -{ \ - static gen_helper_sve_fp2scalar * const fns[4] = { \ - NULL, gen_helper_sve_##name##_h, \ - gen_helper_sve_##name##_s, \ - gen_helper_sve_##name##_d \ - }; \ - static uint64_t const val[4][2] = { \ - { -1, -1 }, \ - { float16_##const0, float16_##const1 }, \ - { float32_##const0, float32_##const1 }, \ - { float64_##const0, float64_##const1 }, \ - }; \ - return do_fp_imm(s, a, val[a->esz][a->imm], fns[a->esz]); \ -} +#define DO_FP_IMM(NAME, name, const0, const1) \ + static gen_helper_sve_fp2scalar * const name##_fns[4] = { \ + NULL, gen_helper_sve_##name##_h, \ + gen_helper_sve_##name##_s, \ + gen_helper_sve_##name##_d \ + }; \ + static uint64_t const name##_const[4][2] = { \ + { -1, -1 }, \ + { float16_##const0, float16_##const1 }, \ + { float32_##const0, float32_##const1 }, \ + { float64_##const0, float64_##const1 }, \ + }; \ + TRANS_FEAT(NAME##_zpzi, aa64_sve, do_fp_imm, a, \ + name##_const[a->esz][a->imm], name##_fns[a->esz]) DO_FP_IMM(FADD, fadds, half, one) DO_FP_IMM(FSUB, fsubs, half, one) From d961b3e40bd2c98de8bac554597e905daab13b91 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:58 -0700 Subject: [PATCH 690/935] target/arm: Use TRANS_FEAT for DO_FPCMP Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-106-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index e2ae387d62..886cf539a5 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3970,14 +3970,11 @@ static bool do_fp_cmp(DisasContext *s, arg_rprr_esz *a, } #define DO_FPCMP(NAME, name) \ -static bool trans_##NAME##_ppzz(DisasContext *s, arg_rprr_esz *a) \ -{ \ - static gen_helper_gvec_4_ptr * const fns[4] = { \ + static gen_helper_gvec_4_ptr * const name##_fns[4] = { \ NULL, gen_helper_sve_##name##_h, \ gen_helper_sve_##name##_s, gen_helper_sve_##name##_d \ }; \ - return do_fp_cmp(s, a, fns[a->esz]); \ -} + TRANS_FEAT(NAME##_ppzz, aa64_sve, do_fp_cmp, a, name##_fns[a->esz]) DO_FPCMP(FCMGE, fcmge) DO_FPCMP(FCMGT, fcmgt) From df9024760efa9a32e24629eb80665c8c4ec5f145 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:18:59 -0700 Subject: [PATCH 691/935] target/arm: Remove assert in trans_FCMLA_zzxz Since 636ddeb15c0, we do not require rd == ra. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-107-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 886cf539a5..436d09b928 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -4027,8 +4027,6 @@ static bool trans_FCMLA_zzxz(DisasContext *s, arg_FCMLA_zzxz *a) NULL, }; - tcg_debug_assert(a->rd == a->ra); - return gen_gvec_fpst_zzzz(s, fns[a->esz], a->rd, a->rn, a->rm, a->ra, a->index * 4 + a->rot, a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); From e600d64980f2a2f1377ade1c055497e164ec3a61 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:19:00 -0700 Subject: [PATCH 692/935] target/arm: Use TRANS_FEAT for FCMLA_zzxz Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-108-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 436d09b928..70e8d90ae8 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -4018,19 +4018,12 @@ TRANS_FEAT(FCMLA_zpzzz, aa64_sve, gen_gvec_fpst_zzzzp, fcmla_fns[a->esz], a->rd, a->rn, a->rm, a->ra, a->pg, a->rot, a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) -static bool trans_FCMLA_zzxz(DisasContext *s, arg_FCMLA_zzxz *a) -{ - static gen_helper_gvec_4_ptr * const fns[4] = { - NULL, - gen_helper_gvec_fcmlah_idx, - gen_helper_gvec_fcmlas_idx, - NULL, - }; - - return gen_gvec_fpst_zzzz(s, fns[a->esz], a->rd, a->rn, a->rm, a->ra, - a->index * 4 + a->rot, - a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); -} +static gen_helper_gvec_4_ptr * const fcmla_idx_fns[4] = { + NULL, gen_helper_gvec_fcmlah_idx, gen_helper_gvec_fcmlas_idx, NULL +}; +TRANS_FEAT(FCMLA_zzxz, aa64_sve, gen_gvec_fpst_zzzz, fcmla_idx_fns[a->esz], + a->rd, a->rn, a->rm, a->ra, a->index * 4 + a->rot, + a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR) /* *** SVE Floating Point Unary Operations Predicated Group From 6100d084934e8152886625a071ca6b9579ebb260 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:19:01 -0700 Subject: [PATCH 693/935] target/arm: Use TRANS_FEAT for do_narrow_extract Rename from do_sve2_narrow_extract and hoist the sve2 check into the TRANS_FEAT macro. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-109-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 223 +++++++++++++++++-------------------- 1 file changed, 102 insertions(+), 121 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 70e8d90ae8..8e7f8308c7 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -6345,11 +6345,10 @@ TRANS_FEAT(SLI, aa64_sve2, gen_gvec_fn_arg_zzi, gen_gvec_sli, a) TRANS_FEAT(SABA, aa64_sve2, gen_gvec_fn_arg_zzz, gen_gvec_saba, a) TRANS_FEAT(UABA, aa64_sve2, gen_gvec_fn_arg_zzz, gen_gvec_uaba, a) -static bool do_sve2_narrow_extract(DisasContext *s, arg_rri_esz *a, - const GVecGen2 ops[3]) +static bool do_narrow_extract(DisasContext *s, arg_rri_esz *a, + const GVecGen2 ops[3]) { - if (a->esz < 0 || a->esz > MO_32 || a->imm != 0 || - !dc_isar_feature(aa64_sve2, s)) { + if (a->esz < 0 || a->esz > MO_32 || a->imm != 0) { return false; } if (sve_access_check(s)) { @@ -6382,24 +6381,21 @@ static void gen_sqxtnb_vec(unsigned vece, TCGv_vec d, TCGv_vec n) tcg_temp_free_vec(t); } -static bool trans_SQXTNB(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2 ops[3] = { - { .fniv = gen_sqxtnb_vec, - .opt_opc = sqxtn_list, - .fno = gen_helper_sve2_sqxtnb_h, - .vece = MO_16 }, - { .fniv = gen_sqxtnb_vec, - .opt_opc = sqxtn_list, - .fno = gen_helper_sve2_sqxtnb_s, - .vece = MO_32 }, - { .fniv = gen_sqxtnb_vec, - .opt_opc = sqxtn_list, - .fno = gen_helper_sve2_sqxtnb_d, - .vece = MO_64 }, - }; - return do_sve2_narrow_extract(s, a, ops); -} +static const GVecGen2 sqxtnb_ops[3] = { + { .fniv = gen_sqxtnb_vec, + .opt_opc = sqxtn_list, + .fno = gen_helper_sve2_sqxtnb_h, + .vece = MO_16 }, + { .fniv = gen_sqxtnb_vec, + .opt_opc = sqxtn_list, + .fno = gen_helper_sve2_sqxtnb_s, + .vece = MO_32 }, + { .fniv = gen_sqxtnb_vec, + .opt_opc = sqxtn_list, + .fno = gen_helper_sve2_sqxtnb_d, + .vece = MO_64 }, +}; +TRANS_FEAT(SQXTNB, aa64_sve2, do_narrow_extract, a, sqxtnb_ops) static void gen_sqxtnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n) { @@ -6419,27 +6415,24 @@ static void gen_sqxtnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n) tcg_temp_free_vec(t); } -static bool trans_SQXTNT(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2 ops[3] = { - { .fniv = gen_sqxtnt_vec, - .opt_opc = sqxtn_list, - .load_dest = true, - .fno = gen_helper_sve2_sqxtnt_h, - .vece = MO_16 }, - { .fniv = gen_sqxtnt_vec, - .opt_opc = sqxtn_list, - .load_dest = true, - .fno = gen_helper_sve2_sqxtnt_s, - .vece = MO_32 }, - { .fniv = gen_sqxtnt_vec, - .opt_opc = sqxtn_list, - .load_dest = true, - .fno = gen_helper_sve2_sqxtnt_d, - .vece = MO_64 }, - }; - return do_sve2_narrow_extract(s, a, ops); -} +static const GVecGen2 sqxtnt_ops[3] = { + { .fniv = gen_sqxtnt_vec, + .opt_opc = sqxtn_list, + .load_dest = true, + .fno = gen_helper_sve2_sqxtnt_h, + .vece = MO_16 }, + { .fniv = gen_sqxtnt_vec, + .opt_opc = sqxtn_list, + .load_dest = true, + .fno = gen_helper_sve2_sqxtnt_s, + .vece = MO_32 }, + { .fniv = gen_sqxtnt_vec, + .opt_opc = sqxtn_list, + .load_dest = true, + .fno = gen_helper_sve2_sqxtnt_d, + .vece = MO_64 }, +}; +TRANS_FEAT(SQXTNT, aa64_sve2, do_narrow_extract, a, sqxtnt_ops) static const TCGOpcode uqxtn_list[] = { INDEX_op_shli_vec, INDEX_op_umin_vec, 0 @@ -6456,24 +6449,21 @@ static void gen_uqxtnb_vec(unsigned vece, TCGv_vec d, TCGv_vec n) tcg_temp_free_vec(t); } -static bool trans_UQXTNB(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2 ops[3] = { - { .fniv = gen_uqxtnb_vec, - .opt_opc = uqxtn_list, - .fno = gen_helper_sve2_uqxtnb_h, - .vece = MO_16 }, - { .fniv = gen_uqxtnb_vec, - .opt_opc = uqxtn_list, - .fno = gen_helper_sve2_uqxtnb_s, - .vece = MO_32 }, - { .fniv = gen_uqxtnb_vec, - .opt_opc = uqxtn_list, - .fno = gen_helper_sve2_uqxtnb_d, - .vece = MO_64 }, - }; - return do_sve2_narrow_extract(s, a, ops); -} +static const GVecGen2 uqxtnb_ops[3] = { + { .fniv = gen_uqxtnb_vec, + .opt_opc = uqxtn_list, + .fno = gen_helper_sve2_uqxtnb_h, + .vece = MO_16 }, + { .fniv = gen_uqxtnb_vec, + .opt_opc = uqxtn_list, + .fno = gen_helper_sve2_uqxtnb_s, + .vece = MO_32 }, + { .fniv = gen_uqxtnb_vec, + .opt_opc = uqxtn_list, + .fno = gen_helper_sve2_uqxtnb_d, + .vece = MO_64 }, +}; +TRANS_FEAT(UQXTNB, aa64_sve2, do_narrow_extract, a, uqxtnb_ops) static void gen_uqxtnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n) { @@ -6488,27 +6478,24 @@ static void gen_uqxtnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n) tcg_temp_free_vec(t); } -static bool trans_UQXTNT(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2 ops[3] = { - { .fniv = gen_uqxtnt_vec, - .opt_opc = uqxtn_list, - .load_dest = true, - .fno = gen_helper_sve2_uqxtnt_h, - .vece = MO_16 }, - { .fniv = gen_uqxtnt_vec, - .opt_opc = uqxtn_list, - .load_dest = true, - .fno = gen_helper_sve2_uqxtnt_s, - .vece = MO_32 }, - { .fniv = gen_uqxtnt_vec, - .opt_opc = uqxtn_list, - .load_dest = true, - .fno = gen_helper_sve2_uqxtnt_d, - .vece = MO_64 }, - }; - return do_sve2_narrow_extract(s, a, ops); -} +static const GVecGen2 uqxtnt_ops[3] = { + { .fniv = gen_uqxtnt_vec, + .opt_opc = uqxtn_list, + .load_dest = true, + .fno = gen_helper_sve2_uqxtnt_h, + .vece = MO_16 }, + { .fniv = gen_uqxtnt_vec, + .opt_opc = uqxtn_list, + .load_dest = true, + .fno = gen_helper_sve2_uqxtnt_s, + .vece = MO_32 }, + { .fniv = gen_uqxtnt_vec, + .opt_opc = uqxtn_list, + .load_dest = true, + .fno = gen_helper_sve2_uqxtnt_d, + .vece = MO_64 }, +}; +TRANS_FEAT(UQXTNT, aa64_sve2, do_narrow_extract, a, uqxtnt_ops) static const TCGOpcode sqxtun_list[] = { INDEX_op_shli_vec, INDEX_op_umin_vec, INDEX_op_smax_vec, 0 @@ -6527,24 +6514,21 @@ static void gen_sqxtunb_vec(unsigned vece, TCGv_vec d, TCGv_vec n) tcg_temp_free_vec(t); } -static bool trans_SQXTUNB(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2 ops[3] = { - { .fniv = gen_sqxtunb_vec, - .opt_opc = sqxtun_list, - .fno = gen_helper_sve2_sqxtunb_h, - .vece = MO_16 }, - { .fniv = gen_sqxtunb_vec, - .opt_opc = sqxtun_list, - .fno = gen_helper_sve2_sqxtunb_s, - .vece = MO_32 }, - { .fniv = gen_sqxtunb_vec, - .opt_opc = sqxtun_list, - .fno = gen_helper_sve2_sqxtunb_d, - .vece = MO_64 }, - }; - return do_sve2_narrow_extract(s, a, ops); -} +static const GVecGen2 sqxtunb_ops[3] = { + { .fniv = gen_sqxtunb_vec, + .opt_opc = sqxtun_list, + .fno = gen_helper_sve2_sqxtunb_h, + .vece = MO_16 }, + { .fniv = gen_sqxtunb_vec, + .opt_opc = sqxtun_list, + .fno = gen_helper_sve2_sqxtunb_s, + .vece = MO_32 }, + { .fniv = gen_sqxtunb_vec, + .opt_opc = sqxtun_list, + .fno = gen_helper_sve2_sqxtunb_d, + .vece = MO_64 }, +}; +TRANS_FEAT(SQXTUNB, aa64_sve2, do_narrow_extract, a, sqxtunb_ops) static void gen_sqxtunt_vec(unsigned vece, TCGv_vec d, TCGv_vec n) { @@ -6561,27 +6545,24 @@ static void gen_sqxtunt_vec(unsigned vece, TCGv_vec d, TCGv_vec n) tcg_temp_free_vec(t); } -static bool trans_SQXTUNT(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2 ops[3] = { - { .fniv = gen_sqxtunt_vec, - .opt_opc = sqxtun_list, - .load_dest = true, - .fno = gen_helper_sve2_sqxtunt_h, - .vece = MO_16 }, - { .fniv = gen_sqxtunt_vec, - .opt_opc = sqxtun_list, - .load_dest = true, - .fno = gen_helper_sve2_sqxtunt_s, - .vece = MO_32 }, - { .fniv = gen_sqxtunt_vec, - .opt_opc = sqxtun_list, - .load_dest = true, - .fno = gen_helper_sve2_sqxtunt_d, - .vece = MO_64 }, - }; - return do_sve2_narrow_extract(s, a, ops); -} +static const GVecGen2 sqxtunt_ops[3] = { + { .fniv = gen_sqxtunt_vec, + .opt_opc = sqxtun_list, + .load_dest = true, + .fno = gen_helper_sve2_sqxtunt_h, + .vece = MO_16 }, + { .fniv = gen_sqxtunt_vec, + .opt_opc = sqxtun_list, + .load_dest = true, + .fno = gen_helper_sve2_sqxtunt_s, + .vece = MO_32 }, + { .fniv = gen_sqxtunt_vec, + .opt_opc = sqxtun_list, + .load_dest = true, + .fno = gen_helper_sve2_sqxtunt_d, + .vece = MO_64 }, +}; +TRANS_FEAT(SQXTUNT, aa64_sve2, do_narrow_extract, a, sqxtunt_ops) static bool do_sve2_shr_narrow(DisasContext *s, arg_rri_esz *a, const GVecGen2i ops[3]) From 5a528bb5d8e8e298317975e68510f329f89fc709 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:19:02 -0700 Subject: [PATCH 694/935] target/arm: Use TRANS_FEAT for do_shll_tb Rename from do_sve2_shll_tb and hoist the sve2 check into the TRANS_FEAT macro. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-110-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 102 ++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 57 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 8e7f8308c7..0fb118f6ef 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -6194,46 +6194,11 @@ static void gen_ushll_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t imm) } } -static bool do_sve2_shll_tb(DisasContext *s, arg_rri_esz *a, - bool sel, bool uns) +static bool do_shll_tb(DisasContext *s, arg_rri_esz *a, + const GVecGen2i ops[3], bool sel) { - static const TCGOpcode sshll_list[] = { - INDEX_op_shli_vec, INDEX_op_sari_vec, 0 - }; - static const TCGOpcode ushll_list[] = { - INDEX_op_shli_vec, INDEX_op_shri_vec, 0 - }; - static const GVecGen2i ops[2][3] = { - { { .fniv = gen_sshll_vec, - .opt_opc = sshll_list, - .fno = gen_helper_sve2_sshll_h, - .vece = MO_16 }, - { .fniv = gen_sshll_vec, - .opt_opc = sshll_list, - .fno = gen_helper_sve2_sshll_s, - .vece = MO_32 }, - { .fniv = gen_sshll_vec, - .opt_opc = sshll_list, - .fno = gen_helper_sve2_sshll_d, - .vece = MO_64 } }, - { { .fni8 = gen_ushll16_i64, - .fniv = gen_ushll_vec, - .opt_opc = ushll_list, - .fno = gen_helper_sve2_ushll_h, - .vece = MO_16 }, - { .fni8 = gen_ushll32_i64, - .fniv = gen_ushll_vec, - .opt_opc = ushll_list, - .fno = gen_helper_sve2_ushll_s, - .vece = MO_32 }, - { .fni8 = gen_ushll64_i64, - .fniv = gen_ushll_vec, - .opt_opc = ushll_list, - .fno = gen_helper_sve2_ushll_d, - .vece = MO_64 } }, - }; - if (a->esz < 0 || a->esz > 2 || !dc_isar_feature(aa64_sve2, s)) { + if (a->esz < 0 || a->esz > 2) { return false; } if (sve_access_check(s)) { @@ -6241,30 +6206,53 @@ static bool do_sve2_shll_tb(DisasContext *s, arg_rri_esz *a, tcg_gen_gvec_2i(vec_full_reg_offset(s, a->rd), vec_full_reg_offset(s, a->rn), vsz, vsz, (a->imm << 1) | sel, - &ops[uns][a->esz]); + &ops[a->esz]); } return true; } -static bool trans_SSHLLB(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_shll_tb(s, a, false, false); -} +static const TCGOpcode sshll_list[] = { + INDEX_op_shli_vec, INDEX_op_sari_vec, 0 +}; +static const GVecGen2i sshll_ops[3] = { + { .fniv = gen_sshll_vec, + .opt_opc = sshll_list, + .fno = gen_helper_sve2_sshll_h, + .vece = MO_16 }, + { .fniv = gen_sshll_vec, + .opt_opc = sshll_list, + .fno = gen_helper_sve2_sshll_s, + .vece = MO_32 }, + { .fniv = gen_sshll_vec, + .opt_opc = sshll_list, + .fno = gen_helper_sve2_sshll_d, + .vece = MO_64 } +}; +TRANS_FEAT(SSHLLB, aa64_sve2, do_shll_tb, a, sshll_ops, false) +TRANS_FEAT(SSHLLT, aa64_sve2, do_shll_tb, a, sshll_ops, true) -static bool trans_SSHLLT(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_shll_tb(s, a, true, false); -} - -static bool trans_USHLLB(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_shll_tb(s, a, false, true); -} - -static bool trans_USHLLT(DisasContext *s, arg_rri_esz *a) -{ - return do_sve2_shll_tb(s, a, true, true); -} +static const TCGOpcode ushll_list[] = { + INDEX_op_shli_vec, INDEX_op_shri_vec, 0 +}; +static const GVecGen2i ushll_ops[3] = { + { .fni8 = gen_ushll16_i64, + .fniv = gen_ushll_vec, + .opt_opc = ushll_list, + .fno = gen_helper_sve2_ushll_h, + .vece = MO_16 }, + { .fni8 = gen_ushll32_i64, + .fniv = gen_ushll_vec, + .opt_opc = ushll_list, + .fno = gen_helper_sve2_ushll_s, + .vece = MO_32 }, + { .fni8 = gen_ushll64_i64, + .fniv = gen_ushll_vec, + .opt_opc = ushll_list, + .fno = gen_helper_sve2_ushll_d, + .vece = MO_64 }, +}; +TRANS_FEAT(USHLLB, aa64_sve2, do_shll_tb, a, ushll_ops, false) +TRANS_FEAT(USHLLT, aa64_sve2, do_shll_tb, a, ushll_ops, true) static gen_helper_gvec_3 * const bext_fns[4] = { gen_helper_sve2_bext_b, gen_helper_sve2_bext_h, From f7f2f0faa2b5091e27da442b48c0d27d1274b2f6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:19:03 -0700 Subject: [PATCH 695/935] target/arm: Use TRANS_FEAT for do_shr_narrow Rename from do_sve2_shr_narrow and hoist the sve2 check into the TRANS_FEAT macro. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-111-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 470 +++++++++++++++++-------------------- 1 file changed, 211 insertions(+), 259 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 0fb118f6ef..44af7530b6 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -6552,10 +6552,10 @@ static const GVecGen2 sqxtunt_ops[3] = { }; TRANS_FEAT(SQXTUNT, aa64_sve2, do_narrow_extract, a, sqxtunt_ops) -static bool do_sve2_shr_narrow(DisasContext *s, arg_rri_esz *a, - const GVecGen2i ops[3]) +static bool do_shr_narrow(DisasContext *s, arg_rri_esz *a, + const GVecGen2i ops[3]) { - if (a->esz < 0 || a->esz > MO_32 || !dc_isar_feature(aa64_sve2, s)) { + if (a->esz < 0 || a->esz > MO_32) { return false; } assert(a->imm > 0 && a->imm <= (8 << a->esz)); @@ -6604,28 +6604,25 @@ static void gen_shrnb_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) tcg_temp_free_vec(t); } -static bool trans_SHRNB(DisasContext *s, arg_rri_esz *a) -{ - static const TCGOpcode vec_list[] = { INDEX_op_shri_vec, 0 }; - static const GVecGen2i ops[3] = { - { .fni8 = gen_shrnb16_i64, - .fniv = gen_shrnb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_shrnb_h, - .vece = MO_16 }, - { .fni8 = gen_shrnb32_i64, - .fniv = gen_shrnb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_shrnb_s, - .vece = MO_32 }, - { .fni8 = gen_shrnb64_i64, - .fniv = gen_shrnb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_shrnb_d, - .vece = MO_64 }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const TCGOpcode shrnb_vec_list[] = { INDEX_op_shri_vec, 0 }; +static const GVecGen2i shrnb_ops[3] = { + { .fni8 = gen_shrnb16_i64, + .fniv = gen_shrnb_vec, + .opt_opc = shrnb_vec_list, + .fno = gen_helper_sve2_shrnb_h, + .vece = MO_16 }, + { .fni8 = gen_shrnb32_i64, + .fniv = gen_shrnb_vec, + .opt_opc = shrnb_vec_list, + .fno = gen_helper_sve2_shrnb_s, + .vece = MO_32 }, + { .fni8 = gen_shrnb64_i64, + .fniv = gen_shrnb_vec, + .opt_opc = shrnb_vec_list, + .fno = gen_helper_sve2_shrnb_d, + .vece = MO_64 }, +}; +TRANS_FEAT(SHRNB, aa64_sve2, do_shr_narrow, a, shrnb_ops) static void gen_shrnt_i64(unsigned vece, TCGv_i64 d, TCGv_i64 n, int shr) { @@ -6666,51 +6663,42 @@ static void gen_shrnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) tcg_temp_free_vec(t); } -static bool trans_SHRNT(DisasContext *s, arg_rri_esz *a) -{ - static const TCGOpcode vec_list[] = { INDEX_op_shli_vec, 0 }; - static const GVecGen2i ops[3] = { - { .fni8 = gen_shrnt16_i64, - .fniv = gen_shrnt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_shrnt_h, - .vece = MO_16 }, - { .fni8 = gen_shrnt32_i64, - .fniv = gen_shrnt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_shrnt_s, - .vece = MO_32 }, - { .fni8 = gen_shrnt64_i64, - .fniv = gen_shrnt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_shrnt_d, - .vece = MO_64 }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const TCGOpcode shrnt_vec_list[] = { INDEX_op_shli_vec, 0 }; +static const GVecGen2i shrnt_ops[3] = { + { .fni8 = gen_shrnt16_i64, + .fniv = gen_shrnt_vec, + .opt_opc = shrnt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_shrnt_h, + .vece = MO_16 }, + { .fni8 = gen_shrnt32_i64, + .fniv = gen_shrnt_vec, + .opt_opc = shrnt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_shrnt_s, + .vece = MO_32 }, + { .fni8 = gen_shrnt64_i64, + .fniv = gen_shrnt_vec, + .opt_opc = shrnt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_shrnt_d, + .vece = MO_64 }, +}; +TRANS_FEAT(SHRNT, aa64_sve2, do_shr_narrow, a, shrnt_ops) -static bool trans_RSHRNB(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2i ops[3] = { - { .fno = gen_helper_sve2_rshrnb_h }, - { .fno = gen_helper_sve2_rshrnb_s }, - { .fno = gen_helper_sve2_rshrnb_d }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const GVecGen2i rshrnb_ops[3] = { + { .fno = gen_helper_sve2_rshrnb_h }, + { .fno = gen_helper_sve2_rshrnb_s }, + { .fno = gen_helper_sve2_rshrnb_d }, +}; +TRANS_FEAT(RSHRNB, aa64_sve2, do_shr_narrow, a, rshrnb_ops) -static bool trans_RSHRNT(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2i ops[3] = { - { .fno = gen_helper_sve2_rshrnt_h }, - { .fno = gen_helper_sve2_rshrnt_s }, - { .fno = gen_helper_sve2_rshrnt_d }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const GVecGen2i rshrnt_ops[3] = { + { .fno = gen_helper_sve2_rshrnt_h }, + { .fno = gen_helper_sve2_rshrnt_s }, + { .fno = gen_helper_sve2_rshrnt_d }, +}; +TRANS_FEAT(RSHRNT, aa64_sve2, do_shr_narrow, a, rshrnt_ops) static void gen_sqshrunb_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) @@ -6726,27 +6714,24 @@ static void gen_sqshrunb_vec(unsigned vece, TCGv_vec d, tcg_temp_free_vec(t); } -static bool trans_SQSHRUNB(DisasContext *s, arg_rri_esz *a) -{ - static const TCGOpcode vec_list[] = { - INDEX_op_sari_vec, INDEX_op_smax_vec, INDEX_op_umin_vec, 0 - }; - static const GVecGen2i ops[3] = { - { .fniv = gen_sqshrunb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_sqshrunb_h, - .vece = MO_16 }, - { .fniv = gen_sqshrunb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_sqshrunb_s, - .vece = MO_32 }, - { .fniv = gen_sqshrunb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_sqshrunb_d, - .vece = MO_64 }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const TCGOpcode sqshrunb_vec_list[] = { + INDEX_op_sari_vec, INDEX_op_smax_vec, INDEX_op_umin_vec, 0 +}; +static const GVecGen2i sqshrunb_ops[3] = { + { .fniv = gen_sqshrunb_vec, + .opt_opc = sqshrunb_vec_list, + .fno = gen_helper_sve2_sqshrunb_h, + .vece = MO_16 }, + { .fniv = gen_sqshrunb_vec, + .opt_opc = sqshrunb_vec_list, + .fno = gen_helper_sve2_sqshrunb_s, + .vece = MO_32 }, + { .fniv = gen_sqshrunb_vec, + .opt_opc = sqshrunb_vec_list, + .fno = gen_helper_sve2_sqshrunb_d, + .vece = MO_64 }, +}; +TRANS_FEAT(SQSHRUNB, aa64_sve2, do_shr_narrow, a, sqshrunb_ops) static void gen_sqshrunt_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) @@ -6764,51 +6749,42 @@ static void gen_sqshrunt_vec(unsigned vece, TCGv_vec d, tcg_temp_free_vec(t); } -static bool trans_SQSHRUNT(DisasContext *s, arg_rri_esz *a) -{ - static const TCGOpcode vec_list[] = { - INDEX_op_shli_vec, INDEX_op_sari_vec, - INDEX_op_smax_vec, INDEX_op_umin_vec, 0 - }; - static const GVecGen2i ops[3] = { - { .fniv = gen_sqshrunt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_sqshrunt_h, - .vece = MO_16 }, - { .fniv = gen_sqshrunt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_sqshrunt_s, - .vece = MO_32 }, - { .fniv = gen_sqshrunt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_sqshrunt_d, - .vece = MO_64 }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const TCGOpcode sqshrunt_vec_list[] = { + INDEX_op_shli_vec, INDEX_op_sari_vec, + INDEX_op_smax_vec, INDEX_op_umin_vec, 0 +}; +static const GVecGen2i sqshrunt_ops[3] = { + { .fniv = gen_sqshrunt_vec, + .opt_opc = sqshrunt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_sqshrunt_h, + .vece = MO_16 }, + { .fniv = gen_sqshrunt_vec, + .opt_opc = sqshrunt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_sqshrunt_s, + .vece = MO_32 }, + { .fniv = gen_sqshrunt_vec, + .opt_opc = sqshrunt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_sqshrunt_d, + .vece = MO_64 }, +}; +TRANS_FEAT(SQSHRUNT, aa64_sve2, do_shr_narrow, a, sqshrunt_ops) -static bool trans_SQRSHRUNB(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2i ops[3] = { - { .fno = gen_helper_sve2_sqrshrunb_h }, - { .fno = gen_helper_sve2_sqrshrunb_s }, - { .fno = gen_helper_sve2_sqrshrunb_d }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const GVecGen2i sqrshrunb_ops[3] = { + { .fno = gen_helper_sve2_sqrshrunb_h }, + { .fno = gen_helper_sve2_sqrshrunb_s }, + { .fno = gen_helper_sve2_sqrshrunb_d }, +}; +TRANS_FEAT(SQRSHRUNB, aa64_sve2, do_shr_narrow, a, sqrshrunb_ops) -static bool trans_SQRSHRUNT(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2i ops[3] = { - { .fno = gen_helper_sve2_sqrshrunt_h }, - { .fno = gen_helper_sve2_sqrshrunt_s }, - { .fno = gen_helper_sve2_sqrshrunt_d }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const GVecGen2i sqrshrunt_ops[3] = { + { .fno = gen_helper_sve2_sqrshrunt_h }, + { .fno = gen_helper_sve2_sqrshrunt_s }, + { .fno = gen_helper_sve2_sqrshrunt_d }, +}; +TRANS_FEAT(SQRSHRUNT, aa64_sve2, do_shr_narrow, a, sqrshrunt_ops) static void gen_sqshrnb_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) @@ -6828,27 +6804,24 @@ static void gen_sqshrnb_vec(unsigned vece, TCGv_vec d, tcg_temp_free_vec(t); } -static bool trans_SQSHRNB(DisasContext *s, arg_rri_esz *a) -{ - static const TCGOpcode vec_list[] = { - INDEX_op_sari_vec, INDEX_op_smax_vec, INDEX_op_smin_vec, 0 - }; - static const GVecGen2i ops[3] = { - { .fniv = gen_sqshrnb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_sqshrnb_h, - .vece = MO_16 }, - { .fniv = gen_sqshrnb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_sqshrnb_s, - .vece = MO_32 }, - { .fniv = gen_sqshrnb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_sqshrnb_d, - .vece = MO_64 }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const TCGOpcode sqshrnb_vec_list[] = { + INDEX_op_sari_vec, INDEX_op_smax_vec, INDEX_op_smin_vec, 0 +}; +static const GVecGen2i sqshrnb_ops[3] = { + { .fniv = gen_sqshrnb_vec, + .opt_opc = sqshrnb_vec_list, + .fno = gen_helper_sve2_sqshrnb_h, + .vece = MO_16 }, + { .fniv = gen_sqshrnb_vec, + .opt_opc = sqshrnb_vec_list, + .fno = gen_helper_sve2_sqshrnb_s, + .vece = MO_32 }, + { .fniv = gen_sqshrnb_vec, + .opt_opc = sqshrnb_vec_list, + .fno = gen_helper_sve2_sqshrnb_d, + .vece = MO_64 }, +}; +TRANS_FEAT(SQSHRNB, aa64_sve2, do_shr_narrow, a, sqshrnb_ops) static void gen_sqshrnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) @@ -6869,51 +6842,42 @@ static void gen_sqshrnt_vec(unsigned vece, TCGv_vec d, tcg_temp_free_vec(t); } -static bool trans_SQSHRNT(DisasContext *s, arg_rri_esz *a) -{ - static const TCGOpcode vec_list[] = { - INDEX_op_shli_vec, INDEX_op_sari_vec, - INDEX_op_smax_vec, INDEX_op_smin_vec, 0 - }; - static const GVecGen2i ops[3] = { - { .fniv = gen_sqshrnt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_sqshrnt_h, - .vece = MO_16 }, - { .fniv = gen_sqshrnt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_sqshrnt_s, - .vece = MO_32 }, - { .fniv = gen_sqshrnt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_sqshrnt_d, - .vece = MO_64 }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const TCGOpcode sqshrnt_vec_list[] = { + INDEX_op_shli_vec, INDEX_op_sari_vec, + INDEX_op_smax_vec, INDEX_op_smin_vec, 0 +}; +static const GVecGen2i sqshrnt_ops[3] = { + { .fniv = gen_sqshrnt_vec, + .opt_opc = sqshrnt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_sqshrnt_h, + .vece = MO_16 }, + { .fniv = gen_sqshrnt_vec, + .opt_opc = sqshrnt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_sqshrnt_s, + .vece = MO_32 }, + { .fniv = gen_sqshrnt_vec, + .opt_opc = sqshrnt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_sqshrnt_d, + .vece = MO_64 }, +}; +TRANS_FEAT(SQSHRNT, aa64_sve2, do_shr_narrow, a, sqshrnt_ops) -static bool trans_SQRSHRNB(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2i ops[3] = { - { .fno = gen_helper_sve2_sqrshrnb_h }, - { .fno = gen_helper_sve2_sqrshrnb_s }, - { .fno = gen_helper_sve2_sqrshrnb_d }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const GVecGen2i sqrshrnb_ops[3] = { + { .fno = gen_helper_sve2_sqrshrnb_h }, + { .fno = gen_helper_sve2_sqrshrnb_s }, + { .fno = gen_helper_sve2_sqrshrnb_d }, +}; +TRANS_FEAT(SQRSHRNB, aa64_sve2, do_shr_narrow, a, sqrshrnb_ops) -static bool trans_SQRSHRNT(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2i ops[3] = { - { .fno = gen_helper_sve2_sqrshrnt_h }, - { .fno = gen_helper_sve2_sqrshrnt_s }, - { .fno = gen_helper_sve2_sqrshrnt_d }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const GVecGen2i sqrshrnt_ops[3] = { + { .fno = gen_helper_sve2_sqrshrnt_h }, + { .fno = gen_helper_sve2_sqrshrnt_s }, + { .fno = gen_helper_sve2_sqrshrnt_d }, +}; +TRANS_FEAT(SQRSHRNT, aa64_sve2, do_shr_narrow, a, sqrshrnt_ops) static void gen_uqshrnb_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) @@ -6927,27 +6891,24 @@ static void gen_uqshrnb_vec(unsigned vece, TCGv_vec d, tcg_temp_free_vec(t); } -static bool trans_UQSHRNB(DisasContext *s, arg_rri_esz *a) -{ - static const TCGOpcode vec_list[] = { - INDEX_op_shri_vec, INDEX_op_umin_vec, 0 - }; - static const GVecGen2i ops[3] = { - { .fniv = gen_uqshrnb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_uqshrnb_h, - .vece = MO_16 }, - { .fniv = gen_uqshrnb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_uqshrnb_s, - .vece = MO_32 }, - { .fniv = gen_uqshrnb_vec, - .opt_opc = vec_list, - .fno = gen_helper_sve2_uqshrnb_d, - .vece = MO_64 }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const TCGOpcode uqshrnb_vec_list[] = { + INDEX_op_shri_vec, INDEX_op_umin_vec, 0 +}; +static const GVecGen2i uqshrnb_ops[3] = { + { .fniv = gen_uqshrnb_vec, + .opt_opc = uqshrnb_vec_list, + .fno = gen_helper_sve2_uqshrnb_h, + .vece = MO_16 }, + { .fniv = gen_uqshrnb_vec, + .opt_opc = uqshrnb_vec_list, + .fno = gen_helper_sve2_uqshrnb_s, + .vece = MO_32 }, + { .fniv = gen_uqshrnb_vec, + .opt_opc = uqshrnb_vec_list, + .fno = gen_helper_sve2_uqshrnb_d, + .vece = MO_64 }, +}; +TRANS_FEAT(UQSHRNB, aa64_sve2, do_shr_narrow, a, uqshrnb_ops) static void gen_uqshrnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr) @@ -6963,50 +6924,41 @@ static void gen_uqshrnt_vec(unsigned vece, TCGv_vec d, tcg_temp_free_vec(t); } -static bool trans_UQSHRNT(DisasContext *s, arg_rri_esz *a) -{ - static const TCGOpcode vec_list[] = { - INDEX_op_shli_vec, INDEX_op_shri_vec, INDEX_op_umin_vec, 0 - }; - static const GVecGen2i ops[3] = { - { .fniv = gen_uqshrnt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_uqshrnt_h, - .vece = MO_16 }, - { .fniv = gen_uqshrnt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_uqshrnt_s, - .vece = MO_32 }, - { .fniv = gen_uqshrnt_vec, - .opt_opc = vec_list, - .load_dest = true, - .fno = gen_helper_sve2_uqshrnt_d, - .vece = MO_64 }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const TCGOpcode uqshrnt_vec_list[] = { + INDEX_op_shli_vec, INDEX_op_shri_vec, INDEX_op_umin_vec, 0 +}; +static const GVecGen2i uqshrnt_ops[3] = { + { .fniv = gen_uqshrnt_vec, + .opt_opc = uqshrnt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_uqshrnt_h, + .vece = MO_16 }, + { .fniv = gen_uqshrnt_vec, + .opt_opc = uqshrnt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_uqshrnt_s, + .vece = MO_32 }, + { .fniv = gen_uqshrnt_vec, + .opt_opc = uqshrnt_vec_list, + .load_dest = true, + .fno = gen_helper_sve2_uqshrnt_d, + .vece = MO_64 }, +}; +TRANS_FEAT(UQSHRNT, aa64_sve2, do_shr_narrow, a, uqshrnt_ops) -static bool trans_UQRSHRNB(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2i ops[3] = { - { .fno = gen_helper_sve2_uqrshrnb_h }, - { .fno = gen_helper_sve2_uqrshrnb_s }, - { .fno = gen_helper_sve2_uqrshrnb_d }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const GVecGen2i uqrshrnb_ops[3] = { + { .fno = gen_helper_sve2_uqrshrnb_h }, + { .fno = gen_helper_sve2_uqrshrnb_s }, + { .fno = gen_helper_sve2_uqrshrnb_d }, +}; +TRANS_FEAT(UQRSHRNB, aa64_sve2, do_shr_narrow, a, uqrshrnb_ops) -static bool trans_UQRSHRNT(DisasContext *s, arg_rri_esz *a) -{ - static const GVecGen2i ops[3] = { - { .fno = gen_helper_sve2_uqrshrnt_h }, - { .fno = gen_helper_sve2_uqrshrnt_s }, - { .fno = gen_helper_sve2_uqrshrnt_d }, - }; - return do_sve2_shr_narrow(s, a, ops); -} +static const GVecGen2i uqrshrnt_ops[3] = { + { .fno = gen_helper_sve2_uqrshrnt_h }, + { .fno = gen_helper_sve2_uqrshrnt_s }, + { .fno = gen_helper_sve2_uqrshrnt_d }, +}; +TRANS_FEAT(UQRSHRNT, aa64_sve2, do_shr_narrow, a, uqrshrnt_ops) #define DO_SVE2_ZZZ_NARROW(NAME, name) \ static gen_helper_gvec_3 * const name##_fns[4] = { \ From 72c7f90621b46b6d7efb98fb64045638c7e3032f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:19:04 -0700 Subject: [PATCH 696/935] target/arm: Use TRANS_FEAT for do_FMLAL_zzzw Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-112-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 44af7530b6..57bff0d345 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -7149,33 +7149,15 @@ TRANS_FEAT(FLOGB, aa64_sve2, gen_gvec_fpst_arg_zpz, flogb_fns[a->esz], static bool do_FMLAL_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sub, bool sel) { - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } return gen_gvec_ptr_zzzz(s, gen_helper_sve2_fmlal_zzzw_s, a->rd, a->rn, a->rm, a->ra, (sel << 1) | sub, cpu_env); } -static bool trans_FMLALB_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_FMLAL_zzzw(s, a, false, false); -} - -static bool trans_FMLALT_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_FMLAL_zzzw(s, a, false, true); -} - -static bool trans_FMLSLB_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_FMLAL_zzzw(s, a, true, false); -} - -static bool trans_FMLSLT_zzzw(DisasContext *s, arg_rrrr_esz *a) -{ - return do_FMLAL_zzzw(s, a, true, true); -} +TRANS_FEAT(FMLALB_zzzw, aa64_sve2, do_FMLAL_zzzw, a, false, false) +TRANS_FEAT(FMLALT_zzzw, aa64_sve2, do_FMLAL_zzzw, a, false, true) +TRANS_FEAT(FMLSLB_zzzw, aa64_sve2, do_FMLAL_zzzw, a, true, false) +TRANS_FEAT(FMLSLT_zzzw, aa64_sve2, do_FMLAL_zzzw, a, true, true) static bool do_FMLAL_zzxw(DisasContext *s, arg_rrxr_esz *a, bool sub, bool sel) { From fc7c8829447b8b01ed8d33f01228562f8af36790 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:19:05 -0700 Subject: [PATCH 697/935] target/arm: Use TRANS_FEAT for do_FMLAL_zzxw Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-113-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 57bff0d345..5fb66547ec 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -7161,33 +7161,15 @@ TRANS_FEAT(FMLSLT_zzzw, aa64_sve2, do_FMLAL_zzzw, a, true, true) static bool do_FMLAL_zzxw(DisasContext *s, arg_rrxr_esz *a, bool sub, bool sel) { - if (!dc_isar_feature(aa64_sve2, s)) { - return false; - } return gen_gvec_ptr_zzzz(s, gen_helper_sve2_fmlal_zzxw_s, a->rd, a->rn, a->rm, a->ra, (a->index << 2) | (sel << 1) | sub, cpu_env); } -static bool trans_FMLALB_zzxw(DisasContext *s, arg_rrxr_esz *a) -{ - return do_FMLAL_zzxw(s, a, false, false); -} - -static bool trans_FMLALT_zzxw(DisasContext *s, arg_rrxr_esz *a) -{ - return do_FMLAL_zzxw(s, a, false, true); -} - -static bool trans_FMLSLB_zzxw(DisasContext *s, arg_rrxr_esz *a) -{ - return do_FMLAL_zzxw(s, a, true, false); -} - -static bool trans_FMLSLT_zzxw(DisasContext *s, arg_rrxr_esz *a) -{ - return do_FMLAL_zzxw(s, a, true, true); -} +TRANS_FEAT(FMLALB_zzxw, aa64_sve2, do_FMLAL_zzxw, a, false, false) +TRANS_FEAT(FMLALT_zzxw, aa64_sve2, do_FMLAL_zzxw, a, false, true) +TRANS_FEAT(FMLSLB_zzxw, aa64_sve2, do_FMLAL_zzxw, a, true, false) +TRANS_FEAT(FMLSLT_zzxw, aa64_sve2, do_FMLAL_zzxw, a, true, true) TRANS_FEAT(SMMLA, aa64_sve_i8mm, gen_gvec_ool_arg_zzzz, gen_helper_gvec_smmla_b, a, 0) From 1402a6b88f8d7ec0591427d8e8221c6d18d16d9b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:19:06 -0700 Subject: [PATCH 698/935] target/arm: Add sve feature check for remaining trans_* functions For all remaining trans_* functions that do not already have a check, add one now. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-114-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 177 ++++++++++++++++++++++++++++++++++--- 1 file changed, 163 insertions(+), 14 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 5fb66547ec..836511d719 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -1311,6 +1311,9 @@ TRANS_FEAT(INDEX_rr, aa64_sve, do_index, a->esz, a->rd, static bool trans_ADDVL(DisasContext *s, arg_ADDVL *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { TCGv_i64 rd = cpu_reg_sp(s, a->rd); TCGv_i64 rn = cpu_reg_sp(s, a->rn); @@ -1321,6 +1324,9 @@ static bool trans_ADDVL(DisasContext *s, arg_ADDVL *a) static bool trans_ADDPL(DisasContext *s, arg_ADDPL *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { TCGv_i64 rd = cpu_reg_sp(s, a->rd); TCGv_i64 rn = cpu_reg_sp(s, a->rn); @@ -1331,6 +1337,9 @@ static bool trans_ADDPL(DisasContext *s, arg_ADDPL *a) static bool trans_RDVL(DisasContext *s, arg_RDVL *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { TCGv_i64 reg = cpu_reg(s, a->rd); tcg_gen_movi_i64(reg, a->imm * vec_full_reg_size(s)); @@ -1451,6 +1460,9 @@ static bool trans_AND_pppp(DisasContext *s, arg_rprr_s *a) .prefer_i64 = TCG_TARGET_REG_BITS == 64, }; + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!a->s) { if (a->rn == a->rm) { if (a->pg == a->rn) { @@ -1486,6 +1498,9 @@ static bool trans_BIC_pppp(DisasContext *s, arg_rprr_s *a) .prefer_i64 = TCG_TARGET_REG_BITS == 64, }; + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!a->s && a->pg == a->rn) { return gen_gvec_fn_ppp(s, tcg_gen_gvec_andc, a->rd, a->rn, a->rm); } @@ -1514,6 +1529,9 @@ static bool trans_EOR_pppp(DisasContext *s, arg_rprr_s *a) .prefer_i64 = TCG_TARGET_REG_BITS == 64, }; + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } /* Alias NOT (predicate) is EOR Pd.B, Pg/Z, Pn.B, Pg.B */ if (!a->s && a->pg == a->rm) { return gen_gvec_fn_ppp(s, tcg_gen_gvec_andc, a->rd, a->pg, a->rn); @@ -1523,7 +1541,7 @@ static bool trans_EOR_pppp(DisasContext *s, arg_rprr_s *a) static bool trans_SEL_pppp(DisasContext *s, arg_rprr_s *a) { - if (a->s) { + if (a->s || !dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { @@ -1558,6 +1576,9 @@ static bool trans_ORR_pppp(DisasContext *s, arg_rprr_s *a) .prefer_i64 = TCG_TARGET_REG_BITS == 64, }; + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!a->s && a->pg == a->rn && a->rn == a->rm) { return do_mov_p(s, a->rd, a->rn); } @@ -1585,6 +1606,10 @@ static bool trans_ORN_pppp(DisasContext *s, arg_rprr_s *a) .fno = gen_helper_sve_orn_pppp, .prefer_i64 = TCG_TARGET_REG_BITS == 64, }; + + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } return do_pppp_flags(s, a, &op); } @@ -1609,6 +1634,10 @@ static bool trans_NOR_pppp(DisasContext *s, arg_rprr_s *a) .fno = gen_helper_sve_nor_pppp, .prefer_i64 = TCG_TARGET_REG_BITS == 64, }; + + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } return do_pppp_flags(s, a, &op); } @@ -1633,6 +1662,10 @@ static bool trans_NAND_pppp(DisasContext *s, arg_rprr_s *a) .fno = gen_helper_sve_nand_pppp, .prefer_i64 = TCG_TARGET_REG_BITS == 64, }; + + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } return do_pppp_flags(s, a, &op); } @@ -1642,6 +1675,9 @@ static bool trans_NAND_pppp(DisasContext *s, arg_rprr_s *a) static bool trans_PTEST(DisasContext *s, arg_PTEST *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { int nofs = pred_full_reg_offset(s, a->rn); int gofs = pred_full_reg_offset(s, a->pg); @@ -1998,6 +2034,9 @@ static void do_sat_addsub_vec(DisasContext *s, int esz, int rd, int rn, static bool trans_CNT_r(DisasContext *s, arg_CNT_r *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { unsigned fullsz = vec_full_reg_size(s); unsigned numelem = decode_pred_count(fullsz, a->pat, a->esz); @@ -2008,6 +2047,9 @@ static bool trans_CNT_r(DisasContext *s, arg_CNT_r *a) static bool trans_INCDEC_r(DisasContext *s, arg_incdec_cnt *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { unsigned fullsz = vec_full_reg_size(s); unsigned numelem = decode_pred_count(fullsz, a->pat, a->esz); @@ -2021,6 +2063,9 @@ static bool trans_INCDEC_r(DisasContext *s, arg_incdec_cnt *a) static bool trans_SINCDEC_r_32(DisasContext *s, arg_incdec_cnt *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!sve_access_check(s)) { return true; } @@ -2045,6 +2090,9 @@ static bool trans_SINCDEC_r_32(DisasContext *s, arg_incdec_cnt *a) static bool trans_SINCDEC_r_64(DisasContext *s, arg_incdec_cnt *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!sve_access_check(s)) { return true; } @@ -2062,7 +2110,7 @@ static bool trans_SINCDEC_r_64(DisasContext *s, arg_incdec_cnt *a) static bool trans_INCDEC_v(DisasContext *s, arg_incdec2_cnt *a) { - if (a->esz == 0) { + if (a->esz == 0 || !dc_isar_feature(aa64_sve, s)) { return false; } @@ -2085,7 +2133,7 @@ static bool trans_INCDEC_v(DisasContext *s, arg_incdec2_cnt *a) static bool trans_SINCDEC_v(DisasContext *s, arg_incdec2_cnt *a) { - if (a->esz == 0) { + if (a->esz == 0 || !dc_isar_feature(aa64_sve, s)) { return false; } @@ -2126,6 +2174,10 @@ TRANS_FEAT(EOR_zzi, aa64_sve, do_zz_dbm, a, tcg_gen_gvec_xori) static bool trans_DUPM(DisasContext *s, arg_DUPM *a) { uint64_t imm; + + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!logic_imm_decode_wmask(&imm, extract32(a->dbm, 12, 1), extract32(a->dbm, 0, 6), extract32(a->dbm, 6, 6))) { @@ -2171,7 +2223,7 @@ static void do_cpy_m(DisasContext *s, int esz, int rd, int rn, int pg, static bool trans_FCPY(DisasContext *s, arg_FCPY *a) { - if (a->esz == 0) { + if (a->esz == 0 || !dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { @@ -2184,6 +2236,9 @@ static bool trans_FCPY(DisasContext *s, arg_FCPY *a) static bool trans_CPY_m_i(DisasContext *s, arg_rpri_esz *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { do_cpy_m(s, a->esz, a->rd, a->rn, a->pg, tcg_constant_i64(a->imm)); } @@ -2197,6 +2252,9 @@ static bool trans_CPY_z_i(DisasContext *s, arg_CPY_z_i *a) gen_helper_sve_cpy_z_s, gen_helper_sve_cpy_z_d, }; + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { unsigned vsz = vec_full_reg_size(s); tcg_gen_gvec_2i_ool(vec_full_reg_offset(s, a->rd), @@ -2250,6 +2308,9 @@ TRANS_FEAT(EXT_sve2, aa64_sve2, do_EXT, a->rd, a->rn, (a->rn + 1) % 32, a->imm) static bool trans_DUP_s(DisasContext *s, arg_DUP_s *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { unsigned vsz = vec_full_reg_size(s); tcg_gen_gvec_dup_i64(a->esz, vec_full_reg_offset(s, a->rd), @@ -2260,6 +2321,9 @@ static bool trans_DUP_s(DisasContext *s, arg_DUP_s *a) static bool trans_DUP_x(DisasContext *s, arg_DUP_x *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if ((a->imm & 0x1f) == 0) { return false; } @@ -2308,6 +2372,9 @@ static void do_insr_i64(DisasContext *s, arg_rrr_esz *a, TCGv_i64 val) static bool trans_INSR_f(DisasContext *s, arg_rrr_esz *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { TCGv_i64 t = tcg_temp_new_i64(); tcg_gen_ld_i64(t, cpu_env, vec_reg_offset(s, a->rm, 0, MO_64)); @@ -2319,6 +2386,9 @@ static bool trans_INSR_f(DisasContext *s, arg_rrr_esz *a) static bool trans_INSR_r(DisasContext *s, arg_rrr_esz *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { do_insr_i64(s, a, cpu_reg(s, a->rm)); } @@ -2359,7 +2429,7 @@ static bool trans_UNPK(DisasContext *s, arg_UNPK *a) { gen_helper_sve_sunpk_d, gen_helper_sve_uunpk_d }, }; - if (a->esz == 0) { + if (a->esz == 0 || !dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { @@ -2787,6 +2857,9 @@ TRANS_FEAT(LASTB_r, aa64_sve, do_last_general, a, true) static bool trans_CPY_m_r(DisasContext *s, arg_rpr_esz *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { do_cpy_m(s, a->esz, a->rd, a->rd, a->pg, cpu_reg_sp(s, a->rn)); } @@ -2795,6 +2868,9 @@ static bool trans_CPY_m_r(DisasContext *s, arg_rpr_esz *a) static bool trans_CPY_m_v(DisasContext *s, arg_rpr_esz *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { int ofs = vec_reg_offset(s, a->rn, 0, a->esz); TCGv_i64 t = load_esz(cpu_env, ofs, a->esz); @@ -3102,6 +3178,9 @@ static void do_cntp(DisasContext *s, TCGv_i64 val, int esz, int pn, int pg) static bool trans_CNTP(DisasContext *s, arg_CNTP *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { do_cntp(s, cpu_reg(s, a->rd), a->esz, a->rn, a->pg); } @@ -3110,6 +3189,9 @@ static bool trans_CNTP(DisasContext *s, arg_CNTP *a) static bool trans_INCDECP_r(DisasContext *s, arg_incdec_pred *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { TCGv_i64 reg = cpu_reg(s, a->rd); TCGv_i64 val = tcg_temp_new_i64(); @@ -3127,7 +3209,7 @@ static bool trans_INCDECP_r(DisasContext *s, arg_incdec_pred *a) static bool trans_INCDECP_z(DisasContext *s, arg_incdec2_pred *a) { - if (a->esz == 0) { + if (a->esz == 0 || !dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { @@ -3144,6 +3226,9 @@ static bool trans_INCDECP_z(DisasContext *s, arg_incdec2_pred *a) static bool trans_SINCDECP_r_32(DisasContext *s, arg_incdec_pred *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { TCGv_i64 reg = cpu_reg(s, a->rd); TCGv_i64 val = tcg_temp_new_i64(); @@ -3156,6 +3241,9 @@ static bool trans_SINCDECP_r_32(DisasContext *s, arg_incdec_pred *a) static bool trans_SINCDECP_r_64(DisasContext *s, arg_incdec_pred *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { TCGv_i64 reg = cpu_reg(s, a->rd); TCGv_i64 val = tcg_temp_new_i64(); @@ -3168,7 +3256,7 @@ static bool trans_SINCDECP_r_64(DisasContext *s, arg_incdec_pred *a) static bool trans_SINCDECP_z(DisasContext *s, arg_incdec2_pred *a) { - if (a->esz == 0) { + if (a->esz == 0 || !dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { @@ -3185,6 +3273,9 @@ static bool trans_SINCDECP_z(DisasContext *s, arg_incdec2_pred *a) static bool trans_CTERM(DisasContext *s, arg_CTERM *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!sve_access_check(s)) { return true; } @@ -3221,7 +3312,9 @@ static bool trans_WHILE(DisasContext *s, arg_WHILE *a) bool eq = a->eq == a->lt; /* The greater-than conditions are all SVE2. */ - if (!a->lt && !dc_isar_feature(aa64_sve2, s)) { + if (a->lt + ? !dc_isar_feature(aa64_sve, s) + : !dc_isar_feature(aa64_sve2, s)) { return false; } if (!sve_access_check(s)) { @@ -3389,7 +3482,7 @@ static bool trans_WHILE_ptr(DisasContext *s, arg_WHILE_ptr *a) static bool trans_FDUP(DisasContext *s, arg_FDUP *a) { - if (a->esz == 0) { + if (a->esz == 0 || !dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { @@ -3406,6 +3499,9 @@ static bool trans_FDUP(DisasContext *s, arg_FDUP *a) static bool trans_DUP_i(DisasContext *s, arg_DUP_i *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { unsigned vsz = vec_full_reg_size(s); int dofs = vec_full_reg_offset(s, a->rd); @@ -3453,6 +3549,9 @@ static bool trans_SUBR_zzi(DisasContext *s, arg_rri_esz *a) .scalar_first = true } }; + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { unsigned vsz = vec_full_reg_size(s); tcg_gen_gvec_2s(vec_full_reg_offset(s, a->rd), @@ -3815,7 +3914,7 @@ static bool trans_FADDA(DisasContext *s, arg_rprr_esz *a) TCGv_i64 t_val; TCGv_i32 t_desc; - if (a->esz == 0) { + if (a->esz == 0 || !dc_isar_feature(aa64_sve, s)) { return false; } if (!sve_access_check(s)) { @@ -4367,6 +4466,9 @@ static void do_str(DisasContext *s, uint32_t vofs, int len, int rn, int imm) static bool trans_LDR_zri(DisasContext *s, arg_rri *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { int size = vec_full_reg_size(s); int off = vec_full_reg_offset(s, a->rd); @@ -4377,6 +4479,9 @@ static bool trans_LDR_zri(DisasContext *s, arg_rri *a) static bool trans_LDR_pri(DisasContext *s, arg_rri *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { int size = pred_full_reg_size(s); int off = pred_full_reg_offset(s, a->rd); @@ -4387,6 +4492,9 @@ static bool trans_LDR_pri(DisasContext *s, arg_rri *a) static bool trans_STR_zri(DisasContext *s, arg_rri *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { int size = vec_full_reg_size(s); int off = vec_full_reg_offset(s, a->rd); @@ -4397,6 +4505,9 @@ static bool trans_STR_zri(DisasContext *s, arg_rri *a) static bool trans_STR_pri(DisasContext *s, arg_rri *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { int size = pred_full_reg_size(s); int off = pred_full_reg_offset(s, a->rd); @@ -4597,7 +4708,7 @@ static void do_ld_zpa(DisasContext *s, int zt, int pg, static bool trans_LD_zprr(DisasContext *s, arg_rprr_load *a) { - if (a->rm == 31) { + if (a->rm == 31 || !dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { @@ -4611,6 +4722,9 @@ static bool trans_LD_zprr(DisasContext *s, arg_rprr_load *a) static bool trans_LD_zpri(DisasContext *s, arg_rpri_load *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { int vsz = vec_full_reg_size(s); int elements = vsz >> dtype_esz[a->dtype]; @@ -4712,6 +4826,9 @@ static bool trans_LDFF1_zprr(DisasContext *s, arg_rprr_load *a) gen_helper_sve_ldff1dd_be_r_mte } }, }; + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { TCGv_i64 addr = new_tmp_a64(s); tcg_gen_shli_i64(addr, cpu_reg(s, a->rm), dtype_msz(a->dtype)); @@ -4810,6 +4927,9 @@ static bool trans_LDNF1_zpri(DisasContext *s, arg_rpri_load *a) gen_helper_sve_ldnf1dd_be_r_mte } }, }; + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { int vsz = vec_full_reg_size(s); int elements = vsz >> dtype_esz[a->dtype]; @@ -4867,7 +4987,7 @@ static void do_ldrq(DisasContext *s, int zt, int pg, TCGv_i64 addr, int dtype) static bool trans_LD1RQ_zprr(DisasContext *s, arg_rprr_load *a) { - if (a->rm == 31) { + if (a->rm == 31 || !dc_isar_feature(aa64_sve, s)) { return false; } if (sve_access_check(s)) { @@ -4882,6 +5002,9 @@ static bool trans_LD1RQ_zprr(DisasContext *s, arg_rprr_load *a) static bool trans_LD1RQ_zpri(DisasContext *s, arg_rpri_load *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (sve_access_check(s)) { TCGv_i64 addr = new_tmp_a64(s); tcg_gen_addi_i64(addr, cpu_reg_sp(s, a->rn), a->imm * 16); @@ -4993,6 +5116,9 @@ static bool trans_LD1R_zpri(DisasContext *s, arg_rpri_load *a) TCGLabel *over; TCGv_i64 temp, clean_addr; + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!sve_access_check(s)) { return true; } @@ -5161,6 +5287,9 @@ static void do_st_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, static bool trans_ST_zprr(DisasContext *s, arg_rprr_store *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (a->rm == 31 || a->msz > a->esz) { return false; } @@ -5175,6 +5304,9 @@ static bool trans_ST_zprr(DisasContext *s, arg_rprr_store *a) static bool trans_ST_zpri(DisasContext *s, arg_rpri_store *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (a->msz > a->esz) { return false; } @@ -5558,6 +5690,9 @@ static bool trans_LD1_zprz(DisasContext *s, arg_LD1_zprz *a) bool be = s->be_data == MO_BE; bool mte = s->mte_active[0]; + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!sve_access_check(s)) { return true; } @@ -5586,6 +5721,9 @@ static bool trans_LD1_zpiz(DisasContext *s, arg_LD1_zpiz *a) if (a->esz < a->msz || (a->esz == a->msz && !a->u)) { return false; } + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!sve_access_check(s)) { return true; } @@ -5740,6 +5878,9 @@ static bool trans_ST1_zprz(DisasContext *s, arg_ST1_zprz *a) if (a->esz < a->msz || (a->msz == 0 && a->scale)) { return false; } + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!sve_access_check(s)) { return true; } @@ -5767,6 +5908,9 @@ static bool trans_ST1_zpiz(DisasContext *s, arg_ST1_zpiz *a) if (a->esz < a->msz) { return false; } + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } if (!sve_access_check(s)) { return true; } @@ -5827,6 +5971,9 @@ static bool trans_STNT1_zprz(DisasContext *s, arg_ST1_zprz *a) static bool trans_PRF(DisasContext *s, arg_PRF *a) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } /* Prefetch is a nop within QEMU. */ (void)sve_access_check(s); return true; @@ -5834,7 +5981,7 @@ static bool trans_PRF(DisasContext *s, arg_PRF *a) static bool trans_PRF_rr(DisasContext *s, arg_PRF_rr *a) { - if (a->rm == 31) { + if (a->rm == 31 || !dc_isar_feature(aa64_sve, s)) { return false; } /* Prefetch is a nop within QEMU. */ @@ -6070,7 +6217,9 @@ static bool do_trans_pmull(DisasContext *s, arg_rrr_esz *a, bool sel) gen_helper_gvec_pmull_q, gen_helper_sve2_pmull_h, NULL, gen_helper_sve2_pmull_d, }; - if (a->esz == 0 && !dc_isar_feature(aa64_sve2_pmull128, s)) { + if (a->esz == 0 + ? !dc_isar_feature(aa64_sve2_pmull128, s) + : !dc_isar_feature(aa64_sve, s)) { return false; } return gen_gvec_ool_arg_zzz(s, fns[a->esz], a, sel); From b1071174d2a2ab371082b7d4b5f19e98edc61ac6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 May 2022 11:19:07 -0700 Subject: [PATCH 699/935] target/arm: Remove aa64_sve check from before disas_sve We now have individual checks on all insns within disas_sve. Signed-off-by: Richard Henderson Message-id: 20220527181907.189259-115-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index f502545307..935e1929bb 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -14772,7 +14772,7 @@ static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) unallocated_encoding(s); break; case 0x2: - if (!dc_isar_feature(aa64_sve, s) || !disas_sve(s, insn)) { + if (!disas_sve(s, insn)) { unallocated_encoding(s); } break; From ee344768c1a19417e005bd96c2c6e256986380d5 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Sat, 20 Nov 2021 19:41:58 +0100 Subject: [PATCH 700/935] MAINTAINERS: Add myself as the maintainer for Hyper-V VMBus This way there is some contact point for incoming patches, and somebody to review and pick up them. Signed-off-by: Maciej S. Szmigiero --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index dff0200f70..00dc4a8ecb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1777,6 +1777,12 @@ F: include/hw/block/fdc.h F: tests/qtest/fdc-test.c T: git https://gitlab.com/jsnow/qemu.git ide +Hyper-V VMBus +M: Maciej S. Szmigiero +S: Odd Fixes +F: hw/hyperv/vmbus.c +F: include/hw/hyperv/vmbus*.h + OMAP M: Peter Maydell L: qemu-arm@nongnu.org From 6ede46b910ac66fd10bc169fb0a6f681429a9c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 6 Nov 2021 14:41:55 +0100 Subject: [PATCH 701/935] hw/hyperv/vmbus: Remove unused vmbus_load/save_req() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vmbus_save_req() and vmbus_load_req() are not used. Remove them to avoid maintaining dead code. This essentially reverts commit 4dd8a7064b8a6527f99a62be11 ("vmbus: add infrastructure to save/load vmbus requests"). Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20211106134155.582312-2-philmd@redhat.com> [MSS: Remove also corresponding variables, which are now unused] Signed-off-by: Maciej S. Szmigiero --- hw/hyperv/vmbus.c | 99 --------------------------------------- include/hw/hyperv/vmbus.h | 3 -- 2 files changed, 102 deletions(-) diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c index 8aad29f1bb..30bc04e1c4 100644 --- a/hw/hyperv/vmbus.c +++ b/hw/hyperv/vmbus.c @@ -1273,105 +1273,6 @@ void vmbus_free_req(void *req) g_free(req); } -static const VMStateDescription vmstate_sgent = { - .name = "vmbus/sgentry", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT64(base, ScatterGatherEntry), - VMSTATE_UINT64(len, ScatterGatherEntry), - VMSTATE_END_OF_LIST() - } -}; - -typedef struct VMBusChanReqSave { - uint16_t chan_idx; - uint16_t pkt_type; - uint32_t msglen; - void *msg; - uint64_t transaction_id; - bool need_comp; - uint32_t num; - ScatterGatherEntry *sgl; -} VMBusChanReqSave; - -static const VMStateDescription vmstate_vmbus_chan_req = { - .name = "vmbus/vmbus_chan_req", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT16(chan_idx, VMBusChanReqSave), - VMSTATE_UINT16(pkt_type, VMBusChanReqSave), - VMSTATE_UINT32(msglen, VMBusChanReqSave), - VMSTATE_VBUFFER_ALLOC_UINT32(msg, VMBusChanReqSave, 0, NULL, msglen), - VMSTATE_UINT64(transaction_id, VMBusChanReqSave), - VMSTATE_BOOL(need_comp, VMBusChanReqSave), - VMSTATE_UINT32(num, VMBusChanReqSave), - VMSTATE_STRUCT_VARRAY_POINTER_UINT32(sgl, VMBusChanReqSave, num, - vmstate_sgent, ScatterGatherEntry), - VMSTATE_END_OF_LIST() - } -}; - -void vmbus_save_req(QEMUFile *f, VMBusChanReq *req) -{ - VMBusChanReqSave req_save; - - req_save.chan_idx = req->chan->subchan_idx; - req_save.pkt_type = req->pkt_type; - req_save.msglen = req->msglen; - req_save.msg = req->msg; - req_save.transaction_id = req->transaction_id; - req_save.need_comp = req->need_comp; - req_save.num = req->sgl.nsg; - req_save.sgl = g_memdup(req->sgl.sg, - req_save.num * sizeof(ScatterGatherEntry)); - - vmstate_save_state(f, &vmstate_vmbus_chan_req, &req_save, NULL); - - g_free(req_save.sgl); -} - -void *vmbus_load_req(QEMUFile *f, VMBusDevice *dev, uint32_t size) -{ - VMBusChanReqSave req_save; - VMBusChanReq *req = NULL; - VMBusChannel *chan = NULL; - uint32_t i; - - vmstate_load_state(f, &vmstate_vmbus_chan_req, &req_save, 0); - - if (req_save.chan_idx >= dev->num_channels) { - error_report("%s: %u(chan_idx) > %u(num_channels)", __func__, - req_save.chan_idx, dev->num_channels); - goto out; - } - chan = &dev->channels[req_save.chan_idx]; - - if (vmbus_channel_reserve(chan, 0, req_save.msglen)) { - goto out; - } - - req = vmbus_alloc_req(chan, size, req_save.pkt_type, req_save.msglen, - req_save.transaction_id, req_save.need_comp); - if (req_save.msglen) { - memcpy(req->msg, req_save.msg, req_save.msglen); - } - - for (i = 0; i < req_save.num; i++) { - qemu_sglist_add(&req->sgl, req_save.sgl[i].base, req_save.sgl[i].len); - } - -out: - if (req_save.msglen) { - g_free(req_save.msg); - } - if (req_save.num) { - g_free(req_save.sgl); - } - return req; -} - static void channel_event_cb(EventNotifier *e) { VMBusChannel *chan = container_of(e, VMBusChannel, notifier); diff --git a/include/hw/hyperv/vmbus.h b/include/hw/hyperv/vmbus.h index f98bea3888..8ea660dd8e 100644 --- a/include/hw/hyperv/vmbus.h +++ b/include/hw/hyperv/vmbus.h @@ -223,7 +223,4 @@ int vmbus_map_sgl(VMBusChanReq *req, DMADirection dir, struct iovec *iov, void vmbus_unmap_sgl(VMBusChanReq *req, DMADirection dir, struct iovec *iov, unsigned iov_cnt, size_t accessed); -void vmbus_save_req(QEMUFile *f, VMBusChanReq *req); -void *vmbus_load_req(QEMUFile *f, VMBusDevice *dev, uint32_t size); - #endif From 658f2da1f33aaf86d7b345891f479462a7d1e2d3 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 27 May 2022 16:35:31 +0100 Subject: [PATCH 702/935] .gitlab-ci.d/container-cross: Fix RISC-V container dependencies / stages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "riscv64-debian-cross-container" job does not depend on any other container job from the first stage, so we can move it to the first stage, too. The "riscv64-debian-test-cross-container" job needs the debian11 container, so we should add a proper "needs:" statement here. Signed-off-by: Thomas Huth Message-Id: <20220524093141.91012-1-thuth@redhat.com> Signed-off-by: Alex Bennée Reviewed-by: Alistair Francis Message-Id: <20220527153603.887929-2-alex.bennee@linaro.org> --- .gitlab-ci.d/container-cross.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.d/container-cross.yml b/.gitlab-ci.d/container-cross.yml index e622ac2d21..ac15fce9b6 100644 --- a/.gitlab-ci.d/container-cross.yml +++ b/.gitlab-ci.d/container-cross.yml @@ -125,7 +125,7 @@ ppc64el-debian-cross-container: riscv64-debian-cross-container: extends: .container_job_template - stage: containers-layer2 + stage: containers # as we are currently based on 'sid/unstable' we may break so... allow_failure: true variables: @@ -135,6 +135,7 @@ riscv64-debian-cross-container: riscv64-debian-test-cross-container: extends: .container_job_template stage: containers-layer2 + needs: ['amd64-debian11-container'] variables: NAME: debian-riscv64-test-cross From 6fd4e75610c08820faabf9c544f2f2af2b1b8334 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 27 May 2022 16:35:32 +0100 Subject: [PATCH 703/935] .gitlab-ci.d/crossbuilds: Fix the dependency of the cross-i386-tci job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cross-i386-tci job uses the fedora-i386-cross image, so we should make sure that the corresponding job that builds it (the i386-fedora-cross-container job) has finished before we start the TCI job. Signed-off-by: Thomas Huth Reviewed-by: Richard Henderson Message-Id: <20220524092600.89997-1-thuth@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20220527153603.887929-3-alex.bennee@linaro.org> --- .gitlab-ci.d/crossbuilds.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.d/crossbuilds.yml b/.gitlab-ci.d/crossbuilds.yml index 17d6cb3e45..4a5fb6ea2a 100644 --- a/.gitlab-ci.d/crossbuilds.yml +++ b/.gitlab-ci.d/crossbuilds.yml @@ -62,6 +62,8 @@ cross-i386-user: cross-i386-tci: extends: .cross_accel_build_job timeout: 60m + needs: + job: i386-fedora-cross-container variables: IMAGE: fedora-i386-cross ACCEL: tcg-interpreter From 861dca3707a73cbe022cefe52f7224b28350316b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 27 May 2022 16:35:33 +0100 Subject: [PATCH 704/935] gitlab-ci: add meson JUnit test result into report MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows the gitlab UI to show the test results in different ways, see doc: https://docs.gitlab.com/ee/ci/unit_test_reports.html#how-it-works Previous we only reports avocado test results (.avocado_test_job_template), with this change, the qemu/meson tests are also covered. Signed-off-by: Marc-André Lureau Message-Id: <20220525173411.612224-1-marcandre.lureau@redhat.com> [AJB: expand the commit description] Signed-off-by: Alex Bennée Reviewed-by: Thomas Huth Message-Id: <20220527153603.887929-4-alex.bennee@linaro.org> --- .gitlab-ci.d/buildtest-template.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.d/buildtest-template.yml b/.gitlab-ci.d/buildtest-template.yml index dc6d67aacf..b381345dbc 100644 --- a/.gitlab-ci.d/buildtest-template.yml +++ b/.gitlab-ci.d/buildtest-template.yml @@ -44,6 +44,8 @@ expire_in: 7 days paths: - build/meson-logs/testlog.txt + reports: + junit: build/meson-logs/testlog.junit.xml .avocado_test_job_template: extends: .common_test_job_template From 85b141ea6ae448b718d438d9cf0009d73116f8d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 27 May 2022 16:35:34 +0100 Subject: [PATCH 705/935] meson.build: fix summary display of test compilers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The recent refactoring of configure.sh dropped a number of variables we relied on for printing out information. Make it simpler. Fixes: eebf199c09 (tests/tcg: invoke Makefile.target directly from QEMU's makefile) Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20220527153603.887929-5-alex.bennee@linaro.org> --- meson.build | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/meson.build b/meson.build index bf318d9cbb..bc6234c85e 100644 --- a/meson.build +++ b/meson.build @@ -3735,12 +3735,8 @@ foreach target: target_dirs config_cross_tcg = keyval.load(tcg_mak) target = config_cross_tcg['TARGET_NAME'] compiler = '' - if 'DOCKER_CROSS_CC_GUEST' in config_cross_tcg - summary_info += {target + ' tests': config_cross_tcg['DOCKER_CROSS_CC_GUEST'] + - ' via ' + config_cross_tcg['DOCKER_IMAGE']} - elif 'CROSS_CC_GUEST' in config_cross_tcg - summary_info += {target + ' tests' - : config_cross_tcg['CROSS_CC_GUEST'] } + if 'CC' in config_cross_tcg + summary_info += {target + ' tests': config_cross_tcg['CC']} endif endif endforeach From 06885cf93556adc3fd67aad0c279a0deb400bb7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 27 May 2022 16:35:35 +0100 Subject: [PATCH 706/935] tests/lcitool: fix up indentation to correct style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 3 space indentation snuck into the initial commit. Clean it up before we let it get established. I've also: - removed unused os import - added double lines between functions - added some comments and grouped and sorted the generation stanzas My lint tool is also recommending using f-strings but that requires python 3.6. Signed-off-by: Alex Bennée Cc: Daniel P. Berrangé Reviewed-by: Daniel P. Berrangé Message-Id: <20220527153603.887929-6-alex.bennee@linaro.org> --- tests/lcitool/refresh | 128 ++++++++++++++++++++++++------------------ 1 file changed, 73 insertions(+), 55 deletions(-) diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh index fb49bbc441..dc1fc21ef9 100755 --- a/tests/lcitool/refresh +++ b/tests/lcitool/refresh @@ -13,14 +13,13 @@ # the top-level directory. import sys -import os import subprocess from pathlib import Path if len(sys.argv) != 1: - print("syntax: %s" % sys.argv[0], file=sys.stderr) - sys.exit(1) + print("syntax: %s" % sys.argv[0], file=sys.stderr) + sys.exit(1) self_dir = Path(__file__).parent src_dir = self_dir.parent.parent @@ -30,76 +29,95 @@ lcitool_path = Path(self_dir, "libvirt-ci", "lcitool") lcitool_cmd = [lcitool_path, "--data-dir", self_dir] + def atomic_write(filename, content): - tmp = filename.with_suffix(filename.suffix + ".tmp") - try: - with tmp.open("w") as fp: - print(content, file=fp, end="") - tmp.rename(filename) - except Exception as ex: - tmp.unlink() - raise + tmp = filename.with_suffix(filename.suffix + ".tmp") + try: + with tmp.open("w") as fp: + print(content, file=fp, end="") + tmp.rename(filename) + except Exception as ex: + tmp.unlink() + raise + def generate(filename, cmd, trailer): - print("Generate %s" % filename) - lcitool=subprocess.run(cmd, capture_output=True) + print("Generate %s" % filename) + lcitool = subprocess.run(cmd, capture_output=True) - if lcitool.returncode != 0: - raise Exception("Failed to generate %s: %s" % (filename, lcitool.stderr)) + if lcitool.returncode != 0: + raise Exception("Failed to generate %s: %s" % (filename, lcitool.stderr)) + + content = lcitool.stdout.decode("utf8") + if trailer is not None: + content += trailer + atomic_write(filename, content) - content = lcitool.stdout.decode("utf8") - if trailer is not None: - content += trailer - atomic_write(filename, content) def generate_dockerfile(host, target, cross=None, trailer=None): - filename = Path(src_dir, "tests", "docker", "dockerfiles", host + ".docker") - cmd = lcitool_cmd + ["dockerfile"] - if cross is not None: - cmd.extend(["--cross", cross]) - cmd.extend([target, "qemu"]) - generate(filename, cmd, trailer) + filename = Path(src_dir, "tests", "docker", "dockerfiles", host + ".docker") + cmd = lcitool_cmd + ["dockerfile"] + if cross is not None: + cmd.extend(["--cross", cross]) + cmd.extend([target, "qemu"]) + generate(filename, cmd, trailer) + def generate_cirrus(target, trailer=None): - filename = Path(src_dir, ".gitlab-ci.d", "cirrus", target + ".vars") - cmd = lcitool_cmd + ["variables", target, "qemu"] - generate(filename, cmd, trailer) + filename = Path(src_dir, ".gitlab-ci.d", "cirrus", target + ".vars") + cmd = lcitool_cmd + ["variables", target, "qemu"] + generate(filename, cmd, trailer) + ubuntu2004_tsanhack = [ - "# Apply patch https://reviews.llvm.org/D75820\n", - "# This is required for TSan in clang-10 to compile with QEMU.\n", - "RUN sed -i 's/^const/static const/g' /usr/lib/llvm-10/lib/clang/10.0.0/include/sanitizer/tsan_interface.h\n" + "# Apply patch https://reviews.llvm.org/D75820\n", + "# This is required for TSan in clang-10 to compile with QEMU.\n", + "RUN sed -i 's/^const/static const/g' /usr/lib/llvm-10/lib/clang/10.0.0/include/sanitizer/tsan_interface.h\n" ] -def debian_cross_build(prefix, targets): - conf = "ENV QEMU_CONFIGURE_OPTS --cross-prefix=%s\n" % (prefix) - targets = "ENV DEF_TARGET_LIST %s\n" % (targets) - return "".join([conf, targets]) +def debian_cross_build(prefix, targets): + conf = "ENV QEMU_CONFIGURE_OPTS --cross-prefix=%s\n" % (prefix) + targets = "ENV DEF_TARGET_LIST %s\n" % (targets) + return "".join([conf, targets]) + +# +# Update all the various build configurations. +# Please keep each group sorted alphabetically for easy reading. +# try: - generate_dockerfile("centos8", "centos-stream-8") - generate_dockerfile("fedora", "fedora-35") - generate_dockerfile("ubuntu2004", "ubuntu-2004", - trailer="".join(ubuntu2004_tsanhack)) - generate_dockerfile("opensuse-leap", "opensuse-leap-152") - generate_dockerfile("alpine", "alpine-edge") + # + # Standard native builds + # + generate_dockerfile("alpine", "alpine-edge") + generate_dockerfile("centos8", "centos-stream-8") + generate_dockerfile("fedora", "fedora-35") + generate_dockerfile("opensuse-leap", "opensuse-leap-152") + generate_dockerfile("ubuntu2004", "ubuntu-2004", + trailer="".join(ubuntu2004_tsanhack)) - generate_dockerfile("debian-arm64-cross", "debian-11", - cross="aarch64", - trailer=debian_cross_build("aarch64-linux-gnu-", - "aarch64-softmmu,aarch64-linux-user")) + # + # Cross compiling builds + # + generate_dockerfile("debian-arm64-cross", "debian-11", + cross="aarch64", + trailer=debian_cross_build("aarch64-linux-gnu-", + "aarch64-softmmu,aarch64-linux-user")) - generate_dockerfile("debian-s390x-cross", "debian-11", - cross="s390x", - trailer=debian_cross_build("s390x-linux-gnu-", - "s390x-softmmu,s390x-linux-user")) + generate_dockerfile("debian-s390x-cross", "debian-11", + cross="s390x", + trailer=debian_cross_build("s390x-linux-gnu-", + "s390x-softmmu,s390x-linux-user")) - generate_cirrus("freebsd-12") - generate_cirrus("freebsd-13") - generate_cirrus("macos-11") + # + # Cirrus packages lists for GitLab + # + generate_cirrus("freebsd-12") + generate_cirrus("freebsd-13") + generate_cirrus("macos-11") - sys.exit(0) + sys.exit(0) except Exception as ex: - print(str(ex), file=sys.stderr) - sys.exit(1) + print(str(ex), file=sys.stderr) + sys.exit(1) From 18ad049d90feede8affee797822fca41d1472b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 27 May 2022 16:35:36 +0100 Subject: [PATCH 707/935] tests/docker: update debian-armhf-cross with lcitool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use lcitool to update debian-armhf-cross to a Debian 11 based system. Signed-off-by: Alex Bennée Reviewed-by: Daniel P. Berrangé Message-Id: <20220527153603.887929-7-alex.bennee@linaro.org> --- .gitlab-ci.d/container-cross.yml | 3 +- tests/docker/Makefile.include | 1 - .../dockerfiles/debian-armhf-cross.docker | 184 +++++++++++++++--- tests/lcitool/refresh | 5 + 4 files changed, 166 insertions(+), 27 deletions(-) diff --git a/.gitlab-ci.d/container-cross.yml b/.gitlab-ci.d/container-cross.yml index ac15fce9b6..4d1830f3fc 100644 --- a/.gitlab-ci.d/container-cross.yml +++ b/.gitlab-ci.d/container-cross.yml @@ -34,8 +34,7 @@ armel-debian-cross-container: armhf-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-armhf-cross diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index ca2157db46..d6e0710554 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -90,7 +90,6 @@ endif docker-image-debian-alpha-cross: docker-image-debian10 docker-image-debian-armel-cross: docker-image-debian10 -docker-image-debian-armhf-cross: docker-image-debian10 docker-image-debian-hppa-cross: docker-image-debian10 docker-image-debian-m68k-cross: docker-image-debian10 docker-image-debian-mips-cross: docker-image-debian10 diff --git a/tests/docker/dockerfiles/debian-armhf-cross.docker b/tests/docker/dockerfiles/debian-armhf-cross.docker index 25d7618833..a2ebce96f8 100644 --- a/tests/docker/dockerfiles/debian-armhf-cross.docker +++ b/tests/docker/dockerfiles/debian-armhf-cross.docker @@ -1,29 +1,165 @@ +# THIS FILE WAS AUTO-GENERATED # -# Docker armhf cross-compiler target +# $ lcitool dockerfile --layers all --cross armv7l debian-11 qemu # -# This docker target builds on the debian Stretch base image. -# -FROM qemu/debian10 +# https://gitlab.com/libvirt/libvirt-ci -# Add the foreign architecture we want and install dependencies -RUN dpkg --add-architecture armhf -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - crossbuild-essential-armhf -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a armhf --arch-only qemu +FROM docker.io/library/debian:11-slim -# Specify the cross prefix for this image (see tests/docker/common.rc) +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y eatmydata && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y \ + bash \ + bc \ + bsdextrautils \ + bzip2 \ + ca-certificates \ + ccache \ + dbus \ + debianutils \ + diffutils \ + exuberant-ctags \ + findutils \ + gcovr \ + genisoimage \ + gettext \ + git \ + hostname \ + libpcre2-dev \ + libspice-protocol-dev \ + llvm \ + locales \ + make \ + meson \ + ncat \ + ninja-build \ + openssh-client \ + perl-base \ + pkgconf \ + python3 \ + python3-numpy \ + python3-opencv \ + python3-pillow \ + python3-pip \ + python3-sphinx \ + python3-sphinx-rtd-theme \ + python3-venv \ + python3-yaml \ + rpm2cpio \ + sed \ + sparse \ + tar \ + tesseract-ocr \ + tesseract-ocr-eng \ + texinfo && \ + eatmydata apt-get autoremove -y && \ + eatmydata apt-get autoclean -y && \ + sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ + dpkg-reconfigure locales + +ENV LANG "en_US.UTF-8" +ENV MAKE "/usr/bin/make" +ENV NINJA "/usr/bin/ninja" +ENV PYTHON "/usr/bin/python3" +ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" + +RUN export DEBIAN_FRONTEND=noninteractive && \ + dpkg --add-architecture armhf && \ + eatmydata apt-get update && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y dpkg-dev && \ + eatmydata apt-get install --no-install-recommends -y \ + g++-arm-linux-gnueabihf \ + gcc-arm-linux-gnueabihf \ + libaio-dev:armhf \ + libasan5:armhf \ + libasound2-dev:armhf \ + libattr1-dev:armhf \ + libbpf-dev:armhf \ + libbrlapi-dev:armhf \ + libbz2-dev:armhf \ + libc6-dev:armhf \ + libcacard-dev:armhf \ + libcap-ng-dev:armhf \ + libcapstone-dev:armhf \ + libcurl4-gnutls-dev:armhf \ + libdaxctl-dev:armhf \ + libdrm-dev:armhf \ + libepoxy-dev:armhf \ + libfdt-dev:armhf \ + libffi-dev:armhf \ + libfuse3-dev:armhf \ + libgbm-dev:armhf \ + libgcrypt20-dev:armhf \ + libglib2.0-dev:armhf \ + libglusterfs-dev:armhf \ + libgnutls28-dev:armhf \ + libgtk-3-dev:armhf \ + libibumad-dev:armhf \ + libibverbs-dev:armhf \ + libiscsi-dev:armhf \ + libjemalloc-dev:armhf \ + libjpeg62-turbo-dev:armhf \ + liblttng-ust-dev:armhf \ + liblzo2-dev:armhf \ + libncursesw5-dev:armhf \ + libnfs-dev:armhf \ + libnuma-dev:armhf \ + libpam0g-dev:armhf \ + libpixman-1-dev:armhf \ + libpng-dev:armhf \ + libpulse-dev:armhf \ + librbd-dev:armhf \ + librdmacm-dev:armhf \ + libsasl2-dev:armhf \ + libsdl2-dev:armhf \ + libsdl2-image-dev:armhf \ + libseccomp-dev:armhf \ + libselinux1-dev:armhf \ + libslirp-dev:armhf \ + libsnappy-dev:armhf \ + libspice-server-dev:armhf \ + libssh-gcrypt-dev:armhf \ + libsystemd-dev:armhf \ + libtasn1-6-dev:armhf \ + libubsan1:armhf \ + libudev-dev:armhf \ + liburing-dev:armhf \ + libusb-1.0-0-dev:armhf \ + libusbredirhost-dev:armhf \ + libvdeplug-dev:armhf \ + libvirglrenderer-dev:armhf \ + libvte-2.91-dev:armhf \ + libxen-dev:armhf \ + libzstd-dev:armhf \ + nettle-dev:armhf \ + systemtap-sdt-dev:armhf \ + xfslibs-dev:armhf \ + zlib1g-dev:armhf && \ + eatmydata apt-get autoremove -y && \ + eatmydata apt-get autoclean -y && \ + mkdir -p /usr/local/share/meson/cross && \ + echo "[binaries]\n\ +c = '/usr/bin/arm-linux-gnueabihf-gcc'\n\ +ar = '/usr/bin/arm-linux-gnueabihf-gcc-ar'\n\ +strip = '/usr/bin/arm-linux-gnueabihf-strip'\n\ +pkgconfig = '/usr/bin/arm-linux-gnueabihf-pkg-config'\n\ +\n\ +[host_machine]\n\ +system = 'linux'\n\ +cpu_family = 'arm'\n\ +cpu = 'armhf'\n\ +endian = 'little'" > /usr/local/share/meson/cross/arm-linux-gnueabihf && \ + dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ + mkdir -p /usr/libexec/ccache-wrappers && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabihf-c++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabihf-cc && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabihf-g++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabihf-gcc + +ENV ABI "arm-linux-gnueabihf" +ENV MESON_OPTS "--cross-file=arm-linux-gnueabihf" ENV QEMU_CONFIGURE_OPTS --cross-prefix=arm-linux-gnueabihf- -ENV DEF_TARGET_LIST arm-softmmu,arm-linux-user,armeb-linux-user - -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - libbz2-dev:armhf \ - liblzo2-dev:armhf \ - librdmacm-dev:armhf \ - libsnappy-dev:armhf \ - libxen-dev:armhf +ENV DEF_TARGET_LIST arm-softmmu,arm-linux-user diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh index dc1fc21ef9..7e4a92f630 100755 --- a/tests/lcitool/refresh +++ b/tests/lcitool/refresh @@ -105,6 +105,11 @@ try: trailer=debian_cross_build("aarch64-linux-gnu-", "aarch64-softmmu,aarch64-linux-user")) + generate_dockerfile("debian-armhf-cross", "debian-11", + cross="armv7l", + trailer=debian_cross_build("arm-linux-gnueabihf-", + "arm-softmmu,arm-linux-user")) + generate_dockerfile("debian-s390x-cross", "debian-11", cross="s390x", trailer=debian_cross_build("s390x-linux-gnu-", From 94806241878e2f8908a04f82fe4086ce56690d80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 27 May 2022 16:35:37 +0100 Subject: [PATCH 708/935] tests/docker: update debian-armel-cross with lcitool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use lcitool to update debian-armel-cross to a Debian 11 based system. Signed-off-by: Alex Bennée Reviewed-by: Daniel P. Berrangé Message-Id: <20220527153603.887929-8-alex.bennee@linaro.org> --- .gitlab-ci.d/container-cross.yml | 3 +- tests/docker/Makefile.include | 1 - .../dockerfiles/debian-armel-cross.docker | 178 ++++++++++++++++-- tests/lcitool/refresh | 5 + 4 files changed, 164 insertions(+), 23 deletions(-) diff --git a/.gitlab-ci.d/container-cross.yml b/.gitlab-ci.d/container-cross.yml index 4d1830f3fc..caef7decf4 100644 --- a/.gitlab-ci.d/container-cross.yml +++ b/.gitlab-ci.d/container-cross.yml @@ -27,8 +27,7 @@ arm64-debian-cross-container: armel-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-armel-cross diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index d6e0710554..d9109bcc77 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -89,7 +89,6 @@ DOCKER_PARTIAL_IMAGES += fedora endif docker-image-debian-alpha-cross: docker-image-debian10 -docker-image-debian-armel-cross: docker-image-debian10 docker-image-debian-hppa-cross: docker-image-debian10 docker-image-debian-m68k-cross: docker-image-debian10 docker-image-debian-mips-cross: docker-image-debian10 diff --git a/tests/docker/dockerfiles/debian-armel-cross.docker b/tests/docker/dockerfiles/debian-armel-cross.docker index b7b1a3585f..a6153e5a83 100644 --- a/tests/docker/dockerfiles/debian-armel-cross.docker +++ b/tests/docker/dockerfiles/debian-armel-cross.docker @@ -1,26 +1,164 @@ +# THIS FILE WAS AUTO-GENERATED # -# Docker armel cross-compiler target +# $ lcitool dockerfile --layers all --cross armv6l debian-11 qemu # -# This docker target builds on the debian Stretch base image. -# -FROM qemu/debian10 -MAINTAINER Philippe Mathieu-Daudé +# https://gitlab.com/libvirt/libvirt-ci -# Add the foreign architecture we want and install dependencies -RUN dpkg --add-architecture armel && \ - apt update && \ - apt install -yy crossbuild-essential-armel && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a armel --arch-only qemu +FROM docker.io/library/debian:11-slim -# Specify the cross prefix for this image (see tests/docker/common.rc) +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y eatmydata && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y \ + bash \ + bc \ + bsdextrautils \ + bzip2 \ + ca-certificates \ + ccache \ + dbus \ + debianutils \ + diffutils \ + exuberant-ctags \ + findutils \ + gcovr \ + genisoimage \ + gettext \ + git \ + hostname \ + libpcre2-dev \ + libspice-protocol-dev \ + llvm \ + locales \ + make \ + meson \ + ncat \ + ninja-build \ + openssh-client \ + perl-base \ + pkgconf \ + python3 \ + python3-numpy \ + python3-opencv \ + python3-pillow \ + python3-pip \ + python3-sphinx \ + python3-sphinx-rtd-theme \ + python3-venv \ + python3-yaml \ + rpm2cpio \ + sed \ + sparse \ + tar \ + tesseract-ocr \ + tesseract-ocr-eng \ + texinfo && \ + eatmydata apt-get autoremove -y && \ + eatmydata apt-get autoclean -y && \ + sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ + dpkg-reconfigure locales + +ENV LANG "en_US.UTF-8" +ENV MAKE "/usr/bin/make" +ENV NINJA "/usr/bin/ninja" +ENV PYTHON "/usr/bin/python3" +ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" + +RUN export DEBIAN_FRONTEND=noninteractive && \ + dpkg --add-architecture armel && \ + eatmydata apt-get update && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y dpkg-dev && \ + eatmydata apt-get install --no-install-recommends -y \ + g++-arm-linux-gnueabi \ + gcc-arm-linux-gnueabi \ + libaio-dev:armel \ + libasan5:armel \ + libasound2-dev:armel \ + libattr1-dev:armel \ + libbpf-dev:armel \ + libbrlapi-dev:armel \ + libbz2-dev:armel \ + libc6-dev:armel \ + libcacard-dev:armel \ + libcap-ng-dev:armel \ + libcapstone-dev:armel \ + libcurl4-gnutls-dev:armel \ + libdaxctl-dev:armel \ + libdrm-dev:armel \ + libepoxy-dev:armel \ + libfdt-dev:armel \ + libffi-dev:armel \ + libfuse3-dev:armel \ + libgbm-dev:armel \ + libgcrypt20-dev:armel \ + libglib2.0-dev:armel \ + libglusterfs-dev:armel \ + libgnutls28-dev:armel \ + libgtk-3-dev:armel \ + libibumad-dev:armel \ + libibverbs-dev:armel \ + libiscsi-dev:armel \ + libjemalloc-dev:armel \ + libjpeg62-turbo-dev:armel \ + liblttng-ust-dev:armel \ + liblzo2-dev:armel \ + libncursesw5-dev:armel \ + libnfs-dev:armel \ + libnuma-dev:armel \ + libpam0g-dev:armel \ + libpixman-1-dev:armel \ + libpng-dev:armel \ + libpulse-dev:armel \ + librbd-dev:armel \ + librdmacm-dev:armel \ + libsasl2-dev:armel \ + libsdl2-dev:armel \ + libsdl2-image-dev:armel \ + libseccomp-dev:armel \ + libselinux1-dev:armel \ + libslirp-dev:armel \ + libsnappy-dev:armel \ + libspice-server-dev:armel \ + libssh-gcrypt-dev:armel \ + libsystemd-dev:armel \ + libtasn1-6-dev:armel \ + libubsan1:armel \ + libudev-dev:armel \ + liburing-dev:armel \ + libusb-1.0-0-dev:armel \ + libusbredirhost-dev:armel \ + libvdeplug-dev:armel \ + libvirglrenderer-dev:armel \ + libvte-2.91-dev:armel \ + libzstd-dev:armel \ + nettle-dev:armel \ + systemtap-sdt-dev:armel \ + xfslibs-dev:armel \ + zlib1g-dev:armel && \ + eatmydata apt-get autoremove -y && \ + eatmydata apt-get autoclean -y && \ + mkdir -p /usr/local/share/meson/cross && \ + echo "[binaries]\n\ +c = '/usr/bin/arm-linux-gnueabi-gcc'\n\ +ar = '/usr/bin/arm-linux-gnueabi-gcc-ar'\n\ +strip = '/usr/bin/arm-linux-gnueabi-strip'\n\ +pkgconfig = '/usr/bin/arm-linux-gnueabi-pkg-config'\n\ +\n\ +[host_machine]\n\ +system = 'linux'\n\ +cpu_family = 'arm'\n\ +cpu = 'arm'\n\ +endian = 'little'" > /usr/local/share/meson/cross/arm-linux-gnueabi && \ + dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ + mkdir -p /usr/libexec/ccache-wrappers && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabi-c++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabi-cc && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabi-g++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabi-gcc + +ENV ABI "arm-linux-gnueabi" +ENV MESON_OPTS "--cross-file=arm-linux-gnueabi" ENV QEMU_CONFIGURE_OPTS --cross-prefix=arm-linux-gnueabi- ENV DEF_TARGET_LIST arm-softmmu,arm-linux-user,armeb-linux-user - -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - libbz2-dev:armel \ - liblzo2-dev:armel \ - librdmacm-dev:armel \ - libsnappy-dev:armel diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh index 7e4a92f630..4dc5527234 100755 --- a/tests/lcitool/refresh +++ b/tests/lcitool/refresh @@ -105,6 +105,11 @@ try: trailer=debian_cross_build("aarch64-linux-gnu-", "aarch64-softmmu,aarch64-linux-user")) + generate_dockerfile("debian-armel-cross", "debian-11", + cross="armv6l", + trailer=debian_cross_build("arm-linux-gnueabi-", + "arm-softmmu,arm-linux-user,armeb-linux-user")) + generate_dockerfile("debian-armhf-cross", "debian-11", cross="armv7l", trailer=debian_cross_build("arm-linux-gnueabihf-", From 432ae739c6ce6f31f74da62be34325890ded278b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 27 May 2022 16:35:38 +0100 Subject: [PATCH 709/935] tests/docker: update debian-mipsel-cross with lcitool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use lcitool to update debian-mipsel-cross to a Debian 11 based system. Signed-off-by: Alex Bennée Reviewed-by: Daniel P. Berrangé Message-Id: <20220527153603.887929-9-alex.bennee@linaro.org> --- .gitlab-ci.d/container-cross.yml | 3 +- tests/docker/Makefile.include | 1 - .../dockerfiles/debian-mipsel-cross.docker | 179 +++++++++++++++--- tests/lcitool/refresh | 5 + 4 files changed, 161 insertions(+), 27 deletions(-) diff --git a/.gitlab-ci.d/container-cross.yml b/.gitlab-ci.d/container-cross.yml index caef7decf4..1a533e6fc0 100644 --- a/.gitlab-ci.d/container-cross.yml +++ b/.gitlab-ci.d/container-cross.yml @@ -102,8 +102,7 @@ mips-debian-cross-container: mipsel-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-mipsel-cross diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index d9109bcc77..0ac5975419 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -94,7 +94,6 @@ docker-image-debian-m68k-cross: docker-image-debian10 docker-image-debian-mips-cross: docker-image-debian10 docker-image-debian-mips64-cross: docker-image-debian10 docker-image-debian-mips64el-cross: docker-image-debian10 -docker-image-debian-mipsel-cross: docker-image-debian10 docker-image-debian-ppc64el-cross: docker-image-debian10 docker-image-debian-sh4-cross: docker-image-debian10 docker-image-debian-sparc64-cross: docker-image-debian10 diff --git a/tests/docker/dockerfiles/debian-mipsel-cross.docker b/tests/docker/dockerfiles/debian-mipsel-cross.docker index 0e5dd42d3c..b6d99ae324 100644 --- a/tests/docker/dockerfiles/debian-mipsel-cross.docker +++ b/tests/docker/dockerfiles/debian-mipsel-cross.docker @@ -1,31 +1,162 @@ +# THIS FILE WAS AUTO-GENERATED # -# Docker mipsel cross-compiler target +# $ lcitool dockerfile --layers all --cross mipsel debian-11 qemu # -# This docker target builds on the debian Stretch base image. -# -FROM qemu/debian10 +# https://gitlab.com/libvirt/libvirt-ci -MAINTAINER Philippe Mathieu-Daudé +FROM docker.io/library/debian:11-slim -# Add the foreign architecture we want and install dependencies -RUN dpkg --add-architecture mipsel -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - gcc-mipsel-linux-gnu +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y eatmydata && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y \ + bash \ + bc \ + bsdextrautils \ + bzip2 \ + ca-certificates \ + ccache \ + dbus \ + debianutils \ + diffutils \ + exuberant-ctags \ + findutils \ + gcovr \ + genisoimage \ + gettext \ + git \ + hostname \ + libpcre2-dev \ + libspice-protocol-dev \ + llvm \ + locales \ + make \ + meson \ + ncat \ + ninja-build \ + openssh-client \ + perl-base \ + pkgconf \ + python3 \ + python3-numpy \ + python3-opencv \ + python3-pillow \ + python3-pip \ + python3-sphinx \ + python3-sphinx-rtd-theme \ + python3-venv \ + python3-yaml \ + rpm2cpio \ + sed \ + sparse \ + tar \ + tesseract-ocr \ + tesseract-ocr-eng \ + texinfo && \ + eatmydata apt-get autoremove -y && \ + eatmydata apt-get autoclean -y && \ + sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ + dpkg-reconfigure locales -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a mipsel --arch-only qemu +ENV LANG "en_US.UTF-8" +ENV MAKE "/usr/bin/make" +ENV NINJA "/usr/bin/ninja" +ENV PYTHON "/usr/bin/python3" +ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" -# Specify the cross prefix for this image (see tests/docker/common.rc) +RUN export DEBIAN_FRONTEND=noninteractive && \ + dpkg --add-architecture mipsel && \ + eatmydata apt-get update && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y dpkg-dev && \ + eatmydata apt-get install --no-install-recommends -y \ + g++-mipsel-linux-gnu \ + gcc-mipsel-linux-gnu \ + libaio-dev:mipsel \ + libasound2-dev:mipsel \ + libattr1-dev:mipsel \ + libbpf-dev:mipsel \ + libbrlapi-dev:mipsel \ + libbz2-dev:mipsel \ + libc6-dev:mipsel \ + libcacard-dev:mipsel \ + libcap-ng-dev:mipsel \ + libcapstone-dev:mipsel \ + libcurl4-gnutls-dev:mipsel \ + libdaxctl-dev:mipsel \ + libdrm-dev:mipsel \ + libepoxy-dev:mipsel \ + libfdt-dev:mipsel \ + libffi-dev:mipsel \ + libfuse3-dev:mipsel \ + libgbm-dev:mipsel \ + libgcrypt20-dev:mipsel \ + libglib2.0-dev:mipsel \ + libglusterfs-dev:mipsel \ + libgnutls28-dev:mipsel \ + libgtk-3-dev:mipsel \ + libibumad-dev:mipsel \ + libibverbs-dev:mipsel \ + libiscsi-dev:mipsel \ + libjemalloc-dev:mipsel \ + libjpeg62-turbo-dev:mipsel \ + liblttng-ust-dev:mipsel \ + liblzo2-dev:mipsel \ + libncursesw5-dev:mipsel \ + libnfs-dev:mipsel \ + libnuma-dev:mipsel \ + libpam0g-dev:mipsel \ + libpixman-1-dev:mipsel \ + libpng-dev:mipsel \ + libpulse-dev:mipsel \ + librbd-dev:mipsel \ + librdmacm-dev:mipsel \ + libsasl2-dev:mipsel \ + libsdl2-dev:mipsel \ + libsdl2-image-dev:mipsel \ + libseccomp-dev:mipsel \ + libselinux1-dev:mipsel \ + libslirp-dev:mipsel \ + libsnappy-dev:mipsel \ + libspice-server-dev:mipsel \ + libssh-gcrypt-dev:mipsel \ + libsystemd-dev:mipsel \ + libtasn1-6-dev:mipsel \ + libudev-dev:mipsel \ + liburing-dev:mipsel \ + libusb-1.0-0-dev:mipsel \ + libusbredirhost-dev:mipsel \ + libvdeplug-dev:mipsel \ + libvirglrenderer-dev:mipsel \ + libvte-2.91-dev:mipsel \ + libzstd-dev:mipsel \ + nettle-dev:mipsel \ + systemtap-sdt-dev:mipsel \ + xfslibs-dev:mipsel \ + zlib1g-dev:mipsel && \ + eatmydata apt-get autoremove -y && \ + eatmydata apt-get autoclean -y && \ + mkdir -p /usr/local/share/meson/cross && \ + echo "[binaries]\n\ +c = '/usr/bin/mipsel-linux-gnu-gcc'\n\ +ar = '/usr/bin/mipsel-linux-gnu-gcc-ar'\n\ +strip = '/usr/bin/mipsel-linux-gnu-strip'\n\ +pkgconfig = '/usr/bin/mipsel-linux-gnu-pkg-config'\n\ +\n\ +[host_machine]\n\ +system = 'linux'\n\ +cpu_family = 'mips'\n\ +cpu = 'mipsel'\n\ +endian = 'little'" > /usr/local/share/meson/cross/mipsel-linux-gnu && \ + dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ + mkdir -p /usr/libexec/ccache-wrappers && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mipsel-linux-gnu-c++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mipsel-linux-gnu-cc && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mipsel-linux-gnu-g++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mipsel-linux-gnu-gcc + +ENV ABI "mipsel-linux-gnu" +ENV MESON_OPTS "--cross-file=mipsel-linux-gnu" ENV QEMU_CONFIGURE_OPTS --cross-prefix=mipsel-linux-gnu- - -# Install extra libraries to increase code coverage -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - libbz2-dev:mipsel \ - liblzo2-dev:mipsel \ - librdmacm-dev:mipsel \ - libsnappy-dev:mipsel +ENV DEF_TARGET_LIST mipsel-softmmu,mipsel-linux-user diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh index 4dc5527234..a4b7452189 100755 --- a/tests/lcitool/refresh +++ b/tests/lcitool/refresh @@ -115,6 +115,11 @@ try: trailer=debian_cross_build("arm-linux-gnueabihf-", "arm-softmmu,arm-linux-user")) + generate_dockerfile("debian-mipsel-cross", "debian-11", + cross="mipsel", + trailer=debian_cross_build("mipsel-linux-gnu-", + "mipsel-softmmu,mipsel-linux-user")) + generate_dockerfile("debian-s390x-cross", "debian-11", cross="s390x", trailer=debian_cross_build("s390x-linux-gnu-", From 1e834d1714e72579d595d5395a3bb35b12a05d09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 27 May 2022 16:35:39 +0100 Subject: [PATCH 710/935] tests/docker: update debian-mips64el-cross with lcitool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use lcitool to update debian-mips64el-cross to a Debian 11 based system. Signed-off-by: Alex Bennée Reviewed-by: Daniel P. Berrangé Message-Id: <20220527153603.887929-10-alex.bennee@linaro.org> --- .gitlab-ci.d/container-cross.yml | 3 +- tests/docker/Makefile.include | 1 - .../dockerfiles/debian-mips64el-cross.docker | 177 +++++++++++++++--- tests/lcitool/refresh | 5 + 4 files changed, 159 insertions(+), 27 deletions(-) diff --git a/.gitlab-ci.d/container-cross.yml b/.gitlab-ci.d/container-cross.yml index 1a533e6fc0..411dc06bf8 100644 --- a/.gitlab-ci.d/container-cross.yml +++ b/.gitlab-ci.d/container-cross.yml @@ -88,8 +88,7 @@ mips64-debian-cross-container: mips64el-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-mips64el-cross diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index 0ac5975419..d9f37ae8fa 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -93,7 +93,6 @@ docker-image-debian-hppa-cross: docker-image-debian10 docker-image-debian-m68k-cross: docker-image-debian10 docker-image-debian-mips-cross: docker-image-debian10 docker-image-debian-mips64-cross: docker-image-debian10 -docker-image-debian-mips64el-cross: docker-image-debian10 docker-image-debian-ppc64el-cross: docker-image-debian10 docker-image-debian-sh4-cross: docker-image-debian10 docker-image-debian-sparc64-cross: docker-image-debian10 diff --git a/tests/docker/dockerfiles/debian-mips64el-cross.docker b/tests/docker/dockerfiles/debian-mips64el-cross.docker index c990b683b7..b02dcb7fd9 100644 --- a/tests/docker/dockerfiles/debian-mips64el-cross.docker +++ b/tests/docker/dockerfiles/debian-mips64el-cross.docker @@ -1,33 +1,162 @@ +# THIS FILE WAS AUTO-GENERATED # -# Docker mips64el cross-compiler target -# -# This docker target builds on the debian Stretch base image. +# $ lcitool dockerfile --layers all --cross mips64el debian-11 qemu # +# https://gitlab.com/libvirt/libvirt-ci -FROM qemu/debian10 +FROM docker.io/library/debian:11-slim -MAINTAINER Philippe Mathieu-Daudé +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y eatmydata && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y \ + bash \ + bc \ + bsdextrautils \ + bzip2 \ + ca-certificates \ + ccache \ + dbus \ + debianutils \ + diffutils \ + exuberant-ctags \ + findutils \ + gcovr \ + genisoimage \ + gettext \ + git \ + hostname \ + libpcre2-dev \ + libspice-protocol-dev \ + llvm \ + locales \ + make \ + meson \ + ncat \ + ninja-build \ + openssh-client \ + perl-base \ + pkgconf \ + python3 \ + python3-numpy \ + python3-opencv \ + python3-pillow \ + python3-pip \ + python3-sphinx \ + python3-sphinx-rtd-theme \ + python3-venv \ + python3-yaml \ + rpm2cpio \ + sed \ + sparse \ + tar \ + tesseract-ocr \ + tesseract-ocr-eng \ + texinfo && \ + eatmydata apt-get autoremove -y && \ + eatmydata apt-get autoclean -y && \ + sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ + dpkg-reconfigure locales -# Add the foreign architecture we want and install dependencies -RUN dpkg --add-architecture mips64el && \ - apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - gcc-mips64el-linux-gnuabi64 +ENV LANG "en_US.UTF-8" +ENV MAKE "/usr/bin/make" +ENV NINJA "/usr/bin/ninja" +ENV PYTHON "/usr/bin/python3" +ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a mips64el --arch-only qemu +RUN export DEBIAN_FRONTEND=noninteractive && \ + dpkg --add-architecture mips64el && \ + eatmydata apt-get update && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y dpkg-dev && \ + eatmydata apt-get install --no-install-recommends -y \ + g++-mips64el-linux-gnuabi64 \ + gcc-mips64el-linux-gnuabi64 \ + libaio-dev:mips64el \ + libasound2-dev:mips64el \ + libattr1-dev:mips64el \ + libbpf-dev:mips64el \ + libbrlapi-dev:mips64el \ + libbz2-dev:mips64el \ + libc6-dev:mips64el \ + libcacard-dev:mips64el \ + libcap-ng-dev:mips64el \ + libcapstone-dev:mips64el \ + libcurl4-gnutls-dev:mips64el \ + libdaxctl-dev:mips64el \ + libdrm-dev:mips64el \ + libepoxy-dev:mips64el \ + libfdt-dev:mips64el \ + libffi-dev:mips64el \ + libfuse3-dev:mips64el \ + libgbm-dev:mips64el \ + libgcrypt20-dev:mips64el \ + libglib2.0-dev:mips64el \ + libglusterfs-dev:mips64el \ + libgnutls28-dev:mips64el \ + libgtk-3-dev:mips64el \ + libibumad-dev:mips64el \ + libibverbs-dev:mips64el \ + libiscsi-dev:mips64el \ + libjemalloc-dev:mips64el \ + libjpeg62-turbo-dev:mips64el \ + liblttng-ust-dev:mips64el \ + liblzo2-dev:mips64el \ + libncursesw5-dev:mips64el \ + libnfs-dev:mips64el \ + libnuma-dev:mips64el \ + libpam0g-dev:mips64el \ + libpixman-1-dev:mips64el \ + libpng-dev:mips64el \ + libpulse-dev:mips64el \ + librbd-dev:mips64el \ + librdmacm-dev:mips64el \ + libsasl2-dev:mips64el \ + libsdl2-dev:mips64el \ + libsdl2-image-dev:mips64el \ + libseccomp-dev:mips64el \ + libselinux1-dev:mips64el \ + libslirp-dev:mips64el \ + libsnappy-dev:mips64el \ + libspice-server-dev:mips64el \ + libssh-gcrypt-dev:mips64el \ + libsystemd-dev:mips64el \ + libtasn1-6-dev:mips64el \ + libudev-dev:mips64el \ + liburing-dev:mips64el \ + libusb-1.0-0-dev:mips64el \ + libusbredirhost-dev:mips64el \ + libvdeplug-dev:mips64el \ + libvirglrenderer-dev:mips64el \ + libvte-2.91-dev:mips64el \ + libzstd-dev:mips64el \ + nettle-dev:mips64el \ + systemtap-sdt-dev:mips64el \ + xfslibs-dev:mips64el \ + zlib1g-dev:mips64el && \ + eatmydata apt-get autoremove -y && \ + eatmydata apt-get autoclean -y && \ + mkdir -p /usr/local/share/meson/cross && \ + echo "[binaries]\n\ +c = '/usr/bin/mips64el-linux-gnuabi64-gcc'\n\ +ar = '/usr/bin/mips64el-linux-gnuabi64-gcc-ar'\n\ +strip = '/usr/bin/mips64el-linux-gnuabi64-strip'\n\ +pkgconfig = '/usr/bin/mips64el-linux-gnuabi64-pkg-config'\n\ +\n\ +[host_machine]\n\ +system = 'linux'\n\ +cpu_family = 'mips64'\n\ +cpu = 'mips64el'\n\ +endian = 'little'" > /usr/local/share/meson/cross/mips64el-linux-gnuabi64 && \ + dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ + mkdir -p /usr/libexec/ccache-wrappers && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mips64el-linux-gnuabi64-c++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mips64el-linux-gnuabi64-cc && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mips64el-linux-gnuabi64-g++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/mips64el-linux-gnuabi64-gcc -# Specify the cross prefix for this image (see tests/docker/common.rc) +ENV ABI "mips64el-linux-gnuabi64" +ENV MESON_OPTS "--cross-file=mips64el-linux-gnuabi64" ENV QEMU_CONFIGURE_OPTS --cross-prefix=mips64el-linux-gnuabi64- ENV DEF_TARGET_LIST mips64el-softmmu,mips64el-linux-user - -# Install extra libraries to increase code coverage -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - libbz2-dev:mips64el \ - liblzo2-dev:mips64el \ - librdmacm-dev:mips64el \ - libsnappy-dev:mips64el diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh index a4b7452189..341a07e677 100755 --- a/tests/lcitool/refresh +++ b/tests/lcitool/refresh @@ -115,6 +115,11 @@ try: trailer=debian_cross_build("arm-linux-gnueabihf-", "arm-softmmu,arm-linux-user")) + generate_dockerfile("debian-mips64el-cross", "debian-11", + cross="mips64el", + trailer=debian_cross_build("mips64el-linux-gnuabi64-", + "mips64el-softmmu,mips64el-linux-user")) + generate_dockerfile("debian-mipsel-cross", "debian-11", cross="mipsel", trailer=debian_cross_build("mipsel-linux-gnu-", From 4ec740e12da8a969f1ae3f9147dde9ce3a79a506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 27 May 2022 16:35:40 +0100 Subject: [PATCH 711/935] tests/docker: update debian-ppc64el-cross with lcitool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use lcitool to update debian-ppc64el-cross to a Debian 11 based system. Signed-off-by: Alex Bennée Reviewed-by: Daniel P. Berrangé Message-Id: <20220527153603.887929-11-alex.bennee@linaro.org> --- .gitlab-ci.d/container-cross.yml | 3 +- tests/docker/Makefile.include | 1 - .../dockerfiles/debian-ppc64el-cross.docker | 178 +++++++++++++++--- tests/lcitool/refresh | 5 + 4 files changed, 163 insertions(+), 24 deletions(-) diff --git a/.gitlab-ci.d/container-cross.yml b/.gitlab-ci.d/container-cross.yml index 411dc06bf8..147e667744 100644 --- a/.gitlab-ci.d/container-cross.yml +++ b/.gitlab-ci.d/container-cross.yml @@ -114,8 +114,7 @@ powerpc-test-cross-container: ppc64el-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-ppc64el-cross diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index d9f37ae8fa..e68f91b853 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -93,7 +93,6 @@ docker-image-debian-hppa-cross: docker-image-debian10 docker-image-debian-m68k-cross: docker-image-debian10 docker-image-debian-mips-cross: docker-image-debian10 docker-image-debian-mips64-cross: docker-image-debian10 -docker-image-debian-ppc64el-cross: docker-image-debian10 docker-image-debian-sh4-cross: docker-image-debian10 docker-image-debian-sparc64-cross: docker-image-debian10 diff --git a/tests/docker/dockerfiles/debian-ppc64el-cross.docker b/tests/docker/dockerfiles/debian-ppc64el-cross.docker index 5de12b01cd..bcf04bc90b 100644 --- a/tests/docker/dockerfiles/debian-ppc64el-cross.docker +++ b/tests/docker/dockerfiles/debian-ppc64el-cross.docker @@ -1,28 +1,164 @@ +# THIS FILE WAS AUTO-GENERATED # -# Docker ppc64el cross-compiler target +# $ lcitool dockerfile --layers all --cross ppc64le debian-11 qemu # -# This docker target builds on the debian Stretch base image. -# -FROM qemu/debian10 +# https://gitlab.com/libvirt/libvirt-ci -# Add the foreign architecture we want and install dependencies -RUN dpkg --add-architecture ppc64el && \ - apt update && \ - apt install -yy crossbuild-essential-ppc64el +FROM docker.io/library/debian:11-slim -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a ppc64el --arch-only qemu +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y eatmydata && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y \ + bash \ + bc \ + bsdextrautils \ + bzip2 \ + ca-certificates \ + ccache \ + dbus \ + debianutils \ + diffutils \ + exuberant-ctags \ + findutils \ + gcovr \ + genisoimage \ + gettext \ + git \ + hostname \ + libpcre2-dev \ + libspice-protocol-dev \ + llvm \ + locales \ + make \ + meson \ + ncat \ + ninja-build \ + openssh-client \ + perl-base \ + pkgconf \ + python3 \ + python3-numpy \ + python3-opencv \ + python3-pillow \ + python3-pip \ + python3-sphinx \ + python3-sphinx-rtd-theme \ + python3-venv \ + python3-yaml \ + rpm2cpio \ + sed \ + sparse \ + tar \ + tesseract-ocr \ + tesseract-ocr-eng \ + texinfo && \ + eatmydata apt-get autoremove -y && \ + eatmydata apt-get autoclean -y && \ + sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ + dpkg-reconfigure locales -# Specify the cross prefix for this image (see tests/docker/common.rc) +ENV LANG "en_US.UTF-8" +ENV MAKE "/usr/bin/make" +ENV NINJA "/usr/bin/ninja" +ENV PYTHON "/usr/bin/python3" +ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" + +RUN export DEBIAN_FRONTEND=noninteractive && \ + dpkg --add-architecture ppc64el && \ + eatmydata apt-get update && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y dpkg-dev && \ + eatmydata apt-get install --no-install-recommends -y \ + g++-powerpc64le-linux-gnu \ + gcc-powerpc64le-linux-gnu \ + libaio-dev:ppc64el \ + libasan5:ppc64el \ + libasound2-dev:ppc64el \ + libattr1-dev:ppc64el \ + libbpf-dev:ppc64el \ + libbrlapi-dev:ppc64el \ + libbz2-dev:ppc64el \ + libc6-dev:ppc64el \ + libcacard-dev:ppc64el \ + libcap-ng-dev:ppc64el \ + libcapstone-dev:ppc64el \ + libcurl4-gnutls-dev:ppc64el \ + libdaxctl-dev:ppc64el \ + libdrm-dev:ppc64el \ + libepoxy-dev:ppc64el \ + libfdt-dev:ppc64el \ + libffi-dev:ppc64el \ + libfuse3-dev:ppc64el \ + libgbm-dev:ppc64el \ + libgcrypt20-dev:ppc64el \ + libglib2.0-dev:ppc64el \ + libglusterfs-dev:ppc64el \ + libgnutls28-dev:ppc64el \ + libgtk-3-dev:ppc64el \ + libibumad-dev:ppc64el \ + libibverbs-dev:ppc64el \ + libiscsi-dev:ppc64el \ + libjemalloc-dev:ppc64el \ + libjpeg62-turbo-dev:ppc64el \ + liblttng-ust-dev:ppc64el \ + liblzo2-dev:ppc64el \ + libncursesw5-dev:ppc64el \ + libnfs-dev:ppc64el \ + libnuma-dev:ppc64el \ + libpam0g-dev:ppc64el \ + libpixman-1-dev:ppc64el \ + libpng-dev:ppc64el \ + libpulse-dev:ppc64el \ + librbd-dev:ppc64el \ + librdmacm-dev:ppc64el \ + libsasl2-dev:ppc64el \ + libsdl2-dev:ppc64el \ + libsdl2-image-dev:ppc64el \ + libseccomp-dev:ppc64el \ + libselinux1-dev:ppc64el \ + libslirp-dev:ppc64el \ + libsnappy-dev:ppc64el \ + libspice-server-dev:ppc64el \ + libssh-gcrypt-dev:ppc64el \ + libsystemd-dev:ppc64el \ + libtasn1-6-dev:ppc64el \ + libubsan1:ppc64el \ + libudev-dev:ppc64el \ + liburing-dev:ppc64el \ + libusb-1.0-0-dev:ppc64el \ + libusbredirhost-dev:ppc64el \ + libvdeplug-dev:ppc64el \ + libvirglrenderer-dev:ppc64el \ + libvte-2.91-dev:ppc64el \ + libzstd-dev:ppc64el \ + nettle-dev:ppc64el \ + systemtap-sdt-dev:ppc64el \ + xfslibs-dev:ppc64el \ + zlib1g-dev:ppc64el && \ + eatmydata apt-get autoremove -y && \ + eatmydata apt-get autoclean -y && \ + mkdir -p /usr/local/share/meson/cross && \ + echo "[binaries]\n\ +c = '/usr/bin/powerpc64le-linux-gnu-gcc'\n\ +ar = '/usr/bin/powerpc64le-linux-gnu-gcc-ar'\n\ +strip = '/usr/bin/powerpc64le-linux-gnu-strip'\n\ +pkgconfig = '/usr/bin/powerpc64le-linux-gnu-pkg-config'\n\ +\n\ +[host_machine]\n\ +system = 'linux'\n\ +cpu_family = 'ppc64'\n\ +cpu = 'powerpc64le'\n\ +endian = 'little'" > /usr/local/share/meson/cross/powerpc64le-linux-gnu && \ + dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ + mkdir -p /usr/libexec/ccache-wrappers && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/powerpc64le-linux-gnu-c++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/powerpc64le-linux-gnu-cc && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/powerpc64le-linux-gnu-g++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/powerpc64le-linux-gnu-gcc + +ENV ABI "powerpc64le-linux-gnu" +ENV MESON_OPTS "--cross-file=powerpc64le-linux-gnu" ENV QEMU_CONFIGURE_OPTS --cross-prefix=powerpc64le-linux-gnu- ENV DEF_TARGET_LIST ppc64-softmmu,ppc64-linux-user - -# Install extra libraries to increase code coverage -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - libbz2-dev:ppc64el \ - liblzo2-dev:ppc64el \ - librdmacm-dev:ppc64el \ - libsnappy-dev:ppc64el diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh index 341a07e677..b947bb170d 100755 --- a/tests/lcitool/refresh +++ b/tests/lcitool/refresh @@ -125,6 +125,11 @@ try: trailer=debian_cross_build("mipsel-linux-gnu-", "mipsel-softmmu,mipsel-linux-user")) + generate_dockerfile("debian-ppc64el-cross", "debian-11", + cross="ppc64le", + trailer=debian_cross_build("powerpc64le-linux-gnu-", + "ppc64-softmmu,ppc64-linux-user")) + generate_dockerfile("debian-s390x-cross", "debian-11", cross="s390x", trailer=debian_cross_build("s390x-linux-gnu-", From 9e19fd7d4a569f5802ede460fe03fd2d4d0c295c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 27 May 2022 16:35:41 +0100 Subject: [PATCH 712/935] tests/docker: update debian-amd64 with lcitool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The one minor wrinkle we need to account for is the netmap support still requires building from source. We also include cscope and GNU global as they are used in one of the builds. Signed-off-by: Alex Bennée Cc: Philippe Mathieu-Daudé Cc: Luigi Rizzo Cc: Giuseppe Lettieri Cc: Vincenzo Maffione Reviewed-by: Daniel P. Berrangé Message-Id: <20220527153603.887929-12-alex.bennee@linaro.org> --- .gitlab-ci.d/containers.yml | 3 +- tests/docker/dockerfiles/debian-amd64.docker | 194 ++++++++++++++----- tests/lcitool/refresh | 19 ++ 3 files changed, 164 insertions(+), 52 deletions(-) diff --git a/.gitlab-ci.d/containers.yml b/.gitlab-ci.d/containers.yml index e9df90bbdd..be34cbc7ba 100644 --- a/.gitlab-ci.d/containers.yml +++ b/.gitlab-ci.d/containers.yml @@ -14,8 +14,7 @@ amd64-debian11-container: amd64-debian-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-amd64 diff --git a/tests/docker/dockerfiles/debian-amd64.docker b/tests/docker/dockerfiles/debian-amd64.docker index ed546edcd6..503e282802 100644 --- a/tests/docker/dockerfiles/debian-amd64.docker +++ b/tests/docker/dockerfiles/debian-amd64.docker @@ -1,59 +1,153 @@ +# THIS FILE WAS AUTO-GENERATED # -# Docker x86_64 target +# $ lcitool dockerfile --layers all debian-11 qemu # -# This docker target builds on the Debian Buster base image. Further -# libraries which are not widely available are installed by hand. -# -FROM qemu/debian10 -MAINTAINER Philippe Mathieu-Daudé +# https://gitlab.com/libvirt/libvirt-ci -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy qemu +FROM docker.io/library/debian:11-slim -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - cscope \ - genisoimage \ - exuberant-ctags \ - global \ - libbz2-dev \ - liblzo2-dev \ - libgcrypt20-dev \ - libfdt-dev \ - librdmacm-dev \ - libsasl2-dev \ - libsnappy-dev \ - libvte-dev \ - netcat-openbsd \ - openssh-client \ - python3-numpy \ - python3-opencv \ - python3-venv +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y eatmydata && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y \ + bash \ + bc \ + bsdextrautils \ + bzip2 \ + ca-certificates \ + ccache \ + clang \ + dbus \ + debianutils \ + diffutils \ + exuberant-ctags \ + findutils \ + g++ \ + gcc \ + gcovr \ + genisoimage \ + gettext \ + git \ + hostname \ + libaio-dev \ + libasan5 \ + libasound2-dev \ + libattr1-dev \ + libbpf-dev \ + libbrlapi-dev \ + libbz2-dev \ + libc6-dev \ + libcacard-dev \ + libcap-ng-dev \ + libcapstone-dev \ + libcurl4-gnutls-dev \ + libdaxctl-dev \ + libdrm-dev \ + libepoxy-dev \ + libfdt-dev \ + libffi-dev \ + libfuse3-dev \ + libgbm-dev \ + libgcrypt20-dev \ + libglib2.0-dev \ + libglusterfs-dev \ + libgnutls28-dev \ + libgtk-3-dev \ + libibumad-dev \ + libibverbs-dev \ + libiscsi-dev \ + libjemalloc-dev \ + libjpeg62-turbo-dev \ + liblttng-ust-dev \ + liblzo2-dev \ + libncursesw5-dev \ + libnfs-dev \ + libnuma-dev \ + libpam0g-dev \ + libpcre2-dev \ + libpixman-1-dev \ + libpmem-dev \ + libpng-dev \ + libpulse-dev \ + librbd-dev \ + librdmacm-dev \ + libsasl2-dev \ + libsdl2-dev \ + libsdl2-image-dev \ + libseccomp-dev \ + libselinux1-dev \ + libslirp-dev \ + libsnappy-dev \ + libspice-protocol-dev \ + libspice-server-dev \ + libssh-gcrypt-dev \ + libsystemd-dev \ + libtasn1-6-dev \ + libubsan1 \ + libudev-dev \ + liburing-dev \ + libusb-1.0-0-dev \ + libusbredirhost-dev \ + libvdeplug-dev \ + libvirglrenderer-dev \ + libvte-2.91-dev \ + libxen-dev \ + libzstd-dev \ + llvm \ + locales \ + make \ + meson \ + multipath-tools \ + ncat \ + nettle-dev \ + ninja-build \ + openssh-client \ + perl-base \ + pkgconf \ + python3 \ + python3-numpy \ + python3-opencv \ + python3-pillow \ + python3-pip \ + python3-sphinx \ + python3-sphinx-rtd-theme \ + python3-venv \ + python3-yaml \ + rpm2cpio \ + sed \ + sparse \ + systemtap-sdt-dev \ + tar \ + tesseract-ocr \ + tesseract-ocr-eng \ + texinfo \ + xfslibs-dev \ + zlib1g-dev && \ + eatmydata apt-get autoremove -y && \ + eatmydata apt-get autoclean -y && \ + sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ + dpkg-reconfigure locales && \ + dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ + mkdir -p /usr/libexec/ccache-wrappers && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/c++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc -# virgl -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - libegl1-mesa-dev \ - libepoxy-dev \ - libgbm-dev -RUN git clone https://gitlab.freedesktop.org/virgl/virglrenderer.git /usr/src/virglrenderer && \ - cd /usr/src/virglrenderer && git checkout virglrenderer-0.8.0 -RUN cd /usr/src/virglrenderer && ./autogen.sh && ./configure --disable-tests && make install - -# netmap -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - linux-headers-amd64 +ENV LANG "en_US.UTF-8" +ENV MAKE "/usr/bin/make" +ENV NINJA "/usr/bin/ninja" +ENV PYTHON "/usr/bin/python3" +ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" +# netmap/cscope/global +RUN DEBIAN_FRONTEND=noninteractive eatmydata \ + apt install -y --no-install-recommends \ + cscope\ + global\ + linux-headers-amd64 RUN git clone https://github.com/luigirizzo/netmap.git /usr/src/netmap RUN cd /usr/src/netmap && git checkout v11.3 RUN cd /usr/src/netmap/LINUX && ./configure --no-drivers --no-apps --kernel-dir=$(ls -d /usr/src/linux-headers-*-amd64) && make install ENV QEMU_CONFIGURE_OPTS --enable-netmap - -RUN ldconfig - -# gcrypt -ENV QEMU_CONFIGURE_OPTS $QEMU_CONFIGURE_OPTS --enable-gcrypt diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh index b947bb170d..5e260f8cd6 100755 --- a/tests/lcitool/refresh +++ b/tests/lcitool/refresh @@ -76,6 +76,23 @@ ubuntu2004_tsanhack = [ ] +# Netmap still needs to be manually built as it is yet to be packaged +# into a distro. We also add cscope and gtags which are used in the CI +# test +debian11_extras = [ + "# netmap/cscope/global\n", + "RUN DEBIAN_FRONTEND=noninteractive eatmydata \\\n", + " apt install -y --no-install-recommends \\\n", + " cscope\\\n", + " global\\\n", + " linux-headers-amd64\n", + "RUN git clone https://github.com/luigirizzo/netmap.git /usr/src/netmap\n", + "RUN cd /usr/src/netmap && git checkout v11.3\n", + "RUN cd /usr/src/netmap/LINUX && ./configure --no-drivers --no-apps --kernel-dir=$(ls -d /usr/src/linux-headers-*-amd64) && make install\n", + "ENV QEMU_CONFIGURE_OPTS --enable-netmap\n" +] + + def debian_cross_build(prefix, targets): conf = "ENV QEMU_CONFIGURE_OPTS --cross-prefix=%s\n" % (prefix) targets = "ENV DEF_TARGET_LIST %s\n" % (targets) @@ -92,6 +109,8 @@ try: # generate_dockerfile("alpine", "alpine-edge") generate_dockerfile("centos8", "centos-stream-8") + generate_dockerfile("debian-amd64", "debian-11", + trailer="".join(debian11_extras)) generate_dockerfile("fedora", "fedora-35") generate_dockerfile("opensuse-leap", "opensuse-leap-152") generate_dockerfile("ubuntu2004", "ubuntu-2004", From ea857a3b7976010a7fe7b59a89941964028f502a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 May 2022 16:35:42 +0100 Subject: [PATCH 713/935] configure: do not define or use the CPP variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just hardcode $(CC) -E, it should be enough. Signed-off-by: Paolo Bonzini Reviewed-by: Richard Henderson Message-Id: <20220517092616.1272238-2-pbonzini@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20220527153603.887929-13-alex.bennee@linaro.org> --- configure | 3 --- pc-bios/optionrom/Makefile | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/configure b/configure index f2baf2f526..c88ef94fec 100755 --- a/configure +++ b/configure @@ -376,7 +376,6 @@ fi ar="${AR-${cross_prefix}ar}" as="${AS-${cross_prefix}as}" ccas="${CCAS-$cc}" -cpp="${CPP-$cc -E}" objcopy="${OBJCOPY-${cross_prefix}objcopy}" ld="${LD-${cross_prefix}ld}" ranlib="${RANLIB-${cross_prefix}ranlib}" @@ -2014,7 +2013,6 @@ echo "CC=$cc" >> $config_host_mak echo "AR=$ar" >> $config_host_mak echo "AS=$as" >> $config_host_mak echo "CCAS=$ccas" >> $config_host_mak -echo "CPP=$cpp" >> $config_host_mak echo "OBJCOPY=$objcopy" >> $config_host_mak echo "LD=$ld" >> $config_host_mak echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak @@ -2257,7 +2255,6 @@ preserve_env() { preserve_env AR preserve_env AS preserve_env CC -preserve_env CPP preserve_env CFLAGS preserve_env CXX preserve_env CXXFLAGS diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile index 2494ad9c25..17ccc76241 100644 --- a/pc-bios/optionrom/Makefile +++ b/pc-bios/optionrom/Makefile @@ -50,7 +50,7 @@ override LDFLAGS = -m $(LD_I386_EMULATION) -T $(SRC_DIR)/flat.lds pvh.img: pvh.o pvh_main.o %.o: %.S - $(call quiet-command,$(CPP) $(CPPFLAGS) -c -o - $< | $(AS) $(ASFLAGS) -o $@,"AS","$@") + $(call quiet-command,$(CC) $(CPPFLAGS) -E -o - $< | $(AS) $(ASFLAGS) -o $@,"AS","$@") %.o: %.c $(call quiet-command,$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@,"CC","$@") From 231ca96316f17d0af8c5e72cc2c496c68ee23ab6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 May 2022 16:35:43 +0100 Subject: [PATCH 714/935] build: clean up ninja invocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix an incorrect "@@:" and move "-d keepdepfile" to the NINJAFLAGS variable. Signed-off-by: Paolo Bonzini Reviewed-by: Richard Henderson Message-Id: <20220517092616.1272238-3-pbonzini@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20220527153603.887929-14-alex.bennee@linaro.org> --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index b842dbccdb..fad312040f 100644 --- a/Makefile +++ b/Makefile @@ -143,7 +143,7 @@ MAKE.q = $(findstring q,$(firstword $(filter-out --%,$(MAKEFLAGS)))) MAKE.nq = $(if $(word 2, $(MAKE.n) $(MAKE.q)),nq) NINJAFLAGS = $(if $V,-v) $(if $(MAKE.n), -n) $(if $(MAKE.k), -k0) \ $(filter-out -j, $(lastword -j1 $(filter -l% -j%, $(MAKEFLAGS)))) \ - + -d keepdepfile ninja-cmd-goals = $(or $(MAKECMDGOALS), all) ninja-cmd-goals += $(foreach t, $(.check.build-suites), $(.check-$t.deps)) ninja-cmd-goals += $(foreach t, $(.bench.build-suites), $(.bench-$t.deps)) @@ -160,8 +160,8 @@ $(ninja-targets): run-ninja # --output-sync line. run-ninja: config-host.mak ifneq ($(filter $(ninja-targets), $(ninja-cmd-goals)),) - +$(quiet-@)$(if $(MAKE.nq),@:, $(NINJA) -d keepdepfile \ - $(NINJAFLAGS) $(sort $(filter $(ninja-targets), $(ninja-cmd-goals))) | cat) + +$(if $(MAKE.nq),@:,$(quiet-@)$(NINJA) $(NINJAFLAGS) \ + $(sort $(filter $(ninja-targets), $(ninja-cmd-goals))) | cat) endif endif From 9b32ba53f36428abdecc79a0a047c2636af130d1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 May 2022 16:35:44 +0100 Subject: [PATCH 715/935] build: add a more generic way to specify make->ninja dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let any make target specify ninja goals that needs to be built for it (though selecting the goals is _not_ recursive on depending targets) instead of having a custom mechanism only for "make check" and "make bench". Signed-off-by: Paolo Bonzini Message-Id: <20220517092616.1272238-4-pbonzini@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20220527153603.887929-15-alex.bennee@linaro.org> --- Makefile | 3 +-- scripts/mtest2make.py | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index fad312040f..3c0d89057e 100644 --- a/Makefile +++ b/Makefile @@ -145,8 +145,7 @@ NINJAFLAGS = $(if $V,-v) $(if $(MAKE.n), -n) $(if $(MAKE.k), -k0) \ $(filter-out -j, $(lastword -j1 $(filter -l% -j%, $(MAKEFLAGS)))) \ -d keepdepfile ninja-cmd-goals = $(or $(MAKECMDGOALS), all) -ninja-cmd-goals += $(foreach t, $(.check.build-suites), $(.check-$t.deps)) -ninja-cmd-goals += $(foreach t, $(.bench.build-suites), $(.bench-$t.deps)) +ninja-cmd-goals += $(foreach g, $(MAKECMDGOALS), $(.ninja-goals.$g)))) makefile-targets := build.ninja ctags TAGS cscope dist clean uninstall # "ninja -t targets" also lists all prerequisites. If build system diff --git a/scripts/mtest2make.py b/scripts/mtest2make.py index 304634b71e..0fe81efbbc 100644 --- a/scripts/mtest2make.py +++ b/scripts/mtest2make.py @@ -81,12 +81,12 @@ def emit_prolog(suites, prefix): def emit_suite_deps(name, suite, prefix): deps = ' '.join(suite.deps) - targets = f'{prefix}-{name} {prefix}-report-{name}.junit.xml {prefix} {prefix}-report.junit.xml' + targets = [f'{prefix}-{name}', f'{prefix}-report-{name}.junit.xml', f'{prefix}', f'{prefix}-report.junit.xml', + f'{prefix}-build'] print() print(f'.{prefix}-{name}.deps = {deps}') - print(f'ifneq ($(filter {prefix}-build {targets}, $(MAKECMDGOALS)),)') - print(f'.{prefix}.build-suites += {name}') - print(f'endif') + for t in targets: + print(f'.ninja-goals.{t} += $(.{prefix}-{name}.deps)') def emit_suite(name, suite, prefix): emit_suite_deps(name, suite, prefix) From 95808875be96e17b885a9e4f050897c67e8b9aaf Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 May 2022 16:35:45 +0100 Subject: [PATCH 716/935] build: do a full build before running TCG tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TCG tests need both QEMU and firmware to be built, so do "ninja all" before trying to run them. Signed-off-by: Paolo Bonzini Reviewed-by: Richard Henderson Message-Id: <20220517092616.1272238-5-pbonzini@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20220527153603.887929-16-alex.bennee@linaro.org> --- tests/Makefile.include | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index ec84b2ebc0..72ce0561f4 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -57,7 +57,7 @@ $(TCG_TESTS_TARGETS:%=build-tcg-tests-%): build-tcg-tests-%: $(BUILD_DIR)/tests/ "BUILD","$* guest-tests") .PHONY: $(TCG_TESTS_TARGETS:%=run-tcg-tests-%) -$(TCG_TESTS_TARGETS:%=run-tcg-tests-%): run-tcg-tests-%: build-tcg-tests-% $(if $(CONFIG_PLUGIN),test-plugins) +$(TCG_TESTS_TARGETS:%=run-tcg-tests-%): run-tcg-tests-%: build-tcg-tests-% $(call quiet-command, \ $(MAKE) -C tests/tcg/$* -f ../Makefile.target $(SUBDIR_MAKEFLAGS) \ TARGET="$*" SRC_PATH="$(SRC_PATH)" SPEED=$(SPEED) run, \ @@ -74,6 +74,7 @@ $(TCG_TESTS_TARGETS:%=clean-tcg-tests-%): clean-tcg-tests-%: build-tcg: $(BUILD_TCG_TARGET_RULES) .PHONY: check-tcg +.ninja-goals.check-tcg = all $(if $(CONFIG_PLUGIN),test-plugins) check-tcg: $(RUN_TCG_TARGET_RULES) .PHONY: clean-tcg From 45f1eecdd63f9e4fa93fef01dd826e7706ac6d7b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 May 2022 16:35:46 +0100 Subject: [PATCH 717/935] configure, meson: move symlinking of ROMs to meson MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is useful because pc-bios/meson.build already has a list of all ROM files, and thus does not need to use wildcards. The problems with wildcards are mentioned above the definition of the LINKS variable, but then the recommendation is disattended. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini Message-Id: <20220517092616.1272238-6-pbonzini@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20220527153603.887929-17-alex.bennee@linaro.org> --- configure | 15 --------------- pc-bios/meson.build | 17 ++++++++++++----- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/configure b/configure index c88ef94fec..7b6adc29fe 100755 --- a/configure +++ b/configure @@ -2100,21 +2100,6 @@ LINKS="$LINKS tests/avocado tests/data" LINKS="$LINKS tests/qemu-iotests/check" LINKS="$LINKS python" LINKS="$LINKS contrib/plugins/Makefile " -for bios_file in \ - $source_path/pc-bios/*.bin \ - $source_path/pc-bios/*.elf \ - $source_path/pc-bios/*.lid \ - $source_path/pc-bios/*.rom \ - $source_path/pc-bios/*.dtb \ - $source_path/pc-bios/*.img \ - $source_path/pc-bios/openbios-* \ - $source_path/pc-bios/u-boot.* \ - $source_path/pc-bios/palcode-* \ - $source_path/pc-bios/qemu_vga.ndrv - -do - LINKS="$LINKS pc-bios/$(basename $bios_file)" -done for f in $LINKS ; do if [ -e "$source_path/$f" ]; then mkdir -p `dirname ./$f` diff --git a/pc-bios/meson.build b/pc-bios/meson.build index c86dedf7df..41ba1c0ec7 100644 --- a/pc-bios/meson.build +++ b/pc-bios/meson.build @@ -23,7 +23,7 @@ if unpack_edk2_blobs endforeach endif -blobs = files( +blobs = [ 'bios.bin', 'bios-256k.bin', 'bios-microvm.bin', @@ -83,11 +83,18 @@ blobs = files( 'npcm7xx_bootrom.bin', 'vof.bin', 'vof-nvram.bin', -) +] -if get_option('install_blobs') - install_data(blobs, install_dir: qemu_datadir) -endif +ln_s = [find_program('ln', required: true), '-sf'] +foreach f : blobs + roms += custom_target(f, + build_by_default: have_system, + output: f, + input: files('meson.build'), # dummy input + install: get_option('install_blobs'), + install_dir: qemu_datadir, + command: [ ln_s, meson.project_source_root() / 'pc-bios' / f, '@OUTPUT@' ]) +endforeach subdir('descriptors') subdir('keymaps') From 867998cf5680329a150cb6d51a15d6990be49c77 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 May 2022 16:35:47 +0100 Subject: [PATCH 718/935] tests/tcg: correct target CPU for sparc32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We do not want v8plus for pure sparc32, as the difference with the V8 ABI are only meaningful on 64-bit CPUs suh as ultrasparc; supersparc is the best CPU to use for 32-bit. Signed-off-by: Paolo Bonzini Reviewed-by: Richard Henderson Message-Id: <20220517092616.1272238-7-pbonzini@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20220527153603.887929-18-alex.bennee@linaro.org> --- tests/tcg/configure.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh index 691d90abac..59f2403d1a 100755 --- a/tests/tcg/configure.sh +++ b/tests/tcg/configure.sh @@ -70,7 +70,7 @@ fi : ${cross_cc_riscv64="riscv64-linux-gnu-gcc"} : ${cross_cc_s390x="s390x-linux-gnu-gcc"} : ${cross_cc_sh4="sh4-linux-gnu-gcc"} -: ${cross_cc_cflags_sparc="-m32 -mv8plus -mcpu=ultrasparc"} +: ${cross_cc_cflags_sparc="-m32 -mcpu=supersparc"} : ${cross_cc_sparc64="sparc64-linux-gnu-gcc"} : ${cross_cc_cflags_sparc64="-m64 -mcpu=ultrasparc"} : ${cross_cc_x86_64="x86_64-linux-gnu-gcc"} From cd362defbbd09cbbc08b3bb465141542887b8cef Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 May 2022 16:35:48 +0100 Subject: [PATCH 719/935] tests/tcg: merge configure.sh back into main configure script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tests/tcg/configure.sh has a complicated story. In the beginning its code ran as part of the creation of config-target.mak files, and that is where it placed the information on the target compiler. However, probing for the buildability of TCG tests required multiple inclusions of config-target.mak in the _main_ Makefile (not in Makefile.target, which took care of building the QEMU executables in the pre-Meson era), which polluted the namespace. Thus, it was moved to a separate directory. It created small config-*.mak files in $(BUILD_DIR)/tests/tcg. Those were also included multiple times, but at least they were small and manageable; this was also an important step in disentangling the TCG tests from Makefile.target. Since then, Meson has allowed the configure script to go on a diet. A few compilation tests survive (mostly for sanitizers) but these days it mostly takes care of command line parsing, looking for tools, and setting up the environment for Meson to do its stuff. It's time to extend configure with the capability to build for more than just one target: not just tests, but also firmware. As a first step, integrate all the logic to find cross compilers in the configure script, and move tests/tcg/configure.sh back there (though as a separate loop, not integrated in the one that generates target configurations for Meson). tests/tcg is actually very close to being buildable as a standalone project, so I actually expect the compiler tests to move back to tests/tcg, as a "configure" script of sorts which would run at Make time after the docker images are built. The GCC tree has a similar idea of doing only bare-bones tree-wide configuration and leaving the rest for Make time. Signed-off-by: Paolo Bonzini Acked-by: Richard Henderson Message-Id: <20220517092616.1272238-8-pbonzini@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20220527153603.887929-19-alex.bennee@linaro.org> --- configure | 398 +++++++++++++++++++++++++++++++++++++++-- tests/Makefile.include | 1 - tests/tcg/configure.sh | 376 -------------------------------------- 3 files changed, 388 insertions(+), 387 deletions(-) delete mode 100755 tests/tcg/configure.sh diff --git a/configure b/configure index 7b6adc29fe..f91ac632e7 100755 --- a/configure +++ b/configure @@ -109,6 +109,20 @@ error_exit() { } do_compiler() { + # Run the compiler, capturing its output to the log. First argument + # is compiler binary to execute. + local compiler="$1" + shift + if test -n "$BASH_VERSION"; then eval ' + echo >>config.log " +funcs: ${FUNCNAME[*]} +lines: ${BASH_LINENO[*]}" + '; fi + echo $compiler "$@" >> config.log + $compiler "$@" >> config.log 2>&1 || return $? +} + +do_compiler_werror() { # Run the compiler, capturing its output to the log. First argument # is compiler binary to execute. compiler="$1" @@ -142,15 +156,15 @@ lines: ${BASH_LINENO[*]}" } do_cc() { - do_compiler "$cc" $CPU_CFLAGS "$@" + do_compiler_werror "$cc" $CPU_CFLAGS "$@" } do_cxx() { - do_compiler "$cxx" $CPU_CFLAGS "$@" + do_compiler_werror "$cxx" $CPU_CFLAGS "$@" } do_objc() { - do_compiler "$objcc" $CPU_CFLAGS "$@" + do_compiler_werror "$objcc" $CPU_CFLAGS "$@" } # Append $2 to the variable named $1, with space separation @@ -345,11 +359,9 @@ for opt do ;; --cross-cc-cflags-*) cc_arch=${opt#--cross-cc-cflags-}; cc_arch=${cc_arch%%=*} eval "cross_cc_cflags_${cc_arch}=\$optarg" - cross_cc_vars="$cross_cc_vars cross_cc_cflags_${cc_arch}" ;; --cross-cc-*) cc_arch=${opt#--cross-cc-}; cc_arch=${cc_arch%%=*} eval "cross_cc_${cc_arch}=\$optarg" - cross_cc_vars="$cross_cc_vars cross_cc_${cc_arch}" ;; esac done @@ -944,7 +956,6 @@ esac if eval test -z "\${cross_cc_$cpu}"; then eval "cross_cc_${cpu}=\$cc" - cross_cc_vars="$cross_cc_vars cross_cc_${cpu}" fi default_target_list="" @@ -1800,6 +1811,248 @@ case "$slirp" in ;; esac +########################################## +# functions to probe cross compilers + +container="no" +if test $use_containers = "yes"; then + if has "docker" || has "podman"; then + container=$($python $source_path/tests/docker/docker.py probe) + fi +fi + +# cross compilers defaults, can be overridden with --cross-cc-ARCH +: ${cross_cc_aarch64="aarch64-linux-gnu-gcc"} +: ${cross_cc_aarch64_be="$cross_cc_aarch64"} +: ${cross_cc_cflags_aarch64_be="-mbig-endian"} +: ${cross_cc_alpha="alpha-linux-gnu-gcc"} +: ${cross_cc_arm="arm-linux-gnueabihf-gcc"} +: ${cross_cc_cflags_armeb="-mbig-endian"} +: ${cross_cc_hexagon="hexagon-unknown-linux-musl-clang"} +: ${cross_cc_cflags_hexagon="-mv67 -O2 -static"} +: ${cross_cc_hppa="hppa-linux-gnu-gcc"} +: ${cross_cc_i386="i686-linux-gnu-gcc"} +: ${cross_cc_cflags_i386="-m32"} +: ${cross_cc_m68k="m68k-linux-gnu-gcc"} +: ${cross_cc_microblaze="microblaze-linux-musl-gcc"} +: ${cross_cc_mips64el="mips64el-linux-gnuabi64-gcc"} +: ${cross_cc_mips64="mips64-linux-gnuabi64-gcc"} +: ${cross_cc_mipsel="mipsel-linux-gnu-gcc"} +: ${cross_cc_mips="mips-linux-gnu-gcc"} +: ${cross_cc_nios2="nios2-linux-gnu-gcc"} +: ${cross_cc_ppc="powerpc-linux-gnu-gcc"} +: ${cross_cc_cflags_ppc="-m32"} +: ${cross_cc_ppc64="powerpc64-linux-gnu-gcc"} +: ${cross_cc_cflags_ppc64="-m64 -mbig-endian"} +: ${cross_cc_ppc64le="$cross_cc_ppc64"} +: ${cross_cc_cflags_ppc64le="-m64 -mlittle-endian"} +: ${cross_cc_riscv64="riscv64-linux-gnu-gcc"} +: ${cross_cc_s390x="s390x-linux-gnu-gcc"} +: ${cross_cc_sh4="sh4-linux-gnu-gcc"} +: ${cross_cc_cflags_sparc="-m32 -mcpu=supersparc"} +: ${cross_cc_sparc64="sparc64-linux-gnu-gcc"} +: ${cross_cc_cflags_sparc64="-m64 -mcpu=ultrasparc"} +: ${cross_cc_x86_64="x86_64-linux-gnu-gcc"} +: ${cross_cc_cflags_x86_64="-m64"} + +# tricore is special as it doesn't have a compiler +: ${cross_as_tricore="tricore-as"} +: ${cross_ld_tricore="tricore-ld"} + +probe_target_compiler() { + # reset all output variables + container_image= + container_hosts= + container_cross_cc= + container_cross_as= + container_cross_ld= + target_cc= + target_as= + target_ld= + + case $1 in + aarch64) container_hosts="x86_64 aarch64" ;; + alpha) container_hosts=x86_64 ;; + arm) container_hosts="x86_64 aarch64" ;; + cris) container_hosts=x86_64 ;; + hexagon) container_hosts=x86_64 ;; + hppa) container_hosts=x86_64 ;; + i386) container_hosts=x86_64 ;; + m68k) container_hosts=x86_64 ;; + microblaze) container_hosts=x86_64 ;; + mips64el) container_hosts=x86_64 ;; + mips64) container_hosts=x86_64 ;; + mipsel) container_hosts=x86_64 ;; + mips) container_hosts=x86_64 ;; + nios2) container_hosts=x86_64 ;; + ppc) container_hosts=x86_64 ;; + ppc64|ppc64le) container_hosts=x86_64 ;; + riscv64) container_hosts=x86_64 ;; + s390x) container_hosts=x86_64 ;; + sh4) container_hosts=x86_64 ;; + sparc64) container_hosts=x86_64 ;; + tricore) container_hosts=x86_64 ;; + x86_64) container_hosts="aarch64 ppc64el x86_64" ;; + xtensa*) container_hosts=x86_64 ;; + esac + + for host in $container_hosts; do + test "$container" != no || continue + test "$host" = "$cpu" || continue + case $1 in + aarch64) + # We don't have any bigendian build tools so we only use this for AArch64 + container_image=debian-arm64-cross + container_cross_cc=aarch64-linux-gnu-gcc-10 + ;; + alpha) + container_image=debian-alpha-cross + container_cross_cc=alpha-linux-gnu-gcc + ;; + arm) + # We don't have any bigendian build tools so we only use this for ARM + container_image=debian-armhf-cross + container_cross_cc=arm-linux-gnueabihf-gcc + ;; + cris) + container_image=fedora-cris-cross + container_cross_cc=cris-linux-gnu-gcc + ;; + hexagon) + container_image=debian-hexagon-cross + container_cross_cc=hexagon-unknown-linux-musl-clang + ;; + hppa) + container_image=debian-hppa-cross + container_cross_cc=hppa-linux-gnu-gcc + ;; + i386) + container_image=fedora-i386-cross + container_cross_cc=gcc + ;; + m68k) + container_image=debian-m68k-cross + container_cross_cc=m68k-linux-gnu-gcc + ;; + microblaze) + container_image=debian-microblaze-cross + container_cross_cc=microblaze-linux-musl-gcc + ;; + mips64el) + container_image=debian-mips64el-cross + container_cross_cc=mips64el-linux-gnuabi64-gcc + ;; + mips64) + container_image=debian-mips64-cross + container_cross_cc=mips64-linux-gnuabi64-gcc + ;; + mipsel) + container_image=debian-mipsel-cross + container_cross_cc=mipsel-linux-gnu-gcc + ;; + mips) + container_image=debian-mips-cross + container_cross_cc=mips-linux-gnu-gcc + ;; + nios2) + container_image=debian-nios2-cross + container_cross_cc=nios2-linux-gnu-gcc + ;; + ppc) + container_image=debian-powerpc-test-cross + container_cross_cc=powerpc-linux-gnu-gcc-10 + ;; + ppc64|ppc64le) + container_image=debian-powerpc-test-cross + container_cross_cc=powerpc${1#ppc}-linux-gnu-gcc-10 + ;; + riscv64) + container_image=debian-riscv64-test-cross + container_cross_cc=riscv64-linux-gnu-gcc + ;; + s390x) + container_image=debian-s390x-cross + container_cross_cc=s390x-linux-gnu-gcc + ;; + sh4) + container_image=debian-sh4-cross + container_cross_cc=sh4-linux-gnu-gcc + ;; + sparc64) + container_image=debian-sparc64-cross + container_cross_cc=sparc64-linux-gnu-gcc + ;; + tricore) + container_image=debian-tricore-cross + container_cross_as=tricore-as + container_cross_ld=tricore-ld + ;; + x86_64) + container_image=debian-amd64-cross + container_cross_cc=x86_64-linux-gnu-gcc + ;; + xtensa*) + # FIXME: xtensa-linux-user? + container_hosts=x86_64 + container_image=debian-xtensa-cross + + # default to the dc232b cpu + container_cross_cc=/opt/2020.07/xtensa-dc232b-elf/bin/xtensa-dc232b-elf-gcc + ;; + esac + done + + eval "target_cflags=\${cross_cc_cflags_$1}" + if eval test -n "\"\${cross_cc_$1}\""; then + if eval has "\"\${cross_cc_$1}\""; then + eval "target_cc=\"\${cross_cc_$1}\"" + case $1 in + i386|x86_64) + if $target_cc --version | grep -qi "clang"; then + unset target_cc + fi + ;; + esac + fi + fi + if eval test -n "\"\${cross_as_$1}\""; then + if eval has "\"\${cross_as_$1}\""; then + eval "target_as=\"\${cross_as_$1}\"" + fi + fi + if eval test -n "\"\${cross_ld_$1}\""; then + if eval has "\"\${cross_ld_$1}\""; then + eval "target_ld=\"\${cross_ld_$1}\"" + fi + fi +} + +write_target_makefile() { + if test -n "$target_cc"; then + echo "CC=$target_cc" + fi + if test -n "$target_as"; then + echo "AS=$target_as" + fi + if test -n "$target_ld"; then + echo "LD=$target_ld" + fi +} + +write_container_target_makefile() { + if test -n "$container_cross_cc"; then + echo "CC=\$(DOCKER_SCRIPT) cc --cc $container_cross_cc -i qemu/$container_image -s $source_path --" + fi + if test -n "$container_cross_as"; then + echo "AS=\$(DOCKER_SCRIPT) cc --cc $container_cross_as -i qemu/$container_image -s $source_path --" + fi + if test -n "$container_cross_ld"; then + echo "LD=\$(DOCKER_SCRIPT) cc --cc $container_cross_ld -i qemu/$container_image -s $source_path --" + fi +} + + + ########################################## # End of CC checks # After here, no more $cc or $ld runs @@ -2107,11 +2360,136 @@ for f in $LINKS ; do fi done -(for i in $cross_cc_vars; do - export $i +# tests/tcg configuration +(makefile=tests/tcg/Makefile.prereqs +echo "# Automatically generated by configure - do not modify" > $makefile + +config_host_mak=tests/tcg/config-host.mak +echo "# Automatically generated by configure - do not modify" > $config_host_mak +echo "SRC_PATH=$source_path" >> $config_host_mak +echo "HOST_CC=$host_cc" >> $config_host_mak + +tcg_tests_targets= +for target in $target_list; do + arch=${target%%-*} + + probe_target_compiler ${arch} + config_target_mak=tests/tcg/config-$target.mak + + echo "# Automatically generated by configure - do not modify" > $config_target_mak + echo "TARGET_NAME=$arch" >> $config_target_mak + case $target in + *-softmmu) + test -f $source_path/tests/tcg/$arch/Makefile.softmmu-target || continue + qemu="qemu-system-$arch" + ;; + *-linux-user|*-bsd-user) + qemu="qemu-$arch" + ;; + esac + + got_cross_cc=no + unset build_static + + if test -n "$target_cc"; then + write_c_skeleton + if ! do_compiler "$target_cc" $target_cflags \ + -o $TMPE $TMPC -static ; then + # For host systems we might get away with building without -static + if do_compiler "$target_cc" $target_cflags \ + -o $TMPE $TMPC ; then + got_cross_cc=yes + fi + else + got_cross_cc=yes + build_static=y + fi + elif test -n "$target_as" && test -n "$target_ld"; then + # Special handling for assembler only tests + case $target in + tricore-softmmu) got_cross_cc=yes ;; + esac + fi + + if test $got_cross_cc = yes; then + # Test for compiler features for optional tests. We only do this + # for cross compilers because ensuring the docker containers based + # compilers is a requirememt for adding a new test that needs a + # compiler feature. + + echo "BUILD_STATIC=$build_static" >> $config_target_mak + write_target_makefile >> $config_target_mak + case $target in + aarch64-*) + if do_compiler "$target_cc" $target_cflags \ + -march=armv8.1-a+sve -o $TMPE $TMPC; then + echo "CROSS_CC_HAS_SVE=y" >> $config_target_mak + fi + if do_compiler "$target_cc" $target_cflags \ + -march=armv8.1-a+sve2 -o $TMPE $TMPC; then + echo "CROSS_CC_HAS_SVE2=y" >> $config_target_mak + fi + if do_compiler "$target_cc" $target_cflags \ + -march=armv8.3-a -o $TMPE $TMPC; then + echo "CROSS_CC_HAS_ARMV8_3=y" >> $config_target_mak + fi + if do_compiler "$target_cc" $target_cflags \ + -mbranch-protection=standard -o $TMPE $TMPC; then + echo "CROSS_CC_HAS_ARMV8_BTI=y" >> $config_target_mak + fi + if do_compiler "$target_cc" $target_cflags \ + -march=armv8.5-a+memtag -o $TMPE $TMPC; then + echo "CROSS_CC_HAS_ARMV8_MTE=y" >> $config_target_mak + fi + ;; + ppc*) + if do_compiler "$target_cc" $target_cflags \ + -mpower8-vector -o $TMPE $TMPC; then + echo "CROSS_CC_HAS_POWER8_VECTOR=y" >> $config_target_mak + fi + if do_compiler "$target_cc" $target_cflags \ + -mpower10 -o $TMPE $TMPC; then + echo "CROSS_CC_HAS_POWER10=y" >> $config_target_mak + fi + ;; + i386-linux-user) + if do_compiler "$target_cc" $target_cflags \ + -Werror -fno-pie -o $TMPE $TMPC; then + echo "CROSS_CC_HAS_I386_NOPIE=y" >> $config_target_mak + fi + ;; + esac + elif test -n "$container_image"; then + echo "build-tcg-tests-$target: docker-image-$container_image" >> $makefile + echo "BUILD_STATIC=y" >> $config_target_mak + write_container_target_makefile >> $config_target_mak + case $target in + aarch64-*) + echo "CROSS_CC_HAS_SVE=y" >> $config_target_mak + echo "CROSS_CC_HAS_SVE2=y" >> $config_target_mak + echo "CROSS_CC_HAS_ARMV8_3=y" >> $config_target_mak + echo "CROSS_CC_HAS_ARMV8_BTI=y" >> $config_target_mak + echo "CROSS_CC_HAS_ARMV8_MTE=y" >> $config_target_mak + ;; + ppc*) + echo "CROSS_CC_HAS_POWER8_VECTOR=y" >> $config_target_mak + echo "CROSS_CC_HAS_POWER10=y" >> $config_target_mak + ;; + i386-linux-user) + echo "CROSS_CC_HAS_I386_NOPIE=y" >> $config_target_mak + ;; + esac + got_cross_cc=yes + fi + if test $got_cross_cc = yes; then + mkdir -p tests/tcg/$target + echo "QEMU=$PWD/$qemu" >> $config_target_mak + echo "EXTRA_CFLAGS=$target_cflags" >> $config_target_mak + echo "run-tcg-tests-$target: $qemu\$(EXESUF)" >> $makefile + tcg_tests_targets="$tcg_tests_targets $target" + fi done -export target_list source_path use_containers cpu host_cc -$source_path/tests/tcg/configure.sh) +echo "TCG_TESTS_TARGETS=$tcg_tests_targets" >> $makefile) config_mak=pc-bios/optionrom/config.mak echo "# Automatically generated by configure - do not modify" > $config_mak diff --git a/tests/Makefile.include b/tests/Makefile.include index 72ce0561f4..6a1688e33e 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -37,7 +37,6 @@ export SRC_PATH SPEED = quick -include tests/tcg/Makefile.prereqs -config-host.mak: $(SRC_PATH)/tests/tcg/configure.sh tests/tcg/Makefile.prereqs: config-host.mak # Per guest TCG tests diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh deleted file mode 100755 index 59f2403d1a..0000000000 --- a/tests/tcg/configure.sh +++ /dev/null @@ -1,376 +0,0 @@ -#! /bin/sh - -if test -z "$source_path"; then - echo Do not invoke this script directly. It is called - echo automatically by configure. - exit 1 -fi - -write_c_skeleton() { - cat > $TMPC </dev/null 2>&1 -} - -do_compiler() { - # Run the compiler, capturing its output to the log. First argument - # is compiler binary to execute. - local compiler="$1" - shift - if test -n "$BASH_VERSION"; then eval ' - echo >>config.log " -funcs: ${FUNCNAME[*]} -lines: ${BASH_LINENO[*]}" - '; fi - echo $compiler "$@" >> config.log - $compiler "$@" >> config.log 2>&1 || return $? -} - - -TMPDIR1="config-temp" -TMPC="${TMPDIR1}/qemu-conf.c" -TMPE="${TMPDIR1}/qemu-conf.exe" - -container="no" -if test $use_containers = "yes"; then - if has "docker" || has "podman"; then - container=$($python $source_path/tests/docker/docker.py probe) - fi -fi - -# cross compilers defaults, can be overridden with --cross-cc-ARCH -: ${cross_cc_aarch64="aarch64-linux-gnu-gcc"} -: ${cross_cc_aarch64_be="$cross_cc_aarch64"} -: ${cross_cc_cflags_aarch64_be="-mbig-endian"} -: ${cross_cc_alpha="alpha-linux-gnu-gcc"} -: ${cross_cc_arm="arm-linux-gnueabihf-gcc"} -: ${cross_cc_cflags_armeb="-mbig-endian"} -: ${cross_cc_hexagon="hexagon-unknown-linux-musl-clang"} -: ${cross_cc_cflags_hexagon="-mv67 -O2 -static"} -: ${cross_cc_hppa="hppa-linux-gnu-gcc"} -: ${cross_cc_i386="i686-linux-gnu-gcc"} -: ${cross_cc_cflags_i386="-m32"} -: ${cross_cc_m68k="m68k-linux-gnu-gcc"} -: ${cross_cc_microblaze="microblaze-linux-musl-gcc"} -: ${cross_cc_mips64el="mips64el-linux-gnuabi64-gcc"} -: ${cross_cc_mips64="mips64-linux-gnuabi64-gcc"} -: ${cross_cc_mipsel="mipsel-linux-gnu-gcc"} -: ${cross_cc_mips="mips-linux-gnu-gcc"} -: ${cross_cc_nios2="nios2-linux-gnu-gcc"} -: ${cross_cc_ppc="powerpc-linux-gnu-gcc"} -: ${cross_cc_cflags_ppc="-m32"} -: ${cross_cc_ppc64="powerpc64-linux-gnu-gcc"} -: ${cross_cc_cflags_ppc64="-m64 -mbig-endian"} -: ${cross_cc_ppc64le="$cross_cc_ppc64"} -: ${cross_cc_cflags_ppc64le="-m64 -mlittle-endian"} -: ${cross_cc_riscv64="riscv64-linux-gnu-gcc"} -: ${cross_cc_s390x="s390x-linux-gnu-gcc"} -: ${cross_cc_sh4="sh4-linux-gnu-gcc"} -: ${cross_cc_cflags_sparc="-m32 -mcpu=supersparc"} -: ${cross_cc_sparc64="sparc64-linux-gnu-gcc"} -: ${cross_cc_cflags_sparc64="-m64 -mcpu=ultrasparc"} -: ${cross_cc_x86_64="x86_64-linux-gnu-gcc"} -: ${cross_cc_cflags_x86_64="-m64"} - -# tricore is special as it doesn't have a compiler -: ${cross_as_tricore="tricore-as"} -: ${cross_ld_tricore="tricore-ld"} - -makefile=tests/tcg/Makefile.prereqs -echo "# Automatically generated by configure - do not modify" > $makefile - -config_host_mak=tests/tcg/config-host.mak -echo "# Automatically generated by configure - do not modify" > $config_host_mak -echo "SRC_PATH=$source_path" >> $config_host_mak -echo "HOST_CC=$host_cc" >> $config_host_mak - -tcg_tests_targets= -for target in $target_list; do - arch=${target%%-*} - - # reset all container fields - container_image= - container_hosts= - container_cross_cc= - container_cross_as= - container_cross_ld= - - # suppress clang - supress_clang= - - case $target in - aarch64-*) - # We don't have any bigendian build tools so we only use this for AArch64 - container_hosts="x86_64 aarch64" - container_image=debian-arm64-cross - container_cross_cc=aarch64-linux-gnu-gcc-10 - ;; - alpha-*) - container_hosts=x86_64 - container_image=debian-alpha-cross - container_cross_cc=alpha-linux-gnu-gcc - ;; - arm-*) - # We don't have any bigendian build tools so we only use this for ARM - container_hosts="x86_64 aarch64" - container_image=debian-armhf-cross - container_cross_cc=arm-linux-gnueabihf-gcc - ;; - cris-*) - container_hosts=x86_64 - container_image=fedora-cris-cross - container_cross_cc=cris-linux-gnu-gcc - ;; - hexagon-*) - container_hosts=x86_64 - container_image=debian-hexagon-cross - container_cross_cc=hexagon-unknown-linux-musl-clang - ;; - hppa-*) - container_hosts=x86_64 - container_image=debian-hppa-cross - container_cross_cc=hppa-linux-gnu-gcc - ;; - i386-*) - container_hosts=x86_64 - container_image=fedora-i386-cross - container_cross_cc=gcc - supress_clang=yes - ;; - m68k-*) - container_hosts=x86_64 - container_image=debian-m68k-cross - container_cross_cc=m68k-linux-gnu-gcc - ;; - microblaze-*) - container_hosts=x86_64 - container_image=debian-microblaze-cross - container_cross_cc=microblaze-linux-musl-gcc - ;; - mips64el-*) - container_hosts=x86_64 - container_image=debian-mips64el-cross - container_cross_cc=mips64el-linux-gnuabi64-gcc - ;; - mips64-*) - container_hosts=x86_64 - container_image=debian-mips64-cross - container_cross_cc=mips64-linux-gnuabi64-gcc - ;; - mipsel-*) - container_hosts=x86_64 - container_image=debian-mipsel-cross - container_cross_cc=mipsel-linux-gnu-gcc - ;; - mips-*) - container_hosts=x86_64 - container_image=debian-mips-cross - container_cross_cc=mips-linux-gnu-gcc - ;; - nios2-*) - container_hosts=x86_64 - container_image=debian-nios2-cross - container_cross_cc=nios2-linux-gnu-gcc - ;; - ppc-*) - container_hosts=x86_64 - container_image=debian-powerpc-test-cross - container_cross_cc=powerpc-linux-gnu-gcc-10 - ;; - ppc64-*|ppc64le-*) - container_hosts=x86_64 - container_image=debian-powerpc-test-cross - container_cross_cc=${target%%-*}-linux-gnu-gcc-10 - container_cross_cc=powerpc${container_cross_cc#ppc} - ;; - riscv64-*) - container_hosts=x86_64 - container_image=debian-riscv64-test-cross - container_cross_cc=riscv64-linux-gnu-gcc - ;; - s390x-*) - container_hosts=x86_64 - container_image=debian-s390x-cross - container_cross_cc=s390x-linux-gnu-gcc - ;; - sh4-*) - container_hosts=x86_64 - container_image=debian-sh4-cross - container_cross_cc=sh4-linux-gnu-gcc - ;; - sparc64-*) - container_hosts=x86_64 - container_image=debian-sparc64-cross - container_cross_cc=sparc64-linux-gnu-gcc - ;; - tricore-softmmu) - container_hosts=x86_64 - container_image=debian-tricore-cross - container_cross_as=tricore-as - container_cross_ld=tricore-ld - ;; - x86_64-*) - container_hosts="aarch64 ppc64el x86_64" - container_image=debian-amd64-cross - container_cross_cc=x86_64-linux-gnu-gcc - supress_clang=yes - ;; - xtensa*-softmmu) - container_hosts=x86_64 - container_image=debian-xtensa-cross - - # default to the dc232b cpu - container_cross_cc=/opt/2020.07/xtensa-dc232b-elf/bin/xtensa-dc232b-elf-gcc - ;; - esac - - config_target_mak=tests/tcg/config-$target.mak - - echo "# Automatically generated by configure - do not modify" > $config_target_mak - echo "TARGET_NAME=$arch" >> $config_target_mak - case $target in - *-softmmu) - test -f $source_path/tests/tcg/$arch/Makefile.softmmu-target || continue - qemu="qemu-system-$arch" - ;; - *-linux-user|*-bsd-user) - qemu="qemu-$arch" - ;; - esac - - eval "target_compiler_cflags=\${cross_cc_cflags_$arch}" - - got_cross_cc=no - - if eval test "x\"\${cross_cc_$arch}\"" != xyes; then - eval "target_compiler=\"\${cross_cc_$arch}\"" - - if has $target_compiler; then - if test "$supress_clang" = yes && - $target_compiler --version | grep -qi "clang"; then - got_cross_cc=no - else - write_c_skeleton - if ! do_compiler "$target_compiler" $target_compiler_cflags \ - -o $TMPE $TMPC -static ; then - # For host systems we might get away with building without -static - if do_compiler "$target_compiler" $target_compiler_cflags \ - -o $TMPE $TMPC ; then - got_cross_cc=yes - echo "CC=$target_compiler" >> $config_target_mak - fi - else - got_cross_cc=yes - echo "BUILD_STATIC=y" >> $config_target_mak - echo "CC=$target_compiler" >> $config_target_mak - fi - fi - fi - - # Special handling for assembler only tests - eval "target_as=\"\${cross_as_$arch}\"" - eval "target_ld=\"\${cross_ld_$arch}\"" - if has $target_as && has $target_ld; then - case $target in - tricore-softmmu) - echo "AS=$target_as" >> $config_target_mak - echo "LD=$target_ld" >> $config_target_mak - got_cross_cc=yes - ;; - esac - fi - fi - - if test $got_cross_cc = yes; then - # Test for compiler features for optional tests. We only do this - # for cross compilers because ensuring the docker containers based - # compilers is a requirememt for adding a new test that needs a - # compiler feature. - - case $target in - aarch64-*) - if do_compiler "$target_compiler" $target_compiler_cflags \ - -march=armv8.1-a+sve -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_SVE=y" >> $config_target_mak - fi - if do_compiler "$target_compiler" $target_compiler_cflags \ - -march=armv8.1-a+sve2 -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_SVE2=y" >> $config_target_mak - fi - if do_compiler "$target_compiler" $target_compiler_cflags \ - -march=armv8.3-a -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_ARMV8_3=y" >> $config_target_mak - fi - if do_compiler "$target_compiler" $target_compiler_cflags \ - -mbranch-protection=standard -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_ARMV8_BTI=y" >> $config_target_mak - fi - if do_compiler "$target_compiler" $target_compiler_cflags \ - -march=armv8.5-a+memtag -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_ARMV8_MTE=y" >> $config_target_mak - fi - ;; - ppc*) - if do_compiler "$target_compiler" $target_compiler_cflags \ - -mpower8-vector -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_POWER8_VECTOR=y" >> $config_target_mak - fi - if do_compiler "$target_compiler" $target_compiler_cflags \ - -mpower10 -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_POWER10=y" >> $config_target_mak - fi - ;; - i386-linux-user) - if do_compiler "$target_compiler" $target_compiler_cflags \ - -Werror -fno-pie -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_I386_NOPIE=y" >> $config_target_mak - fi - ;; - esac - elif test $got_cross_cc = no && test "$container" != no && \ - test -n "$container_image"; then - for host in $container_hosts; do - if test "$host" = "$cpu"; then - echo "build-tcg-tests-$target: docker-image-$container_image" >> $makefile - echo "BUILD_STATIC=y" >> $config_target_mak - echo "CC=\$(DOCKER_SCRIPT) cc --cc $container_cross_cc -i qemu/$container_image -s $source_path --" >> $config_target_mak - if test -n "$container_cross_as"; then - echo "AS=\$(DOCKER_SCRIPT) cc --cc $container_cross_as -i qemu/$container_image -s $source_path --" >> $config_target_mak - fi - if test -n "$container_cross_ld"; then - echo "LD=\$(DOCKER_SCRIPT) cc --cc $container_cross_ld -i qemu/$container_image -s $source_path --" >> $config_target_mak - fi - case $target in - aarch64-*) - echo "CROSS_CC_HAS_SVE=y" >> $config_target_mak - echo "CROSS_CC_HAS_SVE2=y" >> $config_target_mak - echo "CROSS_CC_HAS_ARMV8_3=y" >> $config_target_mak - echo "CROSS_CC_HAS_ARMV8_BTI=y" >> $config_target_mak - echo "CROSS_CC_HAS_ARMV8_MTE=y" >> $config_target_mak - ;; - ppc*) - echo "CROSS_CC_HAS_POWER8_VECTOR=y" >> $config_target_mak - echo "CROSS_CC_HAS_POWER10=y" >> $config_target_mak - ;; - i386-linux-user) - echo "CROSS_CC_HAS_I386_NOPIE=y" >> $config_target_mak - ;; - esac - got_cross_cc=yes - break - fi - done - fi - if test $got_cross_cc = yes; then - mkdir -p tests/tcg/$target - echo "QEMU=$PWD/$qemu" >> $config_target_mak - echo "EXTRA_CFLAGS=$target_compiler_cflags" >> $config_target_mak - echo "run-tcg-tests-$target: $qemu\$(EXESUF)" >> $makefile - tcg_tests_targets="$tcg_tests_targets $target" - fi -done -echo "TCG_TESTS_TARGETS=$tcg_tests_targets" >> $makefile From 46af66edcb9c123069a941f495ba8b13f486851a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 May 2022 16:35:49 +0100 Subject: [PATCH 720/935] configure: add missing cross compiler fallbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The arm compiler can be used for armeb, and the sparc64 compiler can be used for sparc. Signed-off-by: Paolo Bonzini Reviewed-by: Richard Henderson Message-Id: <20220517092616.1272238-9-pbonzini@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20220527153603.887929-20-alex.bennee@linaro.org> --- configure | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/configure b/configure index f91ac632e7..fbf6d39f96 100755 --- a/configure +++ b/configure @@ -1827,6 +1827,7 @@ fi : ${cross_cc_cflags_aarch64_be="-mbig-endian"} : ${cross_cc_alpha="alpha-linux-gnu-gcc"} : ${cross_cc_arm="arm-linux-gnueabihf-gcc"} +: ${cross_cc_armeb="$cross_cc_arm"} : ${cross_cc_cflags_armeb="-mbig-endian"} : ${cross_cc_hexagon="hexagon-unknown-linux-musl-clang"} : ${cross_cc_cflags_hexagon="-mv67 -O2 -static"} @@ -1849,9 +1850,10 @@ fi : ${cross_cc_riscv64="riscv64-linux-gnu-gcc"} : ${cross_cc_s390x="s390x-linux-gnu-gcc"} : ${cross_cc_sh4="sh4-linux-gnu-gcc"} -: ${cross_cc_cflags_sparc="-m32 -mcpu=supersparc"} : ${cross_cc_sparc64="sparc64-linux-gnu-gcc"} : ${cross_cc_cflags_sparc64="-m64 -mcpu=ultrasparc"} +: ${cross_cc_sparc="$cross_cc_sparc64"} +: ${cross_cc_cflags_sparc="-m32 -mcpu=supersparc"} : ${cross_cc_x86_64="x86_64-linux-gnu-gcc"} : ${cross_cc_cflags_x86_64="-m64"} From 2ad60f6f8c12ca0acd8834fdd70e088361b8791f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 May 2022 16:35:50 +0100 Subject: [PATCH 721/935] configure: handle host compiler in probe_target_compiler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation for handling more binaries than just cc, handle the case of "probe_target_compiler $cpu" directly in the function, setting the target_* variables based on the ones that are used to build QEMU. The clang check also needs to be moved after this fallback. Signed-off-by: Paolo Bonzini Reviewed-by: Richard Henderson Message-Id: <20220517092616.1272238-10-pbonzini@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20220527153603.887929-21-alex.bennee@linaro.org> --- configure | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/configure b/configure index fbf6d39f96..217c8b3cac 100755 --- a/configure +++ b/configure @@ -954,10 +954,6 @@ case $git_submodules_action in ;; esac -if eval test -z "\${cross_cc_$cpu}"; then - eval "cross_cc_${cpu}=\$cc" -fi - default_target_list="" mak_wilds="" @@ -2008,13 +2004,6 @@ probe_target_compiler() { if eval test -n "\"\${cross_cc_$1}\""; then if eval has "\"\${cross_cc_$1}\""; then eval "target_cc=\"\${cross_cc_$1}\"" - case $1 in - i386|x86_64) - if $target_cc --version | grep -qi "clang"; then - unset target_cc - fi - ;; - esac fi fi if eval test -n "\"\${cross_as_$1}\""; then @@ -2027,6 +2016,20 @@ probe_target_compiler() { eval "target_ld=\"\${cross_ld_$1}\"" fi fi + if test "$1" = $cpu; then + : ${target_cc:=$cc} + : ${target_as:=$as} + : ${target_ld:=$ld} + fi + if test -n "$target_cc"; then + case $1 in + i386|x86_64) + if $target_cc --version | grep -qi "clang"; then + unset target_cc + fi + ;; + esac + fi } write_target_makefile() { From 5adb43be79dd125f8bf7bce0fd4b0c4f03e0aa71 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 May 2022 16:35:51 +0100 Subject: [PATCH 722/935] configure: introduce --cross-prefix-*= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also in preparation for handling more binaries from the cross binutils, support an option --cross-prefix-ARCH. All cross_cc_* defaults are replaced with cross_prefix_*; the cross_cc_* fallbacks are extended to the cross-compilation prefix, but the compiler fallbacks remain as well. This way, for example, --cross-cc-arm=arm-linux-gnueabihf-clang also applies to armeb binaries. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini Message-Id: <20220517092616.1272238-11-pbonzini@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20220527153603.887929-22-alex.bennee@linaro.org> --- configure | 137 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 77 insertions(+), 60 deletions(-) diff --git a/configure b/configure index 217c8b3cac..f55ae82a5d 100755 --- a/configure +++ b/configure @@ -363,6 +363,11 @@ for opt do --cross-cc-*) cc_arch=${opt#--cross-cc-}; cc_arch=${cc_arch%%=*} eval "cross_cc_${cc_arch}=\$optarg" ;; + --cross-prefix-*[!a-zA-Z0-9_-]*=*) error_exit "Passed bad --cross-prefix-FOO option" + ;; + --cross-prefix-*) cc_arch=${opt#--cross-prefix-}; cc_arch=${cc_arch%%=*} + eval "cross_prefix_${cc_arch}=\$optarg" + ;; esac done # OS specific @@ -728,6 +733,8 @@ for opt do ;; --cross-cc-*) ;; + --cross-prefix-*) + ;; --enable-debug-info) meson_option_add -Ddebug=true ;; --disable-debug-info) meson_option_add -Ddebug=false @@ -1016,6 +1023,7 @@ Advanced options (experts only): --extra-ldflags=LDFLAGS append extra linker flags LDFLAGS --cross-cc-ARCH=CC use compiler when building ARCH guest test cases --cross-cc-cflags-ARCH= use compiler flags when building ARCH guest tests + --cross-prefix-ARCH=PREFIX cross compiler prefix when building ARCH guest test cases --make=MAKE use specified make [$make] --python=PYTHON use specified python [$python] --meson=MESON use specified meson [$meson] @@ -1818,44 +1826,54 @@ if test $use_containers = "yes"; then fi # cross compilers defaults, can be overridden with --cross-cc-ARCH -: ${cross_cc_aarch64="aarch64-linux-gnu-gcc"} +: ${cross_prefix_aarch64="aarch64-linux-gnu-"} +: ${cross_prefix_aarch64_be="$cross_prefix_aarch64"} +: ${cross_prefix_alpha="alpha-linux-gnu-"} +: ${cross_prefix_arm="arm-linux-gnueabihf-"} +: ${cross_prefix_armeb="$cross_prefix_arm"} +: ${cross_prefix_hexagon="hexagon-unknown-linux-musl-"} +: ${cross_prefix_hppa="hppa-linux-gnu-"} +: ${cross_prefix_i386="i686-linux-gnu-"} +: ${cross_prefix_m68k="m68k-linux-gnu-"} +: ${cross_prefix_microblaze="microblaze-linux-musl-"} +: ${cross_prefix_mips64el="mips64el-linux-gnuabi64-"} +: ${cross_prefix_mips64="mips64-linux-gnuabi64-"} +: ${cross_prefix_mipsel="mipsel-linux-gnu-"} +: ${cross_prefix_mips="mips-linux-gnu-"} +: ${cross_prefix_nios2="nios2-linux-gnu-"} +: ${cross_prefix_ppc="powerpc-linux-gnu-"} +: ${cross_prefix_ppc64="powerpc64-linux-gnu-"} +: ${cross_prefix_ppc64le="$cross_prefix_ppc64"} +: ${cross_prefix_riscv64="riscv64-linux-gnu-"} +: ${cross_prefix_s390x="s390x-linux-gnu-"} +: ${cross_prefix_sh4="sh4-linux-gnu-"} +: ${cross_prefix_sparc64="sparc64-linux-gnu-"} +: ${cross_prefix_sparc="$cross_prefix_sparc64"} +: ${cross_prefix_x86_64="x86_64-linux-gnu-"} + : ${cross_cc_aarch64_be="$cross_cc_aarch64"} : ${cross_cc_cflags_aarch64_be="-mbig-endian"} -: ${cross_cc_alpha="alpha-linux-gnu-gcc"} -: ${cross_cc_arm="arm-linux-gnueabihf-gcc"} : ${cross_cc_armeb="$cross_cc_arm"} : ${cross_cc_cflags_armeb="-mbig-endian"} : ${cross_cc_hexagon="hexagon-unknown-linux-musl-clang"} : ${cross_cc_cflags_hexagon="-mv67 -O2 -static"} -: ${cross_cc_hppa="hppa-linux-gnu-gcc"} -: ${cross_cc_i386="i686-linux-gnu-gcc"} : ${cross_cc_cflags_i386="-m32"} -: ${cross_cc_m68k="m68k-linux-gnu-gcc"} -: ${cross_cc_microblaze="microblaze-linux-musl-gcc"} -: ${cross_cc_mips64el="mips64el-linux-gnuabi64-gcc"} -: ${cross_cc_mips64="mips64-linux-gnuabi64-gcc"} -: ${cross_cc_mipsel="mipsel-linux-gnu-gcc"} -: ${cross_cc_mips="mips-linux-gnu-gcc"} -: ${cross_cc_nios2="nios2-linux-gnu-gcc"} -: ${cross_cc_ppc="powerpc-linux-gnu-gcc"} : ${cross_cc_cflags_ppc="-m32"} -: ${cross_cc_ppc64="powerpc64-linux-gnu-gcc"} : ${cross_cc_cflags_ppc64="-m64 -mbig-endian"} : ${cross_cc_ppc64le="$cross_cc_ppc64"} : ${cross_cc_cflags_ppc64le="-m64 -mlittle-endian"} -: ${cross_cc_riscv64="riscv64-linux-gnu-gcc"} -: ${cross_cc_s390x="s390x-linux-gnu-gcc"} -: ${cross_cc_sh4="sh4-linux-gnu-gcc"} -: ${cross_cc_sparc64="sparc64-linux-gnu-gcc"} : ${cross_cc_cflags_sparc64="-m64 -mcpu=ultrasparc"} : ${cross_cc_sparc="$cross_cc_sparc64"} : ${cross_cc_cflags_sparc="-m32 -mcpu=supersparc"} -: ${cross_cc_x86_64="x86_64-linux-gnu-gcc"} : ${cross_cc_cflags_x86_64="-m64"} -# tricore is special as it doesn't have a compiler -: ${cross_as_tricore="tricore-as"} -: ${cross_ld_tricore="tricore-ld"} +compute_target_variable() { + if eval test -n "\"\${cross_prefix_$1}\""; then + if eval has "\"\${cross_prefix_$1}\$3\""; then + eval "$2=\"\${cross_prefix_$1}\$3\"" + fi + fi +} probe_target_compiler() { # reset all output variables @@ -1901,93 +1919,99 @@ probe_target_compiler() { aarch64) # We don't have any bigendian build tools so we only use this for AArch64 container_image=debian-arm64-cross - container_cross_cc=aarch64-linux-gnu-gcc-10 + container_cross_prefix=aarch64-linux-gnu- + container_cross_cc=${container_cross_prefix}gcc-10 ;; alpha) container_image=debian-alpha-cross - container_cross_cc=alpha-linux-gnu-gcc + container_cross_prefix=alpha-linux-gnu- ;; arm) # We don't have any bigendian build tools so we only use this for ARM container_image=debian-armhf-cross - container_cross_cc=arm-linux-gnueabihf-gcc + container_cross_prefix=arm-linux-gnueabihf- ;; cris) container_image=fedora-cris-cross - container_cross_cc=cris-linux-gnu-gcc + container_cross_prefix=cris-linux-gnu- ;; hexagon) container_image=debian-hexagon-cross - container_cross_cc=hexagon-unknown-linux-musl-clang + container_cross_prefix=hexagon-unknown-linux-musl- + container_cross_cc=${container_cross_prefix}clang ;; hppa) container_image=debian-hppa-cross - container_cross_cc=hppa-linux-gnu-gcc + container_cross_prefix=hppa-linux-gnu- ;; i386) container_image=fedora-i386-cross - container_cross_cc=gcc + container_cross_prefix= ;; m68k) container_image=debian-m68k-cross - container_cross_cc=m68k-linux-gnu-gcc + container_cross_prefix=m68k-linux-gnu- ;; microblaze) container_image=debian-microblaze-cross - container_cross_cc=microblaze-linux-musl-gcc + container_cross_prefix=microblaze-linux-musl- ;; mips64el) container_image=debian-mips64el-cross - container_cross_cc=mips64el-linux-gnuabi64-gcc + container_cross_prefix=mips64el-linux-gnuabi64- ;; mips64) container_image=debian-mips64-cross - container_cross_cc=mips64-linux-gnuabi64-gcc + container_cross_prefix=mips64-linux-gnuabi64- ;; mipsel) container_image=debian-mipsel-cross - container_cross_cc=mipsel-linux-gnu-gcc + container_cross_prefix=mipsel-linux-gnu- ;; mips) container_image=debian-mips-cross - container_cross_cc=mips-linux-gnu-gcc + container_cross_prefix=mips-linux-gnu- ;; nios2) container_image=debian-nios2-cross - container_cross_cc=nios2-linux-gnu-gcc + container_cross_prefix=nios2-linux-gnu- ;; ppc) container_image=debian-powerpc-test-cross - container_cross_cc=powerpc-linux-gnu-gcc-10 + container_cross_prefix=powerpc-linux-gnu- + container_cross_cc=${container_cross_prefix}gcc-10 ;; ppc64|ppc64le) container_image=debian-powerpc-test-cross - container_cross_cc=powerpc${1#ppc}-linux-gnu-gcc-10 + container_cross_prefix=powerpc${1#ppc}-linux-gnu- + container_cross_cc=${container_cross_prefix}gcc-10 ;; riscv64) container_image=debian-riscv64-test-cross - container_cross_cc=riscv64-linux-gnu-gcc + container_cross_prefix=riscv64-linux-gnu- ;; s390x) container_image=debian-s390x-cross - container_cross_cc=s390x-linux-gnu-gcc + container_cross_prefix=s390x-linux-gnu- ;; sh4) container_image=debian-sh4-cross - container_cross_cc=sh4-linux-gnu-gcc + container_cross_prefix=sh4-linux-gnu- ;; sparc64) container_image=debian-sparc64-cross - container_cross_cc=sparc64-linux-gnu-gcc + container_cross_prefix=sparc64-linux-gnu- ;; tricore) container_image=debian-tricore-cross + container_cross_prefix=tricore- container_cross_as=tricore-as container_cross_ld=tricore-ld + break ;; x86_64) container_image=debian-amd64-cross - container_cross_cc=x86_64-linux-gnu-gcc + container_cross_prefix=x86_64-linux-gnu- ;; xtensa*) # FIXME: xtensa-linux-user? @@ -1995,9 +2019,12 @@ probe_target_compiler() { container_image=debian-xtensa-cross # default to the dc232b cpu - container_cross_cc=/opt/2020.07/xtensa-dc232b-elf/bin/xtensa-dc232b-elf-gcc + container_cross_prefix=/opt/2020.07/xtensa-dc232b-elf/bin/xtensa-dc232b-elf- ;; esac + : ${container_cross_cc:=${container_cross_prefix}gcc} + : ${container_cross_as:=${container_cross_prefix}as} + : ${container_cross_ld:=${container_cross_prefix}ld} done eval "target_cflags=\${cross_cc_cflags_$1}" @@ -2005,17 +2032,11 @@ probe_target_compiler() { if eval has "\"\${cross_cc_$1}\""; then eval "target_cc=\"\${cross_cc_$1}\"" fi + else + compute_target_variable $1 target_cc gcc fi - if eval test -n "\"\${cross_as_$1}\""; then - if eval has "\"\${cross_as_$1}\""; then - eval "target_as=\"\${cross_as_$1}\"" - fi - fi - if eval test -n "\"\${cross_ld_$1}\""; then - if eval has "\"\${cross_ld_$1}\""; then - eval "target_ld=\"\${cross_ld_$1}\"" - fi - fi + compute_target_variable $1 target_as as + compute_target_variable $1 target_ld ld if test "$1" = $cpu; then : ${target_cc:=$cc} : ${target_as:=$as} @@ -2048,12 +2069,8 @@ write_container_target_makefile() { if test -n "$container_cross_cc"; then echo "CC=\$(DOCKER_SCRIPT) cc --cc $container_cross_cc -i qemu/$container_image -s $source_path --" fi - if test -n "$container_cross_as"; then - echo "AS=\$(DOCKER_SCRIPT) cc --cc $container_cross_as -i qemu/$container_image -s $source_path --" - fi - if test -n "$container_cross_ld"; then - echo "LD=\$(DOCKER_SCRIPT) cc --cc $container_cross_ld -i qemu/$container_image -s $source_path --" - fi + echo "AS=\$(DOCKER_SCRIPT) cc --cc $container_cross_as -i qemu/$container_image -s $source_path --" + echo "LD=\$(DOCKER_SCRIPT) cc --cc $container_cross_ld -i qemu/$container_image -s $source_path --" } From 87eb014c5e80039bf6bee4f05557f48827239cb4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 May 2022 16:35:52 +0100 Subject: [PATCH 723/935] configure: include more binutils in tests/tcg makefile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Firmware builds require paths to all the binutils; it is not enough to use only cc, or even as/ld as in the case of tests/tcg/tricore. Adjust the cross-compiler configurator to detect also ar, nm, objcopy, ranlib and strip. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini Message-Id: <20220517092616.1272238-12-pbonzini@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20220527153603.887929-23-alex.bennee@linaro.org> --- configure | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/configure b/configure index f55ae82a5d..ced8283b98 100755 --- a/configure +++ b/configure @@ -1880,11 +1880,21 @@ probe_target_compiler() { container_image= container_hosts= container_cross_cc= + container_cross_ar= container_cross_as= container_cross_ld= + container_cross_nm= + container_cross_objcopy= + container_cross_ranlib= + container_cross_strip= target_cc= + target_ar= target_as= target_ld= + target_nm= + target_objcopy= + target_ranlib= + target_strip= case $1 in aarch64) container_hosts="x86_64 aarch64" ;; @@ -2023,8 +2033,13 @@ probe_target_compiler() { ;; esac : ${container_cross_cc:=${container_cross_prefix}gcc} + : ${container_cross_ar:=${container_cross_prefix}ar} : ${container_cross_as:=${container_cross_prefix}as} : ${container_cross_ld:=${container_cross_prefix}ld} + : ${container_cross_nm:=${container_cross_prefix}nm} + : ${container_cross_objcopy:=${container_cross_prefix}objcopy} + : ${container_cross_ranlib:=${container_cross_prefix}ranlib} + : ${container_cross_strip:=${container_cross_prefix}strip} done eval "target_cflags=\${cross_cc_cflags_$1}" @@ -2035,12 +2050,26 @@ probe_target_compiler() { else compute_target_variable $1 target_cc gcc fi + target_ccas=$target_cc + compute_target_variable $1 target_ar ar compute_target_variable $1 target_as as compute_target_variable $1 target_ld ld + compute_target_variable $1 target_nm nm + compute_target_variable $1 target_objcopy objcopy + compute_target_variable $1 target_ranlib ranlib + compute_target_variable $1 target_strip strip if test "$1" = $cpu; then : ${target_cc:=$cc} + : ${target_ccas:=$ccas} : ${target_as:=$as} : ${target_ld:=$ld} + : ${target_ar:=$ar} + : ${target_as:=$as} + : ${target_ld:=$ld} + : ${target_nm:=$nm} + : ${target_objcopy:=$objcopy} + : ${target_ranlib:=$ranlib} + : ${target_strip:=$strip} fi if test -n "$target_cc"; then case $1 in @@ -2056,6 +2085,10 @@ probe_target_compiler() { write_target_makefile() { if test -n "$target_cc"; then echo "CC=$target_cc" + echo "CCAS=$target_ccas" + fi + if test -n "$target_ar"; then + echo "AR=$target_ar" fi if test -n "$target_as"; then echo "AS=$target_as" @@ -2063,14 +2096,32 @@ write_target_makefile() { if test -n "$target_ld"; then echo "LD=$target_ld" fi + if test -n "$target_nm"; then + echo "NM=$target_nm" + fi + if test -n "$target_objcopy"; then + echo "OBJCOPY=$target_objcopy" + fi + if test -n "$target_ranlib"; then + echo "RANLIB=$target_ranlib" + fi + if test -n "$target_strip"; then + echo "STRIP=$target_strip" + fi } write_container_target_makefile() { if test -n "$container_cross_cc"; then echo "CC=\$(DOCKER_SCRIPT) cc --cc $container_cross_cc -i qemu/$container_image -s $source_path --" + echo "CCAS=\$(DOCKER_SCRIPT) cc --cc $container_cross_cc -i qemu/$container_image -s $source_path --" fi + echo "AR=\$(DOCKER_SCRIPT) cc --cc $container_cross_ar -i qemu/$container_image -s $source_path --" echo "AS=\$(DOCKER_SCRIPT) cc --cc $container_cross_as -i qemu/$container_image -s $source_path --" echo "LD=\$(DOCKER_SCRIPT) cc --cc $container_cross_ld -i qemu/$container_image -s $source_path --" + echo "NM=\$(DOCKER_SCRIPT) cc --cc $container_cross_nm -i qemu/$container_image -s $source_path --" + echo "OBJCOPY=\$(DOCKER_SCRIPT) cc --cc $container_cross_objcopy -i qemu/$container_image -s $source_path --" + echo "RANLIB=\$(DOCKER_SCRIPT) cc --cc $container_cross_ranlib -i qemu/$container_image -s $source_path --" + echo "STRIP=\$(DOCKER_SCRIPT) cc --cc $container_cross_strip -i qemu/$container_image -s $source_path --" } From ad38884512a72206463a95a30451253946d4218b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 May 2022 16:35:53 +0100 Subject: [PATCH 724/935] configure: move symlink configuration earlier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure that the pc-bios/optionrom and pc-bios/s390-ccw directory exist at the time when we'll write out the compiler configuration for them. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini Message-Id: <20220517092616.1272238-13-pbonzini@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20220527153603.887929-24-alex.bennee@linaro.org> --- configure | 49 ++++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/configure b/configure index ced8283b98..aa17b0fa55 100755 --- a/configure +++ b/configure @@ -2190,6 +2190,30 @@ if test "$QEMU_GA_VERSION" = ""; then QEMU_GA_VERSION=$(cat $source_path/VERSION) fi +# Set up build tree symlinks that point back into the source tree +# (these can be both files and directories). +# Caution: avoid adding files or directories here using wildcards. This +# will result in problems later if a new file matching the wildcard is +# added to the source tree -- nothing will cause configure to be rerun +# so the build tree will be missing the link back to the new file, and +# tests might fail. Prefer to keep the relevant files in their own +# directory and symlink the directory instead. +LINKS="Makefile" +LINKS="$LINKS tests/tcg/Makefile.target" +LINKS="$LINKS pc-bios/optionrom/Makefile" +LINKS="$LINKS pc-bios/s390-ccw/Makefile" +LINKS="$LINKS .gdbinit scripts" # scripts needed by relative path in .gdbinit +LINKS="$LINKS tests/avocado tests/data" +LINKS="$LINKS tests/qemu-iotests/check" +LINKS="$LINKS python" +LINKS="$LINKS contrib/plugins/Makefile " +for f in $LINKS ; do + if [ -e "$source_path/$f" ]; then + mkdir -p `dirname ./$f` + symlink "$source_path/$f" "$f" + fi +done + # Mac OS X ships with a broken assembler roms= if { test "$cpu" = "i386" || test "$cpu" = "x86_64"; } && \ @@ -2408,31 +2432,6 @@ if test "$safe_stack" = "yes"; then echo "CONFIG_SAFESTACK=y" >> $config_host_mak fi -# If we're using a separate build tree, set it up now. -# LINKS are things to symlink back into the source tree -# (these can be both files and directories). -# Caution: do not add files or directories here using wildcards. This -# will result in problems later if a new file matching the wildcard is -# added to the source tree -- nothing will cause configure to be rerun -# so the build tree will be missing the link back to the new file, and -# tests might fail. Prefer to keep the relevant files in their own -# directory and symlink the directory instead. -LINKS="Makefile" -LINKS="$LINKS tests/tcg/Makefile.target" -LINKS="$LINKS pc-bios/optionrom/Makefile" -LINKS="$LINKS pc-bios/s390-ccw/Makefile" -LINKS="$LINKS .gdbinit scripts" # scripts needed by relative path in .gdbinit -LINKS="$LINKS tests/avocado tests/data" -LINKS="$LINKS tests/qemu-iotests/check" -LINKS="$LINKS python" -LINKS="$LINKS contrib/plugins/Makefile " -for f in $LINKS ; do - if [ -e "$source_path/$f" ]; then - mkdir -p `dirname ./$f` - symlink "$source_path/$f" "$f" - fi -done - # tests/tcg configuration (makefile=tests/tcg/Makefile.prereqs echo "# Automatically generated by configure - do not modify" > $makefile From 9ffed42614585026834fd63cdf586b78b1f72c66 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 May 2022 16:35:54 +0100 Subject: [PATCH 725/935] configure: enable cross-compilation of s390-ccw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While container-based cross compilers are not supported, this already makes it possible to build s390-ccw on any machine that has s390x GCC and binutils installed. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini Message-Id: <20220517092616.1272238-14-pbonzini@redhat.com> Signed-off-by: Alex Bennée Acked-by: Thomas Huth Message-Id: <20220527153603.887929-25-alex.bennee@linaro.org> --- configure | 18 +++++++++++++----- pc-bios/s390-ccw/Makefile | 9 +++++---- pc-bios/s390-ccw/netboot.mak | 2 +- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/configure b/configure index aa17b0fa55..f509bce304 100755 --- a/configure +++ b/configure @@ -2231,24 +2231,32 @@ if { test "$cpu" = "i386" || test "$cpu" = "x86_64"; } && \ done fi -# Only build s390-ccw bios if we're on s390x and the compiler has -march=z900 -# or -march=z10 (which is the lowest architecture level that Clang supports) -if test "$cpu" = "s390x" ; then +# Only build s390-ccw bios if the compiler has -march=z900 or -march=z10 +# (which is the lowest architecture level that Clang supports) +probe_target_compiler s390x +if test -n "$target_cc" && test "$softmmu" = yes; then write_c_skeleton - compile_prog "-march=z900" "" + do_compiler "$target_cc" $target_cc_cflags -march=z900 -o $TMPO -c $TMPC has_z900=$? - if [ $has_z900 = 0 ] || compile_object "-march=z10 -msoft-float -Werror"; then + if [ $has_z900 = 0 ] || do_compiler "$target_cc" $target_cc_cflags -march=z10 -msoft-float -Werror -o $TMPO -c $TMPC; then if [ $has_z900 != 0 ]; then echo "WARNING: Your compiler does not support the z900!" echo " The s390-ccw bios will only work with guest CPUs >= z10." fi roms="$roms s390-ccw" + config_mak=pc-bios/s390-ccw/config-host.mak + echo "# Automatically generated by configure - do not modify" > $config_mak + echo "SRC_PATH=$source_path/pc-bios/s390-ccw" >> $config_mak + write_target_makefile >> $config_mak # SLOF is required for building the s390-ccw firmware on s390x, # since it is using the libnet code from SLOF for network booting. git_submodules="${git_submodules} roms/SLOF" fi fi +####################################### +# generate config-host.mak + # Check that the C++ compiler exists and works with the C compiler. # All the QEMU_CXXFLAGS are based on QEMU_CFLAGS. Keep this at the end to don't miss any other that could be added. if has $cxx; then diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile index 0eb68efc7b..6eb713bf37 100644 --- a/pc-bios/s390-ccw/Makefile +++ b/pc-bios/s390-ccw/Makefile @@ -2,8 +2,9 @@ all: build-all # Dummy command so that make thinks it has done something @true -include ../../config-host.mak +include config-host.mak CFLAGS = -O2 -g +MAKEFLAGS += -rR quiet-command = $(if $(V),$1,$(if $(2),@printf " %-7s %s\n" $2 $3 && $1, @$1)) cc-option = $(if $(shell $(CC) $1 $2 -S -o /dev/null -xc /dev/null \ @@ -11,7 +12,7 @@ cc-option = $(if $(shell $(CC) $1 $2 -S -o /dev/null -xc /dev/null \ VPATH_SUFFIXES = %.c %.h %.S %.m %.mak %.sh %.rc Kconfig% %.json.in set-vpath = $(if $1,$(foreach PATTERN,$(VPATH_SUFFIXES),$(eval vpath $(PATTERN) $1))) -$(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw) +$(call set-vpath, $(SRC_PATH)) # Flags for dependency generation QEMU_DGFLAGS = -MMD -MP -MT $@ -MF $(@D)/$(*F).d @@ -49,8 +50,8 @@ s390-ccw.img: s390-ccw.elf $(OBJECTS): Makefile -ifneq ($(wildcard $(SRC_PATH)/roms/SLOF/lib/libnet),) -include $(SRC_PATH)/pc-bios/s390-ccw/netboot.mak +ifneq ($(wildcard $(SRC_PATH)/../../roms/SLOF/lib/libnet),) +include $(SRC_PATH)/netboot.mak else s390-netboot.img: @echo "s390-netboot.img not built since roms/SLOF/ is not available." diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak index 68b4d7edcb..1a06befa4b 100644 --- a/pc-bios/s390-ccw/netboot.mak +++ b/pc-bios/s390-ccw/netboot.mak @@ -1,5 +1,5 @@ -SLOF_DIR := $(SRC_PATH)/roms/SLOF +SLOF_DIR := $(SRC_PATH)/../../roms/SLOF NETOBJS := start.o sclp.o cio.o virtio.o virtio-net.o jump2ipl.o netmain.o From 33ab4787422b04a3f4c94bbded6b05021d08b27d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 May 2022 16:35:55 +0100 Subject: [PATCH 726/935] configure: enable cross-compilation of optionrom MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While container-based cross compilers are not supported, this already makes it possible to build x86 optionroms on any machine that has an installation of GCC and binutils for 32- or 64-bit x86. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini Message-Id: <20220517092616.1272238-15-pbonzini@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20220527153603.887929-26-alex.bennee@linaro.org> --- configure | 30 ++++++++++++++++++++++-------- pc-bios/optionrom/Makefile | 2 -- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/configure b/configure index f509bce304..1ae5c950f0 100755 --- a/configure +++ b/configure @@ -2082,6 +2082,13 @@ probe_target_compiler() { fi } +probe_target_compilers() { + for i; do + probe_target_compiler $i + test -n "$target_cc" && return 0 + done +} + write_target_makefile() { if test -n "$target_cc"; then echo "CC=$target_cc" @@ -2190,6 +2197,10 @@ if test "$QEMU_GA_VERSION" = ""; then QEMU_GA_VERSION=$(cat $source_path/VERSION) fi + +####################################### +# cross-compiled firmware targets + # Set up build tree symlinks that point back into the source tree # (these can be both files and directories). # Caution: avoid adding files or directories here using wildcards. This @@ -2216,19 +2227,27 @@ done # Mac OS X ships with a broken assembler roms= -if { test "$cpu" = "i386" || test "$cpu" = "x86_64"; } && \ +probe_target_compilers i386 x86_64 +if test -n "$target_cc" && test "$targetos" != "darwin" && test "$targetos" != "sunos" && \ test "$targetos" != "haiku" && test "$softmmu" = yes ; then # Different host OS linkers have different ideas about the name of the ELF # emulation. Linux and OpenBSD/amd64 use 'elf_i386'; FreeBSD uses the _fbsd # variant; OpenBSD/i386 uses the _obsd variant; and Windows uses i386pe. for emu in elf_i386 elf_i386_fbsd elf_i386_obsd i386pe; do - if "$ld" -verbose 2>&1 | grep -q "^[[:space:]]*$emu[[:space:]]*$"; then + if "$target_ld" -verbose 2>&1 | grep -q "^[[:space:]]*$emu[[:space:]]*$"; then ld_i386_emulation="$emu" - roms="optionrom" break fi done + if test -n "$ld_i386_emulation"; then + roms="optionrom" + config_mak=pc-bios/optionrom/config.mak + echo "# Automatically generated by configure - do not modify" > $config_mak + echo "TOPSRC_DIR=$source_path" >> $config_mak + echo "LD_I386_EMULATION=$ld_i386_emulation" >> $config_mak + write_target_makefile >> $config_mak + fi fi # Only build s390-ccw bios if the compiler has -march=z900 or -march=z10 @@ -2381,7 +2400,6 @@ echo "GLIB_LIBS=$glib_libs" >> $config_host_mak echo "GLIB_BINDIR=$glib_bindir" >> $config_host_mak echo "GLIB_VERSION=$(pkg-config --modversion glib-2.0)" >> $config_host_mak echo "QEMU_LDFLAGS=$QEMU_LDFLAGS" >> $config_host_mak -echo "LD_I386_EMULATION=$ld_i386_emulation" >> $config_host_mak echo "STRIP=$strip" >> $config_host_mak echo "EXESUF=$EXESUF" >> $config_host_mak @@ -2571,10 +2589,6 @@ for target in $target_list; do done echo "TCG_TESTS_TARGETS=$tcg_tests_targets" >> $makefile) -config_mak=pc-bios/optionrom/config.mak -echo "# Automatically generated by configure - do not modify" > $config_mak -echo "TOPSRC_DIR=$source_path" >> $config_mak - if test "$skip_meson" = no; then cross="config-meson.cross.new" meson_quote() { diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile index 17ccc76241..f639915b4f 100644 --- a/pc-bios/optionrom/Makefile +++ b/pc-bios/optionrom/Makefile @@ -6,7 +6,6 @@ all: multiboot.bin multiboot_dma.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bi # Dummy command so that make thinks it has done something @true -include ../../config-host.mak CFLAGS = -O2 -g quiet-command = $(if $(V),$1,$(if $(2),@printf " %-7s %s\n" $2 $3 && $1, @$1)) @@ -44,7 +43,6 @@ Wa = -Wa, override ASFLAGS += -32 override CFLAGS += $(call cc-option, $(Wa)-32) -LD_I386_EMULATION ?= elf_i386 override LDFLAGS = -m $(LD_I386_EMULATION) -T $(SRC_DIR)/flat.lds pvh.img: pvh.o pvh_main.o From d695918f7bd92604e561b6963e4ca9aef83f489b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 May 2022 16:35:56 +0100 Subject: [PATCH 727/935] configure: enable cross compilation of vof MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While container-based cross compilers are not supported, this already makes it possible to build vof on any machine that has an installation of GCC and binutils for 32- or 64-bit PowerPC. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini Message-Id: <20220517092616.1272238-16-pbonzini@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20220527153603.887929-27-alex.bennee@linaro.org> --- configure | 10 ++++++++++ pc-bios/vof/Makefile | 17 +++++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/configure b/configure index 1ae5c950f0..11e7f30553 100755 --- a/configure +++ b/configure @@ -2213,6 +2213,7 @@ LINKS="Makefile" LINKS="$LINKS tests/tcg/Makefile.target" LINKS="$LINKS pc-bios/optionrom/Makefile" LINKS="$LINKS pc-bios/s390-ccw/Makefile" +LINKS="$LINKS pc-bios/vof/Makefile" LINKS="$LINKS .gdbinit scripts" # scripts needed by relative path in .gdbinit LINKS="$LINKS tests/avocado tests/data" LINKS="$LINKS tests/qemu-iotests/check" @@ -2250,6 +2251,15 @@ if test -n "$target_cc" && fi fi +probe_target_compilers ppc ppc64 +if test -n "$target_cc" && test "$softmmu" = yes; then + roms="$roms vof" + config_mak=pc-bios/vof/config.mak + echo "# Automatically generated by configure - do not modify" > $config_mak + echo "SRC_DIR=$source_path/pc-bios/vof" >> $config_mak + write_target_makefile >> $config_mak +fi + # Only build s390-ccw bios if the compiler has -march=z900 or -march=z10 # (which is the lowest architecture level that Clang supports) probe_target_compiler s390x diff --git a/pc-bios/vof/Makefile b/pc-bios/vof/Makefile index aa1678c4d8..391ac0d600 100644 --- a/pc-bios/vof/Makefile +++ b/pc-bios/vof/Makefile @@ -1,11 +1,10 @@ -all: build-all +include config.mak +VPATH=$(SRC_DIR) +all: vof.bin -build-all: vof.bin - -CROSS ?= -CC = $(CROSS)gcc -LD = $(CROSS)ld -OBJCOPY = $(CROSS)objcopy +CC ?= $(CROSS)gcc +LD ?= $(CROSS)ld +OBJCOPY ?= $(CROSS)objcopy %.o: %.S $(CC) -m32 -mbig-endian -mcpu=power4 -c -o $@ $< @@ -14,10 +13,12 @@ OBJCOPY = $(CROSS)objcopy $(CC) -m32 -mbig-endian -mcpu=power4 -c -fno-stack-protector -o $@ $< vof.elf: entry.o main.o ci.o bootmem.o libc.o - $(LD) -nostdlib -e_start -Tvof.lds -EB -o $@ $^ + $(LD) -nostdlib -e_start -T$(SRC_DIR)/vof.lds -EB -o $@ $^ %.bin: %.elf $(OBJCOPY) -O binary -j .text -j .data -j .toc -j .got2 $^ $@ clean: rm -f *.o vof.bin vof.elf *~ + +.PHONY: all clean From f21db42631ae1f3feaa3bf94edd9c06c24b4aeb6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 May 2022 16:35:57 +0100 Subject: [PATCH 728/935] configure: remove unused variables from config-host.mak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only compiler variable that is still needed is $(CC), for contrib/plugins/Makefile. All firmware builds have their own config-host.mak file. Signed-off-by: Paolo Bonzini Message-Id: <20220517092616.1272238-17-pbonzini@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20220527153603.887929-28-alex.bennee@linaro.org> --- configure | 6 ------ 1 file changed, 6 deletions(-) diff --git a/configure b/configure index 11e7f30553..b9ccff9067 100755 --- a/configure +++ b/configure @@ -2397,11 +2397,6 @@ echo "GENISOIMAGE=$genisoimage" >> $config_host_mak echo "MESON=$meson" >> $config_host_mak echo "NINJA=$ninja" >> $config_host_mak echo "CC=$cc" >> $config_host_mak -echo "AR=$ar" >> $config_host_mak -echo "AS=$as" >> $config_host_mak -echo "CCAS=$ccas" >> $config_host_mak -echo "OBJCOPY=$objcopy" >> $config_host_mak -echo "LD=$ld" >> $config_host_mak echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak echo "QEMU_CXXFLAGS=$QEMU_CXXFLAGS" >> $config_host_mak echo "QEMU_OBJCFLAGS=$QEMU_OBJCFLAGS" >> $config_host_mak @@ -2410,7 +2405,6 @@ echo "GLIB_LIBS=$glib_libs" >> $config_host_mak echo "GLIB_BINDIR=$glib_bindir" >> $config_host_mak echo "GLIB_VERSION=$(pkg-config --modversion glib-2.0)" >> $config_host_mak echo "QEMU_LDFLAGS=$QEMU_LDFLAGS" >> $config_host_mak -echo "STRIP=$strip" >> $config_host_mak echo "EXESUF=$EXESUF" >> $config_host_mak # use included Linux headers From 6a0e7ea7b87cfa684bbcebaebafaef14c29a8872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 27 May 2022 16:35:58 +0100 Subject: [PATCH 729/935] gitlab: introduce a common base job template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently job rules are spread across the various templates and jobs, making it hard to understand exactly what runs in what scenario. This leads to inconsistency in the rules and increased maint burden. The intent is that we introduce a common '.base_job_template' which will have a general purpose 'rules:' block. No other template or job should define 'rules:', but instead they must rely on the inherited rules. To allow behaviour to be tweaked, rules will be influenced by a number of variables with the naming scheme 'QEMU_JOB_nnnn'. Signed-off-by: Daniel P. Berrangé Message-Id: <20220526110705.59952-2-berrange@redhat.com> Signed-off-by: Alex Bennée Reviewed-by: Thomas Huth Message-Id: <20220527153603.887929-29-alex.bennee@linaro.org> --- .gitlab-ci.d/base.yml | 28 +++++++++++++++++++++++++++ .gitlab-ci.d/qemu-project.yml | 1 + docs/devel/ci-jobs.rst.inc | 36 ++++++++++++++++++++++++++++++++++- 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 .gitlab-ci.d/base.yml diff --git a/.gitlab-ci.d/base.yml b/.gitlab-ci.d/base.yml new file mode 100644 index 0000000000..10eb6ab8bc --- /dev/null +++ b/.gitlab-ci.d/base.yml @@ -0,0 +1,28 @@ + +# The order of rules defined here is critically important. +# They are evaluated in order and first match wins. +# +# Thus we group them into a number of stages, ordered from +# most restrictive to least restrictive +# +.base_job_template: + rules: + ############################################################# + # Stage 1: exclude scenarios where we definitely don't + # want jobs to run + ############################################################# + + + ############################################################# + # Stage 2: fine tune execution of jobs in specific scenarios + # where the catch all logic is inapprorpaite + ############################################################# + + + ############################################################# + # Stage 3: catch all logic applying to any job not matching + # an earlier criteria + ############################################################# + + # Jobs can run if any jobs they depend on were successfull + - when: on_success diff --git a/.gitlab-ci.d/qemu-project.yml b/.gitlab-ci.d/qemu-project.yml index 871262fe0e..691d9bf5dc 100644 --- a/.gitlab-ci.d/qemu-project.yml +++ b/.gitlab-ci.d/qemu-project.yml @@ -2,6 +2,7 @@ # https://gitlab.com/qemu-project/qemu/-/pipelines include: + - local: '/.gitlab-ci.d/base.yml' - local: '/.gitlab-ci.d/stages.yml' - local: '/.gitlab-ci.d/edk2.yml' - local: '/.gitlab-ci.d/opensbi.yml' diff --git a/docs/devel/ci-jobs.rst.inc b/docs/devel/ci-jobs.rst.inc index 92e25872aa..eb6a9e6122 100644 --- a/docs/devel/ci-jobs.rst.inc +++ b/docs/devel/ci-jobs.rst.inc @@ -28,7 +28,35 @@ For further information about how to set these variables, please refer to:: https://docs.gitlab.com/ee/user/project/push_options.html#push-options-for-gitlab-cicd -Here is a list of the most used variables: +Variable naming and grouping +---------------------------- + +The variables used by QEMU's CI configuration are grouped together +in a handful of namespaces + + * QEMU_JOB_nnnn - variables to be defined in individual jobs + or templates, to influence the shared rules defined in the + .base_job_template. + + * QEMU_CI_nnn - variables to be set by contributors in their + repository CI settings, or as git push variables, to influence + which jobs get run in a pipeline + + * nnn - other misc variables not falling into the above + categories, or using different names for historical reasons + and not yet converted. + +Maintainer controlled job variables +----------------------------------- + +The following variables may be set when defining a job in the +CI configuration file. + +Contributor controlled runtime variables +---------------------------------------- + +The following variables may be set by contributors to control +job execution QEMU_CI_AVOCADO_TESTING ~~~~~~~~~~~~~~~~~~~~~~~ @@ -38,6 +66,12 @@ these artifacts are not already cached, downloading them make the jobs reach the timeout limit). Set this variable to have the tests using the Avocado framework run automatically. +Other misc variables +-------------------- + +These variables are primarily to control execution of jobs on +private runners + AARCH64_RUNNER_AVAILABLE ~~~~~~~~~~~~~~~~~~~~~~~~ If you've got access to an aarch64 host that can be used as a gitlab-CI From 00125414ba1b9d04dfec3af6fb75e39591b53892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 27 May 2022 16:35:59 +0100 Subject: [PATCH 730/935] gitlab: convert Cirrus jobs to .base_job_template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This folds the Cirrus job rules into the base job template, introducing two new variables - QEMU_JOB_CIRRUS - identifies the job as making use of Cirrus CI via cirrus-run - QEMU_JOB_OPTIONAL - identifies the job as one that is not run by default, primarily due to resource constraints. It can be manually invoked by users if they wish to validate that scenario. Signed-off-by: Daniel P. Berrangé Message-Id: <20220526110705.59952-3-berrange@redhat.com> Signed-off-by: Alex Bennée Reviewed-by: Thomas Huth Message-Id: <20220527153603.887929-30-alex.bennee@linaro.org> --- .gitlab-ci.d/base.yml | 9 +++++++++ .gitlab-ci.d/cirrus.yml | 16 ++++++++-------- docs/devel/ci-jobs.rst.inc | 14 ++++++++++++++ 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/.gitlab-ci.d/base.yml b/.gitlab-ci.d/base.yml index 10eb6ab8bc..5734caf9fe 100644 --- a/.gitlab-ci.d/base.yml +++ b/.gitlab-ci.d/base.yml @@ -12,12 +12,21 @@ # want jobs to run ############################################################# + # Cirrus jobs can't run unless the creds / target repo are set + - if: '$QEMU_JOB_CIRRUS && ($CIRRUS_GITHUB_REPO == "" || $CIRRUS_API_TOKEN == "")' + when: never + ############################################################# # Stage 2: fine tune execution of jobs in specific scenarios # where the catch all logic is inapprorpaite ############################################################# + # Optional jobs should not be run unless manually triggered + - if: '$QEMU_JOB_OPTIONAL' + when: manual + allow_failure: true + ############################################################# # Stage 3: catch all logic applying to any job not matching diff --git a/.gitlab-ci.d/cirrus.yml b/.gitlab-ci.d/cirrus.yml index b96b22e269..609c364308 100644 --- a/.gitlab-ci.d/cirrus.yml +++ b/.gitlab-ci.d/cirrus.yml @@ -11,6 +11,7 @@ # special care, because we can't just override it at the GitLab CI job # definition level or we risk breaking it completely. .cirrus_build_job: + extends: .base_job_template stage: build image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:master needs: [] @@ -40,11 +41,8 @@ <.gitlab-ci.d/cirrus/build.yml >.gitlab-ci.d/cirrus/$NAME.yml - cat .gitlab-ci.d/cirrus/$NAME.yml - cirrus-run -v --show-build-log always .gitlab-ci.d/cirrus/$NAME.yml - rules: - # Allow on 'staging' branch and 'stable-X.Y-staging' branches only - - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH !~ /staging/' - when: never - - if: "$CIRRUS_GITHUB_REPO && $CIRRUS_API_TOKEN" + variables: + QEMU_JOB_CIRRUS: 1 x64-freebsd-12-build: extends: .cirrus_build_job @@ -90,11 +88,11 @@ x64-macos-11-base-build: # The following jobs run VM-based tests via KVM on a Linux-based Cirrus-CI job .cirrus_kvm_job: + extends: .base_job_template stage: build image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:master needs: [] timeout: 80m - allow_failure: true script: - sed -e "s|[@]CI_REPOSITORY_URL@|$CI_REPOSITORY_URL|g" -e "s|[@]CI_COMMIT_REF_NAME@|$CI_COMMIT_REF_NAME|g" @@ -105,8 +103,10 @@ x64-macos-11-base-build: <.gitlab-ci.d/cirrus/kvm-build.yml >.gitlab-ci.d/cirrus/$NAME.yml - cat .gitlab-ci.d/cirrus/$NAME.yml - cirrus-run -v --show-build-log always .gitlab-ci.d/cirrus/$NAME.yml - rules: - - when: manual + variables: + QEMU_JOB_CIRRUS: 1 + QEMU_JOB_OPTIONAL: 1 + x86-netbsd: extends: .cirrus_kvm_job diff --git a/docs/devel/ci-jobs.rst.inc b/docs/devel/ci-jobs.rst.inc index eb6a9e6122..a539f502da 100644 --- a/docs/devel/ci-jobs.rst.inc +++ b/docs/devel/ci-jobs.rst.inc @@ -52,6 +52,20 @@ Maintainer controlled job variables The following variables may be set when defining a job in the CI configuration file. +QEMU_JOB_CIRRUS +~~~~~~~~~~~~~~~ + +The job makes use of Cirrus CI infrastructure, requiring the +configuration setup for cirrus-run to be present in the repository + +QEMU_JOB_OPTIONAL +~~~~~~~~~~~~~~~~~ + +The job is expected to be successful in general, but is not run +by default due to need to conserve limited CI resources. It is +available to be started manually by the contributor in the CI +pipelines UI. + Contributor controlled runtime variables ---------------------------------------- From 16fee101d9011ea5dfd56a055d19df802e59eb29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 27 May 2022 16:36:00 +0100 Subject: [PATCH 731/935] gitlab: convert static checks to .base_job_template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This folds the static checks into using the base job template rules, introducing one new variable - QEMU_JOB_ONLY_FORKS - a job that should never run on an upstream pipeline. The information it reports is only applicable to contributors in a pre-submission scenario, not time of merge. Signed-off-by: Daniel P. Berrangé Message-Id: <20220526110705.59952-4-berrange@redhat.com> [AJB: fix typo] Signed-off-by: Alex Bennée Reviewed-by: Thomas Huth Message-Id: <20220527153603.887929-31-alex.bennee@linaro.org> --- .gitlab-ci.d/base.yml | 4 ++++ .gitlab-ci.d/static_checks.yml | 19 +++++++------------ docs/devel/ci-jobs.rst.inc | 7 +++++++ 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/.gitlab-ci.d/base.yml b/.gitlab-ci.d/base.yml index 5734caf9fe..e6953c77ae 100644 --- a/.gitlab-ci.d/base.yml +++ b/.gitlab-ci.d/base.yml @@ -16,6 +16,10 @@ - if: '$QEMU_JOB_CIRRUS && ($CIRRUS_GITHUB_REPO == "" || $CIRRUS_API_TOKEN == "")' when: never + # Jobs only intended for forks should always be skipped on upstream + - if: '$QEMU_JOB_ONLY_FORKS == "1" && $CI_PROJECT_NAMESPACE == "qemu-project"' + when: never + ############################################################# # Stage 2: fine tune execution of jobs in specific scenarios diff --git a/.gitlab-ci.d/static_checks.yml b/.gitlab-ci.d/static_checks.yml index 94858e3272..289ad1359e 100644 --- a/.gitlab-ci.d/static_checks.yml +++ b/.gitlab-ci.d/static_checks.yml @@ -1,4 +1,5 @@ check-patch: + extends: .base_job_template stage: build image: python:3.10-alpine needs: [] @@ -6,15 +7,13 @@ check-patch: - .gitlab-ci.d/check-patch.py variables: GIT_DEPTH: 1000 + QEMU_JOB_ONLY_FORKS: 1 before_script: - apk -U add git perl - rules: - - if: '$CI_PROJECT_NAMESPACE == "qemu-project"' - when: never - - when: on_success - allow_failure: true + allow_failure: true check-dco: + extends: .base_job_template stage: build image: python:3.10-alpine needs: [] @@ -23,12 +22,9 @@ check-dco: GIT_DEPTH: 1000 before_script: - apk -U add git - rules: - - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' - when: never - - when: on_success check-python-pipenv: + extends: .base_job_template stage: test image: $CI_REGISTRY_IMAGE/qemu/python:latest script: @@ -39,6 +35,7 @@ check-python-pipenv: job: python-container check-python-tox: + extends: .base_job_template stage: test image: $CI_REGISTRY_IMAGE/qemu/python:latest script: @@ -46,8 +43,6 @@ check-python-tox: variables: GIT_DEPTH: 1 QEMU_TOX_EXTRA_ARGS: --skip-missing-interpreters=false + QEMU_JOB_OPTIONAL: 1 needs: job: python-container - rules: - - when: manual - allow_failure: true diff --git a/docs/devel/ci-jobs.rst.inc b/docs/devel/ci-jobs.rst.inc index a539f502da..4c7e30ab08 100644 --- a/docs/devel/ci-jobs.rst.inc +++ b/docs/devel/ci-jobs.rst.inc @@ -66,6 +66,13 @@ by default due to need to conserve limited CI resources. It is available to be started manually by the contributor in the CI pipelines UI. +QEMU_JOB_ONLY_FORKS +~~~~~~~~~~~~~~~~~~~ + +The job results are only of interest to contributors prior to +submitting code. They are not required as part of the gating +CI pipeline. + Contributor controlled runtime variables ---------------------------------------- From e312d1fdbbb3a53ee30ab84203344588154129f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 27 May 2022 16:36:01 +0100 Subject: [PATCH 732/935] gitlab: convert build/container jobs to .base_job_template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This converts the main build and container jobs to use the base job rules, defining the following new variables - QEMU_JOB_SKIPPED - jobs that are known to be currently broken and should not be run. Can still be manually launched if desired. - QEMU_JOB_AVOCADO - jobs that run the Avocado integration test harness. - QEMU_JOB_PUBLISH - jobs that publish content after the branch is merged upstream As build-tools-and-docs runs on master we declare the requirement of building amd64-debian-container optional as it should already exits once we merge. Signed-off-by: Daniel P. Berrangé Message-Id: <20220526110705.59952-5-berrange@redhat.com> [AJB: fix upstream typo, mention optional container req] Signed-off-by: Alex Bennée Reviewed-by: Thomas Huth Message-Id: <20220527153603.887929-32-alex.bennee@linaro.org> --- .gitlab-ci.d/base.yml | 22 ++++++++++++++++++++++ .gitlab-ci.d/buildtest-template.yml | 16 ++++------------ .gitlab-ci.d/buildtest.yml | 28 +++++++++++++--------------- .gitlab-ci.d/container-cross.yml | 6 ++---- .gitlab-ci.d/container-template.yml | 1 + .gitlab-ci.d/crossbuild-template.yml | 3 +++ .gitlab-ci.d/windows.yml | 1 + docs/devel/ci-jobs.rst.inc | 19 +++++++++++++++++++ 8 files changed, 65 insertions(+), 31 deletions(-) diff --git a/.gitlab-ci.d/base.yml b/.gitlab-ci.d/base.yml index e6953c77ae..4f091d5aad 100644 --- a/.gitlab-ci.d/base.yml +++ b/.gitlab-ci.d/base.yml @@ -16,10 +16,22 @@ - if: '$QEMU_JOB_CIRRUS && ($CIRRUS_GITHUB_REPO == "" || $CIRRUS_API_TOKEN == "")' when: never + # Publishing jobs should only run on the default branch in upstream + - if: '$QEMU_JOB_PUBLISH == "1" && $CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH' + when: never + + # Non-publishing jobs should only run on staging branches in upstream + - if: '$QEMU_JOB_PUBLISH != "1" && $CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH !~ /staging/' + when: never + # Jobs only intended for forks should always be skipped on upstream - if: '$QEMU_JOB_ONLY_FORKS == "1" && $CI_PROJECT_NAMESPACE == "qemu-project"' when: never + # Avocado jobs don't run in forks unless $QEMU_CI_AVOCADO_TESTING is set + - if: '$QEMU_JOB_AVOCADO && $QEMU_CI_AVOCADO_TESTING != "1" && $CI_PROJECT_NAMESPACE != "qemu-project"' + when: never + ############################################################# # Stage 2: fine tune execution of jobs in specific scenarios @@ -31,6 +43,16 @@ when: manual allow_failure: true + # Skipped jobs should not be run unless manually triggered + - if: '$QEMU_JOB_SKIPPED' + when: manual + allow_failure: true + + # Avocado jobs can be manually start in forks if $QEMU_CI_AVOCADO_TESTING is unset + - if: '$QEMU_JOB_AVOCADO && $CI_PROJECT_NAMESPACE != "qemu-project"' + when: manual + allow_failure: true + ############################################################# # Stage 3: catch all logic applying to any job not matching diff --git a/.gitlab-ci.d/buildtest-template.yml b/.gitlab-ci.d/buildtest-template.yml index b381345dbc..73ecfabb8d 100644 --- a/.gitlab-ci.d/buildtest-template.yml +++ b/.gitlab-ci.d/buildtest-template.yml @@ -1,4 +1,5 @@ .native_build_job_template: + extends: .base_job_template stage: build image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest before_script: @@ -27,6 +28,7 @@ fi .common_test_job_template: + extends: .base_job_template stage: test image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest script: @@ -77,15 +79,5 @@ after_script: - cd build - du -chs ${CI_PROJECT_DIR}/avocado-cache - rules: - # Only run these jobs if running on the mainstream namespace, - # or if the user set the QEMU_CI_AVOCADO_TESTING variable (either - # in its namespace setting or via git-push option, see documentation - # in /.gitlab-ci.yml of this repository). - - if: '$CI_PROJECT_NAMESPACE == "qemu-project"' - when: on_success - - if: '$QEMU_CI_AVOCADO_TESTING' - when: on_success - # Otherwise, set to manual (the jobs are created but not run). - - when: manual - allow_failure: true + variables: + QEMU_JOB_AVOCADO: 1 diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index e9620c3074..ecac3ec50c 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -360,12 +360,11 @@ build-cfi-aarch64: expire_in: 2 days paths: - build - rules: + variables: # FIXME: This job is often failing, likely due to out-of-memory problems in # the constrained containers of the shared runners. Thus this is marked as - # manual until the situation has been solved. - - when: manual - allow_failure: true + # skipped until the situation has been solved. + QEMU_JOB_SKIPPED: 1 check-cfi-aarch64: extends: .native_test_job_template @@ -402,12 +401,11 @@ build-cfi-ppc64-s390x: expire_in: 2 days paths: - build - rules: + variables: # FIXME: This job is often failing, likely due to out-of-memory problems in # the constrained containers of the shared runners. Thus this is marked as - # manual until the situation has been solved. - - when: manual - allow_failure: true + # skipped until the situation has been solved. + QEMU_JOB_SKIPPED: 1 check-cfi-ppc64-s390x: extends: .native_test_job_template @@ -579,6 +577,7 @@ build-without-default-features: MAKE_CHECK_ARGS: check-unit check-qtest SPEED=slow build-libvhost-user: + extends: .base_job_template stage: build image: $CI_REGISTRY_IMAGE/qemu/fedora:latest needs: @@ -595,10 +594,13 @@ build-tools-and-docs-debian: extends: .native_build_job_template needs: job: amd64-debian-container + # when running on 'master' we use pre-existing container + optional: true variables: IMAGE: debian-amd64 MAKE_CHECK_ARGS: check-unit check-softfloat ctags TAGS cscope CONFIGURE_ARGS: --disable-system --disable-user --enable-docs --enable-tools + QEMU_JOB_PUBLISH: 1 artifacts: expire_in: 2 days paths: @@ -618,6 +620,7 @@ build-tools-and-docs-debian: # that users can see the results of their commits, regardless # of what topic branch they're currently using pages: + extends: .base_job_template image: $CI_REGISTRY_IMAGE/qemu/debian-amd64:latest stage: test needs: @@ -635,10 +638,5 @@ pages: artifacts: paths: - public - rules: - - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' - when: on_success - - if: '$CI_PROJECT_NAMESPACE == "qemu-project"' - when: never - - if: '$CI_PROJECT_NAMESPACE != "qemu-project"' - when: on_success + variables: + QEMU_JOB_PUBLISH: 1 diff --git a/.gitlab-ci.d/container-cross.yml b/.gitlab-ci.d/container-cross.yml index 147e667744..b7963498a3 100644 --- a/.gitlab-ci.d/container-cross.yml +++ b/.gitlab-ci.d/container-cross.yml @@ -40,15 +40,13 @@ armhf-debian-cross-container: # We never want to build hexagon in the CI system and by default we # always want to refer to the master registry where it lives. hexagon-cross-container: + extends: .base_job_template image: docker:stable stage: containers - rules: - - if: '$CI_PROJECT_NAMESPACE == "qemu-project"' - when: never - - when: always variables: NAME: debian-hexagon-cross GIT_DEPTH: 1 + QEMU_JOB_ONLY_FORKS: 1 services: - docker:dind before_script: diff --git a/.gitlab-ci.d/container-template.yml b/.gitlab-ci.d/container-template.yml index 1baecd9460..c434b9c8f3 100644 --- a/.gitlab-ci.d/container-template.yml +++ b/.gitlab-ci.d/container-template.yml @@ -1,4 +1,5 @@ .container_job_template: + extends: .base_job_template image: docker:stable stage: containers services: diff --git a/.gitlab-ci.d/crossbuild-template.yml b/.gitlab-ci.d/crossbuild-template.yml index 29c3c2b826..28b2142ec2 100644 --- a/.gitlab-ci.d/crossbuild-template.yml +++ b/.gitlab-ci.d/crossbuild-template.yml @@ -1,4 +1,5 @@ .cross_system_build_job: + extends: .base_job_template stage: build image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest timeout: 80m @@ -24,6 +25,7 @@ # KVM), and set extra options (such disabling other accelerators) via the # $EXTRA_CONFIGURE_OPTS variable. .cross_accel_build_job: + extends: .base_job_template stage: build image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest timeout: 30m @@ -36,6 +38,7 @@ - make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS .cross_user_build_job: + extends: .base_job_template stage: build image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest script: diff --git a/.gitlab-ci.d/windows.yml b/.gitlab-ci.d/windows.yml index cf7724b8e5..1b2ede49e1 100644 --- a/.gitlab-ci.d/windows.yml +++ b/.gitlab-ci.d/windows.yml @@ -1,4 +1,5 @@ .shared_msys2_builder: + extends: .base_job_template tags: - shared-windows - windows diff --git a/docs/devel/ci-jobs.rst.inc b/docs/devel/ci-jobs.rst.inc index 4c7e30ab08..0b4926e537 100644 --- a/docs/devel/ci-jobs.rst.inc +++ b/docs/devel/ci-jobs.rst.inc @@ -73,6 +73,25 @@ The job results are only of interest to contributors prior to submitting code. They are not required as part of the gating CI pipeline. +QEMU_JOB_SKIPPED +~~~~~~~~~~~~~~~~ + +The job is not reliably successsful in general, so is not +currently suitable to be run by default. Ideally this should +be a temporary marker until the problems can be addressed, or +the job permanently removed. + +QEMU_JOB_PUBLISH +~~~~~~~~~~~~~~~~ + +The job is for publishing content after a branch has been +merged into the upstream default branch. + +QEMU_JOB_AVOCADO +~~~~~~~~~~~~~~~~ + +The job runs the Avocado integration test suite + Contributor controlled runtime variables ---------------------------------------- From 28357dc525b4798cdef1101cbb459afcd7233280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 27 May 2022 16:36:02 +0100 Subject: [PATCH 733/935] gitlab: don't run CI jobs in forks by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To preserve CI shared runner credits we don't want to run pipelines on every push. This sets up the config so that pipelines are never created for contributors by default. To override this the QEMU_CI variable can be set to a non-zero value. If set to 1, the pipeline will be created but all jobs will remain manually started. The contributor can selectively run jobs that they care about. If set to 2, the pipeline will be created and all jobs will immediately start. This behavior can be controlled using push variables git push -o ci.variable=QEMU_CI=1 To make this more convenient define an alias git config --local alias.push-ci "push -o ci.variable=QEMU_CI=1" git config --local alias.push-ci-now "push -o ci.variable=QEMU_CI=2" Which lets you run git push-ci to create the pipeline, or git push-ci-now to create and run the pipeline Signed-off-by: Daniel P. Berrangé Message-Id: <20220526110705.59952-6-berrange@redhat.com> [AJB: fix typo, replicate alias tips in ci.rst] Signed-off-by: Alex Bennée Reviewed-by: Thomas Huth Message-Id: <20220527153603.887929-33-alex.bennee@linaro.org> --- .gitlab-ci.d/base.yml | 9 +++++++++ docs/devel/ci-jobs.rst.inc | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/.gitlab-ci.d/base.yml b/.gitlab-ci.d/base.yml index 4f091d5aad..f334f3ded7 100644 --- a/.gitlab-ci.d/base.yml +++ b/.gitlab-ci.d/base.yml @@ -28,6 +28,10 @@ - if: '$QEMU_JOB_ONLY_FORKS == "1" && $CI_PROJECT_NAMESPACE == "qemu-project"' when: never + # Forks don't get pipelines unless QEMU_CI=1 or QEMU_CI=2 is set + - if: '$QEMU_CI != "1" && $QEMU_CI != "2" && $CI_PROJECT_NAMESPACE != "qemu-project"' + when: never + # Avocado jobs don't run in forks unless $QEMU_CI_AVOCADO_TESTING is set - if: '$QEMU_JOB_AVOCADO && $QEMU_CI_AVOCADO_TESTING != "1" && $CI_PROJECT_NAMESPACE != "qemu-project"' when: never @@ -59,5 +63,10 @@ # an earlier criteria ############################################################# + # Forks pipeline jobs don't start automatically unless + # QEMU_CI=2 is set + - if: '$QEMU_CI != "2" && $CI_PROJECT_NAMESPACE != "qemu-project"' + when: manual + # Jobs can run if any jobs they depend on were successfull - when: on_success diff --git a/docs/devel/ci-jobs.rst.inc b/docs/devel/ci-jobs.rst.inc index 0b4926e537..9118a61a17 100644 --- a/docs/devel/ci-jobs.rst.inc +++ b/docs/devel/ci-jobs.rst.inc @@ -28,6 +28,32 @@ For further information about how to set these variables, please refer to:: https://docs.gitlab.com/ee/user/project/push_options.html#push-options-for-gitlab-cicd +Setting aliases in your git config +---------------------------------- + +You can use aliases to make it easier to push branches with different +CI configurations. For example define an alias for triggering CI: + +.. code:: + + git config --local alias.push-ci "push -o ci.variable=QEMU_CI=1" + git config --local alias.push-ci-now "push -o ci.variable=QEMU_CI=2" + +Which lets you run: + +.. code:: + + git push-ci + +to create the pipeline, or: + +.. code:: + + git push-ci-now + +to create and run the pipeline + + Variable naming and grouping ---------------------------- @@ -98,6 +124,18 @@ Contributor controlled runtime variables The following variables may be set by contributors to control job execution +QEMU_CI +~~~~~~~ + +By default, no pipelines will be created on contributor forks +in order to preserve CI credits + +Set this variable to 1 to create the pipelines, but leave all +the jobs to be manually started from the UI + +Set this variable to 2 to create the pipelines and run all +the jobs immediately, as was historicaly behaviour + QEMU_CI_AVOCADO_TESTING ~~~~~~~~~~~~~~~~~~~~~~~ By default, tests using the Avocado framework are not run automatically in From 7266ecce502c31387a3cbf83d7297bc9cf27b139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 27 May 2022 16:36:03 +0100 Subject: [PATCH 734/935] docs/devel: clean-up the CI links in the docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There where some broken links so fix those up with proper references to the devel docs. I also did a little light copy-editing to reflect the current state and broke up a paragraph to reduce the "wall of text" effect. Signed-off-by: Alex Bennée Reviewed-by: Daniel P. Berrangé Message-Id: <20220527153603.887929-34-alex.bennee@linaro.org> --- docs/devel/ci-jobs.rst.inc | 2 ++ docs/devel/ci.rst | 11 +++++----- docs/devel/submitting-a-patch.rst | 36 ++++++++++++++++--------------- docs/devel/testing.rst | 2 ++ 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/docs/devel/ci-jobs.rst.inc b/docs/devel/ci-jobs.rst.inc index 9118a61a17..1f28fec0d0 100644 --- a/docs/devel/ci-jobs.rst.inc +++ b/docs/devel/ci-jobs.rst.inc @@ -1,3 +1,5 @@ +.. _ci_var: + Custom CI/CD variables ====================== diff --git a/docs/devel/ci.rst b/docs/devel/ci.rst index d106610096..ed88a2010b 100644 --- a/docs/devel/ci.rst +++ b/docs/devel/ci.rst @@ -1,12 +1,13 @@ +.. _ci: + == CI == -QEMU has configurations enabled for a number of different CI services. -The most up to date information about them and their status can be -found at:: - - https://wiki.qemu.org/Testing/CI +Most of QEMU's CI is run on GitLab's infrastructure although a number +of other CI services are used for specialised purposes. The most up to +date information about them and their status can be found on the +`project wiki testing page `_. .. include:: ci-definitions.rst.inc .. include:: ci-jobs.rst.inc diff --git a/docs/devel/submitting-a-patch.rst b/docs/devel/submitting-a-patch.rst index e51259eb9c..d3876ec1b7 100644 --- a/docs/devel/submitting-a-patch.rst +++ b/docs/devel/submitting-a-patch.rst @@ -204,23 +204,25 @@ log`` for these keywords for example usage. Test your patches ~~~~~~~~~~~~~~~~~ -Although QEMU has `continuous integration -services `__ that attempt to test -patches submitted to the list, it still saves everyone time if you have -already tested that your patch compiles and works. Because QEMU is such -a large project, it's okay to use configure arguments to limit what is -built for faster turnaround during your development time; but it is -still wise to also check that your patches work with a full build before -submitting a series, especially if your changes might have an unintended -effect on other areas of the code you don't normally experiment with. -See `Testing `__ for more details on what tests are available. -Also, it is a wise idea to include a testsuite addition as part of your -patches - either to ensure that future changes won't regress your new -feature, or to add a test which exposes the bug that the rest of your -series fixes. Keeping separate commits for the test and the fix allows -reviewers to rebase the test to occur first to prove it catches the -problem, then again to place it last in the series so that bisection -doesn't land on a known-broken state. +Although QEMU uses various :ref:`ci` services that attempt to test +patches submitted to the list, it still saves everyone time if you +have already tested that your patch compiles and works. Because QEMU +is such a large project the default configuration won't create a +testing pipeline on GitLab when a branch is pushed. See the :ref:`CI +variable documentation` for details on how to control the +running of tests; but it is still wise to also check that your patches +work with a full build before submitting a series, especially if your +changes might have an unintended effect on other areas of the code you +don't normally experiment with. See :ref:`testing` for more details on +what tests are available. + +Also, it is a wise idea to include a testsuite addition as part of +your patches - either to ensure that future changes won't regress your +new feature, or to add a test which exposes the bug that the rest of +your series fixes. Keeping separate commits for the test and the fix +allows reviewers to rebase the test to occur first to prove it catches +the problem, then again to place it last in the series so that +bisection doesn't land on a known-broken state. .. _submitting_your_patches: diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst index 5b60a31807..3f6ebd5073 100644 --- a/docs/devel/testing.rst +++ b/docs/devel/testing.rst @@ -1,3 +1,5 @@ +.. _testing: + Testing in QEMU =============== From 4d84bb6c8b42cc781a02e1ac6648875966abc877 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 25 May 2022 08:59:04 -0400 Subject: [PATCH 735/935] hw/tpm/tpm_tis_common.c: Assert that locty is in range MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In tpm_tis_mmio_read(), tpm_tis_mmio_write() and tpm_tis_dump_state(), we calculate a locality index with tpm_tis_locality_from_addr() and then use it as an index into the s->loc[] array. In all these cases, the array index can't overflow because the MemoryRegion is sized to be TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT bytes. However, Coverity can't see that, and it complains (CID 1487138, 1487180, 1487188, 1487198, 1487240). Add an assertion to tpm_tis_locality_from_addr() that the calculated locality index is valid, which will help Coverity and also catch any potential future bug where the MemoryRegion isn't sized exactly. Signed-off-by: Peter Maydell Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau Message-id: 20220525125904.483075-1-stefanb@linux.ibm.com --- hw/tpm/tpm_tis_common.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/tpm/tpm_tis_common.c b/hw/tpm/tpm_tis_common.c index e700d82181..503be2a541 100644 --- a/hw/tpm/tpm_tis_common.c +++ b/hw/tpm/tpm_tis_common.c @@ -50,7 +50,12 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, static uint8_t tpm_tis_locality_from_addr(hwaddr addr) { - return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7); + uint8_t locty; + + locty = (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7); + assert(TPM_TIS_IS_VALID_LOCTY(locty)); + + return locty; } From 79e1d527e13d35b976c947c48a70c23ef3586e76 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 1 Jun 2022 18:33:45 -0700 Subject: [PATCH 736/935] target/m68k: Raise the TRAPn exception with the correct pc Rather than adjust the PC in all of the consumers, raise the exception with the correct PC in the first place. Reviewed-by: Laurent Vivier Signed-off-by: Richard Henderson Message-Id: <20220602013401.303699-2-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/m68k/cpu_loop.c | 1 - target/m68k/op_helper.c | 9 --------- target/m68k/translate.c | 2 +- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/linux-user/m68k/cpu_loop.c b/linux-user/m68k/cpu_loop.c index d1bf8548b7..56417f7401 100644 --- a/linux-user/m68k/cpu_loop.c +++ b/linux-user/m68k/cpu_loop.c @@ -56,7 +56,6 @@ void cpu_loop(CPUM68KState *env) { abi_long ret; n = env->dregs[0]; - env->pc += 2; ret = do_syscall(env, n, env->dregs[1], diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index 8decc61240..d30f988ae0 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -217,11 +217,6 @@ static void cf_interrupt_all(CPUM68KState *env, int is_hw) cpu_loop_exit(cs); return; } - if (cs->exception_index >= EXCP_TRAP0 - && cs->exception_index <= EXCP_TRAP15) { - /* Move the PC after the trap instruction. */ - retaddr += 2; - } } vector = cs->exception_index << 2; @@ -304,10 +299,6 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw) /* Return from an exception. */ m68k_rte(env); return; - case EXCP_TRAP0 ... EXCP_TRAP15: - /* Move the PC after the trap instruction. */ - retaddr += 2; - break; } } diff --git a/target/m68k/translate.c b/target/m68k/translate.c index e4efd988d2..22e5379d3c 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -4860,7 +4860,7 @@ DISAS_INSN(wdebug) DISAS_INSN(trap) { - gen_exception(s, s->base.pc_next, EXCP_TRAP0 + (insn & 0xf)); + gen_exception(s, s->pc, EXCP_TRAP0 + (insn & 0xf)); } static void gen_load_fcr(DisasContext *s, TCGv res, int reg) From 02ea42b36ddcd34739c9320ae2262b1d1e814a6d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 1 Jun 2022 18:33:46 -0700 Subject: [PATCH 737/935] target/m68k: Switch over exception type in m68k_interrupt_all MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace an if ladder with a switch for clarity. Reviewed-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-Id: <20220602013401.303699-3-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- target/m68k/op_helper.c | 49 +++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index d30f988ae0..2b94a6ec84 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -333,7 +333,8 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw) sp &= ~1; } - if (cs->exception_index == EXCP_ACCESS) { + switch (cs->exception_index) { + case EXCP_ACCESS: if (env->mmu.fault) { cpu_abort(cs, "DOUBLE MMU FAULT\n"); } @@ -391,29 +392,39 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw) "ssw: %08x ea: %08x sfc: %d dfc: %d\n", env->mmu.ssw, env->mmu.ar, env->sfc, env->dfc); } - } else if (cs->exception_index == EXCP_ADDRESS) { + break; + + case EXCP_ADDRESS: do_stack_frame(env, &sp, 2, oldsr, 0, retaddr); - } else if (cs->exception_index == EXCP_ILLEGAL || - cs->exception_index == EXCP_DIV0 || - cs->exception_index == EXCP_CHK || - cs->exception_index == EXCP_TRAPCC || - cs->exception_index == EXCP_TRACE) { + break; + + case EXCP_ILLEGAL: + case EXCP_DIV0: + case EXCP_CHK: + case EXCP_TRAPCC: + case EXCP_TRACE: /* FIXME: addr is not only env->pc */ do_stack_frame(env, &sp, 2, oldsr, env->pc, retaddr); - } else if (is_hw && oldsr & SR_M && - cs->exception_index >= EXCP_SPURIOUS && - cs->exception_index <= EXCP_INT_LEVEL_7) { - do_stack_frame(env, &sp, 0, oldsr, 0, retaddr); - oldsr = sr; - env->aregs[7] = sp; - cpu_m68k_set_sr(env, sr &= ~SR_M); - sp = env->aregs[7]; - if (!m68k_feature(env, M68K_FEATURE_UNALIGNED_DATA)) { - sp &= ~1; + break; + + case EXCP_SPURIOUS ... EXCP_INT_LEVEL_7: + if (is_hw && oldsr & SR_M) { + do_stack_frame(env, &sp, 0, oldsr, 0, retaddr); + oldsr = sr; + env->aregs[7] = sp; + cpu_m68k_set_sr(env, sr &= ~SR_M); + sp = env->aregs[7]; + if (!m68k_feature(env, M68K_FEATURE_UNALIGNED_DATA)) { + sp &= ~1; + } + do_stack_frame(env, &sp, 1, oldsr, 0, retaddr); + break; } - do_stack_frame(env, &sp, 1, oldsr, 0, retaddr); - } else { + /* fall through */ + + default: do_stack_frame(env, &sp, 0, oldsr, 0, retaddr); + break; } env->aregs[7] = sp; From eeb8f7b0f84f86b5fa1e17aed851d758e1c7ee0f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 1 Jun 2022 18:33:47 -0700 Subject: [PATCH 738/935] target/m68k: Fix coding style in m68k_interrupt_all MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add parenthesis around & vs &&. Remove assignment to sr in function call argument -- note that sr is unused after the call, so the assignment was never needed, only the result of the & expression. Suggested-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Signed-off-by: Richard Henderson Message-Id: <20220602013401.303699-4-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- target/m68k/op_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index 2b94a6ec84..0f41c2dce3 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -408,11 +408,11 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw) break; case EXCP_SPURIOUS ... EXCP_INT_LEVEL_7: - if (is_hw && oldsr & SR_M) { + if (is_hw && (oldsr & SR_M)) { do_stack_frame(env, &sp, 0, oldsr, 0, retaddr); oldsr = sr; env->aregs[7] = sp; - cpu_m68k_set_sr(env, sr &= ~SR_M); + cpu_m68k_set_sr(env, sr & ~SR_M); sp = env->aregs[7]; if (!m68k_feature(env, M68K_FEATURE_UNALIGNED_DATA)) { sp &= ~1; From cf213dacf8d9bc37889aeaebc781f5f55d705f0d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 1 Jun 2022 18:33:48 -0700 Subject: [PATCH 739/935] linux-user/m68k: Handle EXCP_TRAP1 through EXCP_TRAP15 These are raised by guest instructions, and should not fall through into the default abort case. Signed-off-by: Richard Henderson Message-Id: <20220602013401.303699-5-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/m68k/cpu_loop.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-user/m68k/cpu_loop.c b/linux-user/m68k/cpu_loop.c index 56417f7401..12e5d9cd53 100644 --- a/linux-user/m68k/cpu_loop.c +++ b/linux-user/m68k/cpu_loop.c @@ -75,7 +75,11 @@ void cpu_loop(CPUM68KState *env) case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; + case EXCP_TRAP0 + 1 ... EXCP_TRAP0 + 14: + force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLTRP, env->pc); + break; case EXCP_DEBUG: + case EXCP_TRAP15: force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); break; case EXCP_ATOMIC: From 035c6e7b5d86edee9e96423a590ee3ee0546c921 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 1 Jun 2022 18:33:49 -0700 Subject: [PATCH 740/935] target/m68k: Remove retaddr in m68k_interrupt_all MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only value this variable holds is now env->pc. Reviewed-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-Id: <20220602013401.303699-6-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- target/m68k/op_helper.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index 0f41c2dce3..777869790b 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -287,12 +287,9 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw) { CPUState *cs = env_cpu(env); uint32_t sp; - uint32_t retaddr; uint32_t vector; uint16_t sr, oldsr; - retaddr = env->pc; - if (!is_hw) { switch (cs->exception_index) { case EXCP_RTE: @@ -385,7 +382,7 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw) sp -= 4; cpu_stl_mmuidx_ra(env, sp, env->mmu.ar, MMU_KERNEL_IDX, 0); - do_stack_frame(env, &sp, 7, oldsr, 0, retaddr); + do_stack_frame(env, &sp, 7, oldsr, 0, env->pc); env->mmu.fault = false; if (qemu_loglevel_mask(CPU_LOG_INT)) { qemu_log(" " @@ -395,7 +392,7 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw) break; case EXCP_ADDRESS: - do_stack_frame(env, &sp, 2, oldsr, 0, retaddr); + do_stack_frame(env, &sp, 2, oldsr, 0, env->pc); break; case EXCP_ILLEGAL: @@ -404,12 +401,12 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw) case EXCP_TRAPCC: case EXCP_TRACE: /* FIXME: addr is not only env->pc */ - do_stack_frame(env, &sp, 2, oldsr, env->pc, retaddr); + do_stack_frame(env, &sp, 2, oldsr, env->pc, env->pc); break; case EXCP_SPURIOUS ... EXCP_INT_LEVEL_7: if (is_hw && (oldsr & SR_M)) { - do_stack_frame(env, &sp, 0, oldsr, 0, retaddr); + do_stack_frame(env, &sp, 0, oldsr, 0, env->pc); oldsr = sr; env->aregs[7] = sp; cpu_m68k_set_sr(env, sr & ~SR_M); @@ -417,13 +414,13 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw) if (!m68k_feature(env, M68K_FEATURE_UNALIGNED_DATA)) { sp &= ~1; } - do_stack_frame(env, &sp, 1, oldsr, 0, retaddr); + do_stack_frame(env, &sp, 1, oldsr, 0, env->pc); break; } /* fall through */ default: - do_stack_frame(env, &sp, 0, oldsr, 0, retaddr); + do_stack_frame(env, &sp, 0, oldsr, 0, env->pc); break; } From ad5a5cf97d80501be95f5d255d2ce133e0623b50 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 1 Jun 2022 18:33:50 -0700 Subject: [PATCH 741/935] target/m68k: Fix address argument for EXCP_CHK According to the M68040 Users Manual, section 8.4.3, Six word stack frame (format 2), CHK, CHK2 (and others) are supposed to record the next insn in PC and the address of the trapping instruction in ADDRESS. Create a raise_exception_format2 function to centralize recording of the trapping pc in mmu.ar, plus advancing to the next insn. Update m68k_interrupt_all to pass mmu.ar to do_stack_frame. Update cpu_loop to pass mmu.ar to siginfo.si_addr, as the kernel does in trap_c(). Reviewed-by: Laurent Vivier Signed-off-by: Richard Henderson Message-Id: <20220602013401.303699-7-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/m68k/cpu_loop.c | 2 +- target/m68k/cpu.h | 6 +++++ target/m68k/op_helper.c | 54 ++++++++++++++++++++------------------ 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/linux-user/m68k/cpu_loop.c b/linux-user/m68k/cpu_loop.c index 12e5d9cd53..e24d17e180 100644 --- a/linux-user/m68k/cpu_loop.c +++ b/linux-user/m68k/cpu_loop.c @@ -47,7 +47,7 @@ void cpu_loop(CPUM68KState *env) force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->pc); break; case EXCP_CHK: - force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->pc); + force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->mmu.ar); break; case EXCP_DIV0: force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc); diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index 9b3bf7a448..558c3c67d6 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -122,6 +122,12 @@ typedef struct CPUArchState { /* MMU status. */ struct { + /* + * Holds the "address" value in between raising an exception + * and creation of the exception stack frame. + * Used for both Format 7 exceptions (Access, i.e. mmu) + * and Format 2 exceptions (chk, div0, trapcc, etc). + */ uint32_t ar; uint32_t ssw; /* 68040 */ diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index 777869790b..750d65576f 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -397,13 +397,16 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw) case EXCP_ILLEGAL: case EXCP_DIV0: - case EXCP_CHK: case EXCP_TRAPCC: case EXCP_TRACE: /* FIXME: addr is not only env->pc */ do_stack_frame(env, &sp, 2, oldsr, env->pc, env->pc); break; + case EXCP_CHK: + do_stack_frame(env, &sp, 2, oldsr, env->mmu.ar, env->pc); + break; + case EXCP_SPURIOUS ... EXCP_INT_LEVEL_7: if (is_hw && (oldsr & SR_M)) { do_stack_frame(env, &sp, 0, oldsr, 0, env->pc); @@ -548,6 +551,29 @@ void HELPER(raise_exception)(CPUM68KState *env, uint32_t tt) raise_exception(env, tt); } +G_NORETURN static void +raise_exception_format2(CPUM68KState *env, int tt, int ilen, uintptr_t raddr) +{ + CPUState *cs = env_cpu(env); + + cs->exception_index = tt; + + /* Recover PC and CC_OP for the beginning of the insn. */ + cpu_restore_state(cs, raddr, true); + + /* Flags are current in env->cc_*, or are undefined. */ + env->cc_op = CC_OP_FLAGS; + + /* + * Remember original pc in mmu.ar, for the Format 2 stack frame. + * Adjust PC to end of the insn. + */ + env->mmu.ar = env->pc; + env->pc += ilen; + + cpu_loop_exit(cs); +} + void HELPER(divuw)(CPUM68KState *env, int destr, uint32_t den) { uint32_t num = env->dregs[destr]; @@ -1065,18 +1091,7 @@ void HELPER(chk)(CPUM68KState *env, int32_t val, int32_t ub) env->cc_c = 0 <= ub ? val < 0 || val > ub : val > ub && val < 0; if (val < 0 || val > ub) { - CPUState *cs = env_cpu(env); - - /* Recover PC and CC_OP for the beginning of the insn. */ - cpu_restore_state(cs, GETPC(), true); - - /* flags have been modified by gen_flush_flags() */ - env->cc_op = CC_OP_FLAGS; - /* Adjust PC to end of the insn. */ - env->pc += 2; - - cs->exception_index = EXCP_CHK; - cpu_loop_exit(cs); + raise_exception_format2(env, EXCP_CHK, 2, GETPC()); } } @@ -1097,17 +1112,6 @@ void HELPER(chk2)(CPUM68KState *env, int32_t val, int32_t lb, int32_t ub) env->cc_c = lb <= ub ? val < lb || val > ub : val > ub && val < lb; if (env->cc_c) { - CPUState *cs = env_cpu(env); - - /* Recover PC and CC_OP for the beginning of the insn. */ - cpu_restore_state(cs, GETPC(), true); - - /* flags have been modified by gen_flush_flags() */ - env->cc_op = CC_OP_FLAGS; - /* Adjust PC to end of the insn. */ - env->pc += 4; - - cs->exception_index = EXCP_CHK; - cpu_loop_exit(cs); + raise_exception_format2(env, EXCP_CHK, 4, GETPC()); } } From 710d747b2deaf5f5678aebb1fabbe00224e5cdde Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 1 Jun 2022 18:33:51 -0700 Subject: [PATCH 742/935] target/m68k: Fix pc, c flag, and address argument for EXCP_DIV0 According to the M68040 Users Manual, section 8.4.3, Six word stack frame (format 2), Zero Div (and others) is supposed to record the next insn in PC and the address of the trapping instruction in ADDRESS. While the N, Z and V flags are documented to be undefine on DIV0, the C flag is documented as always cleared. Update helper_div* to take the instruction length as an argument and use raise_exception_format2. Hoist the reset of the C flag above the division by zero check. Update m68k_interrupt_all to pass mmu.ar to do_stack_frame. Update cpu_loop to pass mmu.ar to siginfo.si_addr, as the kernel does in trap_c(). Reviewed-by: Laurent Vivier Signed-off-by: Richard Henderson Message-Id: <20220602013401.303699-8-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/m68k/cpu_loop.c | 2 +- target/m68k/helper.h | 12 +++++----- target/m68k/op_helper.c | 48 +++++++++++++++++++++++--------------- target/m68k/translate.c | 33 +++++++++++++------------- 4 files changed, 52 insertions(+), 43 deletions(-) diff --git a/linux-user/m68k/cpu_loop.c b/linux-user/m68k/cpu_loop.c index e24d17e180..6598bce3c4 100644 --- a/linux-user/m68k/cpu_loop.c +++ b/linux-user/m68k/cpu_loop.c @@ -50,7 +50,7 @@ void cpu_loop(CPUM68KState *env) force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->mmu.ar); break; case EXCP_DIV0: - force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc); + force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->mmu.ar); break; case EXCP_TRAP0: { diff --git a/target/m68k/helper.h b/target/m68k/helper.h index 0a6b4146f6..f016c4c1c2 100644 --- a/target/m68k/helper.h +++ b/target/m68k/helper.h @@ -1,12 +1,12 @@ DEF_HELPER_1(bitrev, i32, i32) DEF_HELPER_1(ff1, i32, i32) DEF_HELPER_FLAGS_2(sats, TCG_CALL_NO_RWG_SE, i32, i32, i32) -DEF_HELPER_3(divuw, void, env, int, i32) -DEF_HELPER_3(divsw, void, env, int, s32) -DEF_HELPER_4(divul, void, env, int, int, i32) -DEF_HELPER_4(divsl, void, env, int, int, s32) -DEF_HELPER_4(divull, void, env, int, int, i32) -DEF_HELPER_4(divsll, void, env, int, int, s32) +DEF_HELPER_4(divuw, void, env, int, i32, int) +DEF_HELPER_4(divsw, void, env, int, s32, int) +DEF_HELPER_5(divul, void, env, int, int, i32, int) +DEF_HELPER_5(divsl, void, env, int, int, s32, int) +DEF_HELPER_5(divull, void, env, int, int, i32, int) +DEF_HELPER_5(divsll, void, env, int, int, s32, int) DEF_HELPER_2(set_sr, void, env, i32) DEF_HELPER_3(cf_movec_to, void, env, i32, i32) DEF_HELPER_3(m68k_movec_to, void, env, i32, i32) diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index 750d65576f..729ee0e934 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -396,7 +396,6 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw) break; case EXCP_ILLEGAL: - case EXCP_DIV0: case EXCP_TRAPCC: case EXCP_TRACE: /* FIXME: addr is not only env->pc */ @@ -404,6 +403,7 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw) break; case EXCP_CHK: + case EXCP_DIV0: do_stack_frame(env, &sp, 2, oldsr, env->mmu.ar, env->pc); break; @@ -574,18 +574,19 @@ raise_exception_format2(CPUM68KState *env, int tt, int ilen, uintptr_t raddr) cpu_loop_exit(cs); } -void HELPER(divuw)(CPUM68KState *env, int destr, uint32_t den) +void HELPER(divuw)(CPUM68KState *env, int destr, uint32_t den, int ilen) { uint32_t num = env->dregs[destr]; uint32_t quot, rem; + env->cc_c = 0; /* always cleared, even if div0 */ + if (den == 0) { - raise_exception_ra(env, EXCP_DIV0, GETPC()); + raise_exception_format2(env, EXCP_DIV0, ilen, GETPC()); } quot = num / den; rem = num % den; - env->cc_c = 0; /* always cleared, even if overflow */ if (quot > 0xffff) { env->cc_v = -1; /* @@ -601,18 +602,19 @@ void HELPER(divuw)(CPUM68KState *env, int destr, uint32_t den) env->cc_v = 0; } -void HELPER(divsw)(CPUM68KState *env, int destr, int32_t den) +void HELPER(divsw)(CPUM68KState *env, int destr, int32_t den, int ilen) { int32_t num = env->dregs[destr]; uint32_t quot, rem; + env->cc_c = 0; /* always cleared, even if overflow/div0 */ + if (den == 0) { - raise_exception_ra(env, EXCP_DIV0, GETPC()); + raise_exception_format2(env, EXCP_DIV0, ilen, GETPC()); } quot = num / den; rem = num % den; - env->cc_c = 0; /* always cleared, even if overflow */ if (quot != (int16_t)quot) { env->cc_v = -1; /* nothing else is modified */ @@ -629,18 +631,20 @@ void HELPER(divsw)(CPUM68KState *env, int destr, int32_t den) env->cc_v = 0; } -void HELPER(divul)(CPUM68KState *env, int numr, int regr, uint32_t den) +void HELPER(divul)(CPUM68KState *env, int numr, int regr, + uint32_t den, int ilen) { uint32_t num = env->dregs[numr]; uint32_t quot, rem; + env->cc_c = 0; /* always cleared, even if div0 */ + if (den == 0) { - raise_exception_ra(env, EXCP_DIV0, GETPC()); + raise_exception_format2(env, EXCP_DIV0, ilen, GETPC()); } quot = num / den; rem = num % den; - env->cc_c = 0; env->cc_z = quot; env->cc_n = quot; env->cc_v = 0; @@ -657,18 +661,20 @@ void HELPER(divul)(CPUM68KState *env, int numr, int regr, uint32_t den) } } -void HELPER(divsl)(CPUM68KState *env, int numr, int regr, int32_t den) +void HELPER(divsl)(CPUM68KState *env, int numr, int regr, + int32_t den, int ilen) { int32_t num = env->dregs[numr]; int32_t quot, rem; + env->cc_c = 0; /* always cleared, even if overflow/div0 */ + if (den == 0) { - raise_exception_ra(env, EXCP_DIV0, GETPC()); + raise_exception_format2(env, EXCP_DIV0, ilen, GETPC()); } quot = num / den; rem = num % den; - env->cc_c = 0; env->cc_z = quot; env->cc_n = quot; env->cc_v = 0; @@ -685,19 +691,21 @@ void HELPER(divsl)(CPUM68KState *env, int numr, int regr, int32_t den) } } -void HELPER(divull)(CPUM68KState *env, int numr, int regr, uint32_t den) +void HELPER(divull)(CPUM68KState *env, int numr, int regr, + uint32_t den, int ilen) { uint64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]); uint64_t quot; uint32_t rem; + env->cc_c = 0; /* always cleared, even if overflow/div0 */ + if (den == 0) { - raise_exception_ra(env, EXCP_DIV0, GETPC()); + raise_exception_format2(env, EXCP_DIV0, ilen, GETPC()); } quot = num / den; rem = num % den; - env->cc_c = 0; /* always cleared, even if overflow */ if (quot > 0xffffffffULL) { env->cc_v = -1; /* @@ -720,19 +728,21 @@ void HELPER(divull)(CPUM68KState *env, int numr, int regr, uint32_t den) env->dregs[numr] = quot; } -void HELPER(divsll)(CPUM68KState *env, int numr, int regr, int32_t den) +void HELPER(divsll)(CPUM68KState *env, int numr, int regr, + int32_t den, int ilen) { int64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]); int64_t quot; int32_t rem; + env->cc_c = 0; /* always cleared, even if overflow/div0 */ + if (den == 0) { - raise_exception_ra(env, EXCP_DIV0, GETPC()); + raise_exception_format2(env, EXCP_DIV0, ilen, GETPC()); } quot = num / den; rem = num % den; - env->cc_c = 0; /* always cleared, even if overflow */ if (quot != (int32_t)quot) { env->cc_v = -1; /* diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 22e5379d3c..6075f49930 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -1601,6 +1601,7 @@ DISAS_INSN(divw) int sign; TCGv src; TCGv destr; + TCGv ilen; /* divX.w ,Dn 32/16 -> 16r:16q */ @@ -1609,20 +1610,20 @@ DISAS_INSN(divw) /* dest.l / src.w */ SRC_EA(env, src, OS_WORD, sign, NULL); - destr = tcg_const_i32(REG(insn, 9)); + destr = tcg_constant_i32(REG(insn, 9)); + ilen = tcg_constant_i32(s->pc - s->base.pc_next); if (sign) { - gen_helper_divsw(cpu_env, destr, src); + gen_helper_divsw(cpu_env, destr, src, ilen); } else { - gen_helper_divuw(cpu_env, destr, src); + gen_helper_divuw(cpu_env, destr, src, ilen); } - tcg_temp_free(destr); set_cc_op(s, CC_OP_FLAGS); } DISAS_INSN(divl) { - TCGv num, reg, den; + TCGv num, reg, den, ilen; int sign; uint16_t ext; @@ -1639,15 +1640,14 @@ DISAS_INSN(divl) /* divX.l , Dr:Dq 64/32 -> 32r:32q */ SRC_EA(env, den, OS_LONG, 0, NULL); - num = tcg_const_i32(REG(ext, 12)); - reg = tcg_const_i32(REG(ext, 0)); + num = tcg_constant_i32(REG(ext, 12)); + reg = tcg_constant_i32(REG(ext, 0)); + ilen = tcg_constant_i32(s->pc - s->base.pc_next); if (sign) { - gen_helper_divsll(cpu_env, num, reg, den); + gen_helper_divsll(cpu_env, num, reg, den, ilen); } else { - gen_helper_divull(cpu_env, num, reg, den); + gen_helper_divull(cpu_env, num, reg, den, ilen); } - tcg_temp_free(reg); - tcg_temp_free(num); set_cc_op(s, CC_OP_FLAGS); return; } @@ -1656,15 +1656,14 @@ DISAS_INSN(divl) /* divXl.l , Dr:Dq 32/32 -> 32r:32q */ SRC_EA(env, den, OS_LONG, 0, NULL); - num = tcg_const_i32(REG(ext, 12)); - reg = tcg_const_i32(REG(ext, 0)); + num = tcg_constant_i32(REG(ext, 12)); + reg = tcg_constant_i32(REG(ext, 0)); + ilen = tcg_constant_i32(s->pc - s->base.pc_next); if (sign) { - gen_helper_divsl(cpu_env, num, reg, den); + gen_helper_divsl(cpu_env, num, reg, den, ilen); } else { - gen_helper_divul(cpu_env, num, reg, den); + gen_helper_divul(cpu_env, num, reg, den, ilen); } - tcg_temp_free(reg); - tcg_temp_free(num); set_cc_op(s, CC_OP_FLAGS); } From 8115fc9368e41f91a8bc27a78c2840beda989cb5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 1 Jun 2022 18:33:52 -0700 Subject: [PATCH 743/935] target/m68k: Fix address argument for EXCP_TRACE According to the M68040 Users Manual, section 8.4.3, Six word stack frame (format 2), Trace (and others) is supposed to record the next insn in PC and the address of the trapping instruction in ADDRESS. Create gen_raise_exception_format2 to record the trapping pc in env->mmu.ar. Update m68k_interrupt_all to pass the value to do_stack_frame. Update cpu_loop to handle EXCP_TRACE. Reviewed-by: Laurent Vivier Signed-off-by: Richard Henderson Message-Id: <20220602013401.303699-9-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/m68k/cpu_loop.c | 3 +++ target/m68k/op_helper.c | 2 +- target/m68k/translate.c | 49 +++++++++++++++++++++++++------------- 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/linux-user/m68k/cpu_loop.c b/linux-user/m68k/cpu_loop.c index 6598bce3c4..fcf9220552 100644 --- a/linux-user/m68k/cpu_loop.c +++ b/linux-user/m68k/cpu_loop.c @@ -52,6 +52,9 @@ void cpu_loop(CPUM68KState *env) case EXCP_DIV0: force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->mmu.ar); break; + case EXCP_TRACE: + force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_TRACE, env->mmu.ar); + break; case EXCP_TRAP0: { abi_long ret; diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index 729ee0e934..3cb71c9140 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -397,13 +397,13 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw) case EXCP_ILLEGAL: case EXCP_TRAPCC: - case EXCP_TRACE: /* FIXME: addr is not only env->pc */ do_stack_frame(env, &sp, 2, oldsr, env->pc, env->pc); break; case EXCP_CHK: case EXCP_DIV0: + case EXCP_TRACE: do_stack_frame(env, &sp, 2, oldsr, env->mmu.ar, env->pc); break; diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 6075f49930..38b72d282a 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -114,6 +114,7 @@ typedef struct DisasContext { DisasContextBase base; CPUM68KState *env; target_ulong pc; + target_ulong pc_prev; CCOp cc_op; /* Current CC operation */ int cc_op_synced; TCGv_i64 mactmp; @@ -298,6 +299,21 @@ static void gen_raise_exception(int nr) tcg_temp_free_i32(tmp); } +static void gen_raise_exception_format2(DisasContext *s, int nr, + target_ulong this_pc) +{ + /* + * Pass the address of the insn to the exception handler, + * for recording in the Format $2 (6-word) stack frame. + * Re-use mmu.ar for the purpose, since that's only valid + * after tlb_fill. + */ + tcg_gen_st_i32(tcg_constant_i32(this_pc), cpu_env, + offsetof(CPUM68KState, mmu.ar)); + gen_raise_exception(nr); + s->base.is_jmp = DISAS_NORETURN; +} + static void gen_exception(DisasContext *s, uint32_t dest, int nr) { update_cc_op(s); @@ -1494,12 +1510,13 @@ static void gen_exit_tb(DisasContext *s) } while (0) /* Generate a jump to an immediate address. */ -static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest) +static void gen_jmp_tb(DisasContext *s, int n, target_ulong dest, + target_ulong src) { if (unlikely(s->ss_active)) { update_cc_op(s); tcg_gen_movi_i32(QREG_PC, dest); - gen_raise_exception(EXCP_TRACE); + gen_raise_exception_format2(s, EXCP_TRACE, src); } else if (translator_use_goto_tb(&s->base, dest)) { tcg_gen_goto_tb(n); tcg_gen_movi_i32(QREG_PC, dest); @@ -1548,9 +1565,9 @@ DISAS_INSN(dbcc) tcg_gen_addi_i32(tmp, tmp, -1); gen_partset_reg(OS_WORD, reg, tmp); tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, -1, l1); - gen_jmp_tb(s, 1, base + offset); + gen_jmp_tb(s, 1, base + offset, s->base.pc_next); gen_set_label(l1); - gen_jmp_tb(s, 0, s->pc); + gen_jmp_tb(s, 0, s->pc, s->base.pc_next); } DISAS_INSN(undef_mac) @@ -3096,13 +3113,13 @@ DISAS_INSN(branch) /* Bcc */ TCGLabel *l1 = gen_new_label(); gen_jmpcc(s, ((insn >> 8) & 0xf) ^ 1, l1); - gen_jmp_tb(s, 1, base + offset); + gen_jmp_tb(s, 1, base + offset, s->base.pc_next); gen_set_label(l1); - gen_jmp_tb(s, 0, s->pc); + gen_jmp_tb(s, 0, s->pc, s->base.pc_next); } else { /* Unconditional branch. */ update_cc_op(s); - gen_jmp_tb(s, 0, base + offset); + gen_jmp_tb(s, 0, base + offset, s->base.pc_next); } } @@ -5485,9 +5502,9 @@ DISAS_INSN(fbcc) l1 = gen_new_label(); update_cc_op(s); gen_fjmpcc(s, insn & 0x3f, l1); - gen_jmp_tb(s, 0, s->pc); + gen_jmp_tb(s, 0, s->pc, s->base.pc_next); gen_set_label(l1); - gen_jmp_tb(s, 1, base + offset); + gen_jmp_tb(s, 1, base + offset, s->base.pc_next); } DISAS_INSN(fscc) @@ -6159,6 +6176,8 @@ static void m68k_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) dc->env = env; dc->pc = dc->base.pc_first; + /* This value will always be filled in properly before m68k_tr_tb_stop. */ + dc->pc_prev = 0xdeadbeef; dc->cc_op = CC_OP_DYNAMIC; dc->cc_op_synced = 1; dc->done_mac = 0; @@ -6192,6 +6211,7 @@ static void m68k_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) do_writebacks(dc); do_release(dc); + dc->pc_prev = dc->base.pc_next; dc->base.pc_next = dc->pc; if (dc->base.is_jmp == DISAS_NEXT) { @@ -6226,17 +6246,12 @@ static void m68k_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) break; case DISAS_TOO_MANY: update_cc_op(dc); - if (dc->ss_active) { - tcg_gen_movi_i32(QREG_PC, dc->pc); - gen_raise_exception(EXCP_TRACE); - } else { - gen_jmp_tb(dc, 0, dc->pc); - } + gen_jmp_tb(dc, 0, dc->pc, dc->pc_prev); break; case DISAS_JUMP: /* We updated CC_OP and PC in gen_jmp/gen_jmp_im. */ if (dc->ss_active) { - gen_raise_exception(EXCP_TRACE); + gen_raise_exception_format2(dc, EXCP_TRACE, dc->pc_prev); } else { tcg_gen_lookup_and_goto_ptr(); } @@ -6247,7 +6262,7 @@ static void m68k_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) * other state that may require returning to the main loop. */ if (dc->ss_active) { - gen_raise_exception(EXCP_TRACE); + gen_raise_exception_format2(dc, EXCP_TRACE, dc->pc_prev); } else { tcg_gen_exit_tb(NULL, 0); } From a1aedd6cbdec67c1d47d961144285f4b95af5fc0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 1 Jun 2022 18:33:53 -0700 Subject: [PATCH 744/935] target/m68k: Fix stack frame for EXCP_ILLEGAL According to the M68040 Users Manual, section 8.4.1, Four word stack frame (format 0), includes Illegal Instruction. Use the correct frame format, which does not use the ADDR argument. Reviewed-by: Laurent Vivier Signed-off-by: Richard Henderson Message-Id: <20220602013401.303699-10-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- target/m68k/op_helper.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index 3cb71c9140..aa62158eb9 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -391,11 +391,14 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw) } break; + case EXCP_ILLEGAL: + do_stack_frame(env, &sp, 0, oldsr, 0, env->pc); + break; + case EXCP_ADDRESS: do_stack_frame(env, &sp, 2, oldsr, 0, env->pc); break; - case EXCP_ILLEGAL: case EXCP_TRAPCC: /* FIXME: addr is not only env->pc */ do_stack_frame(env, &sp, 2, oldsr, env->pc, env->pc); From aeeb90afcec3e18254bc6ac9c511f3b0a1a3796c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 1 Jun 2022 18:33:54 -0700 Subject: [PATCH 745/935] target/m68k: Implement TRAPcc Resolves: https://gitlab.com/qemu-project/qemu/-/issues/754 Reviewed-by: Laurent Vivier Signed-off-by: Richard Henderson Message-Id: <20220602013401.303699-11-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/m68k/cpu_loop.c | 1 + target/m68k/cpu.c | 1 + target/m68k/cpu.h | 2 ++ target/m68k/op_helper.c | 6 +---- target/m68k/translate.c | 49 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 54 insertions(+), 5 deletions(-) diff --git a/linux-user/m68k/cpu_loop.c b/linux-user/m68k/cpu_loop.c index fcf9220552..3d3033155f 100644 --- a/linux-user/m68k/cpu_loop.c +++ b/linux-user/m68k/cpu_loop.c @@ -47,6 +47,7 @@ void cpu_loop(CPUM68KState *env) force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->pc); break; case EXCP_CHK: + case EXCP_TRAPCC: force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->mmu.ar); break; case EXCP_DIV0: diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index 5671067923..5bbefda575 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -158,6 +158,7 @@ static void m68020_cpu_initfn(Object *obj) m68k_set_feature(env, M68K_FEATURE_CHK2); m68k_set_feature(env, M68K_FEATURE_MSP); m68k_set_feature(env, M68K_FEATURE_UNALIGNED_DATA); + m68k_set_feature(env, M68K_FEATURE_TRAPCC); } /* diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index 558c3c67d6..4d8f48e8c7 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -534,6 +534,8 @@ enum m68k_features { M68K_FEATURE_MOVEC, /* Unaligned data accesses (680[2346]0) */ M68K_FEATURE_UNALIGNED_DATA, + /* TRAPcc insn. (680[2346]0, and CPU32) */ + M68K_FEATURE_TRAPCC, }; static inline int m68k_feature(CPUM68KState *env, int feature) diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index aa62158eb9..61948d92bb 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -399,14 +399,10 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw) do_stack_frame(env, &sp, 2, oldsr, 0, env->pc); break; - case EXCP_TRAPCC: - /* FIXME: addr is not only env->pc */ - do_stack_frame(env, &sp, 2, oldsr, env->pc, env->pc); - break; - case EXCP_CHK: case EXCP_DIV0: case EXCP_TRACE: + case EXCP_TRAPCC: do_stack_frame(env, &sp, 2, oldsr, env->mmu.ar, env->pc); break; diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 38b72d282a..e9aa96d768 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -4879,6 +4879,53 @@ DISAS_INSN(trap) gen_exception(s, s->pc, EXCP_TRAP0 + (insn & 0xf)); } +static void do_trapcc(DisasContext *s, DisasCompare *c) +{ + if (c->tcond != TCG_COND_NEVER) { + TCGLabel *over = NULL; + + update_cc_op(s); + + if (c->tcond != TCG_COND_ALWAYS) { + /* Jump over if !c. */ + over = gen_new_label(); + tcg_gen_brcond_i32(tcg_invert_cond(c->tcond), c->v1, c->v2, over); + } + + tcg_gen_movi_i32(QREG_PC, s->pc); + gen_raise_exception_format2(s, EXCP_TRAPCC, s->base.pc_next); + + if (over != NULL) { + gen_set_label(over); + s->base.is_jmp = DISAS_NEXT; + } + } + free_cond(c); +} + +DISAS_INSN(trapcc) +{ + DisasCompare c; + + /* Consume and discard the immediate operand. */ + switch (extract32(insn, 0, 3)) { + case 2: /* trapcc.w */ + (void)read_im16(env, s); + break; + case 3: /* trapcc.l */ + (void)read_im32(env, s); + break; + case 4: /* trapcc (no operand) */ + break; + default: + /* trapcc registered with only valid opmodes */ + g_assert_not_reached(); + } + + gen_cc_cond(&c, s, extract32(insn, 8, 4)); + do_trapcc(s, &c); +} + static void gen_load_fcr(DisasContext *s, TCGv res, int reg) { switch (reg) { @@ -6051,6 +6098,8 @@ void register_m68k_insns (CPUM68KState *env) INSN(scc, 50c0, f0f8, CF_ISA_A); /* Scc.B Dx */ INSN(scc, 50c0, f0c0, M68000); /* Scc.B */ INSN(dbcc, 50c8, f0f8, M68000); + INSN(trapcc, 50fa, f0fe, TRAPCC); /* opmode 010, 011 */ + INSN(trapcc, 50fc, f0ff, TRAPCC); /* opmode 100 */ INSN(tpf, 51f8, fff8, CF_ISA_A); /* Branch instructions. */ From 815c6dea464c661032c6cc76f42160a6240c930e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 1 Jun 2022 18:33:55 -0700 Subject: [PATCH 746/935] target/m68k: Implement TPF in terms of TRAPcc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TPF stands for "trap false", and is a long-form nop for ColdFire. Re-use the immediate consumption code from trapcc; the insn will already expand to a nop because of the TCG_COND_NEVER test within do_trapcc. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Signed-off-by: Richard Henderson Message-Id: <20220602013401.303699-12-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- target/m68k/translate.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index e9aa96d768..8b2157c31f 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -3075,22 +3075,6 @@ DISAS_INSN(addsubq) tcg_temp_free(dest); } -DISAS_INSN(tpf) -{ - switch (insn & 7) { - case 2: /* One extension word. */ - s->pc += 2; - break; - case 3: /* Two extension words. */ - s->pc += 4; - break; - case 4: /* No extension words. */ - break; - default: - disas_undef(env, s, insn); - } -} - DISAS_INSN(branch) { int32_t offset; @@ -6100,7 +6084,8 @@ void register_m68k_insns (CPUM68KState *env) INSN(dbcc, 50c8, f0f8, M68000); INSN(trapcc, 50fa, f0fe, TRAPCC); /* opmode 010, 011 */ INSN(trapcc, 50fc, f0ff, TRAPCC); /* opmode 100 */ - INSN(tpf, 51f8, fff8, CF_ISA_A); + INSN(trapcc, 51fa, fffe, CF_ISA_A); /* TPF (trapf) opmode 010, 011 */ + INSN(trapcc, 51fc, ffff, CF_ISA_A); /* TPF (trapf) opmode 100 */ /* Branch instructions. */ BASE(branch, 6000, f000); From 43accc4862e0a88710411b205fdaf833dadf9951 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 1 Jun 2022 18:33:56 -0700 Subject: [PATCH 747/935] target/m68k: Implement TRAPV Reviewed-by: Laurent Vivier Signed-off-by: Richard Henderson Message-Id: <20220602013401.303699-13-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- target/m68k/translate.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 8b2157c31f..0dfddaa056 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -4910,6 +4910,14 @@ DISAS_INSN(trapcc) do_trapcc(s, &c); } +DISAS_INSN(trapv) +{ + DisasCompare c; + + gen_cc_cond(&c, s, 9); /* V set */ + do_trapcc(s, &c); +} + static void gen_load_fcr(DisasContext *s, TCGv res, int reg) { switch (reg) { @@ -6074,6 +6082,7 @@ void register_m68k_insns (CPUM68KState *env) BASE(nop, 4e71, ffff); INSN(rtd, 4e74, ffff, RTD); BASE(rts, 4e75, ffff); + INSN(trapv, 4e76, ffff, M68000); INSN(rtr, 4e77, ffff, M68000); BASE(jump, 4e80, ffc0); BASE(jump, 4ec0, ffc0); From cc1cc264b14c75c4f3ddd8e33c9dd6f1e497bfdf Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 1 Jun 2022 18:33:57 -0700 Subject: [PATCH 748/935] target/m68k: Implement FTRAPcc Reviewed-by: Laurent Vivier Signed-off-by: Richard Henderson Message-Id: <20220602013401.303699-14-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- target/m68k/translate.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 0dfddaa056..8f3c298ad0 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -5566,6 +5566,34 @@ DISAS_INSN(fscc) tcg_temp_free(tmp); } +DISAS_INSN(ftrapcc) +{ + DisasCompare c; + uint16_t ext; + int cond; + + ext = read_im16(env, s); + cond = ext & 0x3f; + + /* Consume and discard the immediate operand. */ + switch (extract32(insn, 0, 3)) { + case 2: /* ftrapcc.w */ + (void)read_im16(env, s); + break; + case 3: /* ftrapcc.l */ + (void)read_im32(env, s); + break; + case 4: /* ftrapcc (no operand) */ + break; + default: + /* ftrapcc registered with only valid opmodes */ + g_assert_not_reached(); + } + + gen_fcc_cond(&c, s, cond); + do_trapcc(s, &c); +} + #if defined(CONFIG_SOFTMMU) DISAS_INSN(frestore) { @@ -6192,6 +6220,8 @@ void register_m68k_insns (CPUM68KState *env) INSN(fbcc, f280, ffc0, CF_FPU); INSN(fpu, f200, ffc0, FPU); INSN(fscc, f240, ffc0, FPU); + INSN(ftrapcc, f27a, fffe, FPU); /* opmode 010, 011 */ + INSN(ftrapcc, f27c, ffff, FPU); /* opmode 100 */ INSN(fbcc, f280, ff80, FPU); #if defined(CONFIG_SOFTMMU) INSN(frestore, f340, ffc0, CF_FPU); From e105db022715d0a418dbda843fe19eefeb272380 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 1 Jun 2022 18:33:58 -0700 Subject: [PATCH 749/935] tests/tcg/m68k: Add trap.c Test various trap instructions: chk, div, trap, trapv, trapcc, ftrapcc, and the signals and addresses that we expect from them. Reviewed-by: Laurent Vivier Signed-off-by: Richard Henderson Message-Id: <20220602013401.303699-15-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- tests/tcg/m68k/Makefile.target | 3 + tests/tcg/m68k/trap.c | 129 +++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 tests/tcg/m68k/trap.c diff --git a/tests/tcg/m68k/Makefile.target b/tests/tcg/m68k/Makefile.target index 62f109eef4..1163c7ef03 100644 --- a/tests/tcg/m68k/Makefile.target +++ b/tests/tcg/m68k/Makefile.target @@ -3,5 +3,8 @@ # m68k specific tweaks - specifically masking out broken tests # +VPATH += $(SRC_PATH)/tests/tcg/m68k +TESTS += trap + # On m68k Linux supports 4k and 8k pages (but 8k is currently broken) EXTRA_RUNS+=run-test-mmap-4096 # run-test-mmap-8192 diff --git a/tests/tcg/m68k/trap.c b/tests/tcg/m68k/trap.c new file mode 100644 index 0000000000..96cac18d4d --- /dev/null +++ b/tests/tcg/m68k/trap.c @@ -0,0 +1,129 @@ +/* + * Test m68k trap addresses. + */ + +#define _GNU_SOURCE 1 +#include +#include +#include + +static int expect_sig; +static int expect_si_code; +static void *expect_si_addr; +static greg_t expect_mc_pc; +static volatile int got_signal; + +static void sig_handler(int sig, siginfo_t *si, void *puc) +{ + ucontext_t *uc = puc; + mcontext_t *mc = &uc->uc_mcontext; + + assert(sig == expect_sig); + assert(si->si_code == expect_si_code); + assert(si->si_addr == expect_si_addr); + assert(mc->gregs[R_PC] == expect_mc_pc); + + got_signal = 1; +} + +#define FMT_INS [ad] "a"(&expect_si_addr), [pc] "a"(&expect_mc_pc) +#define FMT0_STR(S) \ + "move.l #1f, (%[ad])\n\tmove.l #1f, (%[pc])\n" S "\n1:\n" +#define FMT2_STR(S) \ + "move.l #0f, (%[ad])\n\tmove.l #1f, (%[pc])\n" S "\n1:\n" + +#define CHECK_SIG do { assert(got_signal); got_signal = 0; } while (0) + +int main(int argc, char **argv) +{ + struct sigaction act = { + .sa_sigaction = sig_handler, + .sa_flags = SA_SIGINFO + }; + int t0, t1; + + sigaction(SIGILL, &act, NULL); + sigaction(SIGTRAP, &act, NULL); + sigaction(SIGFPE, &act, NULL); + + expect_sig = SIGFPE; + expect_si_code = FPE_INTOVF; + asm volatile(FMT2_STR("0:\tchk %0, %1") : : "d"(0), "d"(-1), FMT_INS); + CHECK_SIG; + +#if 0 + /* FIXME: chk2 not correctly translated. */ + int bounds[2] = { 0, 1 }; + asm volatile(FMT2_STR("0:\tchk2.l %0, %1") + : : "m"(bounds), "d"(2), FMT_INS); + CHECK_SIG; +#endif + + asm volatile(FMT2_STR("cmp.l %0, %1\n0:\ttrapv") + : : "d"(INT_MIN), "d"(1), FMT_INS); + CHECK_SIG; + + asm volatile(FMT2_STR("cmp.l %0, %0\n0:\ttrapeq") + : : "d"(0), FMT_INS); + CHECK_SIG; + + asm volatile(FMT2_STR("cmp.l %0, %0\n0:\ttrapeq.w #0x1234") + : : "d"(0), FMT_INS); + CHECK_SIG; + + asm volatile(FMT2_STR("cmp.l %0, %0\n0:\ttrapeq.l #0x12345678") + : : "d"(0), FMT_INS); + CHECK_SIG; + + asm volatile(FMT2_STR("fcmp.x %0, %0\n0:\tftrapeq") + : : "f"(0.0L), FMT_INS); + CHECK_SIG; + + expect_si_code = FPE_INTDIV; + + asm volatile(FMT2_STR("0:\tdivs.w %1, %0") + : "=d"(t0) : "d"(0), "0"(1), FMT_INS); + CHECK_SIG; + + asm volatile(FMT2_STR("0:\tdivsl.l %2, %1:%0") + : "=d"(t0), "=d"(t1) : "d"(0), "0"(1), FMT_INS); + CHECK_SIG; + + expect_sig = SIGILL; + expect_si_code = ILL_ILLTRP; + asm volatile(FMT0_STR("trap #1") : : FMT_INS); + CHECK_SIG; + asm volatile(FMT0_STR("trap #2") : : FMT_INS); + CHECK_SIG; + asm volatile(FMT0_STR("trap #3") : : FMT_INS); + CHECK_SIG; + asm volatile(FMT0_STR("trap #4") : : FMT_INS); + CHECK_SIG; + asm volatile(FMT0_STR("trap #5") : : FMT_INS); + CHECK_SIG; + asm volatile(FMT0_STR("trap #6") : : FMT_INS); + CHECK_SIG; + asm volatile(FMT0_STR("trap #7") : : FMT_INS); + CHECK_SIG; + asm volatile(FMT0_STR("trap #8") : : FMT_INS); + CHECK_SIG; + asm volatile(FMT0_STR("trap #9") : : FMT_INS); + CHECK_SIG; + asm volatile(FMT0_STR("trap #10") : : FMT_INS); + CHECK_SIG; + asm volatile(FMT0_STR("trap #11") : : FMT_INS); + CHECK_SIG; + asm volatile(FMT0_STR("trap #12") : : FMT_INS); + CHECK_SIG; + asm volatile(FMT0_STR("trap #13") : : FMT_INS); + CHECK_SIG; + asm volatile(FMT0_STR("trap #14") : : FMT_INS); + CHECK_SIG; + + expect_sig = SIGTRAP; + expect_si_code = TRAP_BRKPT; + asm volatile(FMT0_STR("trap #15") : : FMT_INS); + CHECK_SIG; + + return 0; +} From 7c75571c07def2ded9998a06ad171380a19f6063 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 1 Jun 2022 18:33:59 -0700 Subject: [PATCH 750/935] linux-user/strace: Use is_error in print_syscall_err MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Errors are not all negative numbers: use is_error. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-Id: <20220602013401.303699-16-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/strace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 9fa681dea9..7d882526da 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -689,7 +689,7 @@ print_syscall_err(abi_long ret) const char *errstr; qemu_log(" = "); - if (ret < 0) { + if (is_error(ret)) { errstr = target_strerror(-ret); if (errstr) { qemu_log("-1 errno=%d (%s)", (int)-ret, errstr); From dc3e83d5b17ee896be0478d0231a6ed7f966e0e0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 1 Jun 2022 18:34:00 -0700 Subject: [PATCH 751/935] linux-user/strace: Adjust get_thread_area for m68k Unlike i386, m68k get_thread_area has no arguments. Reviewed-by: Laurent Vivier Signed-off-by: Richard Henderson Message-Id: <20220602013401.303699-17-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/strace.list | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-user/strace.list b/linux-user/strace.list index 278596acd1..72e17b1acf 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -384,8 +384,13 @@ { TARGET_NR_getsockopt, "getsockopt" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_get_thread_area +#if defined(TARGET_I386) && defined(TARGET_ABI32) { TARGET_NR_get_thread_area, "get_thread_area", "%s(0x"TARGET_ABI_FMT_lx")", NULL, NULL }, +#elif defined(TARGET_M68K) +{ TARGET_NR_get_thread_area, "get_thread_area" , "%s()", + NULL, print_syscall_ret_addr }, +#endif #endif #ifdef TARGET_NR_gettid { TARGET_NR_gettid, "gettid" , "%s()", NULL, NULL }, From 36a0ab595f4e24b987e67faa52d4b174f67144b6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 1 Jun 2022 18:34:01 -0700 Subject: [PATCH 752/935] target/m68k: Mark helper_raise_exception as noreturn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also mark raise_exception_ra and raise_exception, lest we generate a warning about helper_raise_exception returning. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Signed-off-by: Richard Henderson Message-Id: <20220602013401.303699-18-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- target/m68k/helper.h | 2 +- target/m68k/op_helper.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/target/m68k/helper.h b/target/m68k/helper.h index f016c4c1c2..c9bed2b884 100644 --- a/target/m68k/helper.h +++ b/target/m68k/helper.h @@ -109,7 +109,7 @@ DEF_HELPER_3(set_mac_extu, void, env, i32, i32) DEF_HELPER_2(flush_flags, void, env, i32) DEF_HELPER_2(set_ccr, void, env, i32) DEF_HELPER_FLAGS_1(get_ccr, TCG_CALL_NO_WG_SE, i32, env) -DEF_HELPER_2(raise_exception, void, env, i32) +DEF_HELPER_2(raise_exception, noreturn, env, i32) DEF_HELPER_FLAGS_3(bfffo_reg, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index 61948d92bb..d9937ca8dc 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -532,7 +532,8 @@ bool m68k_cpu_exec_interrupt(CPUState *cs, int interrupt_request) #endif /* !CONFIG_USER_ONLY */ -static void raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr) +G_NORETURN static void +raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr) { CPUState *cs = env_cpu(env); @@ -540,7 +541,7 @@ static void raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr) cpu_loop_exit_restore(cs, raddr); } -static void raise_exception(CPUM68KState *env, int tt) +G_NORETURN static void raise_exception(CPUM68KState *env, int tt) { raise_exception_ra(env, tt, 0); } From dc24c99116e926b0c56be63acbc086d13e32032b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 16 May 2022 16:10:51 -0700 Subject: [PATCH 753/935] tcg: Add tcg_gen_mov_ptr Add an interface to perform moves between TCGv_ptr. Reviewed-by: Matheus Ferst Signed-off-by: Richard Henderson --- include/tcg/tcg-op.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index b09b8b4a05..209e168305 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -1288,6 +1288,11 @@ static inline void tcg_gen_addi_ptr(TCGv_ptr r, TCGv_ptr a, intptr_t b) glue(tcg_gen_addi_,PTR)((NAT)r, (NAT)a, b); } +static inline void tcg_gen_mov_ptr(TCGv_ptr d, TCGv_ptr s) +{ + glue(tcg_gen_mov_,PTR)((NAT)d, (NAT)s); +} + static inline void tcg_gen_brcondi_ptr(TCGCond cond, TCGv_ptr a, intptr_t b, TCGLabel *label) { From 3cc18d18cc3865d7b1ce2c8b35d52e52abbff397 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 1 Jun 2022 16:22:19 -0700 Subject: [PATCH 754/935] tcg/i386: Fix encoding of OPC_VPSRAQ for INDEX_op_sars_vec We wanted the VPSRAQ variant with the scalar vector shift operand, not the variant with an immediate operand. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1022 Fixes: 47b331b2a8da ("tcg/i386: Implement avx512 scalar shift") Signed-off-by: Richard Henderson --- tcg/i386/tcg-target.c.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index b5c6159853..d52206ba4d 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -375,7 +375,7 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct) #define OPC_PSLLQ (0xf3 | P_EXT | P_DATA16) #define OPC_PSRAW (0xe1 | P_EXT | P_DATA16) #define OPC_PSRAD (0xe2 | P_EXT | P_DATA16) -#define OPC_VPSRAQ (0x72 | P_EXT | P_DATA16 | P_VEXW | P_EVEX) +#define OPC_VPSRAQ (0xe2 | P_EXT | P_DATA16 | P_VEXW | P_EVEX) #define OPC_PSRLW (0xd1 | P_EXT | P_DATA16) #define OPC_PSRLD (0xd2 | P_EXT | P_DATA16) #define OPC_PSRLQ (0xd3 | P_EXT | P_DATA16) From 94bcc91b2e95e02ec57ed18d5a5e7cb75aa19a50 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 2 Jun 2022 01:04:30 +0000 Subject: [PATCH 755/935] tcg/aarch64: Fix illegal insn from out-of-range shli The masking in tcg_out_shl was incorrect, producing an illegal instruction, rather than merely unspecified results for the out-of-range shift. Tested-by: Joel Stanley Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1051 Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 61e284bb5c..d997f7922a 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1261,7 +1261,7 @@ static inline void tcg_out_shl(TCGContext *s, TCGType ext, { int bits = ext ? 64 : 32; int max = bits - 1; - tcg_out_ubfm(s, ext, rd, rn, bits - (m & max), max - (m & max)); + tcg_out_ubfm(s, ext, rd, rn, (bits - m) & max, (max - m) & max); } static inline void tcg_out_shr(TCGContext *s, TCGType ext, From 000117066bbea59a9a37ebf9bf7347a029e2f02c Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Mon, 23 May 2022 12:51:23 +0100 Subject: [PATCH 756/935] s390: Typo fix FLOATING_POINT_SUPPPORT_ENH One less P needed. Signed-off-by: Dr. David Alan Gilbert Message-Id: <20220523115123.150340-1-dgilbert@redhat.com> Signed-off-by: Thomas Huth --- target/s390x/cpu_features_def.h.inc | 2 +- target/s390x/gen-features.c | 6 +++--- target/s390x/tcg/translate.c | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/target/s390x/cpu_features_def.h.inc b/target/s390x/cpu_features_def.h.inc index e86662bb3b..3603e5fb12 100644 --- a/target/s390x/cpu_features_def.h.inc +++ b/target/s390x/cpu_features_def.h.inc @@ -58,7 +58,7 @@ DEF_FEAT(ENHANCED_MONITOR, "emon", STFL, 36, "Enhanced-monitor facility") DEF_FEAT(FLOATING_POINT_EXT, "fpe", STFL, 37, "Floating-point extension facility") DEF_FEAT(ORDER_PRESERVING_COMPRESSION, "opc", STFL, 38, "Order Preserving Compression facility") DEF_FEAT(SET_PROGRAM_PARAMETERS, "sprogp", STFL, 40, "Set-program-parameters facility") -DEF_FEAT(FLOATING_POINT_SUPPPORT_ENH, "fpseh", STFL, 41, "Floating-point-support-enhancement facilities") +DEF_FEAT(FLOATING_POINT_SUPPORT_ENH, "fpseh", STFL, 41, "Floating-point-support-enhancement facilities") DEF_FEAT(DFP, "dfp", STFL, 42, "DFP (decimal-floating-point) facility") DEF_FEAT(DFP_FAST, "dfphp", STFL, 43, "DFP (decimal-floating-point) facility has high performance") DEF_FEAT(PFPO, "pfpo", STFL, 44, "PFPO instruction") diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c index c03ec2c9a9..ad140184b9 100644 --- a/target/s390x/gen-features.c +++ b/target/s390x/gen-features.c @@ -374,7 +374,7 @@ static uint16_t base_GEN10_GA1[] = { S390_FEAT_COMPARE_AND_SWAP_AND_STORE_2, S390_FEAT_GENERAL_INSTRUCTIONS_EXT, S390_FEAT_EXECUTE_EXT, - S390_FEAT_FLOATING_POINT_SUPPPORT_ENH, + S390_FEAT_FLOATING_POINT_SUPPORT_ENH, S390_FEAT_DFP, S390_FEAT_DFP_FAST, S390_FEAT_PFPO, @@ -476,7 +476,7 @@ static uint16_t full_GEN9_GA2[] = { S390_FEAT_MOVE_WITH_OPTIONAL_SPEC, S390_FEAT_EXTRACT_CPU_TIME, S390_FEAT_COMPARE_AND_SWAP_AND_STORE, - S390_FEAT_FLOATING_POINT_SUPPPORT_ENH, + S390_FEAT_FLOATING_POINT_SUPPORT_ENH, S390_FEAT_DFP, }; @@ -700,7 +700,7 @@ static uint16_t qemu_V3_1[] = { S390_FEAT_GENERAL_INSTRUCTIONS_EXT, S390_FEAT_EXECUTE_EXT, S390_FEAT_SET_PROGRAM_PARAMETERS, - S390_FEAT_FLOATING_POINT_SUPPPORT_ENH, + S390_FEAT_FLOATING_POINT_SUPPORT_ENH, S390_FEAT_STFLE_45, S390_FEAT_STFLE_49, S390_FEAT_LOCAL_TLB_CLEARING, diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index b40cb84bae..fd2433d625 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -6185,17 +6185,17 @@ enum DisasInsnEnum { #define FAC_Z S390_FEAT_ZARCH #define FAC_CASS S390_FEAT_COMPARE_AND_SWAP_AND_STORE #define FAC_DFP S390_FEAT_DFP -#define FAC_DFPR S390_FEAT_FLOATING_POINT_SUPPPORT_ENH /* DFP-rounding */ +#define FAC_DFPR S390_FEAT_FLOATING_POINT_SUPPORT_ENH /* DFP-rounding */ #define FAC_DO S390_FEAT_STFLE_45 /* distinct-operands */ #define FAC_EE S390_FEAT_EXECUTE_EXT #define FAC_EI S390_FEAT_EXTENDED_IMMEDIATE #define FAC_FPE S390_FEAT_FLOATING_POINT_EXT -#define FAC_FPSSH S390_FEAT_FLOATING_POINT_SUPPPORT_ENH /* FPS-sign-handling */ -#define FAC_FPRGR S390_FEAT_FLOATING_POINT_SUPPPORT_ENH /* FPR-GR-transfer */ +#define FAC_FPSSH S390_FEAT_FLOATING_POINT_SUPPORT_ENH /* FPS-sign-handling */ +#define FAC_FPRGR S390_FEAT_FLOATING_POINT_SUPPORT_ENH /* FPR-GR-transfer */ #define FAC_GIE S390_FEAT_GENERAL_INSTRUCTIONS_EXT #define FAC_HFP_MA S390_FEAT_HFP_MADDSUB #define FAC_HW S390_FEAT_STFLE_45 /* high-word */ -#define FAC_IEEEE_SIM S390_FEAT_FLOATING_POINT_SUPPPORT_ENH /* IEEE-exception-simulation */ +#define FAC_IEEEE_SIM S390_FEAT_FLOATING_POINT_SUPPORT_ENH /* IEEE-exception-simulation */ #define FAC_MIE S390_FEAT_STFLE_49 /* misc-instruction-extensions */ #define FAC_LAT S390_FEAT_STFLE_49 /* load-and-trap */ #define FAC_LOC S390_FEAT_STFLE_45 /* load/store on condition 1 */ From ec8c293678ffe7b3c01678103608ef75cecb909c Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 6 May 2022 08:50:26 +0200 Subject: [PATCH 757/935] hw/s390x/s390-virtio-ccw: Improve the machine description string The machine name already contains the words "ccw" and "virtio", so using "VirtIO-ccw" in the description likely does not really help the average user to get an idea what this machine type is about. Thus let's switch to "Virtual s390x machine" now, since "virtual machine" should be a familiar term, and "s390x" signals that this is about 64-bit guests (unlike S390 which could mean that it is 31-bit only). Also expand "v" to "version", since this makes it easier to use this macro also with non-numeric machine names in downstream. Message-Id: <20220506065026.513590-1-thuth@redhat.com> Acked-by: Cornelia Huck Signed-off-by: Thomas Huth --- hw/s390x/s390-virtio-ccw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 047cca0487..cc3097bfee 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -768,7 +768,7 @@ bool css_migration_enabled(void) { \ MachineClass *mc = MACHINE_CLASS(oc); \ ccw_machine_##suffix##_class_options(mc); \ - mc->desc = "VirtIO-ccw based S390 machine v" verstr; \ + mc->desc = "Virtual s390x machine (version " verstr ")"; \ if (latest) { \ mc->alias = "s390-ccw-virtio"; \ mc->is_default = true; \ From 54354861d21b69ec0781f43e67b8d4f6edad7e3f Mon Sep 17 00:00:00 2001 From: Janis Schoetterl-Glausch Date: Fri, 6 May 2022 17:39:56 +0200 Subject: [PATCH 758/935] target/s390x: kvm: Honor storage keys during emulation Storage key controlled protection is currently not honored when emulating instructions. If available, enable key protection for the MEM_OP ioctl, thereby enabling it for the s390_cpu_virt_mem_* functions, when using kvm. As a result, the emulation of the following instructions honors storage keys: * CLP The Synch I/O CLP command would need special handling in order to support storage keys, but is currently not supported. * CHSC Performing commands asynchronously would require special handling, but commands are currently always synchronous. * STSI * TSCH Must (and does) not change channel if terminated due to protection. * MSCH Suppressed on protection, works because fetching instruction. * SSCH Suppressed on protection, works because fetching instruction. * STSCH * STCRW Suppressed on protection, this works because no partial store is possible, because the operand cannot span multiple pages. * PCISTB * MPCIFC * STPCIFC Signed-off-by: Janis Schoetterl-Glausch Message-Id: <20220506153956.2217601-3-scgl@linux.ibm.com> Signed-off-by: Thomas Huth --- target/s390x/kvm/kvm.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c index 53098bf541..7bd8db0e7b 100644 --- a/target/s390x/kvm/kvm.c +++ b/target/s390x/kvm/kvm.c @@ -151,12 +151,15 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { static int cap_sync_regs; static int cap_async_pf; static int cap_mem_op; +static int cap_mem_op_extension; static int cap_s390_irq; static int cap_ri; static int cap_hpage_1m; static int cap_vcpu_resets; static int cap_protected; +static bool mem_op_storage_key_support; + static int active_cmma; static int kvm_s390_query_mem_limit(uint64_t *memory_limit) @@ -354,6 +357,8 @@ int kvm_arch_init(MachineState *ms, KVMState *s) cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS); cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF); cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP); + cap_mem_op_extension = kvm_check_extension(s, KVM_CAP_S390_MEM_OP_EXTENSION); + mem_op_storage_key_support = cap_mem_op_extension > 0; cap_s390_irq = kvm_check_extension(s, KVM_CAP_S390_INJECT_IRQ); cap_vcpu_resets = kvm_check_extension(s, KVM_CAP_S390_VCPU_RESETS); cap_protected = kvm_check_extension(s, KVM_CAP_S390_PROTECTED); @@ -842,6 +847,7 @@ int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf, : KVM_S390_MEMOP_LOGICAL_READ, .buf = (uint64_t)hostbuf, .ar = ar, + .key = (cpu->env.psw.mask & PSW_MASK_KEY) >> PSW_SHIFT_KEY, }; int ret; @@ -851,6 +857,9 @@ int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf, if (!hostbuf) { mem_op.flags |= KVM_S390_MEMOP_F_CHECK_ONLY; } + if (mem_op_storage_key_support) { + mem_op.flags |= KVM_S390_MEMOP_F_SKEY_PROTECTION; + } ret = kvm_vcpu_ioctl(CPU(cpu), KVM_S390_MEM_OP, &mem_op); if (ret < 0) { From 117d794396cea7d9c661c95e716eb618406d31aa Mon Sep 17 00:00:00 2001 From: Eric Farman Date: Wed, 25 May 2022 16:58:14 +0200 Subject: [PATCH 759/935] MAINTAINERS: Update s390 vhost entries Commit 7a523d96a0 ("virtio-ccw: move vhost_ccw_scsi to a separate file") introduced a new file hw/s390x/vhost-scsi-ccw.c, which received a couple comments [1][2] to update MAINTAINERS that were missed. Fix that by making the vhost CCW entries a wildcard. [1] https://lore.kernel.org/r/d8d2bbd5021076bdba444d31a6da74f507baede3.camel@linux.ibm.com/ [2] https://lore.kernel.org/r/87k0c4gb9f.fsf@redhat.com/ Signed-off-by: Eric Farman Reviewed-by: Cornelia Huck Message-Id: <20220525145814.2750501-1-farman@linux.ibm.com> Signed-off-by: Thomas Huth --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 00dc4a8ecb..7b7d3f9c02 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2018,8 +2018,7 @@ M: Halil Pasic M: Eric Farman S: Supported F: hw/s390x/virtio-ccw*.[hc] -F: hw/s390x/vhost-vsock-ccw.c -F: hw/s390x/vhost-user-fs-ccw.c +F: hw/s390x/vhost-*-ccw.c T: git https://gitlab.com/cohuck/qemu.git s390-next T: git https://github.com/borntraeger/qemu.git s390-next L: qemu-s390x@nongnu.org From 69d0535db941d1095d6ee2dba019c4c8cf8e2fa1 Mon Sep 17 00:00:00 2001 From: Gautam Agrawal Date: Wed, 1 Jun 2022 00:05:24 +0530 Subject: [PATCH 760/935] tests/tcg: Test overflow conditions Add a test to check for overflow conditions in s390x. This patch is based on the following patches : * https://git.qemu.org/?p=qemu.git;a=commitdiff;h=5a2e67a691501 * https://git.qemu.org/?p=qemu.git;a=commitdiff;h=fc6e0d0f2db51 Signed-off-by: Gautam Agrawal Message-Id: <20220531183524.40948-1-gautamnagrawal@gmail.com> [thuth: Move overflow.c to tests/tcg/multiarch/ to make it generic] Signed-off-by: Thomas Huth --- tests/tcg/multiarch/overflow.c | 58 ++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 tests/tcg/multiarch/overflow.c diff --git a/tests/tcg/multiarch/overflow.c b/tests/tcg/multiarch/overflow.c new file mode 100644 index 0000000000..1c59c2cb70 --- /dev/null +++ b/tests/tcg/multiarch/overflow.c @@ -0,0 +1,58 @@ +#include + +int overflow_add_32(int x, int y) +{ + int res; + return __builtin_add_overflow(x, y, &res); +} + +int overflow_add_64(long long x, long long y) +{ + long long res; + return __builtin_add_overflow(x, y, &res); +} + +int overflow_sub_32(int x, int y) +{ + int res; + return __builtin_sub_overflow(x, y, &res); +} + +int overflow_sub_64(long long x, long long y) +{ + long long res; + return __builtin_sub_overflow(x, y, &res); +} + +int a1_add = -2147483648; +int b1_add = -2147483648; +long long a2_add = -9223372036854775808ULL; +long long b2_add = -9223372036854775808ULL; + +int a1_sub; +int b1_sub = -2147483648; +long long a2_sub = 0L; +long long b2_sub = -9223372036854775808ULL; + +int main() +{ + int ret = 0; + + if (!overflow_add_32(a1_add, b1_add)) { + fprintf(stderr, "data overflow while adding 32 bits\n"); + ret = 1; + } + if (!overflow_add_64(a2_add, b2_add)) { + fprintf(stderr, "data overflow while adding 64 bits\n"); + ret = 1; + } + if (!overflow_sub_32(a1_sub, b1_sub)) { + fprintf(stderr, "data overflow while subtracting 32 bits\n"); + ret = 1; + } + if (!overflow_sub_64(a2_sub, b2_sub)) { + fprintf(stderr, "data overflow while subtracting 64 bits\n"); + ret = 1; + } + return ret; +} From 2ac7d741170bec72bc0a1fd333927f8b98cdc4ca Mon Sep 17 00:00:00 2001 From: Hailiang Zhang Date: Tue, 14 Dec 2021 15:54:24 +0800 Subject: [PATCH 761/935] MAINTAINERS: Change my email address The zhang.zhanghailiang@huawei.com email address has been stopped. Change it to my new email address. Signed-off-by: Hailiang Zhang Message-Id: <20211214075424.6920-1-zhanghailiang@xfusion.com> Acked-by: Gonglei Acked-by: Zhang Chen Signed-off-by: Thomas Huth --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 7b7d3f9c02..ee9693dc3a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3102,7 +3102,7 @@ F: include/qemu/yank.h F: qapi/yank.json COLO Framework -M: zhanghailiang +M: Hailiang Zhang S: Maintained F: migration/colo* F: include/migration/colo.h From c5f1bb4272a6c2d10dd92fd2285ed5adb988088e Mon Sep 17 00:00:00 2001 From: Wenchao Wang Date: Tue, 15 Mar 2022 20:51:22 +0800 Subject: [PATCH 762/935] MAINTAINERS: Update maintainers for Guest x86 HAXM CPUs Clean up the maintainer list. Reviewed-by: Hang Yuan Signed-off-by: Wenchao Wang Message-Id: [thuth: Note: Colin Xu's address bounces] Signed-off-by: Thomas Huth --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index ee9693dc3a..5fe8f7eca2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -488,7 +488,6 @@ Guest CPU Cores (HAXM) --------------------- X86 HAXM CPUs M: Wenchao Wang -M: Colin Xu L: haxm-team@intel.com W: https://github.com/intel/haxm/issues S: Maintained From d412597ec5a8406b2af6aa5fb7740e77c1bd3f8c Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Tue, 31 May 2022 12:09:21 +0400 Subject: [PATCH 763/935] qtest/npcm7xx_pwm-test: Fix memory leak in mft_qom_set g_strdup_printf() allocated memory for path, we should free it with g_free() when no longer needed. Signed-off-by: Miaoqian Lin Reviewed-by: Hao Wu Message-Id: <20220531080921.4704-1-linmq006@gmail.com> Signed-off-by: Thomas Huth --- tests/qtest/npcm7xx_pwm-test.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/qtest/npcm7xx_pwm-test.c b/tests/qtest/npcm7xx_pwm-test.c index c4a5fdcacd..e320a625c4 100644 --- a/tests/qtest/npcm7xx_pwm-test.c +++ b/tests/qtest/npcm7xx_pwm-test.c @@ -268,6 +268,9 @@ static void mft_qom_set(QTestState *qts, int index, const char *name, path, name, value); /* The qom set message returns successfully. */ g_assert_true(qdict_haskey(response, "return")); + + qobject_unref(response); + g_free(path); } static uint32_t get_pll(uint32_t con) From 55c269829de131d611103a7e643d48fe3bd08299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 24 May 2022 16:40:52 +0100 Subject: [PATCH 764/935] tests/qtest: use g_autofree for test_server_create_chr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alex Bennée Message-Id: <20220524154056.2896913-12-alex.bennee@linaro.org> Signed-off-by: Thomas Huth --- tests/qtest/vhost-user-test.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/qtest/vhost-user-test.c b/tests/qtest/vhost-user-test.c index a2cec87684..8bf390be20 100644 --- a/tests/qtest/vhost-user-test.c +++ b/tests/qtest/vhost-user-test.c @@ -524,14 +524,13 @@ static void chr_event(void *opaque, QEMUChrEvent event) static void test_server_create_chr(TestServer *server, const gchar *opt) { - gchar *chr_path; + g_autofree gchar *chr_path = g_strdup_printf("unix:%s%s", + server->socket_path, opt); Chardev *chr; - chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt); chr = qemu_chr_new(server->chr_name, chr_path, server->context); - g_free(chr_path); + g_assert(chr); - g_assert_nonnull(chr); qemu_chr_fe_init(&server->chr, chr, &error_abort); qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read, chr_event, NULL, server, server->context, true); From a743d60bcaa6a3a33f4376f87c1fc7cc977bc811 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 19 May 2022 17:56:23 +0200 Subject: [PATCH 765/935] ui: Remove deprecated parameters of the "-display sdl" option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dropping these deprecated parameters simplifies further refactoring (e.g. QAPIfication is easier without underscores in the name). Message-Id: <20220519155625.1414365-2-thuth@redhat.com> Reviewed-by: Daniel P. Berrangé Reviewed-by: Markus Armbruster Signed-off-by: Thomas Huth --- docs/about/deprecated.rst | 16 ------------- docs/about/removed-features.rst | 17 ++++++++++++++ qemu-options.hx | 32 ++----------------------- softmmu/vl.c | 41 +-------------------------------- 4 files changed, 20 insertions(+), 86 deletions(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index a92ae0f162..562a133f18 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -81,22 +81,6 @@ the process listing. This is replaced by the new ``password-secret`` option which lets the password be securely provided on the command line using a ``secret`` object instance. -``-display sdl,window_close=...`` (since 6.1) -''''''''''''''''''''''''''''''''''''''''''''' - -Use ``-display sdl,window-close=...`` instead (i.e. with a minus instead of -an underscore between "window" and "close"). - -``-alt-grab`` and ``-display sdl,alt_grab=on`` (since 6.2) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -Use ``-display sdl,grab-mod=lshift-lctrl-lalt`` instead. - -``-ctrl-grab`` and ``-display sdl,ctrl_grab=on`` (since 6.2) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -Use ``-display sdl,grab-mod=rctrl`` instead. - ``-sdl`` (since 6.2) '''''''''''''''''''' diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index eb76974347..4c9e001c35 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -370,6 +370,23 @@ The ``opened=on`` option in the command line or QMP ``object-add`` either had no effect (if ``opened`` was the last option) or caused errors. The property is therefore useless and should simply be removed. +``-display sdl,window_close=...`` (removed in 7.1) +'''''''''''''''''''''''''''''''''''''''''''''''''' + +Use ``-display sdl,window-close=...`` instead (i.e. with a minus instead of +an underscore between "window" and "close"). + +``-alt-grab`` and ``-display sdl,alt_grab=on`` (removed in 7.1) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Use ``-display sdl,grab-mod=lshift-lctrl-lalt`` instead. + +``-ctrl-grab`` and ``-display sdl,ctrl_grab=on`` (removed in 7.1) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Use ``-display sdl,grab-mod=rctrl`` instead. + + QEMU Machine Protocol (QMP) commands ------------------------------------ diff --git a/qemu-options.hx b/qemu-options.hx index a664baaa18..726e437a97 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1938,8 +1938,8 @@ DEF("display", HAS_ARG, QEMU_OPTION_display, "-display spice-app[,gl=on|off]\n" #endif #if defined(CONFIG_SDL) - "-display sdl[,alt_grab=on|off][,ctrl_grab=on|off][,gl=on|core|es|off]\n" - " [,grab-mod=][,show-cursor=on|off][,window-close=on|off]\n" + "-display sdl[,gl=on|core|es|off][,grab-mod=][,show-cursor=on|off]\n" + " [,window-close=on|off]\n" #endif #if defined(CONFIG_GTK) "-display gtk[,full-screen=on|off][,gl=on|off][,grab-on-hover=on|off]\n" @@ -2012,12 +2012,6 @@ SRST the mouse grabbing in conjunction with the "g" key. ```` can be either ``lshift-lctrl-lalt`` or ``rctrl``. - ``alt_grab=on|off`` : Use Control+Alt+Shift-g to toggle mouse grabbing. - This parameter is deprecated - use ``grab-mod`` instead. - - ``ctrl_grab=on|off`` : Use Right-Control-g to toggle mouse grabbing. - This parameter is deprecated - use ``grab-mod`` instead. - ``gl=on|off|core|es`` : Use OpenGL for displaying ``show-cursor=on|off`` : Force showing the mouse cursor @@ -2103,28 +2097,6 @@ SRST is displayed in graphical mode. ERST -DEF("alt-grab", 0, QEMU_OPTION_alt_grab, - "-alt-grab use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt)\n", - QEMU_ARCH_ALL) -SRST -``-alt-grab`` - Use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt). Note that - this also affects the special keys (for fullscreen, monitor-mode - switching, etc). This option is deprecated - please use - ``-display sdl,grab-mod=lshift-lctrl-lalt`` instead. -ERST - -DEF("ctrl-grab", 0, QEMU_OPTION_ctrl_grab, - "-ctrl-grab use Right-Ctrl to grab mouse (instead of Ctrl-Alt)\n", - QEMU_ARCH_ALL) -SRST -``-ctrl-grab`` - Use Right-Ctrl to grab mouse (instead of Ctrl-Alt). Note that this - also affects the special keys (for fullscreen, monitor-mode - switching, etc). This option is deprecated - please use - ``-display sdl,grab-mod=rctrl`` instead. -ERST - DEF("sdl", 0, QEMU_OPTION_sdl, "-sdl shorthand for -display sdl\n", QEMU_ARCH_ALL) SRST diff --git a/softmmu/vl.c b/softmmu/vl.c index 84a31eba76..57ab9d5322 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -1079,32 +1079,7 @@ static void parse_display(const char *p) } else { goto invalid_sdl_args; } - } else if (strstart(opts, ",alt_grab=", &nextopt)) { - opts = nextopt; - if (strstart(opts, "on", &nextopt)) { - alt_grab = 1; - } else if (strstart(opts, "off", &nextopt)) { - alt_grab = 0; - } else { - goto invalid_sdl_args; - } - warn_report("alt_grab is deprecated, use grab-mod instead."); - } else if (strstart(opts, ",ctrl_grab=", &nextopt)) { - opts = nextopt; - if (strstart(opts, "on", &nextopt)) { - ctrl_grab = 1; - } else if (strstart(opts, "off", &nextopt)) { - ctrl_grab = 0; - } else { - goto invalid_sdl_args; - } - warn_report("ctrl_grab is deprecated, use grab-mod instead."); - } else if (strstart(opts, ",window_close=", &nextopt) || - strstart(opts, ",window-close=", &nextopt)) { - if (strstart(opts, ",window_close=", NULL)) { - warn_report("window_close with an underscore is deprecated," - " please use window-close instead."); - } + } else if (strstart(opts, ",window-close=", &nextopt)) { opts = nextopt; dpy.has_window_close = true; if (strstart(opts, "on", &nextopt)) { @@ -1962,10 +1937,6 @@ static void qemu_create_early_backends(void) const bool use_gtk = false; #endif - if ((alt_grab || ctrl_grab) && !use_sdl) { - error_report("-alt-grab and -ctrl-grab are only valid " - "for SDL, ignoring option"); - } if (dpy.has_window_close && !use_gtk && !use_sdl) { error_report("window-close is only valid for GTK and SDL, " "ignoring option"); @@ -3273,16 +3244,6 @@ void qemu_init(int argc, char **argv, char **envp) dpy.has_full_screen = true; dpy.full_screen = true; break; - case QEMU_OPTION_alt_grab: - alt_grab = 1; - warn_report("-alt-grab is deprecated, please use " - "-display sdl,grab-mod=lshift-lctrl-lalt instead."); - break; - case QEMU_OPTION_ctrl_grab: - ctrl_grab = 1; - warn_report("-ctrl-grab is deprecated, please use " - "-display sdl,grab-mod=rctrl instead."); - break; case QEMU_OPTION_sdl: warn_report("-sdl is deprecated, use -display sdl instead."); #ifdef CONFIG_SDL From 9eafdeeac3513eb515c0e602fc56aa73353cf20d Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 19 May 2022 17:56:24 +0200 Subject: [PATCH 766/935] ui: Switch "-display sdl" to use the QAPI parser The "-display sdl" option still uses a hand-crafted parser for its parameters since we didn't want to drag an interface we considered somewhat flawed into the QAPI schema. Since the flaws are gone now, it's time to QAPIfy. This introduces the new "DisplaySDL" QAPI struct that is used to hold the parameters that are unique to the SDL display. The only specific parameter is currently "grab-mod" that is used to specify the required modifier keys to escape from the mouse grabbing mode. Message-Id: <20220519155625.1414365-3-thuth@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Thomas Huth --- include/sysemu/sysemu.h | 2 -- qapi/ui.json | 26 ++++++++++++++- softmmu/globals.c | 2 -- softmmu/vl.c | 70 +---------------------------------------- ui/sdl2.c | 10 ++++++ 5 files changed, 36 insertions(+), 74 deletions(-) diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index b4030acd74..812f66a31a 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -42,8 +42,6 @@ extern int graphic_depth; extern int display_opengl; extern const char *keyboard_layout; extern int win2k_install_hack; -extern int alt_grab; -extern int ctrl_grab; extern int graphic_rotate; extern int old_param; extern uint8_t *boot_splash_filedata; diff --git a/qapi/ui.json b/qapi/ui.json index 11a827d10f..413371d5e8 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -1295,6 +1295,29 @@ '*swap-opt-cmd': 'bool' } } +## +# @HotKeyMod: +# +# Set of modifier keys that need to be held for shortcut key actions. +# +# Since: 7.1 +## +{ 'enum' : 'HotKeyMod', + 'data' : [ 'lctrl-lalt', 'lshift-lctrl-lalt', 'rctrl' ] } + +## +# @DisplaySDL: +# +# SDL2 display options. +# +# @grab-mod: Modifier keys that should be pressed together with the +# "G" key to release the mouse grab. +# +# Since: 7.1 +## +{ 'struct' : 'DisplaySDL', + 'data' : { '*grab-mod' : 'HotKeyMod' } } + ## # @DisplayType: # @@ -1374,7 +1397,8 @@ 'curses': { 'type': 'DisplayCurses', 'if': 'CONFIG_CURSES' }, 'egl-headless': { 'type': 'DisplayEGLHeadless', 'if': { 'all': ['CONFIG_OPENGL', 'CONFIG_GBM'] } }, - 'dbus': { 'type': 'DisplayDBus', 'if': 'CONFIG_DBUS_DISPLAY' } + 'dbus': { 'type': 'DisplayDBus', 'if': 'CONFIG_DBUS_DISPLAY' }, + 'sdl': { 'type': 'DisplaySDL', 'if': 'CONFIG_SDL' } } } diff --git a/softmmu/globals.c b/softmmu/globals.c index 916bc12e2b..527edbefdd 100644 --- a/softmmu/globals.c +++ b/softmmu/globals.c @@ -50,8 +50,6 @@ QEMUOptionRom option_rom[MAX_OPTION_ROMS]; int nb_option_roms; int old_param; const char *qemu_name; -int alt_grab; -int ctrl_grab; unsigned int nb_prom_envs; const char *prom_envs[MAX_PROM_ENVS]; uint8_t *boot_splash_filedata; diff --git a/softmmu/vl.c b/softmmu/vl.c index 57ab9d5322..484e9d9921 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -1056,75 +1056,7 @@ static void parse_display(const char *p) exit(0); } - if (strstart(p, "sdl", &opts)) { - /* - * sdl DisplayType needs hand-crafted parser instead of - * parse_display_qapi() due to some options not in - * DisplayOptions, specifically: - * - ctrl_grab + alt_grab - * They can't be moved into the QAPI since they use underscores, - * thus they will get replaced by "grab-mod" in the long term - */ -#if defined(CONFIG_SDL) - dpy.type = DISPLAY_TYPE_SDL; - while (*opts) { - const char *nextopt; - - if (strstart(opts, ",grab-mod=", &nextopt)) { - opts = nextopt; - if (strstart(opts, "lshift-lctrl-lalt", &nextopt)) { - alt_grab = 1; - } else if (strstart(opts, "rctrl", &nextopt)) { - ctrl_grab = 1; - } else { - goto invalid_sdl_args; - } - } else if (strstart(opts, ",window-close=", &nextopt)) { - opts = nextopt; - dpy.has_window_close = true; - if (strstart(opts, "on", &nextopt)) { - dpy.window_close = true; - } else if (strstart(opts, "off", &nextopt)) { - dpy.window_close = false; - } else { - goto invalid_sdl_args; - } - } else if (strstart(opts, ",show-cursor=", &nextopt)) { - opts = nextopt; - dpy.has_show_cursor = true; - if (strstart(opts, "on", &nextopt)) { - dpy.show_cursor = true; - } else if (strstart(opts, "off", &nextopt)) { - dpy.show_cursor = false; - } else { - goto invalid_sdl_args; - } - } else if (strstart(opts, ",gl=", &nextopt)) { - opts = nextopt; - dpy.has_gl = true; - if (strstart(opts, "on", &nextopt)) { - dpy.gl = DISPLAYGL_MODE_ON; - } else if (strstart(opts, "core", &nextopt)) { - dpy.gl = DISPLAYGL_MODE_CORE; - } else if (strstart(opts, "es", &nextopt)) { - dpy.gl = DISPLAYGL_MODE_ES; - } else if (strstart(opts, "off", &nextopt)) { - dpy.gl = DISPLAYGL_MODE_OFF; - } else { - goto invalid_sdl_args; - } - } else { - invalid_sdl_args: - error_report("invalid SDL option string"); - exit(1); - } - opts = nextopt; - } -#else - error_report("SDL display supported is not available in this binary"); - exit(1); -#endif - } else if (strstart(p, "vnc", &opts)) { + if (strstart(p, "vnc", &opts)) { /* * vnc isn't a (local) DisplayType but a protocol for remote * display access. diff --git a/ui/sdl2.c b/ui/sdl2.c index d3741f9b75..8cb77416af 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -40,6 +40,8 @@ static struct sdl2_console *sdl2_console; static SDL_Surface *guest_sprite_surface; static int gui_grab; /* if true, all keyboard/mouse events are grabbed */ +static bool alt_grab; +static bool ctrl_grab; static int gui_saved_grab; static int gui_fullscreen; @@ -853,6 +855,14 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o) gui_fullscreen = o->has_full_screen && o->full_screen; + if (o->u.sdl.has_grab_mod) { + if (o->u.sdl.grab_mod == HOT_KEY_MOD_LSHIFT_LCTRL_LALT) { + alt_grab = true; + } else if (o->u.sdl.grab_mod == HOT_KEY_MOD_RCTRL) { + ctrl_grab = true; + } + } + for (i = 0;; i++) { QemuConsole *con = qemu_console_lookup_by_index(i); if (!con) { From 707d93d4abc6485c638e2aecd93fbd904f2f6b3e Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 19 May 2022 17:56:25 +0200 Subject: [PATCH 767/935] ui: Remove deprecated options "-sdl" and "-curses" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have "-sdl" and "-curses", but no "-gtk" and no "-cocoa" ... these old-style options are rather confusing than helpful nowadays. Now that the deprecation period is over, let's remove them, so we get a cleaner interface (where "-display" is the only way to select the user interface). Message-Id: <20220519155625.1414365-4-thuth@redhat.com> Reviewed-by: Daniel P. Berrangé Signed-off-by: Thomas Huth --- docs/about/deprecated.rst | 10 ---------- docs/about/removed-features.rst | 10 ++++++++++ qemu-options.hx | 24 ++---------------------- softmmu/vl.c | 19 ------------------- 4 files changed, 12 insertions(+), 51 deletions(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 562a133f18..e19bcba242 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -81,16 +81,6 @@ the process listing. This is replaced by the new ``password-secret`` option which lets the password be securely provided on the command line using a ``secret`` object instance. -``-sdl`` (since 6.2) -'''''''''''''''''''' - -Use ``-display sdl`` instead. - -``-curses`` (since 6.2) -''''''''''''''''''''''' - -Use ``-display curses`` instead. - ``-watchdog`` (since 6.2) ''''''''''''''''''''''''' diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 4c9e001c35..c7b9dadd5d 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -386,6 +386,16 @@ Use ``-display sdl,grab-mod=lshift-lctrl-lalt`` instead. Use ``-display sdl,grab-mod=rctrl`` instead. +``-sdl`` (removed in 7.1) +''''''''''''''''''''''''' + +Use ``-display sdl`` instead. + +``-curses`` (removed in 7.1) +'''''''''''''''''''''''''''' + +Use ``-display curses`` instead. + QEMU Machine Protocol (QMP) commands ------------------------------------ diff --git a/qemu-options.hx b/qemu-options.hx index 726e437a97..60cf188da4 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1981,9 +1981,8 @@ DEF("display", HAS_ARG, QEMU_OPTION_display, , QEMU_ARCH_ALL) SRST ``-display type`` - Select type of display to use. This option is a replacement for the - old style -sdl/-curses/... options. Use ``-display help`` to list - the available display types. Valid values for type are + Select type of display to use. Use ``-display help`` to list the available + display types. Valid values for type are ``spice-app[,gl=on|off]`` Start QEMU as a Spice server and launch the default Spice client @@ -2085,25 +2084,6 @@ SRST Use C-a h for help on switching between the console and monitor. ERST -DEF("curses", 0, QEMU_OPTION_curses, - "-curses shorthand for -display curses\n", - QEMU_ARCH_ALL) -SRST -``-curses`` - Normally, if QEMU is compiled with graphical window support, it - displays output such as guest graphics, guest console, and the QEMU - monitor in a window. With this option, QEMU can display the VGA - output when in text mode using a curses/ncurses interface. Nothing - is displayed in graphical mode. -ERST - -DEF("sdl", 0, QEMU_OPTION_sdl, - "-sdl shorthand for -display sdl\n", QEMU_ARCH_ALL) -SRST -``-sdl`` - Enable SDL. -ERST - #ifdef CONFIG_SPICE DEF("spice", HAS_ARG, QEMU_OPTION_spice, "-spice [port=port][,tls-port=secured-port][,x509-dir=

]\n" diff --git a/softmmu/vl.c b/softmmu/vl.c index 484e9d9921..4c1e94b00e 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2800,16 +2800,6 @@ void qemu_init(int argc, char **argv, char **envp) nographic = true; dpy.type = DISPLAY_TYPE_NONE; break; - case QEMU_OPTION_curses: - warn_report("-curses is deprecated, " - "use -display curses instead."); -#ifdef CONFIG_CURSES - dpy.type = DISPLAY_TYPE_CURSES; -#else - error_report("curses or iconv support is disabled"); - exit(1); -#endif - break; case QEMU_OPTION_portrait: graphic_rotate = 90; break; @@ -3176,15 +3166,6 @@ void qemu_init(int argc, char **argv, char **envp) dpy.has_full_screen = true; dpy.full_screen = true; break; - case QEMU_OPTION_sdl: - warn_report("-sdl is deprecated, use -display sdl instead."); -#ifdef CONFIG_SDL - dpy.type = DISPLAY_TYPE_SDL; - break; -#else - error_report("SDL support is disabled"); - exit(1); -#endif case QEMU_OPTION_pidfile: pid_file = optarg; break; From 1e64facc015e16d8e4efa239feaeda9e4e9aeb04 Mon Sep 17 00:00:00 2001 From: Dmitry Tikhov Date: Tue, 12 Apr 2022 11:59:09 +0300 Subject: [PATCH 768/935] hw/nvme: fix narrowing conversion Since nlbas is of type int, it does not work with large namespace size values, e.g., 9 TB size of file backing namespace and 8 byte metadata with 4096 bytes lbasz gives negative nlbas value, which is later promoted to negative int64_t type value and results in negative ns->moff which breaks namespace Signed-off-by: Dmitry Tikhov Reviewed-by: Klaus Jensen Signed-off-by: Klaus Jensen --- hw/nvme/ns.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c index 324f53ea0c..af6504fad2 100644 --- a/hw/nvme/ns.c +++ b/hw/nvme/ns.c @@ -29,7 +29,8 @@ void nvme_ns_init_format(NvmeNamespace *ns) { NvmeIdNs *id_ns = &ns->id_ns; BlockDriverInfo bdi; - int npdg, nlbas, ret; + int npdg, ret; + int64_t nlbas; ns->lbaf = id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)]; ns->lbasz = 1 << ns->lbaf.ds; @@ -42,7 +43,7 @@ void nvme_ns_init_format(NvmeNamespace *ns) id_ns->ncap = id_ns->nsze; id_ns->nuse = id_ns->ncap; - ns->moff = (int64_t)nlbas << ns->lbaf.ds; + ns->moff = nlbas << ns->lbaf.ds; npdg = ns->blkconf.discard_granularity / ns->lbasz; From 51c453266309166c2737623211c0afc12884cccd Mon Sep 17 00:00:00 2001 From: Dmitry Tikhov Date: Fri, 15 Apr 2022 23:48:32 +0300 Subject: [PATCH 769/935] hw/nvme: add missing return statement Since there is no return after nvme_dsm_cb invocation, metadata associated with non-zero block range is currently zeroed. Also this behaviour leads to segfault since we schedule iocb->bh two times. First when entering nvme_dsm_cb with iocb->idx == iocb->nr and second because of missing return on call stack unwinding by calling blk_aio_pwrite_zeroes and subsequent nvme_dsm_cb callback. Fixes: d7d1474fd85d ("hw/nvme: reimplement dsm to allow cancellation") Signed-off-by: Dmitry Tikhov Reviewed-by: Klaus Jensen Signed-off-by: Klaus Jensen --- hw/nvme/ctrl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 03760ddeae..74540a03d5 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -2372,6 +2372,7 @@ static void nvme_dsm_md_cb(void *opaque, int ret) } nvme_dsm_cb(iocb, 0); + return; } iocb->aiocb = blk_aio_pwrite_zeroes(ns->blkconf.blk, nvme_moff(ns, slba), From 2e8f952ae7de23b4847937dbbf51f7a1ab10a2af Mon Sep 17 00:00:00 2001 From: Dmitry Tikhov Date: Thu, 21 Apr 2022 13:51:58 +0300 Subject: [PATCH 770/935] hw/nvme: fix copy cmd for pi enabled namespaces Current implementation have problem in the read part of copy command. Because there is no metadata mangling before nvme_dif_check invocation, reftag error could be thrown for blocks of namespace that have not been previously written to. Signed-off-by: Dmitry Tikhov Reviewed-by: Klaus Jensen Signed-off-by: Klaus Jensen --- hw/nvme/ctrl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 74540a03d5..08574c4dcb 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -2787,6 +2787,10 @@ static void nvme_copy_in_completed_cb(void *opaque, int ret) size_t mlen = nvme_m2b(ns, nlb); uint8_t *mbounce = iocb->bounce + nvme_l2b(ns, nlb); + status = nvme_dif_mangle_mdata(ns, mbounce, mlen, slba); + if (status) { + goto invalid; + } status = nvme_dif_check(ns, iocb->bounce, len, mbounce, mlen, prinfor, slba, apptag, appmask, &reftag); if (status) { From 9235a72a5df0fae1ede89f02717b597ef91cf6ad Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Fri, 6 May 2022 00:21:47 +0200 Subject: [PATCH 771/935] hw/nvme: fix smart aen Pass the right constant to nvme_smart_event(). The NVME_AER* values hold the bit position in the SMART byte, not the shifted value that we expect it to be in nvme_smart_event(). Fixes: c62720f137df ("hw/block/nvme: trigger async event during injecting smart warning") Acked-by: zhenwei pi Signed-off-by: Klaus Jensen --- hw/nvme/ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 08574c4dcb..a2f6069f7f 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -5325,7 +5325,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req) if ((n->temperature >= n->features.temp_thresh_hi) || (n->temperature <= n->features.temp_thresh_low)) { - nvme_smart_event(n, NVME_AER_INFO_SMART_TEMP_THRESH); + nvme_smart_event(n, NVME_SMART_TEMPERATURE); } break; From a859eb9f8f64e116671048a43a07d87bc6527a55 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Fri, 29 Apr 2022 10:33:32 +0200 Subject: [PATCH 772/935] hw/nvme: enforce common serial per subsystem The Identify Controller Serial Number (SN) is the serial number for the NVM subsystem and must be the same across all controller in the NVM subsystem. Enforce this. Reviewed-by: Christoph Hellwig Reviewed-by: Keith Busch Signed-off-by: Klaus Jensen --- hw/nvme/nvme.h | 1 + hw/nvme/subsys.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h index 6773819325..e41771604f 100644 --- a/hw/nvme/nvme.h +++ b/hw/nvme/nvme.h @@ -48,6 +48,7 @@ typedef struct NvmeSubsystem { DeviceState parent_obj; NvmeBus bus; uint8_t subnqn[256]; + char *serial; NvmeCtrl *ctrls[NVME_MAX_CONTROLLERS]; NvmeNamespace *namespaces[NVME_MAX_NAMESPACES + 1]; diff --git a/hw/nvme/subsys.c b/hw/nvme/subsys.c index fb58d63950..691a90d209 100644 --- a/hw/nvme/subsys.c +++ b/hw/nvme/subsys.c @@ -27,6 +27,13 @@ int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp) return -1; } + if (!subsys->serial) { + subsys->serial = g_strdup(n->params.serial); + } else if (strcmp(subsys->serial, n->params.serial)) { + error_setg(errp, "invalid controller serial"); + return -1; + } + subsys->ctrls[cntlid] = n; for (nsid = 1; nsid < ARRAY_SIZE(subsys->namespaces); nsid++) { From 36d83272d5e45dff13e988ee0a59f11c58b442ba Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Fri, 29 Apr 2022 10:33:33 +0200 Subject: [PATCH 773/935] hw/nvme: do not auto-generate eui64 We cannot provide auto-generated unique or persistent namespace identifiers (EUI64, NGUID, UUID) easily. Since 6.1, namespaces have been assigned a generated EUI64 of the form "52:54:00:". This is will be unique within a QEMU instance, but not globally. Revert that this is assigned automatically and immediately deprecate the compatibility parameter. Users can opt-in to this with the `eui64-default=on` device parameter or set it explicitly with `eui64=UINT64`. Cc: libvir-list@redhat.com Reviewed-by: Christoph Hellwig Signed-off-by: Klaus Jensen --- docs/about/deprecated.rst | 7 +++++++ hw/core/machine.c | 1 + hw/nvme/ns.c | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index e19bcba242..47a8628b56 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -296,6 +296,13 @@ contains native support for this feature and thus use of the option ROM approach is obsolete. The native SeaBIOS support can be activated by using ``-machine graphics=off``. +``-device nvme-ns,eui64-default=on|off`` (since 7.1) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In QEMU versions 6.1, 6.2 and 7.0, the ``nvme-ns`` generates an EUI-64 +identifer that is not globally unique. If an EUI-64 identifer is required, the +user must set it explicitly using the ``nvme-ns`` device parameter ``eui64``. + Block device options '''''''''''''''''''' diff --git a/hw/core/machine.c b/hw/core/machine.c index bb0dc8f6a9..c53548d0b1 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -43,6 +43,7 @@ GlobalProperty hw_compat_7_0[] = { { "arm-gicv3-common", "force-8-bit-prio", "on" }, + { "nvme-ns", "eui64-default", "on"}, }; const size_t hw_compat_7_0_len = G_N_ELEMENTS(hw_compat_7_0); diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c index af6504fad2..06a04131f1 100644 --- a/hw/nvme/ns.c +++ b/hw/nvme/ns.c @@ -641,7 +641,7 @@ static Property nvme_ns_props[] = { DEFINE_PROP_SIZE("zoned.zrwas", NvmeNamespace, params.zrwas, 0), DEFINE_PROP_SIZE("zoned.zrwafg", NvmeNamespace, params.zrwafg, -1), DEFINE_PROP_BOOL("eui64-default", NvmeNamespace, params.eui64_default, - true), + false), DEFINE_PROP_END_OF_LIST(), }; From bd9f371c6f6eeb8e907dfc770876ad8ef4ff85fc Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Fri, 29 Apr 2022 10:33:34 +0200 Subject: [PATCH 774/935] hw/nvme: do not auto-generate uuid Do not default to generate an UUID for namespaces if it is not explicitly specified. This is a technically a breaking change in behavior. However, since the UUID changes on every VM launch, it is not spec compliant and is of little use since the UUID cannot be used reliably anyway and the behavior prior to this patch must be considered buggy. Reviewed-by: Keith Busch Reviewed-by: Christoph Hellwig Signed-off-by: Klaus Jensen --- hw/nvme/ns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c index 06a04131f1..1b9c9d1156 100644 --- a/hw/nvme/ns.c +++ b/hw/nvme/ns.c @@ -614,7 +614,7 @@ static Property nvme_ns_props[] = { DEFINE_PROP_BOOL("detached", NvmeNamespace, params.detached, false), DEFINE_PROP_BOOL("shared", NvmeNamespace, params.shared, true), DEFINE_PROP_UINT32("nsid", NvmeNamespace, params.nsid, 0), - DEFINE_PROP_UUID("uuid", NvmeNamespace, params.uuid), + DEFINE_PROP_UUID_NODEFAULT("uuid", NvmeNamespace, params.uuid), DEFINE_PROP_UINT64("eui64", NvmeNamespace, params.eui64, 0), DEFINE_PROP_UINT16("ms", NvmeNamespace, params.ms, 0), DEFINE_PROP_UINT8("mset", NvmeNamespace, params.mset, 0), From 9f2e1acf83c332752f52c39dad390c94ec2ba9f5 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Fri, 29 Apr 2022 10:33:35 +0200 Subject: [PATCH 775/935] hw/nvme: do not report null uuid Do not report the "null uuid" (all zeros) in the namespace identification descriptors. Reported-by: Luis Chamberlain Reported-by: Christoph Hellwig Reviewed-by: Christoph Hellwig Reviewed-by: Keith Busch Signed-off-by: Klaus Jensen --- hw/nvme/ctrl.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index a2f6069f7f..909e357a7e 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -4955,16 +4955,13 @@ static uint16_t nvme_identify_ns_descr_list(NvmeCtrl *n, NvmeRequest *req) return NVME_INVALID_FIELD | NVME_DNR; } - /* - * If the EUI-64 field is 0 and the NGUID field is 0, the namespace must - * provide a valid Namespace UUID in the Namespace Identification Descriptor - * data structure. QEMU does not yet support setting NGUID. - */ - uuid.hdr.nidt = NVME_NIDT_UUID; - uuid.hdr.nidl = NVME_NIDL_UUID; - memcpy(uuid.v, ns->params.uuid.data, NVME_NIDL_UUID); - memcpy(pos, &uuid, sizeof(uuid)); - pos += sizeof(uuid); + if (!qemu_uuid_is_null(&ns->params.uuid)) { + uuid.hdr.nidt = NVME_NIDT_UUID; + uuid.hdr.nidl = NVME_NIDL_UUID; + memcpy(uuid.v, ns->params.uuid.data, NVME_NIDL_UUID); + memcpy(pos, &uuid, sizeof(uuid)); + pos += sizeof(uuid); + } if (ns->params.eui64) { eui64.hdr.nidt = NVME_NIDT_EUI64; From fbba243bc700a4e479331e20544c7f6a41ae87b3 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Fri, 29 Apr 2022 10:33:36 +0200 Subject: [PATCH 776/935] hw/nvme: bump firmware revision The Linux kernel quirks the QEMU NVMe controller pretty heavily because of the namespace identifier mess. Since this is now fixed, bump the firmware revision number to allow the quirk to be disabled for this revision. As of now, bump the firmware revision number to be equal to the QEMU release version number. Reviewed-by: Keith Busch Signed-off-by: Klaus Jensen --- hw/nvme/ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 909e357a7e..1e6e0fcad9 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -6713,7 +6713,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID)); id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID)); strpadcpy((char *)id->mn, sizeof(id->mn), "QEMU NVMe Ctrl", ' '); - strpadcpy((char *)id->fr, sizeof(id->fr), "1.0", ' '); + strpadcpy((char *)id->fr, sizeof(id->fr), QEMU_VERSION, ' '); strpadcpy((char *)id->sn, sizeof(id->sn), n->params.serial, ' '); id->cntlid = cpu_to_le16(n->cntlid); From 8b1e59a6873662a01379cf052384e5dedefe7447 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 19 Apr 2022 13:24:23 +0200 Subject: [PATCH 777/935] hw/nvme: deprecate the use-intel-id compatibility parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since version 5.2 commit 6eb7a071292a ("hw/block/nvme: change controller pci id"), the emulated NVMe controller has defaulted to a non-Intel PCI identifier. Deprecate the compatibility parameter so we can get rid of it once and for all. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Klaus Jensen --- docs/about/deprecated.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 47a8628b56..aa2e320207 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -303,6 +303,14 @@ In QEMU versions 6.1, 6.2 and 7.0, the ``nvme-ns`` generates an EUI-64 identifer that is not globally unique. If an EUI-64 identifer is required, the user must set it explicitly using the ``nvme-ns`` device parameter ``eui64``. +``-device nvme,use-intel-id=on|off`` (since 7.1) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``nvme`` device originally used a PCI Vendor/Device Identifier combination +from Intel that was not properly allocated. Since version 5.2, the controller +has used a properly allocated identifier. Deprecate the ``use-intel-id`` +machine compatibility parameter. + Block device options '''''''''''''''''''' From d7fe639cabf778903f6cab23ff58c905c71375ec Mon Sep 17 00:00:00 2001 From: Dmitry Tikhov Date: Wed, 20 Apr 2022 11:20:44 +0300 Subject: [PATCH 778/935] hw/nvme: add new command abort case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NVMe command set specification for end-to-end data protection formatted namespace states: o If the Reference Tag Check bit of the PRCHK field is set to ‘1’ and the namespace is formatted for Type 3 protection, then the controller: ▪ should not compare the protection Information Reference Tag field to the computed reference tag; and ▪ may ignore the ILBRT and EILBRT fields. If a command is aborted as a result of the Reference Tag Check bit of the PRCHK field being set to ‘1’, then that command should be aborted with a status code of Invalid Protection Information, but may be aborted with a status code of Invalid Field in Command. Currently qemu compares reftag in the nvme_dif_prchk function whenever Reference Tag Check bit is set in the command. For type 3 namespaces however, caller of nvme_dif_prchk - nvme_dif_check does not increment reftag for each subsequent logical block. That way commands incorporating more than one logical block for type 3 formatted namespaces with reftag check bit set, always fail with End-to-end Reference Tag Check Error. Comply with spec by handling case of set Reference Tag Check bit in the type 3 formatted namespace. Fixes: 146f720c5563 ("hw/block/nvme: end-to-end data protection") Signed-off-by: Dmitry Tikhov Signed-off-by: Klaus Jensen --- hw/nvme/dif.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/nvme/dif.c b/hw/nvme/dif.c index 62d885f83e..63c44c86ab 100644 --- a/hw/nvme/dif.c +++ b/hw/nvme/dif.c @@ -26,6 +26,11 @@ uint16_t nvme_check_prinfo(NvmeNamespace *ns, uint8_t prinfo, uint64_t slba, return NVME_INVALID_PROT_INFO | NVME_DNR; } + if ((NVME_ID_NS_DPS_TYPE(ns->id_ns.dps) == NVME_ID_NS_DPS_TYPE_3) && + (prinfo & NVME_PRINFO_PRCHK_REF)) { + return NVME_INVALID_PROT_INFO; + } + return NVME_SUCCESS; } From 9f9dcb96a46a60fcf95f7baebafa3ec5e2a1b5ce Mon Sep 17 00:00:00 2001 From: Stephen Michael Jothen Date: Wed, 25 May 2022 17:33:36 +0200 Subject: [PATCH 779/935] target/i386/tcg: Fix masking of real-mode addresses with A20 bit The correct A20 masking is done if paging is enabled (protected mode) but it seems to have been forgotten in real mode. For example from the AMD64 APM Vol. 2 section 1.2.4: > If the sum of the segment base and effective address carries over into bit 20, > that bit can be optionally truncated to mimic the 20-bit address wrapping of the > 8086 processor by using the A20M# input signal to mask the A20 address bit. Most BIOSes will enable the A20 line on boot, but I found by disabling the A20 line afterwards, the correct wrapping wasn't taking place. `handle_mmu_fault' in target/i386/tcg/sysemu/excp_helper.c seems to be the culprit. In real mode, it fills the TLB with the raw unmasked address. However, for the protected mode, the `mmu_translate' function does the correct A20 masking. The fix then should be to just apply the A20 mask in the first branch of the if statement. Signed-off-by: Stephen Michael Jothen Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/tcg/sysemu/excp_helper.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c index e1b6d88683..48feba7e75 100644 --- a/target/i386/tcg/sysemu/excp_helper.c +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -359,6 +359,7 @@ static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, CPUX86State *env = &cpu->env; int error_code = PG_ERROR_OK; int pg_mode, prot, page_size; + int32_t a20_mask; hwaddr paddr; hwaddr vaddr; @@ -368,7 +369,8 @@ static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, #endif if (!(env->cr[0] & CR0_PG_MASK)) { - paddr = addr; + a20_mask = x86_get_a20_mask(env); + paddr = addr & a20_mask; #ifdef TARGET_X86_64 if (!(env->hflags & HF_LMA_MASK)) { /* Without long mode we can only address 32bits in real mode */ From d8f3a60931a700c327aa2ee10d0beaeea2cb97da Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 30 May 2022 14:24:34 +0200 Subject: [PATCH 780/935] build: add a "make modules" target Signed-off-by: Paolo Bonzini --- meson.build | 3 +++ 1 file changed, 3 insertions(+) diff --git a/meson.build b/meson.build index bc6234c85e..9b3fd4e52b 100644 --- a/meson.build +++ b/meson.build @@ -3285,6 +3285,9 @@ foreach m : block_mods + softmmu_mods install: true, install_dir: qemu_moddir) endforeach +if emulator_modules.length() > 0 + alias_target('modules', emulator_modules) +endif softmmu_ss.add(authz, blockdev, chardev, crypto, io, qmp) common_ss.add(qom, qemuutil) From b0f3184e82817b700ea81bc76ebc8d999de35278 Mon Sep 17 00:00:00 2001 From: Yang Zhong Date: Mon, 30 May 2022 09:18:34 -0400 Subject: [PATCH 781/935] target/i386: Fix wrong count setting The previous patch used wrong count setting with index value, which got wrong value from CPUID(EAX=12,ECX=0):EAX. So the SGX1 instruction can't be exposed to VM and the SGX decice can't work in VM. Fixes: d19d6ffa0710 ("target/i386: introduce helper to access supported CPUID") Signed-off-by: Yang Zhong Message-Id: <20220530131834.1222801-1-yang.zhong@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index bb6a5dd498..9fdfec9d8b 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5559,7 +5559,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, * supports. Features can be further restricted by userspace, but not * made more permissive. */ - x86_cpu_get_supported_cpuid(0x12, index, eax, ebx, ecx, edx); + x86_cpu_get_supported_cpuid(0x12, count, eax, ebx, ecx, edx); if (count == 0) { *eax &= env->features[FEAT_SGX_12_0_EAX]; From 24ce7aa77dd1a3095d994bf53d60cce6e672cf4d Mon Sep 17 00:00:00 2001 From: "Jose R. Ziviani" Date: Sat, 28 May 2022 00:20:23 +0200 Subject: [PATCH 782/935] modules: introduces module_kconfig directive module_kconfig is a new directive that should be used with module_obj whenever that module depends on the Kconfig to be enabled. When the module is enabled in Kconfig we are sure that its dependencies will be enabled as well, thus the module will be loaded without any problem. The correct way to use module_kconfig is by passing the Kconfig option to module_kconfig (or the *config-devices.mak without CONFIG_). Signed-off-by: Jose R. Ziviani Signed-off-by: Dario Faggioli Message-Id: <165369002370.5857.12150544416563557322.stgit@work> Signed-off-by: Paolo Bonzini --- hw/display/qxl.c | 1 + hw/display/vhost-user-gpu-pci.c | 1 + hw/display/vhost-user-gpu.c | 1 + hw/display/vhost-user-vga.c | 1 + hw/display/virtio-gpu-base.c | 1 + hw/display/virtio-gpu-gl.c | 1 + hw/display/virtio-gpu-pci-gl.c | 1 + hw/display/virtio-gpu-pci.c | 1 + hw/display/virtio-gpu.c | 1 + hw/display/virtio-vga-gl.c | 1 + hw/display/virtio-vga.c | 1 + hw/s390x/virtio-ccw-gpu.c | 1 + hw/usb/ccid-card-emulated.c | 1 + hw/usb/ccid-card-passthru.c | 1 + hw/usb/host-libusb.c | 1 + hw/usb/redirect.c | 1 + include/qemu/module.h | 10 ++++++++++ scripts/modinfo-generate.py | 2 ++ 18 files changed, 28 insertions(+) diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 2db34714fb..5b10f697f1 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -2515,6 +2515,7 @@ static const TypeInfo qxl_primary_info = { .class_init = qxl_primary_class_init, }; module_obj("qxl-vga"); +module_kconfig(QXL); static void qxl_secondary_class_init(ObjectClass *klass, void *data) { diff --git a/hw/display/vhost-user-gpu-pci.c b/hw/display/vhost-user-gpu-pci.c index daefcf7101..d119bcae45 100644 --- a/hw/display/vhost-user-gpu-pci.c +++ b/hw/display/vhost-user-gpu-pci.c @@ -44,6 +44,7 @@ static const VirtioPCIDeviceTypeInfo vhost_user_gpu_pci_info = { .instance_init = vhost_user_gpu_pci_initfn, }; module_obj(TYPE_VHOST_USER_GPU_PCI); +module_kconfig(VHOST_USER_GPU); static void vhost_user_gpu_pci_register_types(void) { diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c index 96e56c4467..3340ef9e5f 100644 --- a/hw/display/vhost-user-gpu.c +++ b/hw/display/vhost-user-gpu.c @@ -606,6 +606,7 @@ static const TypeInfo vhost_user_gpu_info = { .class_init = vhost_user_gpu_class_init, }; module_obj(TYPE_VHOST_USER_GPU); +module_kconfig(VHOST_USER_GPU); static void vhost_user_gpu_register_types(void) { diff --git a/hw/display/vhost-user-vga.c b/hw/display/vhost-user-vga.c index 072c9c65bc..0c146080fd 100644 --- a/hw/display/vhost-user-vga.c +++ b/hw/display/vhost-user-vga.c @@ -45,6 +45,7 @@ static const VirtioPCIDeviceTypeInfo vhost_user_vga_info = { .instance_init = vhost_user_vga_inst_initfn, }; module_obj(TYPE_VHOST_USER_VGA); +module_kconfig(VHOST_USER_VGA); static void vhost_user_vga_register_types(void) { diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c index 8ba5da4312..790cec333c 100644 --- a/hw/display/virtio-gpu-base.c +++ b/hw/display/virtio-gpu-base.c @@ -260,6 +260,7 @@ static const TypeInfo virtio_gpu_base_info = { .abstract = true }; module_obj(TYPE_VIRTIO_GPU_BASE); +module_kconfig(VIRTIO_GPU); static void virtio_register_types(void) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 0bca887703..e06be60dfb 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -160,6 +160,7 @@ static const TypeInfo virtio_gpu_gl_info = { .class_init = virtio_gpu_gl_class_init, }; module_obj(TYPE_VIRTIO_GPU_GL); +module_kconfig(VIRTIO_GPU); static void virtio_register_types(void) { diff --git a/hw/display/virtio-gpu-pci-gl.c b/hw/display/virtio-gpu-pci-gl.c index 99b14a0718..a2819e1ca9 100644 --- a/hw/display/virtio-gpu-pci-gl.c +++ b/hw/display/virtio-gpu-pci-gl.c @@ -47,6 +47,7 @@ static const VirtioPCIDeviceTypeInfo virtio_gpu_gl_pci_info = { .instance_init = virtio_gpu_gl_initfn, }; module_obj(TYPE_VIRTIO_GPU_GL_PCI); +module_kconfig(VIRTIO_PCI); static void virtio_gpu_gl_pci_register_types(void) { diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c index e36eee0c40..93f214ff58 100644 --- a/hw/display/virtio-gpu-pci.c +++ b/hw/display/virtio-gpu-pci.c @@ -65,6 +65,7 @@ static const TypeInfo virtio_gpu_pci_base_info = { .abstract = true }; module_obj(TYPE_VIRTIO_GPU_PCI_BASE); +module_kconfig(VIRTIO_PCI); #define TYPE_VIRTIO_GPU_PCI "virtio-gpu-pci" typedef struct VirtIOGPUPCI VirtIOGPUPCI; diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 529b5246b2..cd4a56056f 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1452,6 +1452,7 @@ static const TypeInfo virtio_gpu_info = { .class_init = virtio_gpu_class_init, }; module_obj(TYPE_VIRTIO_GPU); +module_kconfig(VIRTIO_GPU); static void virtio_register_types(void) { diff --git a/hw/display/virtio-vga-gl.c b/hw/display/virtio-vga-gl.c index f22549097c..984faa6b39 100644 --- a/hw/display/virtio-vga-gl.c +++ b/hw/display/virtio-vga-gl.c @@ -37,6 +37,7 @@ static VirtioPCIDeviceTypeInfo virtio_vga_gl_info = { .instance_init = virtio_vga_gl_inst_initfn, }; module_obj(TYPE_VIRTIO_VGA_GL); +module_kconfig(VIRTIO_VGA); static void virtio_vga_register_types(void) { diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index 7b55c8d0e7..c206b5da38 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -231,6 +231,7 @@ static const TypeInfo virtio_vga_base_info = { .abstract = true, }; module_obj(TYPE_VIRTIO_VGA_BASE); +module_kconfig(VIRTIO_VGA); #define TYPE_VIRTIO_VGA "virtio-vga" diff --git a/hw/s390x/virtio-ccw-gpu.c b/hw/s390x/virtio-ccw-gpu.c index 8d995fcb33..0642c5281d 100644 --- a/hw/s390x/virtio-ccw-gpu.c +++ b/hw/s390x/virtio-ccw-gpu.c @@ -69,6 +69,7 @@ static const TypeInfo virtio_ccw_gpu = { .class_init = virtio_ccw_gpu_class_init, }; module_obj(TYPE_VIRTIO_GPU_CCW); +module_kconfig(VIRTIO_CCW); static void virtio_ccw_gpu_register(void) { diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c index 6c8c0355e0..1ddf7297f6 100644 --- a/hw/usb/ccid-card-emulated.c +++ b/hw/usb/ccid-card-emulated.c @@ -613,6 +613,7 @@ static const TypeInfo emulated_card_info = { .class_init = emulated_class_initfn, }; module_obj(TYPE_EMULATED_CCID); +module_kconfig(USB); static void ccid_card_emulated_register_types(void) { diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c index f530ab2565..07ee42f304 100644 --- a/hw/usb/ccid-card-passthru.c +++ b/hw/usb/ccid-card-passthru.c @@ -415,6 +415,7 @@ static const TypeInfo passthru_card_info = { .class_init = passthru_class_initfn, }; module_obj(TYPE_CCID_PASSTHRU); +module_kconfig(USB); static void ccid_card_passthru_register_types(void) { diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index 2b35cb6cdd..28f8af8941 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -1809,6 +1809,7 @@ static const TypeInfo usb_host_dev_info = { .instance_init = usb_host_instance_init, }; module_obj(TYPE_USB_HOST_DEVICE); +module_kconfig(USB); static void usb_host_register_types(void) { diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 3bc4dee7fe..fd7df599bc 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -2620,6 +2620,7 @@ static const TypeInfo usbredir_dev_info = { .instance_init = usbredir_instance_init, }; module_obj(TYPE_USB_REDIR); +module_kconfig(USB); static void usbredir_register_types(void) { diff --git a/include/qemu/module.h b/include/qemu/module.h index 5fcc323b2a..bd73607104 100644 --- a/include/qemu/module.h +++ b/include/qemu/module.h @@ -135,6 +135,16 @@ void module_allow_arch(const char *arch); */ #define module_opts(name) modinfo(opts, name) +/** + * module_kconfig + * + * @name: Kconfig requirement necessary to load the module + * + * This module requires a core module that should be implemented and + * enabled in Kconfig. + */ +#define module_kconfig(name) modinfo(kconfig, name) + /* * module info database * diff --git a/scripts/modinfo-generate.py b/scripts/modinfo-generate.py index f559eed007..689f33c0f2 100755 --- a/scripts/modinfo-generate.py +++ b/scripts/modinfo-generate.py @@ -48,6 +48,8 @@ def generate(name, lines): opts.append(data) elif kind == 'arch': arch = data; + elif kind == 'kconfig': + pass # ignore else: print("unknown:", kind) exit(1) From 05d6814c3eb16524e992bb7048d3385f8e99dd6a Mon Sep 17 00:00:00 2001 From: "Jose R. Ziviani" Date: Sat, 28 May 2022 00:20:35 +0200 Subject: [PATCH 783/935] modules: generates per-target modinfo This patch changes the way modinfo is generated and built. Instead of one modinfo.c it generates one modinfo--softmmu.c per target. It aims a fine-tune control of modules by configuring Kconfig. Signed-off-by: Jose R. Ziviani Signed-off-by: Dario Faggioli Message-Id: <165369003038.5857.13084289285185196779.stgit@work> Signed-off-by: Paolo Bonzini --- meson.build | 25 +++++++++++++------ scripts/modinfo-generate.py | 49 ++++++++++++++++++++++++++----------- 2 files changed, 52 insertions(+), 22 deletions(-) diff --git a/meson.build b/meson.build index 9b3fd4e52b..d738391810 100644 --- a/meson.build +++ b/meson.build @@ -3175,14 +3175,23 @@ foreach d, list : target_modules endforeach if enable_modules - modinfo_src = custom_target('modinfo.c', - output: 'modinfo.c', - input: modinfo_files, - command: [modinfo_generate, '@INPUT@'], - capture: true) - modinfo_lib = static_library('modinfo', modinfo_src) - modinfo_dep = declare_dependency(link_whole: modinfo_lib) - softmmu_ss.add(modinfo_dep) + foreach target : target_dirs + if target.endswith('-softmmu') + config_target = config_target_mak[target] + config_devices_mak = target + '-config-devices.mak' + modinfo_src = custom_target('modinfo-' + target + '.c', + output: 'modinfo-' + target + '.c', + input: modinfo_files, + command: [modinfo_generate, '--devices', config_devices_mak, '@INPUT@'], + capture: true) + + modinfo_lib = static_library('modinfo-' + target + '.c', modinfo_src) + modinfo_dep = declare_dependency(link_with: modinfo_lib) + + arch = config_target['TARGET_NAME'] == 'sparc64' ? 'sparc64' : config_target['TARGET_BASE_ARCH'] + hw_arch[arch].add(modinfo_dep) + endif + endforeach endif nm = find_program('nm') diff --git a/scripts/modinfo-generate.py b/scripts/modinfo-generate.py index 689f33c0f2..b1538fcced 100755 --- a/scripts/modinfo-generate.py +++ b/scripts/modinfo-generate.py @@ -32,7 +32,7 @@ def parse_line(line): continue return (kind, data) -def generate(name, lines): +def generate(name, lines, enabled): arch = "" objs = [] deps = [] @@ -49,7 +49,13 @@ def generate(name, lines): elif kind == 'arch': arch = data; elif kind == 'kconfig': - pass # ignore + # don't add a module which dependency is not enabled + # in kconfig + if data.strip() not in enabled: + print(" /* module {} isn't enabled in Kconfig. */" + .format(data.strip())) + print("/* },{ */") + return None else: print("unknown:", kind) exit(1) @@ -60,8 +66,8 @@ def generate(name, lines): print_array("objs", objs) print_array("deps", deps) print_array("opts", opts) - print("},{"); - return deps + print("},{") + return {dep.strip('" ') for dep in deps} def print_pre(): print("/* generated by scripts/modinfo-generate.py */") @@ -74,23 +80,38 @@ def print_post(): print("}};") def main(args): - deps = {} + if len(args) < 3 or args[0] != '--devices': + print('Expected: modinfo-generate.py --devices ' + 'config-device.mak [modinfo files]', file=sys.stderr) + exit(1) + + # get all devices enabled in kconfig, from *-config-device.mak + enabled = set() + with open(args[1]) as file: + for line in file.readlines(): + config = line.split('=') + if config[1].rstrip() == 'y': + enabled.add(config[0][7:]) # remove CONFIG_ + + deps = set() + modules = set() print_pre() - for modinfo in args: + for modinfo in args[2:]: with open(modinfo) as f: lines = f.readlines() print(" /* %s */" % modinfo) - (basename, ext) = os.path.splitext(modinfo) - deps[basename] = generate(basename, lines) + (basename, _) = os.path.splitext(modinfo) + moddeps = generate(basename, lines, enabled) + if moddeps is not None: + modules.add(basename) + deps.update(moddeps) print_post() - flattened_deps = {flat.strip('" ') for dep in deps.values() for flat in dep} error = False - for dep in flattened_deps: - if dep not in deps.keys(): - print("Dependency {} cannot be satisfied".format(dep), - file=sys.stderr) - error = True + for dep in deps.difference(modules): + print("Dependency {} cannot be satisfied".format(dep), + file=sys.stderr) + error = True if error: exit(1) From c4b8ffcbb8531206e12cf3ad92fa90f7c80ed464 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 27 May 2022 13:46:07 +0300 Subject: [PATCH 784/935] replay: fix event queue flush for qemu shutdown This patch fixes event queue flush in the case of emulator shutdown. replay_finish_events should be called when replay_mode is not cleared. Signed-off-by: Pavel Dovgalyuk Reviewed-by: Richard Henderson Message-Id: <165364836758.688121.7959245442743676491.stgit@pasha-ThinkPad-X280> Signed-off-by: Paolo Bonzini --- replay/replay.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/replay/replay.c b/replay/replay.c index 6df2abc18c..2d3607998a 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -387,9 +387,8 @@ void replay_finish(void) g_free(replay_snapshot); replay_snapshot = NULL; - replay_mode = REPLAY_MODE_NONE; - replay_finish_events(); + replay_mode = REPLAY_MODE_NONE; } void replay_add_blocker(Error *reason) From 75bbe5e5ec2867f098a31bfd553a1fb084289cc2 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 27 May 2022 13:46:13 +0300 Subject: [PATCH 785/935] replay: notify vCPU when BH is scheduled vCPU execution should be suspended when new BH is scheduled. This is needed to avoid guest timeouts caused by the long cycles of the execution. In replay mode execution may hang when vCPU sleeps and block event comes to the queue. This patch adds notification which wakes up vCPU or interrupts execution of guest code. Signed-off-by: Pavel Dovgalyuk Reviewed-by: Richard Henderson -- v2: changed first_cpu to current_cpu (suggested by Richard Henderson) v4: moved vCPU notification to aio_bh_enqueue (suggested by Paolo Bonzini) Message-Id: <165364837317.688121.17680519919871405281.stgit@pasha-ThinkPad-X280> Signed-off-by: Paolo Bonzini --- include/sysemu/cpu-timers.h | 1 + softmmu/icount.c | 8 ++++++++ stubs/icount.c | 4 ++++ util/async.c | 8 ++++++++ 4 files changed, 21 insertions(+) diff --git a/include/sysemu/cpu-timers.h b/include/sysemu/cpu-timers.h index ed6ee5c46c..2e786fe7fb 100644 --- a/include/sysemu/cpu-timers.h +++ b/include/sysemu/cpu-timers.h @@ -59,6 +59,7 @@ int64_t icount_round(int64_t count); /* if the CPUs are idle, start accounting real time to virtual clock. */ void icount_start_warp_timer(void); void icount_account_warp_timer(void); +void icount_notify_exit(void); /* * CPU Ticks and Clock diff --git a/softmmu/icount.c b/softmmu/icount.c index 5ca271620d..1cafec5014 100644 --- a/softmmu/icount.c +++ b/softmmu/icount.c @@ -486,3 +486,11 @@ void icount_configure(QemuOpts *opts, Error **errp) qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 10); } + +void icount_notify_exit(void) +{ + if (icount_enabled() && current_cpu) { + qemu_cpu_kick(current_cpu); + qemu_clock_notify(QEMU_CLOCK_VIRTUAL); + } +} diff --git a/stubs/icount.c b/stubs/icount.c index f13c43568b..6df8c2bf7d 100644 --- a/stubs/icount.c +++ b/stubs/icount.c @@ -43,3 +43,7 @@ void icount_account_warp_timer(void) { abort(); } + +void icount_notify_exit(void) +{ +} diff --git a/util/async.c b/util/async.c index 554ba70cca..63434ddae4 100644 --- a/util/async.c +++ b/util/async.c @@ -33,6 +33,7 @@ #include "block/raw-aio.h" #include "qemu/coroutine_int.h" #include "qemu/coroutine-tls.h" +#include "sysemu/cpu-timers.h" #include "trace.h" /***********************************************************/ @@ -84,6 +85,13 @@ static void aio_bh_enqueue(QEMUBH *bh, unsigned new_flags) } aio_notify(ctx); + /* + * Workaround for record/replay. + * vCPU execution should be suspended when new BH is set. + * This is needed to avoid guest timeouts caused + * by the long cycles of the execution. + */ + icount_notify_exit(); } /* Only called from aio_bh_poll() and aio_ctx_finalize() */ From 60618e2d77691e44bb78e23b2b0cf07b5c405e56 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 27 May 2022 13:46:18 +0300 Subject: [PATCH 786/935] replay: rewrite async event handling This patch decouples checkpoints and async events. It was a tricky part of replay implementation. Now it becomes much simpler and easier to maintain. Signed-off-by: Pavel Dovgalyuk Acked-by: Richard Henderson Message-Id: <165364837856.688121.8785039478408995979.stgit@pasha-ThinkPad-X280> Signed-off-by: Paolo Bonzini --- accel/tcg/tcg-accel-ops-icount.c | 5 +-- docs/replay.txt | 11 ++--- include/sysemu/replay.h | 9 +++- replay/replay-events.c | 20 +++------ replay/replay-internal.h | 6 +-- replay/replay-snapshot.c | 1 - replay/replay.c | 74 +++++++++++++------------------- softmmu/icount.c | 4 +- 8 files changed, 54 insertions(+), 76 deletions(-) diff --git a/accel/tcg/tcg-accel-ops-icount.c b/accel/tcg/tcg-accel-ops-icount.c index 24520ea112..8f1dda4344 100644 --- a/accel/tcg/tcg-accel-ops-icount.c +++ b/accel/tcg/tcg-accel-ops-icount.c @@ -84,8 +84,7 @@ void icount_handle_deadline(void) * Don't interrupt cpu thread, when these events are waiting * (i.e., there is no checkpoint) */ - if (deadline == 0 - && (replay_mode != REPLAY_MODE_PLAY || replay_has_checkpoint())) { + if (deadline == 0) { icount_notify_aio_contexts(); } } @@ -109,7 +108,7 @@ void icount_prepare_for_run(CPUState *cpu) replay_mutex_lock(); - if (cpu->icount_budget == 0 && replay_has_checkpoint()) { + if (cpu->icount_budget == 0) { icount_notify_aio_contexts(); } } diff --git a/docs/replay.txt b/docs/replay.txt index 5b008ca491..6c9fdff09d 100644 --- a/docs/replay.txt +++ b/docs/replay.txt @@ -366,11 +366,9 @@ Here is the list of events that are written into the log: Argument: 4-byte number of executed instructions. - EVENT_INTERRUPT. Used to synchronize interrupt processing. - EVENT_EXCEPTION. Used to synchronize exception handling. - - EVENT_ASYNC. This is a group of events. They are always processed - together with checkpoints. When such an event is generated, it is - stored in the queue and processed only when checkpoint occurs. - Every such event is followed by 1-byte checkpoint id and 1-byte - async event id from the following list: + - EVENT_ASYNC. This is a group of events. When such an event is generated, + it is stored in the queue and processed in icount_account_warp_timer(). + Every such event has it's own id from the following list: - REPLAY_ASYNC_EVENT_BH. Bottom-half callback. This event synchronizes callbacks that affect virtual machine state, but normally called asynchronously. @@ -405,6 +403,5 @@ Here is the list of events that are written into the log: - EVENT_CLOCK + clock_id. Group of events for host clock read operations. Argument: 8-byte clock value. - EVENT_CHECKPOINT + checkpoint_id. Checkpoint for synchronization of - CPU, internal threads, and asynchronous input events. May be followed - by one or more EVENT_ASYNC events. + CPU, internal threads, and asynchronous input events. - EVENT_END. Last event in the log. diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h index 0f3b0f7eac..73dee9ccdf 100644 --- a/include/sysemu/replay.h +++ b/include/sysemu/replay.h @@ -160,9 +160,14 @@ void replay_shutdown_request(ShutdownCause cause); Returns 0 in PLAY mode if checkpoint was not found. Returns 1 in all other cases. */ bool replay_checkpoint(ReplayCheckpoint checkpoint); -/*! Used to determine that checkpoint is pending. +/*! Used to determine that checkpoint or async event is pending. Does not proceed to the next event in the log. */ -bool replay_has_checkpoint(void); +bool replay_has_event(void); +/* + * Processes the async events added to the queue (while recording) + * or reads the events from the file (while replaying). + */ +void replay_async_events(void); /* Asynchronous events queue */ diff --git a/replay/replay-events.c b/replay/replay-events.c index ac47c89834..db1decf9dd 100644 --- a/replay/replay-events.c +++ b/replay/replay-events.c @@ -170,12 +170,11 @@ void replay_block_event(QEMUBH *bh, uint64_t id) } } -static void replay_save_event(Event *event, int checkpoint) +static void replay_save_event(Event *event) { if (replay_mode != REPLAY_MODE_PLAY) { /* put the event into the file */ replay_put_event(EVENT_ASYNC); - replay_put_byte(checkpoint); replay_put_byte(event->event_kind); /* save event-specific data */ @@ -206,34 +205,27 @@ static void replay_save_event(Event *event, int checkpoint) } /* Called with replay mutex locked */ -void replay_save_events(int checkpoint) +void replay_save_events(void) { g_assert(replay_mutex_locked()); - g_assert(checkpoint != CHECKPOINT_CLOCK_WARP_START); - g_assert(checkpoint != CHECKPOINT_CLOCK_VIRTUAL); while (!QTAILQ_EMPTY(&events_list)) { Event *event = QTAILQ_FIRST(&events_list); - replay_save_event(event, checkpoint); + replay_save_event(event); replay_run_event(event); QTAILQ_REMOVE(&events_list, event, events); g_free(event); } } -static Event *replay_read_event(int checkpoint) +static Event *replay_read_event(void) { Event *event; if (replay_state.read_event_kind == -1) { - replay_state.read_event_checkpoint = replay_get_byte(); replay_state.read_event_kind = replay_get_byte(); replay_state.read_event_id = -1; replay_check_error(); } - if (checkpoint != replay_state.read_event_checkpoint) { - return NULL; - } - /* Events that has not to be in the queue */ switch (replay_state.read_event_kind) { case REPLAY_ASYNC_EVENT_BH: @@ -294,11 +286,11 @@ static Event *replay_read_event(int checkpoint) } /* Called with replay mutex locked */ -void replay_read_events(int checkpoint) +void replay_read_events(void) { g_assert(replay_mutex_locked()); while (replay_state.data_kind == EVENT_ASYNC) { - Event *event = replay_read_event(checkpoint); + Event *event = replay_read_event(); if (!event) { break; } diff --git a/replay/replay-internal.h b/replay/replay-internal.h index 97649ed8d7..d6e631a394 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -87,8 +87,6 @@ typedef struct ReplayState { int32_t read_event_kind; /*! Asynchronous event id read from the log */ uint64_t read_event_id; - /*! Asynchronous event checkpoint id read from the log */ - int32_t read_event_checkpoint; } ReplayState; extern ReplayState replay_state; @@ -152,9 +150,9 @@ void replay_finish_events(void); /*! Returns true if there are any unsaved events in the queue */ bool replay_has_events(void); /*! Saves events from queue into the file */ -void replay_save_events(int checkpoint); +void replay_save_events(void); /*! Read events from the file into the input queue */ -void replay_read_events(int checkpoint); +void replay_read_events(void); /*! Adds specified async event to the queue */ void replay_add_event(ReplayAsyncEventKind event_kind, void *opaque, void *opaque2, uint64_t id); diff --git a/replay/replay-snapshot.c b/replay/replay-snapshot.c index e8767a1937..7e935deb15 100644 --- a/replay/replay-snapshot.c +++ b/replay/replay-snapshot.c @@ -61,7 +61,6 @@ static const VMStateDescription vmstate_replay = { VMSTATE_UINT64(block_request_id, ReplayState), VMSTATE_INT32(read_event_kind, ReplayState), VMSTATE_UINT64(read_event_id, ReplayState), - VMSTATE_INT32(read_event_checkpoint, ReplayState), VMSTATE_END_OF_LIST() }, }; diff --git a/replay/replay.c b/replay/replay.c index 2d3607998a..ccd7edec76 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -22,7 +22,7 @@ /* Current version of the replay mechanism. Increase it when file format changes. */ -#define REPLAY_VERSION 0xe0200a +#define REPLAY_VERSION 0xe0200b /* Size of replay log header */ #define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t)) @@ -171,64 +171,49 @@ void replay_shutdown_request(ShutdownCause cause) bool replay_checkpoint(ReplayCheckpoint checkpoint) { - bool res = false; - static bool in_checkpoint; assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST); - if (!replay_file) { - return true; - } - - if (in_checkpoint) { - /* - Recursion occurs when HW event modifies timers. - Prevent performing icount warp in this case and - wait for another invocation of the checkpoint. - */ - g_assert(replay_mode == REPLAY_MODE_PLAY); - return false; - } - in_checkpoint = true; - replay_save_instructions(); if (replay_mode == REPLAY_MODE_PLAY) { g_assert(replay_mutex_locked()); if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) { replay_finish_event(); - } else if (replay_state.data_kind != EVENT_ASYNC) { - res = false; - goto out; + } else { + return false; } - replay_read_events(checkpoint); - /* replay_read_events may leave some unread events. - Return false if not all of the events associated with - checkpoint were processed */ - res = replay_state.data_kind != EVENT_ASYNC; } else if (replay_mode == REPLAY_MODE_RECORD) { g_assert(replay_mutex_locked()); replay_put_event(EVENT_CHECKPOINT + checkpoint); - /* This checkpoint belongs to several threads. - Processing events from different threads is - non-deterministic */ - if (checkpoint != CHECKPOINT_CLOCK_WARP_START - /* FIXME: this is temporary fix, other checkpoints - may also be invoked from the different threads someday. - Asynchronous event processing should be refactored - to create additional replay event kind which is - nailed to the one of the threads and which processes - the event queue. */ - && checkpoint != CHECKPOINT_CLOCK_VIRTUAL) { - replay_save_events(checkpoint); - } - res = true; } -out: - in_checkpoint = false; - return res; + return true; } -bool replay_has_checkpoint(void) +void replay_async_events(void) +{ + static bool processing = false; + /* + * If we are already processing the events, recursion may occur + * in case of incorrect implementation when HW event modifies timers. + * Timer modification may invoke the icount warp, event processing, + * and cause the recursion. + */ + g_assert(!processing); + processing = true; + + replay_save_instructions(); + + if (replay_mode == REPLAY_MODE_PLAY) { + g_assert(replay_mutex_locked()); + replay_read_events(); + } else if (replay_mode == REPLAY_MODE_RECORD) { + g_assert(replay_mutex_locked()); + replay_save_events(); + } + processing = false; +} + +bool replay_has_event(void) { bool res = false; if (replay_mode == REPLAY_MODE_PLAY) { @@ -236,6 +221,7 @@ bool replay_has_checkpoint(void) replay_account_executed_instructions(); res = EVENT_CHECKPOINT <= replay_state.data_kind && replay_state.data_kind <= EVENT_CHECKPOINT_LAST; + res = res || replay_state.data_kind == EVENT_ASYNC; } return res; } diff --git a/softmmu/icount.c b/softmmu/icount.c index 1cafec5014..4504433e16 100644 --- a/softmmu/icount.c +++ b/softmmu/icount.c @@ -322,7 +322,7 @@ void icount_start_warp_timer(void) * to vCPU was processed in advance and vCPU went to sleep. * Therefore we have to wake it up for doing someting. */ - if (replay_has_checkpoint()) { + if (replay_has_event()) { qemu_clock_notify(QEMU_CLOCK_VIRTUAL); } return; @@ -404,6 +404,8 @@ void icount_account_warp_timer(void) return; } + replay_async_events(); + /* warp clock deterministically in record/replay mode */ if (!replay_checkpoint(CHECKPOINT_CLOCK_WARP_ACCOUNT)) { return; From 3e21408b0596aa2babe1e26996a15e7ad5eee71a Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 27 May 2022 13:46:23 +0300 Subject: [PATCH 787/935] replay: simplify async event processing This patch joins replay event id and async event id into single byte in the log. It makes processing a bit faster and log a bit smaller. Signed-off-by: Pavel Dovgalyuk Reviewed-by: Richard Henderson -- v2: minor enum fixes (suggested by Richard Henderson) Message-Id: <165364838393.688121.8191379555130516329.stgit@pasha-ThinkPad-X280> Signed-off-by: Paolo Bonzini --- replay/replay-events.c | 36 ++++++++++++++---------------------- replay/replay-internal.h | 31 ++++++++++++++----------------- replay/replay-snapshot.c | 1 - replay/replay.c | 5 +++-- 4 files changed, 31 insertions(+), 42 deletions(-) diff --git a/replay/replay-events.c b/replay/replay-events.c index db1decf9dd..af0721cc1a 100644 --- a/replay/replay-events.c +++ b/replay/replay-events.c @@ -174,8 +174,8 @@ static void replay_save_event(Event *event) { if (replay_mode != REPLAY_MODE_PLAY) { /* put the event into the file */ - replay_put_event(EVENT_ASYNC); - replay_put_byte(event->event_kind); + g_assert(event->event_kind < REPLAY_ASYNC_COUNT); + replay_put_event(EVENT_ASYNC + event->event_kind); /* save event-specific data */ switch (event->event_kind) { @@ -220,14 +220,10 @@ void replay_save_events(void) static Event *replay_read_event(void) { Event *event; - if (replay_state.read_event_kind == -1) { - replay_state.read_event_kind = replay_get_byte(); - replay_state.read_event_id = -1; - replay_check_error(); - } + ReplayAsyncEventKind event_kind = replay_state.data_kind - EVENT_ASYNC; /* Events that has not to be in the queue */ - switch (replay_state.read_event_kind) { + switch (event_kind) { case REPLAY_ASYNC_EVENT_BH: case REPLAY_ASYNC_EVENT_BH_ONESHOT: if (replay_state.read_event_id == -1) { @@ -236,17 +232,17 @@ static Event *replay_read_event(void) break; case REPLAY_ASYNC_EVENT_INPUT: event = g_new0(Event, 1); - event->event_kind = replay_state.read_event_kind; + event->event_kind = event_kind; event->opaque = replay_read_input_event(); return event; case REPLAY_ASYNC_EVENT_INPUT_SYNC: event = g_new0(Event, 1); - event->event_kind = replay_state.read_event_kind; + event->event_kind = event_kind; event->opaque = 0; return event; case REPLAY_ASYNC_EVENT_CHAR_READ: event = g_new0(Event, 1); - event->event_kind = replay_state.read_event_kind; + event->event_kind = event_kind; event->opaque = replay_event_char_read_load(); return event; case REPLAY_ASYNC_EVENT_BLOCK: @@ -256,18 +252,17 @@ static Event *replay_read_event(void) break; case REPLAY_ASYNC_EVENT_NET: event = g_new0(Event, 1); - event->event_kind = replay_state.read_event_kind; + event->event_kind = event_kind; event->opaque = replay_event_net_load(); return event; default: - error_report("Unknown ID %d of replay event", - replay_state.read_event_kind); + error_report("Unknown ID %d of replay event", event_kind); exit(1); break; } QTAILQ_FOREACH(event, &events_list, events) { - if (event->event_kind == replay_state.read_event_kind + if (event->event_kind == event_kind && (replay_state.read_event_id == -1 || replay_state.read_event_id == event->id)) { break; @@ -276,12 +271,8 @@ static Event *replay_read_event(void) if (event) { QTAILQ_REMOVE(&events_list, event, events); - } else { - return NULL; } - /* Read event-specific data */ - return event; } @@ -289,13 +280,14 @@ static Event *replay_read_event(void) void replay_read_events(void) { g_assert(replay_mutex_locked()); - while (replay_state.data_kind == EVENT_ASYNC) { + while (replay_state.data_kind >= EVENT_ASYNC + && replay_state.data_kind <= EVENT_ASYNC_LAST) { Event *event = replay_read_event(); if (!event) { break; } replay_finish_event(); - replay_state.read_event_kind = -1; + replay_state.read_event_id = -1; replay_run_event(event); g_free(event); @@ -304,7 +296,7 @@ void replay_read_events(void) void replay_init_events(void) { - replay_state.read_event_kind = -1; + replay_state.read_event_id = -1; } void replay_finish_events(void) diff --git a/replay/replay-internal.h b/replay/replay-internal.h index d6e631a394..89e377be90 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -12,6 +12,19 @@ * */ +/* Asynchronous events IDs */ + +typedef enum ReplayAsyncEventKind { + REPLAY_ASYNC_EVENT_BH, + REPLAY_ASYNC_EVENT_BH_ONESHOT, + REPLAY_ASYNC_EVENT_INPUT, + REPLAY_ASYNC_EVENT_INPUT_SYNC, + REPLAY_ASYNC_EVENT_CHAR_READ, + REPLAY_ASYNC_EVENT_BLOCK, + REPLAY_ASYNC_EVENT_NET, + REPLAY_ASYNC_COUNT +} ReplayAsyncEventKind; + /* Any changes to order/number of events will need to bump REPLAY_VERSION */ enum ReplayEvents { /* for instruction event */ @@ -22,6 +35,7 @@ enum ReplayEvents { EVENT_EXCEPTION, /* for async events */ EVENT_ASYNC, + EVENT_ASYNC_LAST = EVENT_ASYNC + REPLAY_ASYNC_COUNT - 1, /* for shutdown requests, range allows recovery of ShutdownCause */ EVENT_SHUTDOWN, EVENT_SHUTDOWN_LAST = EVENT_SHUTDOWN + SHUTDOWN_CAUSE__MAX, @@ -49,21 +63,6 @@ enum ReplayEvents { EVENT_COUNT }; -/* Asynchronous events IDs */ - -enum ReplayAsyncEventKind { - REPLAY_ASYNC_EVENT_BH, - REPLAY_ASYNC_EVENT_BH_ONESHOT, - REPLAY_ASYNC_EVENT_INPUT, - REPLAY_ASYNC_EVENT_INPUT_SYNC, - REPLAY_ASYNC_EVENT_CHAR_READ, - REPLAY_ASYNC_EVENT_BLOCK, - REPLAY_ASYNC_EVENT_NET, - REPLAY_ASYNC_COUNT -}; - -typedef enum ReplayAsyncEventKind ReplayAsyncEventKind; - typedef struct ReplayState { /*! Cached clock values. */ int64_t cached_clock[REPLAY_CLOCK_COUNT]; @@ -83,8 +82,6 @@ typedef struct ReplayState { uint64_t block_request_id; /*! Prior value of the host clock */ uint64_t host_clock_last; - /*! Asynchronous event type read from the log */ - int32_t read_event_kind; /*! Asynchronous event id read from the log */ uint64_t read_event_id; } ReplayState; diff --git a/replay/replay-snapshot.c b/replay/replay-snapshot.c index 7e935deb15..10a7cf7992 100644 --- a/replay/replay-snapshot.c +++ b/replay/replay-snapshot.c @@ -59,7 +59,6 @@ static const VMStateDescription vmstate_replay = { VMSTATE_UINT32(has_unread_data, ReplayState), VMSTATE_UINT64(file_offset, ReplayState), VMSTATE_UINT64(block_request_id, ReplayState), - VMSTATE_INT32(read_event_kind, ReplayState), VMSTATE_UINT64(read_event_id, ReplayState), VMSTATE_END_OF_LIST() }, diff --git a/replay/replay.c b/replay/replay.c index ccd7edec76..4c396bb376 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -22,7 +22,7 @@ /* Current version of the replay mechanism. Increase it when file format changes. */ -#define REPLAY_VERSION 0xe0200b +#define REPLAY_VERSION 0xe0200c /* Size of replay log header */ #define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t)) @@ -221,7 +221,8 @@ bool replay_has_event(void) replay_account_executed_instructions(); res = EVENT_CHECKPOINT <= replay_state.data_kind && replay_state.data_kind <= EVENT_CHECKPOINT_LAST; - res = res || replay_state.data_kind == EVENT_ASYNC; + res = res || (EVENT_ASYNC <= replay_state.data_kind + && replay_state.data_kind <= EVENT_ASYNC_LAST); } return res; } From 04d0583a4f5d00061bf57d17947aa0d5c6a6cecf Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 27 May 2022 13:46:30 +0300 Subject: [PATCH 788/935] docs: convert docs/devel/replay page to rst This patch converts prior .txt replay devel documentation to .rst. Signed-off-by: Pavel Dovgalyuk Reviewed-by: Richard Henderson Message-Id: <165364839013.688121.11935249420738873044.stgit@pasha-ThinkPad-X280> Signed-off-by: Paolo Bonzini --- docs/devel/index-tcg.rst | 1 + docs/devel/{replay.txt => replay.rst} | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) rename docs/devel/{replay.txt => replay.rst} (90%) diff --git a/docs/devel/index-tcg.rst b/docs/devel/index-tcg.rst index 0b0ad12c22..7b9760b26f 100644 --- a/docs/devel/index-tcg.rst +++ b/docs/devel/index-tcg.rst @@ -13,3 +13,4 @@ are only implementing things for HW accelerated hypervisors. multi-thread-tcg tcg-icount tcg-plugins + replay diff --git a/docs/devel/replay.txt b/docs/devel/replay.rst similarity index 90% rename from docs/devel/replay.txt rename to docs/devel/replay.rst index e641c35add..dd8bf3b195 100644 --- a/docs/devel/replay.txt +++ b/docs/devel/replay.rst @@ -1,3 +1,11 @@ +.. + Copyright (c) 2022, ISP RAS + Written by Pavel Dovgalyuk + +======================= +Execution Record/Replay +======================= + Record/replay mechanism, that could be enabled through icount mode, expects the virtual devices to satisfy the following requirements. @@ -5,7 +13,7 @@ The main idea behind this document is that everything that affects the guest state during execution in icount mode should be deterministic. Timers -====== +------ All virtual devices should use virtual clock for timers that change the guest state. Virtual clock is deterministic, therefore such timers are deterministic @@ -19,7 +27,7 @@ the virtual devices (e.g., slirp routing device) that lie outside the replayed guest. Bottom halves -============= +------------- Bottom half callbacks, that affect the guest state, should be invoked through replay_bh_schedule_event or replay_bh_schedule_oneshot_event functions. @@ -27,7 +35,7 @@ Their invocations are saved in record mode and synchronized with the existing log in replay mode. Saving/restoring the VM state -============================= +----------------------------- All fields in the device state structure (including virtual timers) should be restored by loadvm to the same values they had before savevm. @@ -38,7 +46,7 @@ is not defined. It means that you should not call functions like the dependencies that may make restoring the VM state non-deterministic. Stopping the VM -=============== +--------------- Stopping the guest should not interfere with its state (with the exception of the network connections, that could be broken by the remote timeouts). From 43185f7bd4cbe730e7d5a6abcefbf83a5c98f3db Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 27 May 2022 13:46:36 +0300 Subject: [PATCH 789/935] docs: move replay docs to docs/system/replay.rst This patch adds replay description page, converting prior text from docs/replay.txt. The text was also updated and some sections were moved to devel part of the docs. Signed-off-by: Pavel Dovgalyuk Acked-by: Richard Henderson Message-Id: <165364839601.688121.5131456980322853233.stgit@pasha-ThinkPad-X280> Signed-off-by: Paolo Bonzini --- docs/devel/replay.rst | 264 +++++++++++++++++++++++++- docs/replay.txt | 407 ----------------------------------------- docs/system/index.rst | 1 + docs/system/replay.rst | 237 ++++++++++++++++++++++++ 4 files changed, 496 insertions(+), 413 deletions(-) delete mode 100644 docs/replay.txt create mode 100644 docs/system/replay.rst diff --git a/docs/devel/replay.rst b/docs/devel/replay.rst index dd8bf3b195..0244be8b9c 100644 --- a/docs/devel/replay.rst +++ b/docs/devel/replay.rst @@ -1,20 +1,149 @@ .. Copyright (c) 2022, ISP RAS - Written by Pavel Dovgalyuk + Written by Pavel Dovgalyuk and Alex Bennée ======================= Execution Record/Replay ======================= -Record/replay mechanism, that could be enabled through icount mode, expects -the virtual devices to satisfy the following requirements. +Core concepts +============= -The main idea behind this document is that everything that affects +Record/replay functions are used for the deterministic replay of qemu +execution. Execution recording writes a non-deterministic events log, which +can be later used for replaying the execution anywhere and for unlimited +number of times. Execution replaying reads the log and replays all +non-deterministic events including external input, hardware clocks, +and interrupts. + +Several parts of QEMU include function calls to make event log recording +and replaying. +Devices' models that have non-deterministic input from external devices were +changed to write every external event into the execution log immediately. +E.g. network packets are written into the log when they arrive into the virtual +network adapter. + +All non-deterministic events are coming from these devices. But to +replay them we need to know at which moments they occur. We specify +these moments by counting the number of instructions executed between +every pair of consecutive events. + +Academic papers with description of deterministic replay implementation: + +* `Deterministic Replay of System's Execution with Multi-target QEMU Simulator for Dynamic Analysis and Reverse Debugging `_ +* `Don't panic: reverse debugging of kernel drivers `_ + +Modifications of qemu include: + + * wrappers for clock and time functions to save their return values in the log + * saving different asynchronous events (e.g. system shutdown) into the log + * synchronization of the bottom halves execution + * synchronization of the threads from thread pool + * recording/replaying user input (mouse, keyboard, and microphone) + * adding internal checkpoints for cpu and io synchronization + * network filter for recording and replaying the packets + * block driver for making block layer deterministic + * serial port input record and replay + * recording of random numbers obtained from the external sources + +Instruction counting +-------------------- + +QEMU should work in icount mode to use record/replay feature. icount was +designed to allow deterministic execution in absence of external inputs +of the virtual machine. We also use icount to control the occurrence of the +non-deterministic events. The number of instructions elapsed from the last event +is written to the log while recording the execution. In replay mode we +can predict when to inject that event using the instruction counter. + +Locking and thread synchronisation +---------------------------------- + +Previously the synchronisation of the main thread and the vCPU thread +was ensured by the holding of the BQL. However the trend has been to +reduce the time the BQL was held across the system including under TCG +system emulation. As it is important that batches of events are kept +in sequence (e.g. expiring timers and checkpoints in the main thread +while instruction checkpoints are written by the vCPU thread) we need +another lock to keep things in lock-step. This role is now handled by +the replay_mutex_lock. It used to be held only for each event being +written but now it is held for a whole execution period. This results +in a deterministic ping-pong between the two main threads. + +As the BQL is now a finer grained lock than the replay_lock it is almost +certainly a bug, and a source of deadlocks, to take the +replay_mutex_lock while the BQL is held. This is enforced by an assert. +While the unlocks are usually in the reverse order, this is not +necessary; you can drop the replay_lock while holding the BQL, without +doing a more complicated unlock_iothread/replay_unlock/lock_iothread +sequence. + +Checkpoints +----------- + +Replaying the execution of virtual machine is bound by sources of +non-determinism. These are inputs from clock and peripheral devices, +and QEMU thread scheduling. Thread scheduling affect on processing events +from timers, asynchronous input-output, and bottom halves. + +Invocations of timers are coupled with clock reads and changing the state +of the virtual machine. Reads produce non-deterministic data taken from +host clock. And VM state changes should preserve their order. Their relative +order in replay mode must replicate the order of callbacks in record mode. +To preserve this order we use checkpoints. When a specific clock is processed +in record mode we save to the log special "checkpoint" event. +Checkpoints here do not refer to virtual machine snapshots. They are just +record/replay events used for synchronization. + +QEMU in replay mode will try to invoke timers processing in random moment +of time. That's why we do not process a group of timers until the checkpoint +event will be read from the log. Such an event allows synchronizing CPU +execution and timer events. + +Two other checkpoints govern the "warping" of the virtual clock. +While the virtual machine is idle, the virtual clock increments at +1 ns per *real time* nanosecond. This is done by setting up a timer +(called the warp timer) on the virtual real time clock, so that the +timer fires at the next deadline of the virtual clock; the virtual clock +is then incremented (which is called "warping" the virtual clock) as +soon as the timer fires or the CPUs need to go out of the idle state. +Two functions are used for this purpose; because these actions change +virtual machine state and must be deterministic, each of them creates a +checkpoint. ``icount_start_warp_timer`` checks if the CPUs are idle and if so +starts accounting real time to virtual clock. ``icount_account_warp_timer`` +is called when the CPUs get an interrupt or when the warp timer fires, +and it warps the virtual clock by the amount of real time that has passed +since ``icount_start_warp_timer``. + +Virtual devices +=============== + +Record/replay mechanism, that could be enabled through icount mode, expects +the virtual devices to satisfy the following requirement: +everything that affects the guest state during execution in icount mode should be deterministic. Timers ------ +Timers are used to execute callbacks from different subsystems of QEMU +at the specified moments of time. There are several kinds of timers: + + * Real time clock. Based on host time and used only for callbacks that + do not change the virtual machine state. For this reason real time + clock and timers does not affect deterministic replay at all. + * Virtual clock. These timers run only during the emulation. In icount + mode virtual clock value is calculated using executed instructions counter. + That is why it is completely deterministic and does not have to be recorded. + * Host clock. This clock is used by device models that simulate real time + sources (e.g. real time clock chip). Host clock is the one of the sources + of non-determinism. Host clock read operations should be logged to + make the execution deterministic. + * Virtual real time clock. This clock is similar to real time clock but + it is used only for increasing virtual clock while virtual machine is + sleeping. Due to its nature it is also non-deterministic as the host clock + and has to be logged too. + All virtual devices should use virtual clock for timers that change the guest state. Virtual clock is deterministic, therefore such timers are deterministic too. @@ -26,14 +155,50 @@ but its speed depends on the guest execution. This clock is used by the virtual devices (e.g., slirp routing device) that lie outside the replayed guest. +Block devices +------------- + +Block devices record/replay module (``blkreplay``) intercepts calls of +bdrv coroutine functions at the top of block drivers stack. + +All block completion operations are added to the queue in the coroutines. +When the queue is flushed the information about processed requests +is recorded to the log. In replay phase the queue is matched with +events read from the log. Therefore block devices requests are processed +deterministically. + Bottom halves ------------- Bottom half callbacks, that affect the guest state, should be invoked through -replay_bh_schedule_event or replay_bh_schedule_oneshot_event functions. +``replay_bh_schedule_event`` or ``replay_bh_schedule_oneshot_event`` functions. Their invocations are saved in record mode and synchronized with the existing log in replay mode. +Disk I/O events are completely deterministic in our model, because +in both record and replay modes we start virtual machine from the same +disk state. But callbacks that virtual disk controller uses for reading and +writing the disk may occur at different moments of time in record and replay +modes. + +Reading and writing requests are created by CPU thread of QEMU. Later these +requests proceed to block layer which creates "bottom halves". Bottom +halves consist of callback and its parameters. They are processed when +main loop locks the global mutex. These locks are not synchronized with +replaying process because main loop also processes the events that do not +affect the virtual machine state (like user interaction with monitor). + +That is why we had to implement saving and replaying bottom halves callbacks +synchronously to the CPU execution. When the callback is about to execute +it is added to the queue in the replay module. This queue is written to the +log when its callbacks are executed. In replay mode callbacks are not processed +until the corresponding event is read from the events log file. + +Sometimes the block layer uses asynchronous callbacks for its internal purposes +(like reading or writing VM snapshots or disk image cluster tables). In this +case bottom halves are not marked as "replayable" and do not saved +into the log. + Saving/restoring the VM state ----------------------------- @@ -42,7 +207,7 @@ should be restored by loadvm to the same values they had before savevm. Avoid accessing other devices' state, because the order of saving/restoring is not defined. It means that you should not call functions like -'update_irq' in post_load callback. Save everything explicitly to avoid +``update_irq`` in ``post_load`` callback. Save everything explicitly to avoid the dependencies that may make restoring the VM state non-deterministic. Stopping the VM @@ -52,3 +217,90 @@ Stopping the guest should not interfere with its state (with the exception of the network connections, that could be broken by the remote timeouts). VM can be stopped at any moment of replay by the user. Restarting the VM after that stop should not break the replay by the unneeded guest state change. + +Replay log format +================= + +Record/replay log consists of the header and the sequence of execution +events. The header includes 4-byte replay version id and 8-byte reserved +field. Version is updated every time replay log format changes to prevent +using replay log created by another build of qemu. + +The sequence of the events describes virtual machine state changes. +It includes all non-deterministic inputs of VM, synchronization marks and +instruction counts used to correctly inject inputs at replay. + +Synchronization marks (checkpoints) are used for synchronizing qemu threads +that perform operations with virtual hardware. These operations may change +system's state (e.g., change some register or generate interrupt) and +therefore should execute synchronously with CPU thread. + +Every event in the log includes 1-byte event id and optional arguments. +When argument is an array, it is stored as 4-byte array length +and corresponding number of bytes with data. +Here is the list of events that are written into the log: + + - EVENT_INSTRUCTION. Instructions executed since last event. Followed by: + + - 4-byte number of executed instructions. + + - EVENT_INTERRUPT. Used to synchronize interrupt processing. + - EVENT_EXCEPTION. Used to synchronize exception handling. + - EVENT_ASYNC. This is a group of events. When such an event is generated, + it is stored in the queue and processed in icount_account_warp_timer(). + Every such event has it's own id from the following list: + + - REPLAY_ASYNC_EVENT_BH. Bottom-half callback. This event synchronizes + callbacks that affect virtual machine state, but normally called + asynchronously. Followed by: + + - 8-byte operation id. + + - REPLAY_ASYNC_EVENT_INPUT. Input device event. Contains + parameters of keyboard and mouse input operations + (key press/release, mouse pointer movement). Followed by: + + - 9-16 bytes depending of input event. + + - REPLAY_ASYNC_EVENT_INPUT_SYNC. Internal input synchronization event. + - REPLAY_ASYNC_EVENT_CHAR_READ. Character (e.g., serial port) device input + initiated by the sender. Followed by: + + - 1-byte character device id. + - Array with bytes were read. + + - REPLAY_ASYNC_EVENT_BLOCK. Block device operation. Used to synchronize + operations with disk and flash drives with CPU. Followed by: + + - 8-byte operation id. + + - REPLAY_ASYNC_EVENT_NET. Incoming network packet. Followed by: + + - 1-byte network adapter id. + - 4-byte packet flags. + - Array with packet bytes. + + - EVENT_SHUTDOWN. Occurs when user sends shutdown event to qemu, + e.g., by closing the window. + - EVENT_CHAR_WRITE. Used to synchronize character output operations. Followed by: + + - 4-byte output function return value. + - 4-byte offset in the output array. + + - EVENT_CHAR_READ_ALL. Used to synchronize character input operations, + initiated by qemu. Followed by: + + - Array with bytes that were read. + + - EVENT_CHAR_READ_ALL_ERROR. Unsuccessful character input operation, + initiated by qemu. Followed by: + + - 4-byte error code. + + - EVENT_CLOCK + clock_id. Group of events for host clock read operations. Followed by: + + - 8-byte clock value. + + - EVENT_CHECKPOINT + checkpoint_id. Checkpoint for synchronization of + CPU, internal threads, and asynchronous input events. + - EVENT_END. Last event in the log. diff --git a/docs/replay.txt b/docs/replay.txt deleted file mode 100644 index 6c9fdff09d..0000000000 --- a/docs/replay.txt +++ /dev/null @@ -1,407 +0,0 @@ -Copyright (c) 2010-2015 Institute for System Programming - of the Russian Academy of Sciences. - -This work is licensed under the terms of the GNU GPL, version 2 or later. -See the COPYING file in the top-level directory. - -Record/replay -------------- - -Record/replay functions are used for the deterministic replay of qemu execution. -Execution recording writes a non-deterministic events log, which can be later -used for replaying the execution anywhere and for unlimited number of times. -It also supports checkpointing for faster rewind to the specific replay moment. -Execution replaying reads the log and replays all non-deterministic events -including external input, hardware clocks, and interrupts. - -Deterministic replay has the following features: - * Deterministically replays whole system execution and all contents of - the memory, state of the hardware devices, clocks, and screen of the VM. - * Writes execution log into the file for later replaying for multiple times - on different machines. - * Supports i386, x86_64, and Arm hardware platforms. - * Performs deterministic replay of all operations with keyboard and mouse - input devices. - -Usage of the record/replay: - * First, record the execution with the following command line: - qemu-system-i386 \ - -icount shift=7,rr=record,rrfile=replay.bin \ - -drive file=disk.qcow2,if=none,snapshot,id=img-direct \ - -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \ - -device ide-hd,drive=img-blkreplay \ - -netdev user,id=net1 -device rtl8139,netdev=net1 \ - -object filter-replay,id=replay,netdev=net1 - * After recording, you can replay it by using another command line: - qemu-system-i386 \ - -icount shift=7,rr=replay,rrfile=replay.bin \ - -drive file=disk.qcow2,if=none,snapshot,id=img-direct \ - -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \ - -device ide-hd,drive=img-blkreplay \ - -netdev user,id=net1 -device rtl8139,netdev=net1 \ - -object filter-replay,id=replay,netdev=net1 - The only difference with recording is changing the rr option - from record to replay. - * Block device images are not actually changed in the recording mode, - because all of the changes are written to the temporary overlay file. - This behavior is enabled by using blkreplay driver. It should be used - for every enabled block device, as described in 'Block devices' section. - * '-net none' option should be specified when network is not used, - because QEMU adds network card by default. When network is needed, - it should be configured explicitly with replay filter, as described - in 'Network devices' section. - * Interaction with audio devices and serial ports are recorded and replayed - automatically when such devices are enabled. - -Academic papers with description of deterministic replay implementation: -http://www.computer.org/csdl/proceedings/csmr/2012/4666/00/4666a553-abs.html -http://dl.acm.org/citation.cfm?id=2786805.2803179 - -Modifications of qemu include: - * wrappers for clock and time functions to save their return values in the log - * saving different asynchronous events (e.g. system shutdown) into the log - * synchronization of the bottom halves execution - * synchronization of the threads from thread pool - * recording/replaying user input (mouse, keyboard, and microphone) - * adding internal checkpoints for cpu and io synchronization - * network filter for recording and replaying the packets - * block driver for making block layer deterministic - * serial port input record and replay - * recording of random numbers obtained from the external sources - -Locking and thread synchronisation ----------------------------------- - -Previously the synchronisation of the main thread and the vCPU thread -was ensured by the holding of the BQL. However the trend has been to -reduce the time the BQL was held across the system including under TCG -system emulation. As it is important that batches of events are kept -in sequence (e.g. expiring timers and checkpoints in the main thread -while instruction checkpoints are written by the vCPU thread) we need -another lock to keep things in lock-step. This role is now handled by -the replay_mutex_lock. It used to be held only for each event being -written but now it is held for a whole execution period. This results -in a deterministic ping-pong between the two main threads. - -As the BQL is now a finer grained lock than the replay_lock it is almost -certainly a bug, and a source of deadlocks, to take the -replay_mutex_lock while the BQL is held. This is enforced by an assert. -While the unlocks are usually in the reverse order, this is not -necessary; you can drop the replay_lock while holding the BQL, without -doing a more complicated unlock_iothread/replay_unlock/lock_iothread -sequence. - -Non-deterministic events ------------------------- - -Our record/replay system is based on saving and replaying non-deterministic -events (e.g. keyboard input) and simulating deterministic ones (e.g. reading -from HDD or memory of the VM). Saving only non-deterministic events makes -log file smaller and simulation faster. - -The following non-deterministic data from peripheral devices is saved into -the log: mouse and keyboard input, network packets, audio controller input, -serial port input, and hardware clocks (they are non-deterministic -too, because their values are taken from the host machine). Inputs from -simulated hardware, memory of VM, software interrupts, and execution of -instructions are not saved into the log, because they are deterministic and -can be replayed by simulating the behavior of virtual machine starting from -initial state. - -We had to solve three tasks to implement deterministic replay: recording -non-deterministic events, replaying non-deterministic events, and checking -that there is no divergence between record and replay modes. - -We changed several parts of QEMU to make event log recording and replaying. -Devices' models that have non-deterministic input from external devices were -changed to write every external event into the execution log immediately. -E.g. network packets are written into the log when they arrive into the virtual -network adapter. - -All non-deterministic events are coming from these devices. But to -replay them we need to know at which moments they occur. We specify -these moments by counting the number of instructions executed between -every pair of consecutive events. - -Instruction counting --------------------- - -QEMU should work in icount mode to use record/replay feature. icount was -designed to allow deterministic execution in absence of external inputs -of the virtual machine. We also use icount to control the occurrence of the -non-deterministic events. The number of instructions elapsed from the last event -is written to the log while recording the execution. In replay mode we -can predict when to inject that event using the instruction counter. - -Timers ------- - -Timers are used to execute callbacks from different subsystems of QEMU -at the specified moments of time. There are several kinds of timers: - * Real time clock. Based on host time and used only for callbacks that - do not change the virtual machine state. For this reason real time - clock and timers does not affect deterministic replay at all. - * Virtual clock. These timers run only during the emulation. In icount - mode virtual clock value is calculated using executed instructions counter. - That is why it is completely deterministic and does not have to be recorded. - * Host clock. This clock is used by device models that simulate real time - sources (e.g. real time clock chip). Host clock is the one of the sources - of non-determinism. Host clock read operations should be logged to - make the execution deterministic. - * Virtual real time clock. This clock is similar to real time clock but - it is used only for increasing virtual clock while virtual machine is - sleeping. Due to its nature it is also non-deterministic as the host clock - and has to be logged too. - -Checkpoints ------------ - -Replaying of the execution of virtual machine is bound by sources of -non-determinism. These are inputs from clock and peripheral devices, -and QEMU thread scheduling. Thread scheduling affect on processing events -from timers, asynchronous input-output, and bottom halves. - -Invocations of timers are coupled with clock reads and changing the state -of the virtual machine. Reads produce non-deterministic data taken from -host clock. And VM state changes should preserve their order. Their relative -order in replay mode must replicate the order of callbacks in record mode. -To preserve this order we use checkpoints. When a specific clock is processed -in record mode we save to the log special "checkpoint" event. -Checkpoints here do not refer to virtual machine snapshots. They are just -record/replay events used for synchronization. - -QEMU in replay mode will try to invoke timers processing in random moment -of time. That's why we do not process a group of timers until the checkpoint -event will be read from the log. Such an event allows synchronizing CPU -execution and timer events. - -Two other checkpoints govern the "warping" of the virtual clock. -While the virtual machine is idle, the virtual clock increments at -1 ns per *real time* nanosecond. This is done by setting up a timer -(called the warp timer) on the virtual real time clock, so that the -timer fires at the next deadline of the virtual clock; the virtual clock -is then incremented (which is called "warping" the virtual clock) as -soon as the timer fires or the CPUs need to go out of the idle state. -Two functions are used for this purpose; because these actions change -virtual machine state and must be deterministic, each of them creates a -checkpoint. icount_start_warp_timer checks if the CPUs are idle and if so -starts accounting real time to virtual clock. icount_account_warp_timer -is called when the CPUs get an interrupt or when the warp timer fires, -and it warps the virtual clock by the amount of real time that has passed -since icount_start_warp_timer. - -Bottom halves -------------- - -Disk I/O events are completely deterministic in our model, because -in both record and replay modes we start virtual machine from the same -disk state. But callbacks that virtual disk controller uses for reading and -writing the disk may occur at different moments of time in record and replay -modes. - -Reading and writing requests are created by CPU thread of QEMU. Later these -requests proceed to block layer which creates "bottom halves". Bottom -halves consist of callback and its parameters. They are processed when -main loop locks the global mutex. These locks are not synchronized with -replaying process because main loop also processes the events that do not -affect the virtual machine state (like user interaction with monitor). - -That is why we had to implement saving and replaying bottom halves callbacks -synchronously to the CPU execution. When the callback is about to execute -it is added to the queue in the replay module. This queue is written to the -log when its callbacks are executed. In replay mode callbacks are not processed -until the corresponding event is read from the events log file. - -Sometimes the block layer uses asynchronous callbacks for its internal purposes -(like reading or writing VM snapshots or disk image cluster tables). In this -case bottom halves are not marked as "replayable" and do not saved -into the log. - -Block devices -------------- - -Block devices record/replay module intercepts calls of -bdrv coroutine functions at the top of block drivers stack. -To record and replay block operations the drive must be configured -as following: - -drive file=disk.qcow2,if=none,snapshot,id=img-direct - -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay - -device ide-hd,drive=img-blkreplay - -blkreplay driver should be inserted between disk image and virtual driver -controller. Therefore all disk requests may be recorded and replayed. - -All block completion operations are added to the queue in the coroutines. -Queue is flushed at checkpoints and information about processed requests -is recorded to the log. In replay phase the queue is matched with -events read from the log. Therefore block devices requests are processed -deterministically. - -Snapshotting ------------- - -New VM snapshots may be created in replay mode. They can be used later -to recover the desired VM state. All VM states created in replay mode -are associated with the moment of time in the replay scenario. -After recovering the VM state replay will start from that position. - -Default starting snapshot name may be specified with icount field -rrsnapshot as follows: - -icount shift=7,rr=record,rrfile=replay.bin,rrsnapshot=snapshot_name - -This snapshot is created at start of recording and restored at start -of replaying. It also can be loaded while replaying to roll back -the execution. - -'snapshot' flag of the disk image must be removed to save the snapshots -in the overlay (or original image) instead of using the temporary overlay. - -drive file=disk.ovl,if=none,id=img-direct - -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay - -device ide-hd,drive=img-blkreplay - -Use QEMU monitor to create additional snapshots. 'savevm ' command -created the snapshot and 'loadvm ' restores it. To prevent corruption -of the original disk image, use overlay files linked to the original images. -Therefore all new snapshots (including the starting one) will be saved in -overlays and the original image remains unchanged. - -When you need to use snapshots with diskless virtual machine, -it must be started with 'orphan' qcow2 image. This image will be used -for storing VM snapshots. Here is the example of the command line for this: - - qemu-system-i386 -icount shift=3,rr=replay,rrfile=record.bin,rrsnapshot=init \ - -net none -drive file=empty.qcow2,if=none,id=rr - -empty.qcow2 drive does not connected to any virtual block device and used -for VM snapshots only. - -Network devices ---------------- - -Record and replay for network interactions is performed with the network filter. -Each backend must have its own instance of the replay filter as follows: - -netdev user,id=net1 -device rtl8139,netdev=net1 - -object filter-replay,id=replay,netdev=net1 - -Replay network filter is used to record and replay network packets. While -recording the virtual machine this filter puts all packets coming from -the outer world into the log. In replay mode packets from the log are -injected into the network device. All interactions with network backend -in replay mode are disabled. - -Audio devices -------------- - -Audio data is recorded and replay automatically. The command line for recording -and replaying must contain identical specifications of audio hardware, e.g.: - -soundhw ac97 - -Serial ports ------------- - -Serial ports input is recorded and replay automatically. The command lines -for recording and replaying must contain identical number of ports in record -and replay modes, but their backends may differ. -E.g., '-serial stdio' in record mode, and '-serial null' in replay mode. - -Reverse debugging ------------------ - -Reverse debugging allows "executing" the program in reverse direction. -GDB remote protocol supports "reverse step" and "reverse continue" -commands. The first one steps single instruction backwards in time, -and the second one finds the last breakpoint in the past. - -Recorded executions may be used to enable reverse debugging. QEMU can't -execute the code in backwards direction, but can load a snapshot and -replay forward to find the desired position or breakpoint. - -The following GDB commands are supported: - - reverse-stepi (or rsi) - step one instruction backwards - - reverse-continue (or rc) - find last breakpoint in the past - -Reverse step loads the nearest snapshot and replays the execution until -the required instruction is met. - -Reverse continue may include several passes of examining the execution -between the snapshots. Each of the passes include the following steps: - 1. loading the snapshot - 2. replaying to examine the breakpoints - 3. if breakpoint or watchpoint was met - - loading the snapshot again - - replaying to the required breakpoint - 4. else - - proceeding to the p.1 with the earlier snapshot - -Therefore usage of the reverse debugging requires at least one snapshot -created in advance. This can be done by omitting 'snapshot' option -for the block drives and adding 'rrsnapshot' for both record and replay -command lines. -See the "Snapshotting" section to learn more about running record/replay -and creating the snapshot in these modes. - -Replay log format ------------------ - -Record/replay log consists of the header and the sequence of execution -events. The header includes 4-byte replay version id and 8-byte reserved -field. Version is updated every time replay log format changes to prevent -using replay log created by another build of qemu. - -The sequence of the events describes virtual machine state changes. -It includes all non-deterministic inputs of VM, synchronization marks and -instruction counts used to correctly inject inputs at replay. - -Synchronization marks (checkpoints) are used for synchronizing qemu threads -that perform operations with virtual hardware. These operations may change -system's state (e.g., change some register or generate interrupt) and -therefore should execute synchronously with CPU thread. - -Every event in the log includes 1-byte event id and optional arguments. -When argument is an array, it is stored as 4-byte array length -and corresponding number of bytes with data. -Here is the list of events that are written into the log: - - - EVENT_INSTRUCTION. Instructions executed since last event. - Argument: 4-byte number of executed instructions. - - EVENT_INTERRUPT. Used to synchronize interrupt processing. - - EVENT_EXCEPTION. Used to synchronize exception handling. - - EVENT_ASYNC. This is a group of events. When such an event is generated, - it is stored in the queue and processed in icount_account_warp_timer(). - Every such event has it's own id from the following list: - - REPLAY_ASYNC_EVENT_BH. Bottom-half callback. This event synchronizes - callbacks that affect virtual machine state, but normally called - asynchronously. - Argument: 8-byte operation id. - - REPLAY_ASYNC_EVENT_INPUT. Input device event. Contains - parameters of keyboard and mouse input operations - (key press/release, mouse pointer movement). - Arguments: 9-16 bytes depending of input event. - - REPLAY_ASYNC_EVENT_INPUT_SYNC. Internal input synchronization event. - - REPLAY_ASYNC_EVENT_CHAR_READ. Character (e.g., serial port) device input - initiated by the sender. - Arguments: 1-byte character device id. - Array with bytes were read. - - REPLAY_ASYNC_EVENT_BLOCK. Block device operation. Used to synchronize - operations with disk and flash drives with CPU. - Argument: 8-byte operation id. - - REPLAY_ASYNC_EVENT_NET. Incoming network packet. - Arguments: 1-byte network adapter id. - 4-byte packet flags. - Array with packet bytes. - - EVENT_SHUTDOWN. Occurs when user sends shutdown event to qemu, - e.g., by closing the window. - - EVENT_CHAR_WRITE. Used to synchronize character output operations. - Arguments: 4-byte output function return value. - 4-byte offset in the output array. - - EVENT_CHAR_READ_ALL. Used to synchronize character input operations, - initiated by qemu. - Argument: Array with bytes that were read. - - EVENT_CHAR_READ_ALL_ERROR. Unsuccessful character input operation, - initiated by qemu. - Argument: 4-byte error code. - - EVENT_CLOCK + clock_id. Group of events for host clock read operations. - Argument: 8-byte clock value. - - EVENT_CHECKPOINT + checkpoint_id. Checkpoint for synchronization of - CPU, internal threads, and asynchronous input events. - - EVENT_END. Last event in the log. diff --git a/docs/system/index.rst b/docs/system/index.rst index 23e30e26e5..e3695649c5 100644 --- a/docs/system/index.rst +++ b/docs/system/index.rst @@ -27,6 +27,7 @@ or Hypervisor.Framework. secrets authz gdb + replay managed-startup bootindex cpu-hotplug diff --git a/docs/system/replay.rst b/docs/system/replay.rst new file mode 100644 index 0000000000..3105327423 --- /dev/null +++ b/docs/system/replay.rst @@ -0,0 +1,237 @@ +.. _replay: + +.. + Copyright (c) 2010-2022 Institute for System Programming + of the Russian Academy of Sciences. + + This work is licensed under the terms of the GNU GPL, version 2 or later. + See the COPYING file in the top-level directory. + +Record/replay +============= + +Record/replay functions are used for the deterministic replay of qemu execution. +Execution recording writes a non-deterministic events log, which can be later +used for replaying the execution anywhere and for unlimited number of times. +It also supports checkpointing for faster rewind to the specific replay moment. +Execution replaying reads the log and replays all non-deterministic events +including external input, hardware clocks, and interrupts. + +Deterministic replay has the following features: + + * Deterministically replays whole system execution and all contents of + the memory, state of the hardware devices, clocks, and screen of the VM. + * Writes execution log into the file for later replaying for multiple times + on different machines. + * Supports i386, x86_64, ARM, AArch64, Risc-V, MIPS, MIPS64, S390X, Alpha, + PowerPC, PowerPC64, M68000, Microblaze, OpenRISC, Nios II, SPARC, + and Xtensa hardware platforms. + * Performs deterministic replay of all operations with keyboard and mouse + input devices, serial ports, and network. + +Usage of the record/replay: + + * First, record the execution with the following command line: + + .. parsed-literal:: + |qemu_system| \\ + -icount shift=auto,rr=record,rrfile=replay.bin \\ + -drive file=disk.qcow2,if=none,snapshot,id=img-direct \\ + -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \\ + -device ide-hd,drive=img-blkreplay \\ + -netdev user,id=net1 -device rtl8139,netdev=net1 \\ + -object filter-replay,id=replay,netdev=net1 + + * After recording, you can replay it by using another command line: + + .. parsed-literal:: + |qemu_system| \\ + -icount shift=auto,rr=replay,rrfile=replay.bin \\ + -drive file=disk.qcow2,if=none,snapshot,id=img-direct \\ + -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \\ + -device ide-hd,drive=img-blkreplay \\ + -netdev user,id=net1 -device rtl8139,netdev=net1 \\ + -object filter-replay,id=replay,netdev=net1 + + The only difference with recording is changing the rr option + from record to replay. + * Block device images are not actually changed in the recording mode, + because all of the changes are written to the temporary overlay file. + This behavior is enabled by using blkreplay driver. It should be used + for every enabled block device, as described in :ref:`block-label` section. + * ``-net none`` option should be specified when network is not used, + because QEMU adds network card by default. When network is needed, + it should be configured explicitly with replay filter, as described + in :ref:`network-label` section. + * Interaction with audio devices and serial ports are recorded and replayed + automatically when such devices are enabled. + +Core idea +--------- + +Record/replay system is based on saving and replaying non-deterministic +events (e.g. keyboard input) and simulating deterministic ones (e.g. reading +from HDD or memory of the VM). Saving only non-deterministic events makes +log file smaller and simulation faster. + +The following non-deterministic data from peripheral devices is saved into +the log: mouse and keyboard input, network packets, audio controller input, +serial port input, and hardware clocks (they are non-deterministic +too, because their values are taken from the host machine). Inputs from +simulated hardware, memory of VM, software interrupts, and execution of +instructions are not saved into the log, because they are deterministic and +can be replayed by simulating the behavior of virtual machine starting from +initial state. + +Instruction counting +-------------------- + +QEMU should work in icount mode to use record/replay feature. icount was +designed to allow deterministic execution in absence of external inputs +of the virtual machine. Record/replay feature is enabled through ``-icount`` +command-line option, making possible deterministic execution of the machine, +interacting with user or network. + +.. _block-label: + +Block devices +------------- + +Block devices record/replay module intercepts calls of +bdrv coroutine functions at the top of block drivers stack. +To record and replay block operations the drive must be configured +as following: + +.. parsed-literal:: + -drive file=disk.qcow2,if=none,snapshot,id=img-direct + -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay + -device ide-hd,drive=img-blkreplay + +blkreplay driver should be inserted between disk image and virtual driver +controller. Therefore all disk requests may be recorded and replayed. + +.. _snapshotting-label: + +Snapshotting +------------ + +New VM snapshots may be created in replay mode. They can be used later +to recover the desired VM state. All VM states created in replay mode +are associated with the moment of time in the replay scenario. +After recovering the VM state replay will start from that position. + +Default starting snapshot name may be specified with icount field +rrsnapshot as follows: + +.. parsed-literal:: + -icount shift=auto,rr=record,rrfile=replay.bin,rrsnapshot=snapshot_name + +This snapshot is created at start of recording and restored at start +of replaying. It also can be loaded while replaying to roll back +the execution. + +``snapshot`` flag of the disk image must be removed to save the snapshots +in the overlay (or original image) instead of using the temporary overlay. + +.. parsed-literal:: + -drive file=disk.ovl,if=none,id=img-direct + -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay + -device ide-hd,drive=img-blkreplay + +Use QEMU monitor to create additional snapshots. ``savevm `` command +created the snapshot and ``loadvm `` restores it. To prevent corruption +of the original disk image, use overlay files linked to the original images. +Therefore all new snapshots (including the starting one) will be saved in +overlays and the original image remains unchanged. + +When you need to use snapshots with diskless virtual machine, +it must be started with "orphan" qcow2 image. This image will be used +for storing VM snapshots. Here is the example of the command line for this: + +.. parsed-literal:: + |qemu_system| \\ + -icount shift=auto,rr=replay,rrfile=record.bin,rrsnapshot=init \\ + -net none -drive file=empty.qcow2,if=none,id=rr + +``empty.qcow2`` drive does not connected to any virtual block device and used +for VM snapshots only. + +.. _network-label: + +Network devices +--------------- + +Record and replay for network interactions is performed with the network filter. +Each backend must have its own instance of the replay filter as follows: + +.. parsed-literal:: + -netdev user,id=net1 -device rtl8139,netdev=net1 + -object filter-replay,id=replay,netdev=net1 + +Replay network filter is used to record and replay network packets. While +recording the virtual machine this filter puts all packets coming from +the outer world into the log. In replay mode packets from the log are +injected into the network device. All interactions with network backend +in replay mode are disabled. + +Audio devices +------------- + +Audio data is recorded and replay automatically. The command line for recording +and replaying must contain identical specifications of audio hardware, e.g.: + +.. parsed-literal:: + -soundhw ac97 + +Serial ports +------------ + +Serial ports input is recorded and replay automatically. The command lines +for recording and replaying must contain identical number of ports in record +and replay modes, but their backends may differ. +E.g., ``-serial stdio`` in record mode, and ``-serial null`` in replay mode. + +Reverse debugging +----------------- + +Reverse debugging allows "executing" the program in reverse direction. +GDB remote protocol supports "reverse step" and "reverse continue" +commands. The first one steps single instruction backwards in time, +and the second one finds the last breakpoint in the past. + +Recorded executions may be used to enable reverse debugging. QEMU can't +execute the code in backwards direction, but can load a snapshot and +replay forward to find the desired position or breakpoint. + +The following GDB commands are supported: + + - ``reverse-stepi`` (or ``rsi``) - step one instruction backwards + - ``reverse-continue`` (or ``rc``) - find last breakpoint in the past + +Reverse step loads the nearest snapshot and replays the execution until +the required instruction is met. + +Reverse continue may include several passes of examining the execution +between the snapshots. Each of the passes include the following steps: + + #. loading the snapshot + #. replaying to examine the breakpoints + #. if breakpoint or watchpoint was met + + * loading the snapshot again + * replaying to the required breakpoint + + #. else + + * proceeding to the p.1 with the earlier snapshot + +Therefore usage of the reverse debugging requires at least one snapshot +created. This can be done by omitting ``snapshot`` option +for the block drives and adding ``rrsnapshot`` for both record and replay +command lines. +See the :ref:`snapshotting-label` section to learn more about running record/replay +and creating the snapshot in these modes. + +When ``rrsnapshot`` is not used, then snapshot named ``start_debugging`` +created in temporary overlay. This allows using reverse debugging, but with +temporary snapshots (existing within the session). From c9d27a0f9f2ee7e6a57167de7d0dcab406f8bfa7 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 27 May 2022 13:46:42 +0300 Subject: [PATCH 790/935] tests/avocado: update replay_linux test This patch updates replay_linux test to make it compatible with new LinuxTest class. Signed-off-by: Pavel Dovgalyuk Message-Id: <165364840253.688121.10404266209986316381.stgit@pasha-ThinkPad-X280> Signed-off-by: Paolo Bonzini --- tests/avocado/replay_linux.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tests/avocado/replay_linux.py b/tests/avocado/replay_linux.py index 15953f9e49..1099b5647f 100644 --- a/tests/avocado/replay_linux.py +++ b/tests/avocado/replay_linux.py @@ -32,9 +32,16 @@ class ReplayLinux(LinuxTest): bus = 'ide' def setUp(self): - super(ReplayLinux, self).setUp() + # LinuxTest does many replay-incompatible things, but includes + # useful methods. Do not setup LinuxTest here and just + # call some functions. + super(LinuxTest, self).setUp() + self._set_distro() self.boot_path = self.download_boot() - self.cloudinit_path = self.prepare_cloudinit() + self.phone_server = cloudinit.PhoneHomeServer(('0.0.0.0', 0), + self.name) + ssh_pubkey, self.ssh_key = self.set_up_existing_ssh_keys() + self.cloudinit_path = self.prepare_cloudinit(ssh_pubkey) def vm_add_disk(self, vm, path, id, device): bus_string = '' @@ -50,7 +57,9 @@ class ReplayLinux(LinuxTest): vm = self.get_vm() vm.add_args('-smp', '1') vm.add_args('-m', '1024') - vm.add_args('-object', 'filter-replay,id=replay,netdev=hub0port0') + vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22', + '-device', 'virtio-net,netdev=vnet') + vm.add_args('-object', 'filter-replay,id=replay,netdev=vnet') if args: vm.add_args(*args) self.vm_add_disk(vm, self.boot_path, 0, self.hdd) @@ -75,8 +84,8 @@ class ReplayLinux(LinuxTest): stop_check=(lambda : not vm.is_running())) console_drainer.start() if record: - cloudinit.wait_for_phone_home(('0.0.0.0', self.phone_home_port), - self.name) + while not self.phone_server.instance_phoned_back: + self.phone_server.handle_request() vm.shutdown() logger.info('finished the recording with log size %s bytes' % os.path.getsize(replay_path)) From 3cd1dce33d2359fe410bb20f6f980f3f91da79bd Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 27 May 2022 13:46:48 +0300 Subject: [PATCH 791/935] tests/avocado: add replay Linux tests for virtio machine This patch adds two tests for replaying Linux boot process on x86_64 virtio platform. Signed-off-by: Pavel Dovgalyuk Message-Id: <165364840811.688121.11931681195199516354.stgit@pasha-ThinkPad-X280> Signed-off-by: Paolo Bonzini --- tests/avocado/replay_linux.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/avocado/replay_linux.py b/tests/avocado/replay_linux.py index 1099b5647f..3bb1bc8816 100644 --- a/tests/avocado/replay_linux.py +++ b/tests/avocado/replay_linux.py @@ -123,3 +123,29 @@ class ReplayLinuxX8664(ReplayLinux): :avocado: tags=machine:q35 """ self.run_rr(shift=3) + +@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout') +class ReplayLinuxX8664Virtio(ReplayLinux): + """ + :avocado: tags=arch:x86_64 + :avocado: tags=virtio + :avocado: tags=accel:tcg + """ + + hdd = 'virtio-blk-pci' + cd = 'virtio-blk-pci' + bus = None + + chksum = 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0' + + def test_pc_i440fx(self): + """ + :avocado: tags=machine:pc + """ + self.run_rr(shift=1) + + def test_pc_q35(self): + """ + :avocado: tags=machine:q35 + """ + self.run_rr(shift=3) From 9b59af628c97eada68eebc1a9af0c72b75ecf1b8 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 27 May 2022 13:46:53 +0300 Subject: [PATCH 792/935] tests/avocado: add replay Linux test for Aarch64 machines This patch adds two tests for replaying Linux boot process on Aarch64 platform. Signed-off-by: Pavel Dovgalyuk Message-Id: <165364841373.688121.8868079200312201658.stgit@pasha-ThinkPad-X280> Signed-off-by: Paolo Bonzini --- tests/avocado/replay_linux.py | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/avocado/replay_linux.py b/tests/avocado/replay_linux.py index 3bb1bc8816..40e4f6908e 100644 --- a/tests/avocado/replay_linux.py +++ b/tests/avocado/replay_linux.py @@ -13,6 +13,7 @@ import logging import time from avocado import skipUnless +from avocado_qemu import BUILD_DIR from avocado.utils import cloudinit from avocado.utils import network from avocado.utils import vmimage @@ -149,3 +150,42 @@ class ReplayLinuxX8664Virtio(ReplayLinux): :avocado: tags=machine:q35 """ self.run_rr(shift=3) + +@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout') +class ReplayLinuxAarch64(ReplayLinux): + """ + :avocado: tags=accel:tcg + :avocado: tags=arch:aarch64 + :avocado: tags=machine:virt + :avocado: tags=cpu:max + """ + + chksum = '1e18d9c0cf734940c4b5d5ec592facaed2af0ad0329383d5639c997fdf16fe49' + + hdd = 'virtio-blk-device' + cd = 'virtio-blk-device' + bus = None + + def get_common_args(self): + return ('-bios', + os.path.join(BUILD_DIR, 'pc-bios', 'edk2-aarch64-code.fd'), + "-cpu", "max,lpa2=off", + '-device', 'virtio-rng-pci,rng=rng0', + '-object', 'rng-builtin,id=rng0') + + def test_virt_gicv2(self): + """ + :avocado: tags=machine:gic-version=2 + """ + + self.run_rr(shift=3, + args=(*self.get_common_args(), + "-machine", "virt,gic-version=2")) + + def test_virt_gicv3(self): + """ + :avocado: tags=machine:gic-version=3 + """ + + self.run_rr(shift=3, + args=(*self.get_common_args(), From d426ff938b3f95e0b04bb410d47ae50359340a16 Mon Sep 17 00:00:00 2001 From: Dario Faggioli Date: Fri, 27 May 2022 17:30:54 +0200 Subject: [PATCH 793/935] tests/Makefile.include: Fix 'make check-help' output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 3d2f73ef75e ("build: use "meson test" as the test harness"), check-report.tap is no more, and we have check-report.junit.xml. Update the output of 'make check-help', which was still listing 'check-report.tap', accordingly. Fixes: 3d2f73ef75e Signed-off-by: Dario Faggioli Message-Id: <165366545439.6869.11633009118019728798.stgit@work> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- tests/Makefile.include | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index 6a1688e33e..2a1c77440a 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -3,28 +3,28 @@ .PHONY: check-help check-help: @echo "Regression testing targets:" - @echo " $(MAKE) check Run block, qapi-schema, unit, softfloat, qtest and decodetree tests" - @echo " $(MAKE) bench Run speed tests" + @echo " $(MAKE) check Run block, qapi-schema, unit, softfloat, qtest and decodetree tests" + @echo " $(MAKE) bench Run speed tests" @echo @echo "Individual test suites:" - @echo " $(MAKE) check-qtest-TARGET Run qtest tests for given target" - @echo " $(MAKE) check-qtest Run qtest tests" - @echo " $(MAKE) check-unit Run qobject tests" - @echo " $(MAKE) check-qapi-schema Run QAPI schema tests" - @echo " $(MAKE) check-block Run block tests" + @echo " $(MAKE) check-qtest-TARGET Run qtest tests for given target" + @echo " $(MAKE) check-qtest Run qtest tests" + @echo " $(MAKE) check-unit Run qobject tests" + @echo " $(MAKE) check-qapi-schema Run QAPI schema tests" + @echo " $(MAKE) check-block Run block tests" ifneq ($(filter $(all-check-targets), check-softfloat),) - @echo " $(MAKE) check-tcg Run TCG tests" - @echo " $(MAKE) check-softfloat Run FPU emulation tests" + @echo " $(MAKE) check-tcg Run TCG tests" + @echo " $(MAKE) check-softfloat Run FPU emulation tests" endif - @echo " $(MAKE) check-avocado Run avocado (integration) tests for currently configured targets" + @echo " $(MAKE) check-avocado Run avocado (integration) tests for currently configured targets" @echo - @echo " $(MAKE) check-report.tap Generates an aggregated TAP test report" - @echo " $(MAKE) check-venv Creates a Python venv for tests" - @echo " $(MAKE) check-clean Clean the tests and related data" + @echo " $(MAKE) check-report.junit.xml Generates an aggregated XML test report" + @echo " $(MAKE) check-venv Creates a Python venv for tests" + @echo " $(MAKE) check-clean Clean the tests and related data" @echo @echo "The following are useful for CI builds" - @echo " $(MAKE) check-build Build most test binaries" - @echo " $(MAKE) get-vm-images Downloads all images used by avocado tests, according to configured targets (~350 MB each, 1.5 GB max)" + @echo " $(MAKE) check-build Build most test binaries" + @echo " $(MAKE) get-vm-images Downloads all images used by avocado tests, according to configured targets (~350 MB each, 1.5 GB max)" @echo @echo @echo "The variable SPEED can be set to control the gtester speed setting." From efb3934adf9ee7794db7e0ade9f576c634592891 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 24 May 2022 11:10:19 -0400 Subject: [PATCH 794/935] x86: cpu: make sure number of addressable IDs for processor cores meets the spec Accourding Intel's CPUID[EAX=04H] resulting bits 31 - 26 in EAX should be: " **** The nearest power-of-2 integer that is not smaller than (1 + EAX[31:26]) is the number of unique Core_IDs reserved for addressing different processor cores in a physical package. Core ID is a subset of bits of the initial APIC ID. " ensure that values stored in EAX[31-26] always meets this condition. Signed-off-by: Igor Mammedov Message-Id: <20220524151020.2541698-2-imammedo@redhat.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 9fdfec9d8b..94cc4a8700 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5287,7 +5287,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, /* QEMU gives out its own APIC IDs, never pass down bits 31..26. */ *eax &= ~0xFC000000; if ((*eax & 31) && cs->nr_cores > 1) { - *eax |= (cs->nr_cores - 1) << 26; + *eax |= (pow2ceil(cs->nr_cores) - 1) << 26; } } else if (cpu->vendor_cpuid_only && IS_AMD_CPU(env)) { *eax = *ebx = *ecx = *edx = 0; From d7caf13b5fcf742e5680c1d3448ba070fc811644 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 24 May 2022 11:10:20 -0400 Subject: [PATCH 795/935] x86: cpu: fixup number of addressable IDs for logical processors sharing cache When QEMU is started with '-cpu host,host-cache-info=on', it will passthrough host's number of logical processors sharing cache and number of processor cores in the physical package. QEMU already fixes up the later to correctly reflect number of configured cores for VM, however number of logical processors sharing cache is still comes from host CPU, which confuses guest started with: -machine q35,accel=kvm \ -cpu host,host-cache-info=on,l3-cache=off \ -smp 20,sockets=2,dies=1,cores=10,threads=1 \ -numa node,nodeid=0,memdev=ram-node0 \ -numa node,nodeid=1,memdev=ram-node1 \ -numa cpu,socket-id=0,node-id=0 \ -numa cpu,socket-id=1,node-id=1 on 2 socket Xeon 4210R host with 10 cores per socket with CPUID[04H]: ... --- cache 3 --- cache type = unified cache (3) cache level = 0x3 (3) self-initializing cache level = true fully associative cache = false maximum IDs for CPUs sharing cache = 0x1f (31) maximum IDs for cores in pkg = 0xf (15) ... that doesn't match number of logical processors VM was configured with and as result RHEL 9.0 guest complains: sched: CPU #10's llc-sibling CPU #0 is not on the same node! [node: 1 != 0]. Ignoring dependency. WARNING: CPU: 10 PID: 0 at arch/x86/kernel/smpboot.c:421 topology_sane.isra.0+0x67/0x80 ... Call Trace: set_cpu_sibling_map+0x176/0x590 start_secondary+0x5b/0x150 secondary_startup_64_no_verify+0xc2/0xcb Fix it by capping max number of logical processors to vcpus/socket as it was configured, which fixes the issue. Signed-off-by: Igor Mammedov Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2088311 Message-Id: <20220524151020.2541698-3-imammedo@redhat.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 94cc4a8700..6a57ef13af 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5284,10 +5284,22 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, /* cache info: needed for Core compatibility */ if (cpu->cache_info_passthrough) { x86_cpu_get_cache_cpuid(index, count, eax, ebx, ecx, edx); - /* QEMU gives out its own APIC IDs, never pass down bits 31..26. */ - *eax &= ~0xFC000000; - if ((*eax & 31) && cs->nr_cores > 1) { - *eax |= (pow2ceil(cs->nr_cores) - 1) << 26; + /* + * QEMU has its own number of cores/logical cpus, + * set 24..14, 31..26 bit to configured values + */ + if (*eax & 31) { + int host_vcpus_per_cache = 1 + ((*eax & 0x3FFC000) >> 14); + int vcpus_per_socket = env->nr_dies * cs->nr_cores * + cs->nr_threads; + if (cs->nr_cores > 1) { + *eax &= ~0xFC000000; + *eax |= (pow2ceil(cs->nr_cores) - 1) << 26; + } + if (host_vcpus_per_cache > vcpus_per_socket) { + *eax &= ~0x3FFC000; + *eax |= (pow2ceil(vcpus_per_socket) - 1) << 14; + } } } else if (cpu->vendor_cpuid_only && IS_AMD_CPU(env)) { *eax = *ebx = *ecx = *edx = 0; From e7874a50ff3f5b20fb46f36958ad88334e4d55cd Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 25 May 2022 20:09:13 -0400 Subject: [PATCH 796/935] python: update for mypy 0.950 typeshed (included in mypy) recently updated to improve the typing for WriteTransport objects. I was working around this, but now there's a version where I shouldn't work around it. Unfortunately this creates some minor ugliness if I want to support both pre- and post-0.950 versions. For now, for my sanity, just disable the unused-ignores warning. Signed-off-by: John Snow Reviewed-by: Paolo Bonzini Message-Id: <20220526000921.1581503-2-jsnow@redhat.com> Signed-off-by: Paolo Bonzini --- python/qemu/qmp/util.py | 4 +++- python/setup.cfg | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/python/qemu/qmp/util.py b/python/qemu/qmp/util.py index eaa5fc7d5f..ca6225e9cd 100644 --- a/python/qemu/qmp/util.py +++ b/python/qemu/qmp/util.py @@ -40,7 +40,9 @@ async def flush(writer: asyncio.StreamWriter) -> None: drain. The flow control limits are restored after the call is completed. """ - transport = cast(asyncio.WriteTransport, writer.transport) + transport = cast( # type: ignore[redundant-cast] + asyncio.WriteTransport, writer.transport + ) # https://github.com/python/typeshed/issues/5779 low, high = transport.get_write_buffer_limits() # type: ignore diff --git a/python/setup.cfg b/python/setup.cfg index e877ea5647..c2c61c7519 100644 --- a/python/setup.cfg +++ b/python/setup.cfg @@ -79,6 +79,7 @@ strict = True python_version = 3.6 warn_unused_configs = True namespace_packages = True +warn_unused_ignores = False [mypy-qemu.utils.qom_fuse] # fusepy has no type stubs: From caa0f7cbaf4159186d614849ddfbdd89f26d597c Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 25 May 2022 20:09:14 -0400 Subject: [PATCH 797/935] tests: add "TESTS_PYTHON" variable to Makefile This is a convenience feature: $(PYTHON) points to the Python executable we were instructed to use by the configure script. We use that Python to create a virtual environment with the "check-venv" target in tests/Makefile.include. $(TESTS_PYTHON) points to the Python executable belonging to the virtual environment tied to the build. This Python executable is a symlink to the binary used to create the venv, which will be the version provided at configure time. Using $(TESTS_PYTHON) therefore uses the $(PYTHON) executable, but with paths modified to use packages installed to the venv. Signed-off-by: John Snow Reviewed-by: Paolo Bonzini Message-Id: <20220526000921.1581503-3-jsnow@redhat.com> Signed-off-by: Paolo Bonzini --- tests/Makefile.include | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index 2a1c77440a..50237f073a 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -89,6 +89,7 @@ TARGETS=$(patsubst libqemu-%.fa, %, $(filter libqemu-%.fa, $(ninja-targets))) TESTS_VENV_DIR=$(BUILD_DIR)/tests/venv TESTS_VENV_REQ=$(SRC_PATH)/tests/requirements.txt TESTS_RESULTS_DIR=$(BUILD_DIR)/tests/results +TESTS_PYTHON=$(TESTS_VENV_DIR)/bin/python ifndef AVOCADO_TESTS AVOCADO_TESTS=tests/avocado endif @@ -108,7 +109,7 @@ $(TESTS_VENV_DIR): $(TESTS_VENV_REQ) $(PYTHON) -m venv $@, \ VENV, $@) $(call quiet-command, \ - $(TESTS_VENV_DIR)/bin/python -m pip -q install -r $(TESTS_VENV_REQ), \ + $(TESTS_PYTHON) -m pip -q install -r $(TESTS_VENV_REQ), \ PIP, $(TESTS_VENV_REQ)) $(call quiet-command, touch $@) @@ -126,7 +127,7 @@ FEDORA_31_DOWNLOAD=$(filter $(FEDORA_31_ARCHES),$(FEDORA_31_ARCHES_CANDIDATES)) # download one specific Fedora 31 image get-vm-image-fedora-31-%: check-venv $(call quiet-command, \ - $(TESTS_VENV_DIR)/bin/python -m avocado vmimage get \ + $(TESTS_PYTHON) -m avocado vmimage get \ --distro=fedora --distro-version=31 --arch=$*, \ "AVOCADO", "Downloading avocado tests VM image for $*") @@ -135,7 +136,7 @@ get-vm-images: check-venv $(patsubst %,get-vm-image-fedora-31-%, $(FEDORA_31_DOW check-avocado: check-venv $(TESTS_RESULTS_DIR) get-vm-images $(call quiet-command, \ - $(TESTS_VENV_DIR)/bin/python -m avocado \ + $(TESTS_PYTHON) -m avocado \ --show=$(AVOCADO_SHOW) run --job-results-dir=$(TESTS_RESULTS_DIR) \ $(if $(AVOCADO_TAGS),, --filter-by-tags-include-empty \ --filter-by-tags-include-empty-key) \ From aa19dd33ce616c1a34bb569da8e642f0b6f51fa0 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 25 May 2022 20:09:15 -0400 Subject: [PATCH 798/935] tests: use python3 as the python executable name Use "python3" instead of "python" as per PEP0394: https://peps.python.org/pep-0394/ This should always be defined (in a venv, at least!), matching the preferred python shebang of "#!/usr/bin/env python3". Signed-off-by: John Snow Reviewed-by: Paolo Bonzini Message-Id: <20220526000921.1581503-4-jsnow@redhat.com> Signed-off-by: Paolo Bonzini --- tests/Makefile.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index 50237f073a..fae2dd0f3c 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -89,7 +89,7 @@ TARGETS=$(patsubst libqemu-%.fa, %, $(filter libqemu-%.fa, $(ninja-targets))) TESTS_VENV_DIR=$(BUILD_DIR)/tests/venv TESTS_VENV_REQ=$(SRC_PATH)/tests/requirements.txt TESTS_RESULTS_DIR=$(BUILD_DIR)/tests/results -TESTS_PYTHON=$(TESTS_VENV_DIR)/bin/python +TESTS_PYTHON=$(TESTS_VENV_DIR)/bin/python3 ifndef AVOCADO_TESTS AVOCADO_TESTS=tests/avocado endif From a547c82701925400949856488a2c8c8750a3276e Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 25 May 2022 20:09:16 -0400 Subject: [PATCH 799/935] tests: silence pip upgrade warnings during venv creation Turn off the nag warning coaxing us to upgrade pip. It's not really that interesting to see in CI logs, and as long as nothing is broken -- nothing is broken. Signed-off-by: John Snow Reviewed-by: Paolo Bonzini Message-Id: <20220526000921.1581503-5-jsnow@redhat.com> Signed-off-by: Paolo Bonzini --- tests/Makefile.include | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index fae2dd0f3c..ba9f5bd65c 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -109,8 +109,8 @@ $(TESTS_VENV_DIR): $(TESTS_VENV_REQ) $(PYTHON) -m venv $@, \ VENV, $@) $(call quiet-command, \ - $(TESTS_PYTHON) -m pip -q install -r $(TESTS_VENV_REQ), \ - PIP, $(TESTS_VENV_REQ)) + $(TESTS_PYTHON) -m pip -q --disable-pip-version-check install \ + -r $(TESTS_VENV_REQ), PIP, $(TESTS_VENV_REQ)) $(call quiet-command, touch $@) $(TESTS_RESULTS_DIR): From 5a6f1199cb5fca105ca99356ae05f8e48f5c8d97 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 25 May 2022 20:09:17 -0400 Subject: [PATCH 800/935] tests: add quiet-venv-pip macro Factor out the "test venv pip" macro; rewrite the "check-venv" rule to be a little more compact. Replace the "PIP" pseudo-command output with "VENVPIP" to make it 1% more clear that we are talking about using pip to install something into a venv. Signed-off-by: John Snow Reviewed-by: Paolo Bonzini Message-Id: <20220526000921.1581503-6-jsnow@redhat.com> Signed-off-by: Paolo Bonzini --- tests/Makefile.include | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index ba9f5bd65c..fa46c0c61b 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -104,13 +104,13 @@ else AVOCADO_CMDLINE_TAGS=$(addprefix -t , $(AVOCADO_TAGS)) endif +quiet-venv-pip = $(quiet-@)$(call quiet-command-run, \ + $(TESTS_PYTHON) -m pip -q --disable-pip-version-check $1, \ + "VENVPIP","$1") + $(TESTS_VENV_DIR): $(TESTS_VENV_REQ) - $(call quiet-command, \ - $(PYTHON) -m venv $@, \ - VENV, $@) - $(call quiet-command, \ - $(TESTS_PYTHON) -m pip -q --disable-pip-version-check install \ - -r $(TESTS_VENV_REQ), PIP, $(TESTS_VENV_REQ)) + $(call quiet-command, $(PYTHON) -m venv $@, VENV, $@) + $(call quiet-venv-pip,install -r $(TESTS_VENV_REQ)) $(call quiet-command, touch $@) $(TESTS_RESULTS_DIR): From 0e7647aa8a5d5b99a0ffb401ba75f0ae8c171c96 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 25 May 2022 20:09:18 -0400 Subject: [PATCH 801/935] tests: install "qemu" namespace package into venv This patch adds the "qemu" namespace package to the $build/tests/venv directory. It does so in "editable" mode, which means that changes to the source python directory will actively be reflected by the venv. This patch also then removes any sys.path hacking from the avocado test scripts directly. By doing this, the environment of where to find these packages is managed entirely by the virtual environment and not by the scripts themselves. Signed-off-by: John Snow Reviewed-by: Paolo Bonzini Message-Id: <20220526000921.1581503-7-jsnow@redhat.com> Signed-off-by: Paolo Bonzini --- tests/Makefile.include | 1 + tests/avocado/avocado_qemu/__init__.py | 11 +++++------ tests/avocado/virtio_check_params.py | 1 - tests/avocado/virtio_version.py | 1 - tests/requirements.txt | 1 + 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index fa46c0c61b..3accb83b13 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -110,6 +110,7 @@ quiet-venv-pip = $(quiet-@)$(call quiet-command-run, \ $(TESTS_VENV_DIR): $(TESTS_VENV_REQ) $(call quiet-command, $(PYTHON) -m venv $@, VENV, $@) + $(call quiet-venv-pip,install -e "$(SRC_PATH)/python/") $(call quiet-venv-pip,install -r $(TESTS_VENV_REQ)) $(call quiet-command, touch $@) diff --git a/tests/avocado/avocado_qemu/__init__.py b/tests/avocado/avocado_qemu/__init__.py index 39f15c1d51..b656a70c55 100644 --- a/tests/avocado/avocado_qemu/__init__.py +++ b/tests/avocado/avocado_qemu/__init__.py @@ -21,6 +21,11 @@ import avocado from avocado.utils import cloudinit, datadrainer, process, ssh, vmimage from avocado.utils.path import find_command +from qemu.machine import QEMUMachine +from qemu.utils import (get_info_usernet_hostfwd_port, kvm_available, + tcg_available) + + #: The QEMU build root directory. It may also be the source directory #: if building from the source dir, but it's safer to use BUILD_DIR for #: that purpose. Be aware that if this code is moved outside of a source @@ -35,12 +40,6 @@ if os.path.islink(os.path.dirname(os.path.dirname(__file__))): else: SOURCE_DIR = BUILD_DIR -sys.path.append(os.path.join(SOURCE_DIR, 'python')) - -from qemu.machine import QEMUMachine -from qemu.utils import (get_info_usernet_hostfwd_port, kvm_available, - tcg_available) - def has_cmd(name, args=None): """ diff --git a/tests/avocado/virtio_check_params.py b/tests/avocado/virtio_check_params.py index e869690473..4093da8a67 100644 --- a/tests/avocado/virtio_check_params.py +++ b/tests/avocado/virtio_check_params.py @@ -22,7 +22,6 @@ import os import re import logging -sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) from qemu.machine import QEMUMachine from avocado_qemu import QemuSystemTest from avocado import skip diff --git a/tests/avocado/virtio_version.py b/tests/avocado/virtio_version.py index 208910bb84..c84e48813a 100644 --- a/tests/avocado/virtio_version.py +++ b/tests/avocado/virtio_version.py @@ -11,7 +11,6 @@ Check compatibility of virtio device types import sys import os -sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) from qemu.machine import QEMUMachine from avocado_qemu import QemuSystemTest diff --git a/tests/requirements.txt b/tests/requirements.txt index a21b59b443..0ba561b6bd 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,5 +1,6 @@ # Add Python module requirements, one per line, to be installed # in the tests/venv Python virtual environment. For more info, # refer to: https://pip.pypa.io/en/stable/user_guide/#id1 +# Note that qemu.git/python/ is always implicitly installed. avocado-framework==88.1 pycdlib==1.11.0 From f4c66f17051f0dee0e6070c6b78a78e7425b5c96 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 25 May 2022 20:09:19 -0400 Subject: [PATCH 802/935] tests: use tests/venv to run basevm.py-based scripts This patch co-opts the virtual environment being used by avocado tests to also run the basevm.py tests. This is being done in preparation for for the qemu.qmp package being removed from qemu.git. As part of the change, remove any sys.path() hacks and treat "qemu" as a normal third-party import. Signed-off-by: John Snow Reviewed-by: Paolo Bonzini Message-Id: <20220526000921.1581503-8-jsnow@redhat.com> Signed-off-by: Paolo Bonzini --- tests/vm/Makefile.include | 13 +++++++------ tests/vm/basevm.py | 6 +++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include index ae91f5043e..588bc999cc 100644 --- a/tests/vm/Makefile.include +++ b/tests/vm/Makefile.include @@ -84,10 +84,11 @@ vm-clean-all: $(IMAGES_DIR)/%.img: $(SRC_PATH)/tests/vm/% \ $(SRC_PATH)/tests/vm/basevm.py \ - $(SRC_PATH)/tests/vm/Makefile.include + $(SRC_PATH)/tests/vm/Makefile.include \ + check-venv @mkdir -p $(IMAGES_DIR) $(call quiet-command, \ - $(PYTHON) $< \ + $(TESTS_PYTHON) $< \ $(if $(V)$(DEBUG), --debug) \ $(if $(GENISOIMAGE),--genisoimage $(GENISOIMAGE)) \ $(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \ @@ -101,9 +102,9 @@ $(IMAGES_DIR)/%.img: $(SRC_PATH)/tests/vm/% \ # Build in VM $(IMAGE) -vm-build-%: $(IMAGES_DIR)/%.img +vm-build-%: $(IMAGES_DIR)/%.img check-venv $(call quiet-command, \ - $(PYTHON) $(SRC_PATH)/tests/vm/$* \ + $(TESTS_PYTHON) $(SRC_PATH)/tests/vm/$* \ $(if $(V)$(DEBUG), --debug) \ $(if $(DEBUG), --interactive) \ $(if $(J),--jobs $(J)) \ @@ -127,9 +128,9 @@ vm-boot-serial-%: $(IMAGES_DIR)/%.img -device virtio-net-pci,netdev=vnet \ || true -vm-boot-ssh-%: $(IMAGES_DIR)/%.img +vm-boot-ssh-%: $(IMAGES_DIR)/%.img check-venv $(call quiet-command, \ - $(PYTHON) $(SRC_PATH)/tests/vm/$* \ + $(TESTS_PYTHON) $(SRC_PATH)/tests/vm/$* \ $(if $(J),--jobs $(J)) \ $(if $(V)$(DEBUG), --debug) \ $(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \ diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index 254e11c932..d7d0413df3 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -18,9 +18,6 @@ import socket import logging import time import datetime -sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) -from qemu.machine import QEMUMachine -from qemu.utils import get_info_usernet_hostfwd_port, kvm_available import subprocess import hashlib import argparse @@ -31,6 +28,9 @@ import multiprocessing import traceback import shlex +from qemu.machine import QEMUMachine +from qemu.utils import get_info_usernet_hostfwd_port, kvm_available + SSH_KEY_FILE = os.path.join(os.path.dirname(__file__), "..", "keys", "id_rsa") SSH_PUB_KEY_FILE = os.path.join(os.path.dirname(__file__), From e184036a0e12cbfb8980362cd4de18268b4d0c38 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 25 May 2022 20:09:20 -0400 Subject: [PATCH 803/935] tests: add python3-venv to debian10.docker This is needed to be able to add a venv-building step to 'make check'; the clang-user job in particular needs this to be able to run check-unit. Signed-off-by: John Snow Reviewed-by: Paolo Bonzini Message-Id: <20220526000921.1581503-9-jsnow@redhat.com> Signed-off-by: Paolo Bonzini --- tests/docker/dockerfiles/debian10.docker | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker index b414af1b9f..03be923066 100644 --- a/tests/docker/dockerfiles/debian10.docker +++ b/tests/docker/dockerfiles/debian10.docker @@ -34,4 +34,5 @@ RUN apt update && \ python3 \ python3-sphinx \ python3-sphinx-rtd-theme \ + python3-venv \ $(apt-get -s build-dep --arch-only qemu | egrep ^Inst | fgrep '[all]' | cut -d\ -f2) From 1d8cf47e5b8b4faa95954824cb6610d81c50d7d2 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 25 May 2022 20:09:21 -0400 Subject: [PATCH 804/935] tests: run 'device-crash-test' from tests/venv Remove the sys.path hacking from device-crash-test, and add in a little user-friendly message for anyone who was used to running this script directly from the source tree. Modify the GitLab job recipes to create the tests/venv first, then run device-crash-test from that venv. Signed-off-by: John Snow Reviewed-by: Paolo Bonzini Message-Id: <20220526000921.1581503-10-jsnow@redhat.com> Signed-off-by: Paolo Bonzini --- .gitlab-ci.d/buildtest.yml | 8 +++++--- scripts/device-crash-test | 14 +++++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index ecac3ec50c..544385f5be 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -110,7 +110,8 @@ crash-test-debian: IMAGE: debian-amd64 script: - cd build - - scripts/device-crash-test -q ./qemu-system-i386 + - make check-venv + - tests/venv/bin/python3 scripts/device-crash-test -q ./qemu-system-i386 build-system-fedora: extends: .native_build_job_template @@ -155,8 +156,9 @@ crash-test-fedora: IMAGE: fedora script: - cd build - - scripts/device-crash-test -q ./qemu-system-ppc - - scripts/device-crash-test -q ./qemu-system-riscv32 + - make check-venv + - tests/venv/bin/python3 scripts/device-crash-test -q ./qemu-system-ppc + - tests/venv/bin/python3 scripts/device-crash-test -q ./qemu-system-riscv32 build-system-centos: extends: .native_build_job_template diff --git a/scripts/device-crash-test b/scripts/device-crash-test index a203b3fdea..73bcb98693 100755 --- a/scripts/device-crash-test +++ b/scripts/device-crash-test @@ -33,10 +33,18 @@ import re import random import argparse from itertools import chain +from pathlib import Path -sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python')) -from qemu.machine import QEMUMachine -from qemu.qmp import ConnectError +try: + from qemu.machine import QEMUMachine + from qemu.qmp import ConnectError +except ModuleNotFoundError as exc: + path = Path(__file__).resolve() + print(f"Module '{exc.name}' not found.") + print(" Try 'make check-venv' from your build directory,") + print(" and then one way to run this script is like so:") + print(f' > $builddir/tests/venv/bin/python3 "{path}"') + sys.exit(1) logger = logging.getLogger('device-crash-test') dbg = logger.debug From d4bb4432ab43febc0eb41b031c0c3aaf5113a0c6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 6 Jun 2022 12:44:45 +0200 Subject: [PATCH 805/935] regenerate meson-buildoptions.sh Signed-off-by: Paolo Bonzini --- scripts/meson-buildoptions.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 731e5ea1cf..00ea4d8cd1 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -156,13 +156,13 @@ meson_options_help() { printf "%s\n" ' vhost-kernel vhost kernel backend support' printf "%s\n" ' vhost-net vhost-net kernel acceleration support' printf "%s\n" ' vhost-user vhost-user backend support' - printf "%s\n" ' vmnet vmnet.framework network backend support' printf "%s\n" ' vhost-user-blk-server' printf "%s\n" ' build vhost-user-blk server' printf "%s\n" ' vhost-vdpa vhost-vdpa kernel backend support' printf "%s\n" ' virglrenderer virgl rendering support' printf "%s\n" ' virtfs virtio-9p support' printf "%s\n" ' virtiofsd build virtiofs daemon (virtiofsd)' + printf "%s\n" ' vmnet vmnet.framework network backend support' printf "%s\n" ' vnc VNC server' printf "%s\n" ' vnc-jpeg JPEG lossy compression for VNC server' printf "%s\n" ' vnc-sasl SASL authentication for VNC server' @@ -430,6 +430,8 @@ _meson_option_parse() { --disable-virtfs) printf "%s" -Dvirtfs=disabled ;; --enable-virtiofsd) printf "%s" -Dvirtiofsd=enabled ;; --disable-virtiofsd) printf "%s" -Dvirtiofsd=disabled ;; + --enable-vmnet) printf "%s" -Dvmnet=enabled ;; + --disable-vmnet) printf "%s" -Dvmnet=disabled ;; --enable-vnc) printf "%s" -Dvnc=enabled ;; --disable-vnc) printf "%s" -Dvnc=disabled ;; --enable-vnc-jpeg) printf "%s" -Dvnc_jpeg=enabled ;; From 7632a38e7c21c993da74d17afa8dd66d9552da06 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 6 Jun 2022 12:44:57 +0200 Subject: [PATCH 806/935] configure: remove reference to removed option Signed-off-by: Paolo Bonzini --- configure | 1 - 1 file changed, 1 deletion(-) diff --git a/configure b/configure index b9ccff9067..ac18ed4f3a 100755 --- a/configure +++ b/configure @@ -1035,7 +1035,6 @@ Advanced options (experts only): --with-git-submodules=ignore do not update or check git submodules (default if no .git dir) --static enable static build [$static] --bindir=PATH install binaries in PATH - --efi-aarch64=PATH PATH of efi file to use for aarch64 VMs. --with-suffix=SUFFIX suffix for QEMU data inside datadir/libdir/sysconfdir/docdir [$qemu_suffix] --without-default-features default all --enable-* options to "disabled" --without-default-devices do not include any device that is not needed to From ca5765c8521b8284b8277ed4b811ac0ab9010fc8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 6 Jun 2022 16:03:38 +0200 Subject: [PATCH 807/935] meson: qga: do not use deprecated meson.build_root() The function will return the build root of the parent project if called from a subproject; that is irrelevant for QEMU's usage but rarely desirable, and therefore the function was deprecated and replaced by two functions project_build_root() and global_build_root(). Replace it with the former. Signed-off-by: Paolo Bonzini --- qga/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qga/meson.build b/qga/meson.build index 619ff095bc..65c1e93846 100644 --- a/qga/meson.build +++ b/qga/meson.build @@ -125,7 +125,7 @@ if targetos == 'windows' wixl, '-o', '@OUTPUT0@', '@INPUT0@', qemu_ga_msi_arch[cpu], qemu_ga_msi_vss, - '-D', 'BUILD_DIR=' + meson.build_root(), + '-D', 'BUILD_DIR=' + meson.project_build_root(), '-D', 'BIN_DIR=' + glib.get_variable('bindir'), '-D', 'QEMU_GA_VERSION=' + config_host['QEMU_GA_VERSION'], '-D', 'QEMU_GA_MANUFACTURER=' + config_host['QEMU_GA_MANUFACTURER'], From 64baad62cd3d9f2e57f65a8f3be7b5639a77e0b4 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 6 Jun 2022 20:42:51 +0800 Subject: [PATCH 808/935] target/loongarch: Add README This patch gives an introduction to the LoongArch target. Signed-off-by: Song Gao Signed-off-by: Xiaojuan Yang Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-2-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- MAINTAINERS | 6 ++++++ target/loongarch/README | 10 ++++++++++ 2 files changed, 16 insertions(+) create mode 100644 target/loongarch/README diff --git a/MAINTAINERS b/MAINTAINERS index 5fe8f7eca2..319a5d805a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -212,6 +212,12 @@ S: Maintained F: target/hppa/ F: disas/hppa.c +LoongArch TCG CPUs +M: Song Gao +M: Xiaojuan Yang +S: Maintained +F: target/loongarch/ + M68K TCG CPUs M: Laurent Vivier S: Maintained diff --git a/target/loongarch/README b/target/loongarch/README new file mode 100644 index 0000000000..de141c1a58 --- /dev/null +++ b/target/loongarch/README @@ -0,0 +1,10 @@ +- Introduction + + LoongArch is the general processor architecture of Loongson. + + The following versions of the LoongArch core are supported + core: 3A5000 + https://github.com/loongson/LoongArch-Documentation/releases/download/2021.08.17/LoongArch-Vol1-v1.00-EN.pdf + + We can get the latest loongarch documents at https://github.com/loongson/LoongArch-Documentation/tags. + From 228021f05ebfd89a3abc225d47a0d0e6c139dade Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 6 Jun 2022 20:42:52 +0800 Subject: [PATCH 809/935] target/loongarch: Add core definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds target state header, target definitions and initialization routines. Signed-off-by: Song Gao Signed-off-by: Xiaojuan Yang Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20220606124333.2060567-3-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/cpu-param.h | 18 ++ target/loongarch/cpu.c | 324 +++++++++++++++++++++++++++++++++++ target/loongarch/cpu.h | 243 ++++++++++++++++++++++++++ target/loongarch/internals.h | 21 +++ 4 files changed, 606 insertions(+) create mode 100644 target/loongarch/cpu-param.h create mode 100644 target/loongarch/cpu.c create mode 100644 target/loongarch/cpu.h create mode 100644 target/loongarch/internals.h diff --git a/target/loongarch/cpu-param.h b/target/loongarch/cpu-param.h new file mode 100644 index 0000000000..9a769b67e0 --- /dev/null +++ b/target/loongarch/cpu-param.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch CPU parameters for QEMU. + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_CPU_PARAM_H +#define LOONGARCH_CPU_PARAM_H + +#define TARGET_LONG_BITS 64 +#define TARGET_PHYS_ADDR_SPACE_BITS 48 +#define TARGET_VIRT_ADDR_SPACE_BITS 48 + +#define TARGET_PAGE_BITS 14 +#define NB_MMU_MODES 4 + +#endif diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c new file mode 100644 index 0000000000..1f8e37906a --- /dev/null +++ b/target/loongarch/cpu.c @@ -0,0 +1,324 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch CPU + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/qemu-print.h" +#include "qapi/error.h" +#include "qemu/module.h" +#include "sysemu/qtest.h" +#include "exec/exec-all.h" +#include "qapi/qapi-commands-machine-target.h" +#include "cpu.h" +#include "internals.h" +#include "fpu/softfloat-helpers.h" + +const char * const regnames[32] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", +}; + +const char * const fregnames[32] = { + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", +}; + +static const char * const excp_names[] = { + [EXCCODE_INT] = "Interrupt", + [EXCCODE_PIL] = "Page invalid exception for load", + [EXCCODE_PIS] = "Page invalid exception for store", + [EXCCODE_PIF] = "Page invalid exception for fetch", + [EXCCODE_PME] = "Page modified exception", + [EXCCODE_PNR] = "Page Not Readable exception", + [EXCCODE_PNX] = "Page Not Executable exception", + [EXCCODE_PPI] = "Page Privilege error", + [EXCCODE_ADEF] = "Address error for instruction fetch", + [EXCCODE_ADEM] = "Address error for Memory access", + [EXCCODE_SYS] = "Syscall", + [EXCCODE_BRK] = "Break", + [EXCCODE_INE] = "Instruction Non-Existent", + [EXCCODE_IPE] = "Instruction privilege error", + [EXCCODE_FPE] = "Floating Point Exception", + [EXCCODE_DBP] = "Debug breakpoint", +}; + +const char *loongarch_exception_name(int32_t exception) +{ + assert(excp_names[exception]); + return excp_names[exception]; +} + +void G_NORETURN do_raise_exception(CPULoongArchState *env, + uint32_t exception, + uintptr_t pc) +{ + CPUState *cs = env_cpu(env); + + qemu_log_mask(CPU_LOG_INT, "%s: %d (%s)\n", + __func__, + exception, + loongarch_exception_name(exception)); + cs->exception_index = exception; + + cpu_loop_exit_restore(cs, pc); +} + +static void loongarch_cpu_set_pc(CPUState *cs, vaddr value) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + env->pc = value; +} + +#ifdef CONFIG_TCG +static void loongarch_cpu_synchronize_from_tb(CPUState *cs, + const TranslationBlock *tb) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + env->pc = tb->pc; +} +#endif /* CONFIG_TCG */ + +static void loongarch_la464_initfn(Object *obj) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(obj); + CPULoongArchState *env = &cpu->env; + int i; + + for (i = 0; i < 21; i++) { + env->cpucfg[i] = 0x0; + } + + env->cpucfg[0] = 0x14c010; /* PRID */ + + uint32_t data = 0; + data = FIELD_DP32(data, CPUCFG1, ARCH, 2); + data = FIELD_DP32(data, CPUCFG1, PGMMU, 1); + data = FIELD_DP32(data, CPUCFG1, IOCSR, 1); + data = FIELD_DP32(data, CPUCFG1, PALEN, 0x2f); + data = FIELD_DP32(data, CPUCFG1, VALEN, 0x2f); + data = FIELD_DP32(data, CPUCFG1, UAL, 1); + data = FIELD_DP32(data, CPUCFG1, RI, 1); + data = FIELD_DP32(data, CPUCFG1, EP, 1); + data = FIELD_DP32(data, CPUCFG1, RPLV, 1); + data = FIELD_DP32(data, CPUCFG1, HP, 1); + data = FIELD_DP32(data, CPUCFG1, IOCSR_BRD, 1); + env->cpucfg[1] = data; + + data = 0; + data = FIELD_DP32(data, CPUCFG2, FP, 1); + data = FIELD_DP32(data, CPUCFG2, FP_SP, 1); + data = FIELD_DP32(data, CPUCFG2, FP_DP, 1); + data = FIELD_DP32(data, CPUCFG2, FP_VER, 1); + data = FIELD_DP32(data, CPUCFG2, LLFTP, 1); + data = FIELD_DP32(data, CPUCFG2, LLFTP_VER, 1); + data = FIELD_DP32(data, CPUCFG2, LAM, 1); + env->cpucfg[2] = data; + + env->cpucfg[4] = 100 * 1000 * 1000; /* Crystal frequency */ + + data = 0; + data = FIELD_DP32(data, CPUCFG5, CC_MUL, 1); + data = FIELD_DP32(data, CPUCFG5, CC_DIV, 1); + env->cpucfg[5] = data; + + data = 0; + data = FIELD_DP32(data, CPUCFG16, L1_IUPRE, 1); + data = FIELD_DP32(data, CPUCFG16, L1_DPRE, 1); + data = FIELD_DP32(data, CPUCFG16, L2_IUPRE, 1); + data = FIELD_DP32(data, CPUCFG16, L2_IUUNIFY, 1); + data = FIELD_DP32(data, CPUCFG16, L2_IUPRIV, 1); + data = FIELD_DP32(data, CPUCFG16, L3_IUPRE, 1); + data = FIELD_DP32(data, CPUCFG16, L3_IUUNIFY, 1); + data = FIELD_DP32(data, CPUCFG16, L3_IUINCL, 1); + env->cpucfg[16] = data; + + data = 0; + data = FIELD_DP32(data, CPUCFG17, L1IU_WAYS, 3); + data = FIELD_DP32(data, CPUCFG17, L1IU_SETS, 8); + data = FIELD_DP32(data, CPUCFG17, L1IU_SIZE, 6); + env->cpucfg[17] = data; + + data = 0; + data = FIELD_DP32(data, CPUCFG18, L1D_WAYS, 3); + data = FIELD_DP32(data, CPUCFG18, L1D_SETS, 8); + data = FIELD_DP32(data, CPUCFG18, L1D_SIZE, 6); + env->cpucfg[18] = data; + + data = 0; + data = FIELD_DP32(data, CPUCFG19, L2IU_WAYS, 15); + data = FIELD_DP32(data, CPUCFG19, L2IU_SETS, 8); + data = FIELD_DP32(data, CPUCFG19, L2IU_SIZE, 6); + env->cpucfg[19] = data; + + data = 0; + data = FIELD_DP32(data, CPUCFG20, L3IU_WAYS, 15); + data = FIELD_DP32(data, CPUCFG20, L3IU_SETS, 14); + data = FIELD_DP32(data, CPUCFG20, L3IU_SETS, 6); + env->cpucfg[20] = data; +} + +static void loongarch_cpu_list_entry(gpointer data, gpointer user_data) +{ + const char *typename = object_class_get_name(OBJECT_CLASS(data)); + + qemu_printf("%s\n", typename); +} + +void loongarch_cpu_list(void) +{ + GSList *list; + list = object_class_get_list_sorted(TYPE_LOONGARCH_CPU, false); + g_slist_foreach(list, loongarch_cpu_list_entry, NULL); + g_slist_free(list); +} + +static void loongarch_cpu_reset(DeviceState *dev) +{ + CPUState *cs = CPU(dev); + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(cpu); + CPULoongArchState *env = &cpu->env; + + lacc->parent_reset(dev); + + env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3; + env->fcsr0 = 0x0; + + cs->exception_index = -1; +} + +static void loongarch_cpu_disas_set_info(CPUState *s, disassemble_info *info) +{ + info->print_insn = print_insn_loongarch; +} + +static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) +{ + CPUState *cs = CPU(dev); + LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(dev); + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } + + cpu_reset(cs); + qemu_init_vcpu(cs); + + lacc->parent_realize(dev, errp); +} + +static void loongarch_cpu_init(Object *obj) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(obj); + + cpu_set_cpustate_pointers(cpu); +} + +static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model) +{ + ObjectClass *oc; + char *typename; + + typename = g_strdup_printf(LOONGARCH_CPU_TYPE_NAME("%s"), cpu_model); + oc = object_class_by_name(typename); + g_free(typename); + return oc; +} + +void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + int i; + + qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc); + qemu_fprintf(f, " FCSR0 0x%08x fp_status 0x%02x\n", env->fcsr0, + get_float_exception_flags(&env->fp_status)); + + /* gpr */ + for (i = 0; i < 32; i++) { + if ((i & 3) == 0) { + qemu_fprintf(f, " GPR%02d:", i); + } + qemu_fprintf(f, " %s %016" PRIx64, regnames[i], env->gpr[i]); + if ((i & 3) == 3) { + qemu_fprintf(f, "\n"); + } + } + + /* fpr */ + if (flags & CPU_DUMP_FPU) { + for (i = 0; i < 32; i++) { + qemu_fprintf(f, " %s %016" PRIx64, fregnames[i], env->fpr[i]); + if ((i & 3) == 3) { + qemu_fprintf(f, "\n"); + } + } + } +} + +#ifdef CONFIG_TCG +#include "hw/core/tcg-cpu-ops.h" + +static struct TCGCPUOps loongarch_tcg_ops = { + .initialize = loongarch_translate_init, + .synchronize_from_tb = loongarch_cpu_synchronize_from_tb, +}; +#endif /* CONFIG_TCG */ + +static void loongarch_cpu_class_init(ObjectClass *c, void *data) +{ + LoongArchCPUClass *lacc = LOONGARCH_CPU_CLASS(c); + CPUClass *cc = CPU_CLASS(c); + DeviceClass *dc = DEVICE_CLASS(c); + + device_class_set_parent_realize(dc, loongarch_cpu_realizefn, + &lacc->parent_realize); + device_class_set_parent_reset(dc, loongarch_cpu_reset, &lacc->parent_reset); + + cc->class_by_name = loongarch_cpu_class_by_name; + cc->dump_state = loongarch_cpu_dump_state; + cc->set_pc = loongarch_cpu_set_pc; + cc->disas_set_info = loongarch_cpu_disas_set_info; +#ifdef CONFIG_TCG + cc->tcg_ops = &loongarch_tcg_ops; +#endif +} + +#define DEFINE_LOONGARCH_CPU_TYPE(model, initfn) \ + { \ + .parent = TYPE_LOONGARCH_CPU, \ + .instance_init = initfn, \ + .name = LOONGARCH_CPU_TYPE_NAME(model), \ + } + +static const TypeInfo loongarch_cpu_type_infos[] = { + { + .name = TYPE_LOONGARCH_CPU, + .parent = TYPE_CPU, + .instance_size = sizeof(LoongArchCPU), + .instance_init = loongarch_cpu_init, + + .abstract = true, + .class_size = sizeof(LoongArchCPUClass), + .class_init = loongarch_cpu_class_init, + }, + DEFINE_LOONGARCH_CPU_TYPE("la464", loongarch_la464_initfn), +}; + +DEFINE_TYPES(loongarch_cpu_type_infos) diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h new file mode 100644 index 0000000000..3e8ba46377 --- /dev/null +++ b/target/loongarch/cpu.h @@ -0,0 +1,243 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch CPU + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_CPU_H +#define LOONGARCH_CPU_H + +#include "exec/cpu-defs.h" +#include "fpu/softfloat-types.h" +#include "hw/registerfields.h" + +#define TCG_GUEST_DEFAULT_MO (0) + +#define FCSR0_M1 0x1f /* FCSR1 mask, Enables */ +#define FCSR0_M2 0x1f1f0000 /* FCSR2 mask, Cause and Flags */ +#define FCSR0_M3 0x300 /* FCSR3 mask, Round Mode */ +#define FCSR0_RM 8 /* Round Mode bit num on fcsr0 */ + +FIELD(FCSR0, ENABLES, 0, 5) +FIELD(FCSR0, RM, 8, 2) +FIELD(FCSR0, FLAGS, 16, 5) +FIELD(FCSR0, CAUSE, 24, 5) + +#define GET_FP_CAUSE(REG) FIELD_EX32(REG, FCSR0, CAUSE) +#define SET_FP_CAUSE(REG, V) FIELD_DP32(REG, FCSR0, CAUSE, V) +#define GET_FP_ENABLES(REG) FIELD_EX32(REG, FCSR0, ENABLES) +#define SET_FP_ENABLES(REG, V) FIELD_DP32(REG, FCSR0, ENABLES, V) +#define GET_FP_FLAGS(REG) FIELD_EX32(REG, FCSR0, FLAGS) +#define SET_FP_FLAGS(REG, V) FIELD_DP32(REG, FCSR0, FLAGS, V) +#define UPDATE_FP_FLAGS(REG, V) \ + do { \ + (REG) |= FIELD_DP32(0, FCSR0, FLAGS, V); \ + } while (0) + +#define FP_INEXACT 1 +#define FP_UNDERFLOW 2 +#define FP_OVERFLOW 4 +#define FP_DIV0 8 +#define FP_INVALID 16 + +#define EXCCODE_EXTERNAL_INT 64 /* plus external interrupt number */ +#define EXCCODE_INT 0 +#define EXCCODE_PIL 1 +#define EXCCODE_PIS 2 +#define EXCCODE_PIF 3 +#define EXCCODE_PME 4 +#define EXCCODE_PNR 5 +#define EXCCODE_PNX 6 +#define EXCCODE_PPI 7 +#define EXCCODE_ADEF 8 /* Different exception subcode */ +#define EXCCODE_ADEM 8 +#define EXCCODE_ALE 9 +#define EXCCODE_BCE 10 +#define EXCCODE_SYS 11 +#define EXCCODE_BRK 12 +#define EXCCODE_INE 13 +#define EXCCODE_IPE 14 +#define EXCCODE_FPD 15 +#define EXCCODE_SXD 16 +#define EXCCODE_ASXD 17 +#define EXCCODE_FPE 18 /* Different exception subcode */ +#define EXCCODE_VFPE 18 +#define EXCCODE_WPEF 19 /* Different exception subcode */ +#define EXCCODE_WPEM 19 +#define EXCCODE_BTD 20 +#define EXCCODE_BTE 21 +#define EXCCODE_DBP 26 /* Reserved subcode used for debug */ + +/* cpucfg[0] bits */ +FIELD(CPUCFG0, PRID, 0, 32) + +/* cpucfg[1] bits */ +FIELD(CPUCFG1, ARCH, 0, 2) +FIELD(CPUCFG1, PGMMU, 2, 1) +FIELD(CPUCFG1, IOCSR, 3, 1) +FIELD(CPUCFG1, PALEN, 4, 8) +FIELD(CPUCFG1, VALEN, 12, 8) +FIELD(CPUCFG1, UAL, 20, 1) +FIELD(CPUCFG1, RI, 21, 1) +FIELD(CPUCFG1, EP, 22, 1) +FIELD(CPUCFG1, RPLV, 23, 1) +FIELD(CPUCFG1, HP, 24, 1) +FIELD(CPUCFG1, IOCSR_BRD, 25, 1) +FIELD(CPUCFG1, MSG_INT, 26, 1) + +/* cpucfg[2] bits */ +FIELD(CPUCFG2, FP, 0, 1) +FIELD(CPUCFG2, FP_SP, 1, 1) +FIELD(CPUCFG2, FP_DP, 2, 1) +FIELD(CPUCFG2, FP_VER, 3, 3) +FIELD(CPUCFG2, LSX, 6, 1) +FIELD(CPUCFG2, LASX, 7, 1) +FIELD(CPUCFG2, COMPLEX, 8, 1) +FIELD(CPUCFG2, CRYPTO, 9, 1) +FIELD(CPUCFG2, LVZ, 10, 1) +FIELD(CPUCFG2, LVZ_VER, 11, 3) +FIELD(CPUCFG2, LLFTP, 14, 1) +FIELD(CPUCFG2, LLFTP_VER, 15, 3) +FIELD(CPUCFG2, LBT_X86, 18, 1) +FIELD(CPUCFG2, LBT_ARM, 19, 1) +FIELD(CPUCFG2, LBT_MIPS, 20, 1) +FIELD(CPUCFG2, LSPW, 21, 1) +FIELD(CPUCFG2, LAM, 22, 1) + +/* cpucfg[3] bits */ +FIELD(CPUCFG3, CCDMA, 0, 1) +FIELD(CPUCFG3, SFB, 1, 1) +FIELD(CPUCFG3, UCACC, 2, 1) +FIELD(CPUCFG3, LLEXC, 3, 1) +FIELD(CPUCFG3, SCDLY, 4, 1) +FIELD(CPUCFG3, LLDBAR, 5, 1) +FIELD(CPUCFG3, ITLBHMC, 6, 1) +FIELD(CPUCFG3, ICHMC, 7, 1) +FIELD(CPUCFG3, SPW_LVL, 8, 3) +FIELD(CPUCFG3, SPW_HP_HF, 11, 1) +FIELD(CPUCFG3, RVA, 12, 1) +FIELD(CPUCFG3, RVAMAX, 13, 4) + +/* cpucfg[4] bits */ +FIELD(CPUCFG4, CC_FREQ, 0, 32) + +/* cpucfg[5] bits */ +FIELD(CPUCFG5, CC_MUL, 0, 16) +FIELD(CPUCFG5, CC_DIV, 16, 16) + +/* cpucfg[6] bits */ +FIELD(CPUCFG6, PMP, 0, 1) +FIELD(CPUCFG6, PMVER, 1, 3) +FIELD(CPUCFG6, PMNUM, 4, 4) +FIELD(CPUCFG6, PMBITS, 8, 6) +FIELD(CPUCFG6, UPM, 14, 1) + +/* cpucfg[16] bits */ +FIELD(CPUCFG16, L1_IUPRE, 0, 1) +FIELD(CPUCFG16, L1_IUUNIFY, 1, 1) +FIELD(CPUCFG16, L1_DPRE, 2, 1) +FIELD(CPUCFG16, L2_IUPRE, 3, 1) +FIELD(CPUCFG16, L2_IUUNIFY, 4, 1) +FIELD(CPUCFG16, L2_IUPRIV, 5, 1) +FIELD(CPUCFG16, L2_IUINCL, 6, 1) +FIELD(CPUCFG16, L2_DPRE, 7, 1) +FIELD(CPUCFG16, L2_DPRIV, 8, 1) +FIELD(CPUCFG16, L2_DINCL, 9, 1) +FIELD(CPUCFG16, L3_IUPRE, 10, 1) +FIELD(CPUCFG16, L3_IUUNIFY, 11, 1) +FIELD(CPUCFG16, L3_IUPRIV, 12, 1) +FIELD(CPUCFG16, L3_IUINCL, 13, 1) +FIELD(CPUCFG16, L3_DPRE, 14, 1) +FIELD(CPUCFG16, L3_DPRIV, 15, 1) +FIELD(CPUCFG16, L3_DINCL, 16, 1) + +/* cpucfg[17] bits */ +FIELD(CPUCFG17, L1IU_WAYS, 0, 16) +FIELD(CPUCFG17, L1IU_SETS, 16, 8) +FIELD(CPUCFG17, L1IU_SIZE, 24, 7) + +/* cpucfg[18] bits */ +FIELD(CPUCFG18, L1D_WAYS, 0, 16) +FIELD(CPUCFG18, L1D_SETS, 16, 8) +FIELD(CPUCFG18, L1D_SIZE, 24, 7) + +/* cpucfg[19] bits */ +FIELD(CPUCFG19, L2IU_WAYS, 0, 16) +FIELD(CPUCFG19, L2IU_SETS, 16, 8) +FIELD(CPUCFG19, L2IU_SIZE, 24, 7) + +/* cpucfg[20] bits */ +FIELD(CPUCFG20, L3IU_WAYS, 0, 16) +FIELD(CPUCFG20, L3IU_SETS, 16, 8) +FIELD(CPUCFG20, L3IU_SIZE, 24, 7) + +extern const char * const regnames[32]; +extern const char * const fregnames[32]; + +typedef struct CPUArchState { + uint64_t gpr[32]; + uint64_t pc; + + uint64_t fpr[32]; + float_status fp_status; + bool cf[8]; + + uint32_t fcsr0; + uint32_t fcsr0_mask; + + uint32_t cpucfg[21]; + + uint64_t lladdr; /* LL virtual address compared against SC */ + uint64_t llval; + + uint64_t badaddr; +} CPULoongArchState; + +/** + * LoongArchCPU: + * @env: #CPULoongArchState + * + * A LoongArch CPU. + */ +struct ArchCPU { + /*< private >*/ + CPUState parent_obj; + /*< public >*/ + + CPUNegativeOffsetState neg; + CPULoongArchState env; +}; + +#define TYPE_LOONGARCH_CPU "loongarch-cpu" + +OBJECT_DECLARE_CPU_TYPE(LoongArchCPU, LoongArchCPUClass, + LOONGARCH_CPU) + +/** + * LoongArchCPUClass: + * @parent_realize: The parent class' realize handler. + * @parent_reset: The parent class' reset handler. + * + * A LoongArch CPU model. + */ +struct LoongArchCPUClass { + /*< private >*/ + CPUClass parent_class; + /*< public >*/ + + DeviceRealize parent_realize; + DeviceReset parent_reset; +}; + +void loongarch_cpu_list(void); + +#define cpu_list loongarch_cpu_list + +#include "exec/cpu-all.h" + +#define LOONGARCH_CPU_TYPE_SUFFIX "-" TYPE_LOONGARCH_CPU +#define LOONGARCH_CPU_TYPE_NAME(model) model LOONGARCH_CPU_TYPE_SUFFIX +#define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU + +#endif /* LOONGARCH_CPU_H */ diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h new file mode 100644 index 0000000000..9f02287a90 --- /dev/null +++ b/target/loongarch/internals.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch CPU -- internal functions and types + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_INTERNALS_H +#define LOONGARCH_INTERNALS_H + +void loongarch_translate_init(void); + +void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags); + +void G_NORETURN do_raise_exception(CPULoongArchState *env, + uint32_t exception, + uintptr_t pc); + +const char *loongarch_exception_name(int32_t exception); + +#endif From f8da88d78f71da751f089913784fa884df31bd03 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 6 Jun 2022 20:42:53 +0800 Subject: [PATCH 810/935] target/loongarch: Add main translation routines This patch adds main translation routines and basic functions for translation. Signed-off-by: Song Gao Signed-off-by: Xiaojuan Yang Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-4-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/helper.h | 6 ++ target/loongarch/op_helper.c | 21 +++++ target/loongarch/translate.c | 161 +++++++++++++++++++++++++++++++++++ target/loongarch/translate.h | 26 ++++++ 4 files changed, 214 insertions(+) create mode 100644 target/loongarch/helper.h create mode 100644 target/loongarch/op_helper.c create mode 100644 target/loongarch/translate.c create mode 100644 target/loongarch/translate.h diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h new file mode 100644 index 0000000000..eb771c0628 --- /dev/null +++ b/target/loongarch/helper.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +DEF_HELPER_2(raise_exception, noreturn, env, i32) diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c new file mode 100644 index 0000000000..903810951e --- /dev/null +++ b/target/loongarch/op_helper.c @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch emulation helpers for QEMU. + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "cpu.h" +#include "qemu/host-utils.h" +#include "exec/helper-proto.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "internals.h" + +/* Exceptions helpers */ +void helper_raise_exception(CPULoongArchState *env, uint32_t exception) +{ + do_raise_exception(env, exception, GETPC()); +} diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c new file mode 100644 index 0000000000..332a6d2d58 --- /dev/null +++ b/target/loongarch/translate.c @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch emulation for QEMU - main translation routines. + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "tcg/tcg-op.h" +#include "exec/translator.h" +#include "exec/helper-proto.h" +#include "exec/helper-gen.h" + +#include "exec/translator.h" +#include "exec/log.h" +#include "qemu/qemu-print.h" +#include "translate.h" +#include "internals.h" + +/* Global register indices */ +TCGv cpu_gpr[32], cpu_pc; +static TCGv cpu_lladdr, cpu_llval; +TCGv_i32 cpu_fcsr0; +TCGv_i64 cpu_fpr[32]; + +#define DISAS_STOP DISAS_TARGET_0 + +void generate_exception(DisasContext *ctx, int excp) +{ + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); + gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp)); + ctx->base.is_jmp = DISAS_NORETURN; +} + +static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) +{ + if (translator_use_goto_tb(&ctx->base, dest)) { + tcg_gen_goto_tb(n); + tcg_gen_movi_tl(cpu_pc, dest); + tcg_gen_exit_tb(ctx->base.tb, n); + } else { + tcg_gen_movi_tl(cpu_pc, dest); + tcg_gen_lookup_and_goto_ptr(); + } +} + +static void loongarch_tr_init_disas_context(DisasContextBase *dcbase, + CPUState *cs) +{ + int64_t bound; + DisasContext *ctx = container_of(dcbase, DisasContext, base); + + ctx->page_start = ctx->base.pc_first & TARGET_PAGE_MASK; + ctx->mem_idx = ctx->base.tb->flags; + + /* Bound the number of insns to execute to those left on the page. */ + bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; + ctx->base.max_insns = MIN(ctx->base.max_insns, bound); +} + +static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) +{ +} + +static void loongarch_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) +{ + DisasContext *ctx = container_of(dcbase, DisasContext, base); + + tcg_gen_insn_start(ctx->base.pc_next); +} + +static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) +{ + CPULoongArchState *env = cs->env_ptr; + DisasContext *ctx = container_of(dcbase, DisasContext, base); + + ctx->opcode = cpu_ldl_code(env, ctx->base.pc_next); + + if (!decode(ctx, ctx->opcode)) { + qemu_log_mask(LOG_UNIMP, "Error: unknown opcode. " + TARGET_FMT_lx ": 0x%x\n", + ctx->base.pc_next, ctx->opcode); + generate_exception(ctx, EXCCODE_INE); + } + + ctx->base.pc_next += 4; +} + +static void loongarch_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) +{ + DisasContext *ctx = container_of(dcbase, DisasContext, base); + + switch (ctx->base.is_jmp) { + case DISAS_STOP: + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); + tcg_gen_lookup_and_goto_ptr(); + break; + case DISAS_TOO_MANY: + gen_goto_tb(ctx, 0, ctx->base.pc_next); + break; + case DISAS_NORETURN: + break; + default: + g_assert_not_reached(); + } +} + +static void loongarch_tr_disas_log(const DisasContextBase *dcbase, + CPUState *cpu, FILE *logfile) +{ + qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); + target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size); +} + +static const TranslatorOps loongarch_tr_ops = { + .init_disas_context = loongarch_tr_init_disas_context, + .tb_start = loongarch_tr_tb_start, + .insn_start = loongarch_tr_insn_start, + .translate_insn = loongarch_tr_translate_insn, + .tb_stop = loongarch_tr_tb_stop, + .disas_log = loongarch_tr_disas_log, +}; + +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +{ + DisasContext ctx; + + translator_loop(&loongarch_tr_ops, &ctx.base, cs, tb, max_insns); +} + +void loongarch_translate_init(void) +{ + int i; + + cpu_gpr[0] = NULL; + for (i = 1; i < 32; i++) { + cpu_gpr[i] = tcg_global_mem_new(cpu_env, + offsetof(CPULoongArchState, gpr[i]), + regnames[i]); + } + + for (i = 0; i < 32; i++) { + int off = offsetof(CPULoongArchState, fpr[i]); + cpu_fpr[i] = tcg_global_mem_new_i64(cpu_env, off, fregnames[i]); + } + + cpu_pc = tcg_global_mem_new(cpu_env, offsetof(CPULoongArchState, pc), "pc"); + cpu_fcsr0 = tcg_global_mem_new_i32(cpu_env, + offsetof(CPULoongArchState, fcsr0), "fcsr0"); + cpu_lladdr = tcg_global_mem_new(cpu_env, + offsetof(CPULoongArchState, lladdr), "lladdr"); + cpu_llval = tcg_global_mem_new(cpu_env, + offsetof(CPULoongArchState, llval), "llval"); +} + +void restore_state_to_opc(CPULoongArchState *env, TranslationBlock *tb, + target_ulong *data) +{ + env->pc = data[0]; +} diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h new file mode 100644 index 0000000000..6cc7f1a7cd --- /dev/null +++ b/target/loongarch/translate.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch translation routines. + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef TARGET_LOONGARCH_TRANSLATE_H +#define TARGET_LOONGARCH_TRANSLATE_H + +#include "exec/translator.h" + +typedef struct DisasContext { + DisasContextBase base; + target_ulong page_start; + uint32_t opcode; + int mem_idx; +} DisasContext; + +void generate_exception(DisasContext *ctx, int excp); + +extern TCGv cpu_gpr[32], cpu_pc; +extern TCGv_i32 cpu_fscr0; +extern TCGv_i64 cpu_fpr[32]; + +#endif From 143d6785ef725aff6d09bc112c21119c32d9d0ae Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 6 Jun 2022 20:42:54 +0800 Subject: [PATCH 811/935] target/loongarch: Add fixed point arithmetic instruction translation This includes: - ADD.{W/D}, SUB.{W/D} - ADDI.{W/D}, ADDU16ID - ALSL.{W[U]/D} - LU12I.W, LU32I.D LU52I.D - SLT[U], SLT[U]I - PCADDI, PCADDU12I, PCADDU18I, PCALAU12I - AND, OR, NOR, XOR, ANDN, ORN - MUL.{W/D}, MULH.{W[U]/D[U]} - MULW.D.W[U] - DIV.{W[U]/D[U]}, MOD.{W[U]/D[U]} - ANDI, ORI, XORI Signed-off-by: Song Gao Signed-off-by: Xiaojuan Yang Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-5-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/insn_trans/trans_arith.c.inc | 304 ++++++++++++++++++ target/loongarch/insns.decode | 79 +++++ target/loongarch/translate.c | 83 +++++ target/loongarch/translate.h | 19 ++ 4 files changed, 485 insertions(+) create mode 100644 target/loongarch/insn_trans/trans_arith.c.inc create mode 100644 target/loongarch/insns.decode diff --git a/target/loongarch/insn_trans/trans_arith.c.inc b/target/loongarch/insn_trans/trans_arith.c.inc new file mode 100644 index 0000000000..8e45eadbc8 --- /dev/null +++ b/target/loongarch/insn_trans/trans_arith.c.inc @@ -0,0 +1,304 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +static bool gen_rrr(DisasContext *ctx, arg_rrr *a, + DisasExtend src1_ext, DisasExtend src2_ext, + DisasExtend dst_ext, void (*func)(TCGv, TCGv, TCGv)) +{ + TCGv dest = gpr_dst(ctx, a->rd, dst_ext); + TCGv src1 = gpr_src(ctx, a->rj, src1_ext); + TCGv src2 = gpr_src(ctx, a->rk, src2_ext); + + func(dest, src1, src2); + gen_set_gpr(a->rd, dest, dst_ext); + + return true; +} + +static bool gen_rri_v(DisasContext *ctx, arg_rr_i *a, + DisasExtend src_ext, DisasExtend dst_ext, + void (*func)(TCGv, TCGv, TCGv)) +{ + TCGv dest = gpr_dst(ctx, a->rd, dst_ext); + TCGv src1 = gpr_src(ctx, a->rj, src_ext); + TCGv src2 = tcg_constant_tl(a->imm); + + func(dest, src1, src2); + gen_set_gpr(a->rd, dest, dst_ext); + + return true; +} + +static bool gen_rri_c(DisasContext *ctx, arg_rr_i *a, + DisasExtend src_ext, DisasExtend dst_ext, + void (*func)(TCGv, TCGv, target_long)) +{ + TCGv dest = gpr_dst(ctx, a->rd, dst_ext); + TCGv src1 = gpr_src(ctx, a->rj, src_ext); + + func(dest, src1, a->imm); + gen_set_gpr(a->rd, dest, dst_ext); + + return true; +} + +static bool gen_rrr_sa(DisasContext *ctx, arg_rrr_sa *a, + DisasExtend src_ext, DisasExtend dst_ext, + void (*func)(TCGv, TCGv, TCGv, target_long)) +{ + TCGv dest = gpr_dst(ctx, a->rd, dst_ext); + TCGv src1 = gpr_src(ctx, a->rj, src_ext); + TCGv src2 = gpr_src(ctx, a->rk, src_ext); + + func(dest, src1, src2, a->sa); + gen_set_gpr(a->rd, dest, dst_ext); + + return true; +} + +static bool trans_lu12i_w(DisasContext *ctx, arg_lu12i_w *a) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + + tcg_gen_movi_tl(dest, a->imm << 12); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +static bool gen_pc(DisasContext *ctx, arg_r_i *a, + target_ulong (*func)(target_ulong, int)) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + target_ulong addr = func(ctx->base.pc_next, a->imm); + + tcg_gen_movi_tl(dest, addr); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +static void gen_slt(TCGv dest, TCGv src1, TCGv src2) +{ + tcg_gen_setcond_tl(TCG_COND_LT, dest, src1, src2); +} + +static void gen_sltu(TCGv dest, TCGv src1, TCGv src2) +{ + tcg_gen_setcond_tl(TCG_COND_LTU, dest, src1, src2); +} + +static void gen_mulh_w(TCGv dest, TCGv src1, TCGv src2) +{ + tcg_gen_mul_i64(dest, src1, src2); + tcg_gen_sari_i64(dest, dest, 32); +} + +static void gen_mulh_d(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv discard = tcg_temp_new(); + tcg_gen_muls2_tl(discard, dest, src1, src2); + tcg_temp_free(discard); +} + +static void gen_mulh_du(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv discard = tcg_temp_new(); + tcg_gen_mulu2_tl(discard, dest, src1, src2); + tcg_temp_free(discard); +} + +static void prep_divisor_d(TCGv ret, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + TCGv zero = tcg_constant_tl(0); + + /* + * If min / -1, set the divisor to 1. + * This avoids potential host overflow trap and produces min. + * If x / 0, set the divisor to 1. + * This avoids potential host overflow trap; + * the required result is undefined. + */ + tcg_gen_setcondi_tl(TCG_COND_EQ, ret, src1, INT64_MIN); + tcg_gen_setcondi_tl(TCG_COND_EQ, t0, src2, -1); + tcg_gen_setcondi_tl(TCG_COND_EQ, t1, src2, 0); + tcg_gen_and_tl(ret, ret, t0); + tcg_gen_or_tl(ret, ret, t1); + tcg_gen_movcond_tl(TCG_COND_NE, ret, ret, zero, ret, src2); + + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static void prep_divisor_du(TCGv ret, TCGv src2) +{ + TCGv zero = tcg_constant_tl(0); + TCGv one = tcg_constant_tl(1); + + /* + * If x / 0, set the divisor to 1. + * This avoids potential host overflow trap; + * the required result is undefined. + */ + tcg_gen_movcond_tl(TCG_COND_EQ, ret, src2, zero, one, src2); +} + +static void gen_div_d(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + prep_divisor_d(t0, src1, src2); + tcg_gen_div_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_rem_d(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + prep_divisor_d(t0, src1, src2); + tcg_gen_rem_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_div_du(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + prep_divisor_du(t0, src2); + tcg_gen_divu_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_rem_du(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + prep_divisor_du(t0, src2); + tcg_gen_remu_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_div_w(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + /* We need not check for integer overflow for div_w. */ + prep_divisor_du(t0, src2); + tcg_gen_div_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_rem_w(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + /* We need not check for integer overflow for rem_w. */ + prep_divisor_du(t0, src2); + tcg_gen_rem_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_alsl(TCGv dest, TCGv src1, TCGv src2, target_long sa) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_shli_tl(t0, src1, sa); + tcg_gen_add_tl(dest, t0, src2); + tcg_temp_free(t0); +} + +static bool trans_lu32i_d(DisasContext *ctx, arg_lu32i_d *a) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rd, EXT_NONE); + TCGv src2 = tcg_constant_tl(a->imm); + + tcg_gen_deposit_tl(dest, src1, src2, 32, 32); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +static bool trans_lu52i_d(DisasContext *ctx, arg_lu52i_d *a) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = tcg_constant_tl(a->imm); + + tcg_gen_deposit_tl(dest, src1, src2, 52, 12); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +static target_ulong gen_pcaddi(target_ulong pc, int imm) +{ + return pc + (imm << 2); +} + +static target_ulong gen_pcalau12i(target_ulong pc, int imm) +{ + return (pc + (imm << 12)) & ~0xfff; +} + +static target_ulong gen_pcaddu12i(target_ulong pc, int imm) +{ + return pc + (imm << 12); +} + +static target_ulong gen_pcaddu18i(target_ulong pc, int imm) +{ + return pc + ((target_ulong)(imm) << 18); +} + +static bool trans_addu16i_d(DisasContext *ctx, arg_addu16i_d *a) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + + tcg_gen_addi_tl(dest, src1, a->imm << 16); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +TRANS(add_w, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_add_tl) +TRANS(add_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_add_tl) +TRANS(sub_w, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_sub_tl) +TRANS(sub_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_sub_tl) +TRANS(and, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_and_tl) +TRANS(or, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_or_tl) +TRANS(xor, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_xor_tl) +TRANS(nor, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_nor_tl) +TRANS(andn, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_andc_tl) +TRANS(orn, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_orc_tl) +TRANS(slt, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_slt) +TRANS(sltu, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sltu) +TRANS(mul_w, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, tcg_gen_mul_tl) +TRANS(mul_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_mul_tl) +TRANS(mulh_w, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_NONE, gen_mulh_w) +TRANS(mulh_wu, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_NONE, gen_mulh_w) +TRANS(mulh_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_d) +TRANS(mulh_du, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_du) +TRANS(mulw_d_w, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_NONE, tcg_gen_mul_tl) +TRANS(mulw_d_wu, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_NONE, tcg_gen_mul_tl) +TRANS(div_w, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, gen_div_w) +TRANS(mod_w, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, gen_rem_w) +TRANS(div_wu, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_SIGN, gen_div_du) +TRANS(mod_wu, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_SIGN, gen_rem_du) +TRANS(div_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_d) +TRANS(mod_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_d) +TRANS(div_du, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_du) +TRANS(mod_du, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_du) +TRANS(slti, gen_rri_v, EXT_NONE, EXT_NONE, gen_slt) +TRANS(sltui, gen_rri_v, EXT_NONE, EXT_NONE, gen_sltu) +TRANS(addi_w, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_addi_tl) +TRANS(addi_d, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_addi_tl) +TRANS(alsl_w, gen_rrr_sa, EXT_NONE, EXT_SIGN, gen_alsl) +TRANS(alsl_wu, gen_rrr_sa, EXT_NONE, EXT_ZERO, gen_alsl) +TRANS(alsl_d, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_alsl) +TRANS(pcaddi, gen_pc, gen_pcaddi) +TRANS(pcalau12i, gen_pc, gen_pcalau12i) +TRANS(pcaddu12i, gen_pc, gen_pcaddu12i) +TRANS(pcaddu18i, gen_pc, gen_pcaddu18i) +TRANS(andi, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_andi_tl) +TRANS(ori, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_ori_tl) +TRANS(xori, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_xori_tl) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode new file mode 100644 index 0000000000..8579c11984 --- /dev/null +++ b/target/loongarch/insns.decode @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# LoongArch instruction decode definitions. +# +# Copyright (c) 2021 Loongson Technology Corporation Limited +# + +# +# Fields +# +%sa2p1 15:2 !function=plus_1 + +# +# Argument sets +# +&r_i rd imm +&rrr rd rj rk +&rr_i rd rj imm +&rrr_sa rd rj rk sa + +# +# Formats +# +@rrr .... ........ ..... rk:5 rj:5 rd:5 &rrr +@r_i20 .... ... imm:s20 rd:5 &r_i +@rr_i12 .... ...... imm:s12 rj:5 rd:5 &rr_i +@rr_ui12 .... ...... imm:12 rj:5 rd:5 &rr_i +@rr_i16 .... .. imm:s16 rj:5 rd:5 &rr_i +@rrr_sa2p1 .... ........ ... .. rk:5 rj:5 rd:5 &rrr_sa sa=%sa2p1 + +# +# Fixed point arithmetic operation instruction +# +add_w 0000 00000001 00000 ..... ..... ..... @rrr +add_d 0000 00000001 00001 ..... ..... ..... @rrr +sub_w 0000 00000001 00010 ..... ..... ..... @rrr +sub_d 0000 00000001 00011 ..... ..... ..... @rrr +slt 0000 00000001 00100 ..... ..... ..... @rrr +sltu 0000 00000001 00101 ..... ..... ..... @rrr +slti 0000 001000 ............ ..... ..... @rr_i12 +sltui 0000 001001 ............ ..... ..... @rr_i12 +nor 0000 00000001 01000 ..... ..... ..... @rrr +and 0000 00000001 01001 ..... ..... ..... @rrr +or 0000 00000001 01010 ..... ..... ..... @rrr +xor 0000 00000001 01011 ..... ..... ..... @rrr +orn 0000 00000001 01100 ..... ..... ..... @rrr +andn 0000 00000001 01101 ..... ..... ..... @rrr +mul_w 0000 00000001 11000 ..... ..... ..... @rrr +mulh_w 0000 00000001 11001 ..... ..... ..... @rrr +mulh_wu 0000 00000001 11010 ..... ..... ..... @rrr +mul_d 0000 00000001 11011 ..... ..... ..... @rrr +mulh_d 0000 00000001 11100 ..... ..... ..... @rrr +mulh_du 0000 00000001 11101 ..... ..... ..... @rrr +mulw_d_w 0000 00000001 11110 ..... ..... ..... @rrr +mulw_d_wu 0000 00000001 11111 ..... ..... ..... @rrr +div_w 0000 00000010 00000 ..... ..... ..... @rrr +mod_w 0000 00000010 00001 ..... ..... ..... @rrr +div_wu 0000 00000010 00010 ..... ..... ..... @rrr +mod_wu 0000 00000010 00011 ..... ..... ..... @rrr +div_d 0000 00000010 00100 ..... ..... ..... @rrr +mod_d 0000 00000010 00101 ..... ..... ..... @rrr +div_du 0000 00000010 00110 ..... ..... ..... @rrr +mod_du 0000 00000010 00111 ..... ..... ..... @rrr +alsl_w 0000 00000000 010 .. ..... ..... ..... @rrr_sa2p1 +alsl_wu 0000 00000000 011 .. ..... ..... ..... @rrr_sa2p1 +alsl_d 0000 00000010 110 .. ..... ..... ..... @rrr_sa2p1 +lu12i_w 0001 010 .................... ..... @r_i20 +lu32i_d 0001 011 .................... ..... @r_i20 +lu52i_d 0000 001100 ............ ..... ..... @rr_i12 +pcaddi 0001 100 .................... ..... @r_i20 +pcalau12i 0001 101 .................... ..... @r_i20 +pcaddu12i 0001 110 .................... ..... @r_i20 +pcaddu18i 0001 111 .................... ..... @r_i20 +addi_w 0000 001010 ............ ..... ..... @rr_i12 +addi_d 0000 001011 ............ ..... ..... @rr_i12 +addu16i_d 0001 00 ................ ..... ..... @rr_i16 +andi 0000 001101 ............ ..... ..... @rr_ui12 +ori 0000 001110 ............ ..... ..... @rr_ui12 +xori 0000 001111 ............ ..... ..... @rr_ui12 diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 332a6d2d58..65c7dfd3da 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -26,6 +26,11 @@ TCGv_i64 cpu_fpr[32]; #define DISAS_STOP DISAS_TARGET_0 +static inline int plus_1(DisasContext *ctx, int x) +{ + return x + 1; +} + void generate_exception(DisasContext *ctx, int excp) { tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); @@ -57,6 +62,11 @@ static void loongarch_tr_init_disas_context(DisasContextBase *dcbase, /* Bound the number of insns to execute to those left on the page. */ bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; ctx->base.max_insns = MIN(ctx->base.max_insns, bound); + + ctx->ntemp = 0; + memset(ctx->temp, 0, sizeof(ctx->temp)); + + ctx->zero = tcg_constant_tl(0); } static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) @@ -70,6 +80,73 @@ static void loongarch_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) tcg_gen_insn_start(ctx->base.pc_next); } +/* + * Wrappers for getting reg values. + * + * The $zero register does not have cpu_gpr[0] allocated -- we supply the + * constant zero as a source, and an uninitialized sink as destination. + * + * Further, we may provide an extension for word operations. + */ +static TCGv temp_new(DisasContext *ctx) +{ + assert(ctx->ntemp < ARRAY_SIZE(ctx->temp)); + return ctx->temp[ctx->ntemp++] = tcg_temp_new(); +} + +static TCGv gpr_src(DisasContext *ctx, int reg_num, DisasExtend src_ext) +{ + TCGv t; + + if (reg_num == 0) { + return ctx->zero; + } + + switch (src_ext) { + case EXT_NONE: + return cpu_gpr[reg_num]; + case EXT_SIGN: + t = temp_new(ctx); + tcg_gen_ext32s_tl(t, cpu_gpr[reg_num]); + return t; + case EXT_ZERO: + t = temp_new(ctx); + tcg_gen_ext32u_tl(t, cpu_gpr[reg_num]); + return t; + } + g_assert_not_reached(); +} + +static TCGv gpr_dst(DisasContext *ctx, int reg_num, DisasExtend dst_ext) +{ + if (reg_num == 0 || dst_ext) { + return temp_new(ctx); + } + return cpu_gpr[reg_num]; +} + +static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext) +{ + if (reg_num != 0) { + switch (dst_ext) { + case EXT_NONE: + tcg_gen_mov_tl(cpu_gpr[reg_num], t); + break; + case EXT_SIGN: + tcg_gen_ext32s_tl(cpu_gpr[reg_num], t); + break; + case EXT_ZERO: + tcg_gen_ext32u_tl(cpu_gpr[reg_num], t); + break; + default: + g_assert_not_reached(); + } + } +} + +#include "decode-insns.c.inc" +#include "insn_trans/trans_arith.c.inc" + static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { CPULoongArchState *env = cs->env_ptr; @@ -84,6 +161,12 @@ static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) generate_exception(ctx, EXCCODE_INE); } + for (int i = ctx->ntemp - 1; i >= 0; --i) { + tcg_temp_free(ctx->temp[i]); + ctx->temp[i] = NULL; + } + ctx->ntemp = 0; + ctx->base.pc_next += 4; } diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h index 6cc7f1a7cd..9cc12512d1 100644 --- a/target/loongarch/translate.h +++ b/target/loongarch/translate.h @@ -10,11 +10,30 @@ #include "exec/translator.h" +#define TRANS(NAME, FUNC, ...) \ + static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \ + { return FUNC(ctx, a, __VA_ARGS__); } + +/* + * If an operation is being performed on less than TARGET_LONG_BITS, + * it may require the inputs to be sign- or zero-extended; which will + * depend on the exact operation being performed. + */ +typedef enum { + EXT_NONE, + EXT_SIGN, + EXT_ZERO, +} DisasExtend; + typedef struct DisasContext { DisasContextBase base; target_ulong page_start; uint32_t opcode; int mem_idx; + TCGv zero; + /* Space for 3 operands plus 1 extra for address computation. */ + TCGv temp[4]; + uint8_t ntemp; } DisasContext; void generate_exception(DisasContext *ctx, int excp); From 63cfcd47d70de7b3133da894edd06d5bf0a5ad93 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 6 Jun 2022 20:42:55 +0800 Subject: [PATCH 812/935] target/loongarch: Add fixed point shift instruction translation This includes: - SLL.W, SRL.W, SRA.W, ROTR.W - SLLI.W, SRLI.W, SRAI.W, ROTRI.W - SLL.D, SRL.D, SRA.D, ROTR.D - SLLI.D, SRLI.D, SRAI.D, ROTRI.D Signed-off-by: Song Gao Signed-off-by: Xiaojuan Yang Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-6-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/insn_trans/trans_shift.c.inc | 106 ++++++++++++++++++ target/loongarch/insns.decode | 22 ++++ target/loongarch/translate.c | 1 + 3 files changed, 129 insertions(+) create mode 100644 target/loongarch/insn_trans/trans_shift.c.inc diff --git a/target/loongarch/insn_trans/trans_shift.c.inc b/target/loongarch/insn_trans/trans_shift.c.inc new file mode 100644 index 0000000000..5260af2337 --- /dev/null +++ b/target/loongarch/insn_trans/trans_shift.c.inc @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +static void gen_sll_w(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_andi_tl(t0, src2, 0x1f); + tcg_gen_shl_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_srl_w(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_andi_tl(t0, src2, 0x1f); + tcg_gen_shr_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_sra_w(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_andi_tl(t0, src2, 0x1f); + tcg_gen_sar_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_sll_d(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_andi_tl(t0, src2, 0x3f); + tcg_gen_shl_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_srl_d(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_andi_tl(t0, src2, 0x3f); + tcg_gen_shr_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_sra_d(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_andi_tl(t0, src2, 0x3f); + tcg_gen_sar_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static void gen_rotr_w(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv_i32 t1 = tcg_temp_new_i32(); + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv t0 = tcg_temp_new(); + + tcg_gen_andi_tl(t0, src2, 0x1f); + + tcg_gen_trunc_tl_i32(t1, src1); + tcg_gen_trunc_tl_i32(t2, t0); + + tcg_gen_rotr_i32(t1, t1, t2); + tcg_gen_ext_i32_tl(dest, t1); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); + tcg_temp_free(t0); +} + +static void gen_rotr_d(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_andi_tl(t0, src2, 0x3f); + tcg_gen_rotr_tl(dest, src1, t0); + tcg_temp_free(t0); +} + +static bool trans_srai_w(DisasContext *ctx, arg_srai_w *a) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_ZERO); + + tcg_gen_sextract_tl(dest, src1, a->imm, 32 - a->imm); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +TRANS(sll_w, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_sll_w) +TRANS(srl_w, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_srl_w) +TRANS(sra_w, gen_rrr, EXT_SIGN, EXT_NONE, EXT_SIGN, gen_sra_w) +TRANS(sll_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sll_d) +TRANS(srl_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_srl_d) +TRANS(sra_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sra_d) +TRANS(rotr_w, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_rotr_w) +TRANS(rotr_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rotr_d) +TRANS(slli_w, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_shli_tl) +TRANS(slli_d, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shli_tl) +TRANS(srli_w, gen_rri_c, EXT_ZERO, EXT_SIGN, tcg_gen_shri_tl) +TRANS(srli_d, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shri_tl) +TRANS(srai_d, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_sari_tl) +TRANS(rotri_w, gen_rri_v, EXT_NONE, EXT_NONE, gen_rotr_w) +TRANS(rotri_d, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_rotri_tl) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index 8579c11984..673aee4be5 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -23,6 +23,8 @@ # @rrr .... ........ ..... rk:5 rj:5 rd:5 &rrr @r_i20 .... ... imm:s20 rd:5 &r_i +@rr_ui5 .... ........ ..... imm:5 rj:5 rd:5 &rr_i +@rr_ui6 .... ........ .... imm:6 rj:5 rd:5 &rr_i @rr_i12 .... ...... imm:s12 rj:5 rd:5 &rr_i @rr_ui12 .... ...... imm:12 rj:5 rd:5 &rr_i @rr_i16 .... .. imm:s16 rj:5 rd:5 &rr_i @@ -77,3 +79,23 @@ addu16i_d 0001 00 ................ ..... ..... @rr_i16 andi 0000 001101 ............ ..... ..... @rr_ui12 ori 0000 001110 ............ ..... ..... @rr_ui12 xori 0000 001111 ............ ..... ..... @rr_ui12 + +# +# Fixed point shift operation instruction +# +sll_w 0000 00000001 01110 ..... ..... ..... @rrr +srl_w 0000 00000001 01111 ..... ..... ..... @rrr +sra_w 0000 00000001 10000 ..... ..... ..... @rrr +sll_d 0000 00000001 10001 ..... ..... ..... @rrr +srl_d 0000 00000001 10010 ..... ..... ..... @rrr +sra_d 0000 00000001 10011 ..... ..... ..... @rrr +rotr_w 0000 00000001 10110 ..... ..... ..... @rrr +rotr_d 0000 00000001 10111 ..... ..... ..... @rrr +slli_w 0000 00000100 00001 ..... ..... ..... @rr_ui5 +slli_d 0000 00000100 0001 ...... ..... ..... @rr_ui6 +srli_w 0000 00000100 01001 ..... ..... ..... @rr_ui5 +srli_d 0000 00000100 0101 ...... ..... ..... @rr_ui6 +srai_w 0000 00000100 10001 ..... ..... ..... @rr_ui5 +srai_d 0000 00000100 1001 ...... ..... ..... @rr_ui6 +rotri_w 0000 00000100 11001 ..... ..... ..... @rr_ui5 +rotri_d 0000 00000100 1101 ...... ..... ..... @rr_ui6 diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 65c7dfd3da..d5640d5d79 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -146,6 +146,7 @@ static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext) #include "decode-insns.c.inc" #include "insn_trans/trans_arith.c.inc" +#include "insn_trans/trans_shift.c.inc" static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { From ad08cb3f9728caf83fff7958e308ef7f1ad03fae Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 6 Jun 2022 20:42:56 +0800 Subject: [PATCH 813/935] target/loongarch: Add fixed point bit instruction translation This includes: - EXT.W.{B/H} - CL{O/Z}.{W/D}, CT{O/Z}.{W/D} - BYTEPICK.{W/D} - REVB.{2H/4H/2W/D} - REVH.{2W/D} - BITREV.{4B/8B}, BITREV.{W/D} - BSTRINS.{W/D}, BSTRPICK.{W/D} - MASKEQZ, MASKNEZ Signed-off-by: Song Gao Signed-off-by: Xiaojuan Yang Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-7-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/helper.h | 4 + target/loongarch/insn_trans/trans_bit.c.inc | 212 ++++++++++++++++++++ target/loongarch/insns.decode | 39 ++++ target/loongarch/op_helper.c | 21 ++ target/loongarch/translate.c | 1 + 5 files changed, 277 insertions(+) create mode 100644 target/loongarch/insn_trans/trans_bit.c.inc diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index eb771c0628..04e0245d5e 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -4,3 +4,7 @@ */ DEF_HELPER_2(raise_exception, noreturn, env, i32) + +DEF_HELPER_FLAGS_1(bitrev_w, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_1(bitrev_d, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl) diff --git a/target/loongarch/insn_trans/trans_bit.c.inc b/target/loongarch/insn_trans/trans_bit.c.inc new file mode 100644 index 0000000000..9337714ec4 --- /dev/null +++ b/target/loongarch/insn_trans/trans_bit.c.inc @@ -0,0 +1,212 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +static bool gen_rr(DisasContext *ctx, arg_rr *a, + DisasExtend src_ext, DisasExtend dst_ext, + void (*func)(TCGv, TCGv)) +{ + TCGv dest = gpr_dst(ctx, a->rd, dst_ext); + TCGv src1 = gpr_src(ctx, a->rj, src_ext); + + func(dest, src1); + gen_set_gpr(a->rd, dest, dst_ext); + + return true; +} + +static void gen_bytepick_w(TCGv dest, TCGv src1, TCGv src2, target_long sa) +{ + tcg_gen_concat_tl_i64(dest, src1, src2); + tcg_gen_sextract_i64(dest, dest, (32 - sa * 8), 32); +} + +static void gen_bytepick_d(TCGv dest, TCGv src1, TCGv src2, target_long sa) +{ + tcg_gen_extract2_i64(dest, src1, src2, (64 - sa * 8)); +} + +static void gen_bstrins(TCGv dest, TCGv src1, + unsigned int ls, unsigned int len) +{ + tcg_gen_deposit_tl(dest, dest, src1, ls, len); +} + +static bool gen_rr_ms_ls(DisasContext *ctx, arg_rr_ms_ls *a, + DisasExtend src_ext, DisasExtend dst_ext, + void (*func)(TCGv, TCGv, unsigned int, unsigned int)) +{ + TCGv dest = gpr_dst(ctx, a->rd, dst_ext); + TCGv src1 = gpr_src(ctx, a->rj, src_ext); + + if (a->ls > a->ms) { + return false; + } + + func(dest, src1, a->ls, a->ms - a->ls + 1); + gen_set_gpr(a->rd, dest, dst_ext); + + return true; +} + +static void gen_clz_w(TCGv dest, TCGv src1) +{ + tcg_gen_clzi_tl(dest, src1, TARGET_LONG_BITS); + tcg_gen_subi_tl(dest, dest, TARGET_LONG_BITS - 32); +} + +static void gen_clo_w(TCGv dest, TCGv src1) +{ + tcg_gen_not_tl(dest, src1); + tcg_gen_ext32u_tl(dest, dest); + gen_clz_w(dest, dest); +} + +static void gen_ctz_w(TCGv dest, TCGv src1) +{ + tcg_gen_ori_tl(dest, src1, (target_ulong)MAKE_64BIT_MASK(32, 32)); + tcg_gen_ctzi_tl(dest, dest, TARGET_LONG_BITS); +} + +static void gen_cto_w(TCGv dest, TCGv src1) +{ + tcg_gen_not_tl(dest, src1); + gen_ctz_w(dest, dest); +} + +static void gen_clz_d(TCGv dest, TCGv src1) +{ + tcg_gen_clzi_i64(dest, src1, TARGET_LONG_BITS); +} + +static void gen_clo_d(TCGv dest, TCGv src1) +{ + tcg_gen_not_tl(dest, src1); + gen_clz_d(dest, dest); +} + +static void gen_ctz_d(TCGv dest, TCGv src1) +{ + tcg_gen_ctzi_tl(dest, src1, TARGET_LONG_BITS); +} + +static void gen_cto_d(TCGv dest, TCGv src1) +{ + tcg_gen_not_tl(dest, src1); + gen_ctz_d(dest, dest); +} + +static void gen_revb_2w(TCGv dest, TCGv src1) +{ + tcg_gen_bswap64_i64(dest, src1); + tcg_gen_rotri_i64(dest, dest, 32); +} + +static void gen_revb_2h(TCGv dest, TCGv src1) +{ + TCGv mask = tcg_constant_tl(0x00FF00FF); + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + tcg_gen_shri_tl(t0, src1, 8); + tcg_gen_and_tl(t0, t0, mask); + tcg_gen_and_tl(t1, src1, mask); + tcg_gen_shli_tl(t1, t1, 8); + tcg_gen_or_tl(dest, t0, t1); + + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static void gen_revb_4h(TCGv dest, TCGv src1) +{ + TCGv mask = tcg_constant_tl(0x00FF00FF00FF00FFULL); + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + tcg_gen_shri_tl(t0, src1, 8); + tcg_gen_and_tl(t0, t0, mask); + tcg_gen_and_tl(t1, src1, mask); + tcg_gen_shli_tl(t1, t1, 8); + tcg_gen_or_tl(dest, t0, t1); + + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static void gen_revh_2w(TCGv dest, TCGv src1) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 mask = tcg_constant_i64(0x0000ffff0000ffffull); + + tcg_gen_shri_i64(t0, src1, 16); + tcg_gen_and_i64(t1, src1, mask); + tcg_gen_and_i64(t0, t0, mask); + tcg_gen_shli_i64(t1, t1, 16); + tcg_gen_or_i64(dest, t1, t0); + + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +} + +static void gen_revh_d(TCGv dest, TCGv src1) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + TCGv mask = tcg_constant_tl(0x0000FFFF0000FFFFULL); + + tcg_gen_shri_tl(t1, src1, 16); + tcg_gen_and_tl(t1, t1, mask); + tcg_gen_and_tl(t0, src1, mask); + tcg_gen_shli_tl(t0, t0, 16); + tcg_gen_or_tl(t0, t0, t1); + tcg_gen_rotri_tl(dest, t0, 32); + + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static void gen_maskeqz(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv zero = tcg_constant_tl(0); + + tcg_gen_movcond_tl(TCG_COND_EQ, dest, src2, zero, zero, src1); +} + +static void gen_masknez(TCGv dest, TCGv src1, TCGv src2) +{ + TCGv zero = tcg_constant_tl(0); + + tcg_gen_movcond_tl(TCG_COND_NE, dest, src2, zero, zero, src1); +} + +TRANS(ext_w_h, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_ext16s_tl) +TRANS(ext_w_b, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_ext8s_tl) +TRANS(clo_w, gen_rr, EXT_NONE, EXT_NONE, gen_clo_w) +TRANS(clz_w, gen_rr, EXT_ZERO, EXT_NONE, gen_clz_w) +TRANS(cto_w, gen_rr, EXT_NONE, EXT_NONE, gen_cto_w) +TRANS(ctz_w, gen_rr, EXT_NONE, EXT_NONE, gen_ctz_w) +TRANS(clo_d, gen_rr, EXT_NONE, EXT_NONE, gen_clo_d) +TRANS(clz_d, gen_rr, EXT_NONE, EXT_NONE, gen_clz_d) +TRANS(cto_d, gen_rr, EXT_NONE, EXT_NONE, gen_cto_d) +TRANS(ctz_d, gen_rr, EXT_NONE, EXT_NONE, gen_ctz_d) +TRANS(revb_2h, gen_rr, EXT_NONE, EXT_SIGN, gen_revb_2h) +TRANS(revb_4h, gen_rr, EXT_NONE, EXT_NONE, gen_revb_4h) +TRANS(revb_2w, gen_rr, EXT_NONE, EXT_NONE, gen_revb_2w) +TRANS(revb_d, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_bswap64_i64) +TRANS(revh_2w, gen_rr, EXT_NONE, EXT_NONE, gen_revh_2w) +TRANS(revh_d, gen_rr, EXT_NONE, EXT_NONE, gen_revh_d) +TRANS(bitrev_4b, gen_rr, EXT_ZERO, EXT_SIGN, gen_helper_bitswap) +TRANS(bitrev_8b, gen_rr, EXT_NONE, EXT_NONE, gen_helper_bitswap) +TRANS(bitrev_w, gen_rr, EXT_NONE, EXT_SIGN, gen_helper_bitrev_w) +TRANS(bitrev_d, gen_rr, EXT_NONE, EXT_NONE, gen_helper_bitrev_d) +TRANS(maskeqz, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_maskeqz) +TRANS(masknez, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_masknez) +TRANS(bytepick_w, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_w) +TRANS(bytepick_d, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_d) +TRANS(bstrins_w, gen_rr_ms_ls, EXT_NONE, EXT_NONE, gen_bstrins) +TRANS(bstrins_d, gen_rr_ms_ls, EXT_NONE, EXT_NONE, gen_bstrins) +TRANS(bstrpick_w, gen_rr_ms_ls, EXT_NONE, EXT_SIGN, tcg_gen_extract_tl) +TRANS(bstrpick_d, gen_rr_ms_ls, EXT_NONE, EXT_NONE, tcg_gen_extract_tl) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index 673aee4be5..b0bed5531b 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -14,13 +14,16 @@ # Argument sets # &r_i rd imm +&rr rd rj &rrr rd rj rk &rr_i rd rj imm &rrr_sa rd rj rk sa +&rr_ms_ls rd rj ms ls # # Formats # +@rr .... ........ ..... ..... rj:5 rd:5 &rr @rrr .... ........ ..... rk:5 rj:5 rd:5 &rrr @r_i20 .... ... imm:s20 rd:5 &r_i @rr_ui5 .... ........ ..... imm:5 rj:5 rd:5 &rr_i @@ -29,6 +32,10 @@ @rr_ui12 .... ...... imm:12 rj:5 rd:5 &rr_i @rr_i16 .... .. imm:s16 rj:5 rd:5 &rr_i @rrr_sa2p1 .... ........ ... .. rk:5 rj:5 rd:5 &rrr_sa sa=%sa2p1 +@rrr_sa2 .... ........ ... sa:2 rk:5 rj:5 rd:5 &rrr_sa +@rrr_sa3 .... ........ .. sa:3 rk:5 rj:5 rd:5 &rrr_sa +@rr_2bw .... ....... ms:5 . ls:5 rj:5 rd:5 &rr_ms_ls +@rr_2bd .... ...... ms:6 ls:6 rj:5 rd:5 &rr_ms_ls # # Fixed point arithmetic operation instruction @@ -99,3 +106,35 @@ srai_w 0000 00000100 10001 ..... ..... ..... @rr_ui5 srai_d 0000 00000100 1001 ...... ..... ..... @rr_ui6 rotri_w 0000 00000100 11001 ..... ..... ..... @rr_ui5 rotri_d 0000 00000100 1101 ...... ..... ..... @rr_ui6 + +# +# Fixed point bit operation instruction +# +ext_w_h 0000 00000000 00000 10110 ..... ..... @rr +ext_w_b 0000 00000000 00000 10111 ..... ..... @rr +clo_w 0000 00000000 00000 00100 ..... ..... @rr +clz_w 0000 00000000 00000 00101 ..... ..... @rr +cto_w 0000 00000000 00000 00110 ..... ..... @rr +ctz_w 0000 00000000 00000 00111 ..... ..... @rr +clo_d 0000 00000000 00000 01000 ..... ..... @rr +clz_d 0000 00000000 00000 01001 ..... ..... @rr +cto_d 0000 00000000 00000 01010 ..... ..... @rr +ctz_d 0000 00000000 00000 01011 ..... ..... @rr +revb_2h 0000 00000000 00000 01100 ..... ..... @rr +revb_4h 0000 00000000 00000 01101 ..... ..... @rr +revb_2w 0000 00000000 00000 01110 ..... ..... @rr +revb_d 0000 00000000 00000 01111 ..... ..... @rr +revh_2w 0000 00000000 00000 10000 ..... ..... @rr +revh_d 0000 00000000 00000 10001 ..... ..... @rr +bitrev_4b 0000 00000000 00000 10010 ..... ..... @rr +bitrev_8b 0000 00000000 00000 10011 ..... ..... @rr +bitrev_w 0000 00000000 00000 10100 ..... ..... @rr +bitrev_d 0000 00000000 00000 10101 ..... ..... @rr +bytepick_w 0000 00000000 100 .. ..... ..... ..... @rrr_sa2 +bytepick_d 0000 00000000 11 ... ..... ..... ..... @rrr_sa3 +maskeqz 0000 00000001 00110 ..... ..... ..... @rrr +masknez 0000 00000001 00111 ..... ..... ..... @rrr +bstrins_w 0000 0000011 ..... 0 ..... ..... ..... @rr_2bw +bstrpick_w 0000 0000011 ..... 1 ..... ..... ..... @rr_2bw +bstrins_d 0000 000010 ...... ...... ..... ..... @rr_2bd +bstrpick_d 0000 000011 ...... ...... ..... ..... @rr_2bd diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c index 903810951e..f4b22c70a0 100644 --- a/target/loongarch/op_helper.c +++ b/target/loongarch/op_helper.c @@ -19,3 +19,24 @@ void helper_raise_exception(CPULoongArchState *env, uint32_t exception) { do_raise_exception(env, exception, GETPC()); } + +target_ulong helper_bitrev_w(target_ulong rj) +{ + return (int32_t)revbit32(rj); +} + +target_ulong helper_bitrev_d(target_ulong rj) +{ + return revbit64(rj); +} + +target_ulong helper_bitswap(target_ulong v) +{ + v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) | + ((v & (target_ulong)0x5555555555555555ULL) << 1); + v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) | + ((v & (target_ulong)0x3333333333333333ULL) << 2); + v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) | + ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4); + return v; +} diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index d5640d5d79..88afd9b3a8 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -147,6 +147,7 @@ static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext) #include "decode-insns.c.inc" #include "insn_trans/trans_arith.c.inc" #include "insn_trans/trans_shift.c.inc" +#include "insn_trans/trans_bit.c.inc" static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { From bb79174d4e191dc83414072e1a7859095faed567 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 6 Jun 2022 20:42:57 +0800 Subject: [PATCH 814/935] target/loongarch: Add fixed point load/store instruction translation This includes: - LD.{B[U]/H[U]/W[U]/D}, ST.{B/H/W/D} - LDX.{B[U]/H[U]/W[U]/D}, STX.{B/H/W/D} - LDPTR.{W/D}, STPTR.{W/D} - PRELD - LD{GT/LE}.{B/H/W/D}, ST{GT/LE}.{B/H/W/D} - DBAR, IBAR Signed-off-by: Song Gao Signed-off-by: Xiaojuan Yang Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-8-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/helper.h | 3 + .../loongarch/insn_trans/trans_memory.c.inc | 229 ++++++++++++++++++ target/loongarch/insns.decode | 55 +++++ target/loongarch/op_helper.c | 15 ++ target/loongarch/translate.c | 6 + 5 files changed, 308 insertions(+) create mode 100644 target/loongarch/insn_trans/trans_memory.c.inc diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index 04e0245d5e..100622bfc2 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -8,3 +8,6 @@ DEF_HELPER_2(raise_exception, noreturn, env, i32) DEF_HELPER_FLAGS_1(bitrev_w, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(bitrev_d, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl) + +DEF_HELPER_FLAGS_3(asrtle_d, TCG_CALL_NO_WG, void, env, tl, tl) +DEF_HELPER_FLAGS_3(asrtgt_d, TCG_CALL_NO_WG, void, env, tl, tl) diff --git a/target/loongarch/insn_trans/trans_memory.c.inc b/target/loongarch/insn_trans/trans_memory.c.inc new file mode 100644 index 0000000000..10914acf52 --- /dev/null +++ b/target/loongarch/insn_trans/trans_memory.c.inc @@ -0,0 +1,229 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +static bool gen_load(DisasContext *ctx, arg_rr_i *a, MemOp mop) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); + TCGv temp = NULL; + + if (a->imm) { + temp = tcg_temp_new(); + tcg_gen_addi_tl(temp, addr, a->imm); + addr = temp; + } + + tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); + gen_set_gpr(a->rd, dest, EXT_NONE); + + if (temp) { + tcg_temp_free(temp); + } + + return true; +} + +static bool gen_store(DisasContext *ctx, arg_rr_i *a, MemOp mop) +{ + TCGv data = gpr_src(ctx, a->rd, EXT_NONE); + TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); + TCGv temp = NULL; + + if (a->imm) { + temp = tcg_temp_new(); + tcg_gen_addi_tl(temp, addr, a->imm); + addr = temp; + } + + tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop); + + if (temp) { + tcg_temp_free(temp); + } + + return true; +} + +static bool gen_loadx(DisasContext *ctx, arg_rrr *a, MemOp mop) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + TCGv addr = tcg_temp_new(); + + tcg_gen_add_tl(addr, src1, src2); + tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); + gen_set_gpr(a->rd, dest, EXT_NONE); + tcg_temp_free(addr); + + return true; +} + +static bool gen_storex(DisasContext *ctx, arg_rrr *a, MemOp mop) +{ + TCGv data = gpr_src(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + TCGv addr = tcg_temp_new(); + + tcg_gen_add_tl(addr, src1, src2); + tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop); + tcg_temp_free(addr); + + return true; +} + +static bool gen_load_gt(DisasContext *ctx, arg_rrr *a, MemOp mop) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + + gen_helper_asrtgt_d(cpu_env, src1, src2); + tcg_gen_qemu_ld_tl(dest, src1, ctx->mem_idx, mop); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +static bool gen_load_le(DisasContext *ctx, arg_rrr *a, MemOp mop) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + + gen_helper_asrtle_d(cpu_env, src1, src2); + tcg_gen_qemu_ld_tl(dest, src1, ctx->mem_idx, mop); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +static bool gen_store_gt(DisasContext *ctx, arg_rrr *a, MemOp mop) +{ + TCGv data = gpr_src(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + + gen_helper_asrtgt_d(cpu_env, src1, src2); + tcg_gen_qemu_st_tl(data, src1, ctx->mem_idx, mop); + + return true; +} + +static bool gen_store_le(DisasContext *ctx, arg_rrr *a, MemOp mop) +{ + TCGv data = gpr_src(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + + gen_helper_asrtle_d(cpu_env, src1, src2); + tcg_gen_qemu_st_tl(data, src1, ctx->mem_idx, mop); + + return true; +} + +static bool trans_preld(DisasContext *ctx, arg_preld *a) +{ + return true; +} + +static bool trans_dbar(DisasContext *ctx, arg_dbar * a) +{ + tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); + return true; +} + +static bool trans_ibar(DisasContext *ctx, arg_ibar *a) +{ + ctx->base.is_jmp = DISAS_STOP; + return true; +} + +static bool gen_ldptr(DisasContext *ctx, arg_rr_i *a, MemOp mop) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); + TCGv temp = NULL; + + if (a->imm) { + temp = tcg_temp_new(); + tcg_gen_addi_tl(temp, addr, a->imm); + addr = temp; + } + + tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); + gen_set_gpr(a->rd, dest, EXT_NONE); + + if (temp) { + tcg_temp_free(temp); + } + + return true; +} + +static bool gen_stptr(DisasContext *ctx, arg_rr_i *a, MemOp mop) +{ + TCGv data = gpr_src(ctx, a->rd, EXT_NONE); + TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); + TCGv temp = NULL; + + if (a->imm) { + temp = tcg_temp_new(); + tcg_gen_addi_tl(temp, addr, a->im); + addr = temp; + } + + tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop); + + if (temp) { + tcg_temp_free(temp); + } + + return true; +} + +TRANS(ld_b, gen_load, MO_SB) +TRANS(ld_h, gen_load, MO_TESW) +TRANS(ld_w, gen_load, MO_TESL) +TRANS(ld_d, gen_load, MO_TEUQ) +TRANS(st_b, gen_store, MO_UB) +TRANS(st_h, gen_store, MO_TEUW) +TRANS(st_w, gen_store, MO_TEUL) +TRANS(st_d, gen_store, MO_TEUQ) +TRANS(ld_bu, gen_load, MO_UB) +TRANS(ld_hu, gen_load, MO_TEUW) +TRANS(ld_wu, gen_load, MO_TEUL) +TRANS(ldx_b, gen_loadx, MO_SB) +TRANS(ldx_h, gen_loadx, MO_TESW) +TRANS(ldx_w, gen_loadx, MO_TESL) +TRANS(ldx_d, gen_loadx, MO_TEUQ) +TRANS(stx_b, gen_storex, MO_UB) +TRANS(stx_h, gen_storex, MO_TEUW) +TRANS(stx_w, gen_storex, MO_TEUL) +TRANS(stx_d, gen_storex, MO_TEUQ) +TRANS(ldx_bu, gen_loadx, MO_UB) +TRANS(ldx_hu, gen_loadx, MO_TEUW) +TRANS(ldx_wu, gen_loadx, MO_TEUL) +TRANS(ldptr_w, gen_ldptr, MO_TESL) +TRANS(stptr_w, gen_stptr, MO_TEUL) +TRANS(ldptr_d, gen_ldptr, MO_TEUQ) +TRANS(stptr_d, gen_stptr, MO_TEUQ) +TRANS(ldgt_b, gen_load_gt, MO_SB) +TRANS(ldgt_h, gen_load_gt, MO_TESW) +TRANS(ldgt_w, gen_load_gt, MO_TESL) +TRANS(ldgt_d, gen_load_gt, MO_TEUQ) +TRANS(ldle_b, gen_load_le, MO_SB) +TRANS(ldle_h, gen_load_le, MO_TESW) +TRANS(ldle_w, gen_load_le, MO_TESL) +TRANS(ldle_d, gen_load_le, MO_TEUQ) +TRANS(stgt_b, gen_store_gt, MO_UB) +TRANS(stgt_h, gen_store_gt, MO_TEUW) +TRANS(stgt_w, gen_store_gt, MO_TEUL) +TRANS(stgt_d, gen_store_gt, MO_TEUQ) +TRANS(stle_b, gen_store_le, MO_UB) +TRANS(stle_h, gen_store_le, MO_TEUW) +TRANS(stle_w, gen_store_le, MO_TEUL) +TRANS(stle_d, gen_store_le, MO_TEUQ) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index b0bed5531b..1156e6965c 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -8,21 +8,25 @@ # # Fields # +%i14s2 10:s14 !function=shl_2 %sa2p1 15:2 !function=plus_1 # # Argument sets # +&i imm &r_i rd imm &rr rd rj &rrr rd rj rk &rr_i rd rj imm +&hint_r_i hint rj imm &rrr_sa rd rj rk sa &rr_ms_ls rd rj ms ls # # Formats # +@i15 .... ........ ..... imm:15 &i @rr .... ........ ..... ..... rj:5 rd:5 &rr @rrr .... ........ ..... rk:5 rj:5 rd:5 &rrr @r_i20 .... ... imm:s20 rd:5 &r_i @@ -30,7 +34,9 @@ @rr_ui6 .... ........ .... imm:6 rj:5 rd:5 &rr_i @rr_i12 .... ...... imm:s12 rj:5 rd:5 &rr_i @rr_ui12 .... ...... imm:12 rj:5 rd:5 &rr_i +@rr_i14s2 .... .... .............. rj:5 rd:5 &rr_i imm=%i14s2 @rr_i16 .... .. imm:s16 rj:5 rd:5 &rr_i +@hint_r_i12 .... ...... imm:s12 rj:5 hint:5 &hint_r_i @rrr_sa2p1 .... ........ ... .. rk:5 rj:5 rd:5 &rrr_sa sa=%sa2p1 @rrr_sa2 .... ........ ... sa:2 rk:5 rj:5 rd:5 &rrr_sa @rrr_sa3 .... ........ .. sa:3 rk:5 rj:5 rd:5 &rrr_sa @@ -138,3 +144,52 @@ bstrins_w 0000 0000011 ..... 0 ..... ..... ..... @rr_2bw bstrpick_w 0000 0000011 ..... 1 ..... ..... ..... @rr_2bw bstrins_d 0000 000010 ...... ...... ..... ..... @rr_2bd bstrpick_d 0000 000011 ...... ...... ..... ..... @rr_2bd + +# +# Fixed point load/store instruction +# +ld_b 0010 100000 ............ ..... ..... @rr_i12 +ld_h 0010 100001 ............ ..... ..... @rr_i12 +ld_w 0010 100010 ............ ..... ..... @rr_i12 +ld_d 0010 100011 ............ ..... ..... @rr_i12 +st_b 0010 100100 ............ ..... ..... @rr_i12 +st_h 0010 100101 ............ ..... ..... @rr_i12 +st_w 0010 100110 ............ ..... ..... @rr_i12 +st_d 0010 100111 ............ ..... ..... @rr_i12 +ld_bu 0010 101000 ............ ..... ..... @rr_i12 +ld_hu 0010 101001 ............ ..... ..... @rr_i12 +ld_wu 0010 101010 ............ ..... ..... @rr_i12 +ldx_b 0011 10000000 00000 ..... ..... ..... @rrr +ldx_h 0011 10000000 01000 ..... ..... ..... @rrr +ldx_w 0011 10000000 10000 ..... ..... ..... @rrr +ldx_d 0011 10000000 11000 ..... ..... ..... @rrr +stx_b 0011 10000001 00000 ..... ..... ..... @rrr +stx_h 0011 10000001 01000 ..... ..... ..... @rrr +stx_w 0011 10000001 10000 ..... ..... ..... @rrr +stx_d 0011 10000001 11000 ..... ..... ..... @rrr +ldx_bu 0011 10000010 00000 ..... ..... ..... @rrr +ldx_hu 0011 10000010 01000 ..... ..... ..... @rrr +ldx_wu 0011 10000010 10000 ..... ..... ..... @rrr +preld 0010 101011 ............ ..... ..... @hint_r_i12 +dbar 0011 10000111 00100 ............... @i15 +ibar 0011 10000111 00101 ............... @i15 +ldptr_w 0010 0100 .............. ..... ..... @rr_i14s2 +stptr_w 0010 0101 .............. ..... ..... @rr_i14s2 +ldptr_d 0010 0110 .............. ..... ..... @rr_i14s2 +stptr_d 0010 0111 .............. ..... ..... @rr_i14s2 +ldgt_b 0011 10000111 10000 ..... ..... ..... @rrr +ldgt_h 0011 10000111 10001 ..... ..... ..... @rrr +ldgt_w 0011 10000111 10010 ..... ..... ..... @rrr +ldgt_d 0011 10000111 10011 ..... ..... ..... @rrr +ldle_b 0011 10000111 10100 ..... ..... ..... @rrr +ldle_h 0011 10000111 10101 ..... ..... ..... @rrr +ldle_w 0011 10000111 10110 ..... ..... ..... @rrr +ldle_d 0011 10000111 10111 ..... ..... ..... @rrr +stgt_b 0011 10000111 11000 ..... ..... ..... @rrr +stgt_h 0011 10000111 11001 ..... ..... ..... @rrr +stgt_w 0011 10000111 11010 ..... ..... ..... @rrr +stgt_d 0011 10000111 11011 ..... ..... ..... @rrr +stle_b 0011 10000111 11100 ..... ..... ..... @rrr +stle_h 0011 10000111 11101 ..... ..... ..... @rrr +stle_w 0011 10000111 11110 ..... ..... ..... @rrr +stle_d 0011 10000111 11111 ..... ..... ..... @rrr diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c index f4b22c70a0..bd2db783c9 100644 --- a/target/loongarch/op_helper.c +++ b/target/loongarch/op_helper.c @@ -40,3 +40,18 @@ target_ulong helper_bitswap(target_ulong v) ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4); return v; } + +/* loongarch assert op */ +void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, target_ulong rk) +{ + if (rj > rk) { + do_raise_exception(env, EXCCODE_ADEM, GETPC()); + } +} + +void helper_asrtgt_d(CPULoongArchState *env, target_ulong rj, target_ulong rk) +{ + if (rj <= rk) { + do_raise_exception(env, EXCCODE_ADEM, GETPC()); + } +} diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 88afd9b3a8..b8fed26699 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -31,6 +31,11 @@ static inline int plus_1(DisasContext *ctx, int x) return x + 1; } +static inline int shl_2(DisasContext *ctx, int x) +{ + return x << 2; +} + void generate_exception(DisasContext *ctx, int excp) { tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); @@ -148,6 +153,7 @@ static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext) #include "insn_trans/trans_arith.c.inc" #include "insn_trans/trans_shift.c.inc" #include "insn_trans/trans_bit.c.inc" +#include "insn_trans/trans_memory.c.inc" static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { From 94b02d57b09eeb2dcb07a2a196b91310420bd0bf Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 6 Jun 2022 20:42:58 +0800 Subject: [PATCH 815/935] target/loongarch: Add fixed point atomic instruction translation This includes: - LL.{W/D}, SC.{W/D} - AM{SWAP/ADD/AND/OR/XOR/MAX/MIN}[_DB].{W/D} - AM{MAX/MIN}[_DB].{WU/DU} Signed-off-by: Song Gao Signed-off-by: Xiaojuan Yang Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-9-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- .../loongarch/insn_trans/trans_atomic.c.inc | 113 ++++++++++++++++++ .../loongarch/insn_trans/trans_memory.c.inc | 2 +- target/loongarch/insns.decode | 44 +++++++ target/loongarch/translate.c | 1 + 4 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 target/loongarch/insn_trans/trans_atomic.c.inc diff --git a/target/loongarch/insn_trans/trans_atomic.c.inc b/target/loongarch/insn_trans/trans_atomic.c.inc new file mode 100644 index 0000000000..6763c1c301 --- /dev/null +++ b/target/loongarch/insn_trans/trans_atomic.c.inc @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +static bool gen_ll(DisasContext *ctx, arg_rr_i *a, MemOp mop) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv t0 = tcg_temp_new(); + + tcg_gen_addi_tl(t0, src1, a->imm); + tcg_gen_qemu_ld_i64(dest, t0, ctx->mem_idx, mop); + tcg_gen_st_tl(t0, cpu_env, offsetof(CPULoongArchState, lladdr)); + tcg_gen_st_tl(dest, cpu_env, offsetof(CPULoongArchState, llval)); + gen_set_gpr(a->rd, dest, EXT_NONE); + tcg_temp_free(t0); + + return true; +} + +static bool gen_sc(DisasContext *ctx, arg_rr_i *a, MemOp mop) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rd, EXT_NONE); + TCGv t0 = tcg_temp_new(); + TCGv val = tcg_temp_new(); + + TCGLabel *l1 = gen_new_label(); + TCGLabel *done = gen_new_label(); + + tcg_gen_addi_tl(t0, src1, a->imm); + tcg_gen_brcond_tl(TCG_COND_EQ, t0, cpu_lladdr, l1); + tcg_gen_movi_tl(dest, 0); + tcg_gen_br(done); + + gen_set_label(l1); + tcg_gen_mov_tl(val, src2); + /* generate cmpxchg */ + tcg_gen_atomic_cmpxchg_tl(t0, cpu_lladdr, cpu_llval, + val, ctx->mem_idx, mop); + tcg_gen_setcond_tl(TCG_COND_EQ, dest, t0, cpu_llval); + gen_set_label(done); + gen_set_gpr(a->rd, dest, EXT_NONE); + tcg_temp_free(t0); + tcg_temp_free(val); + + return true; +} + +static bool gen_am(DisasContext *ctx, arg_rrr *a, + void (*func)(TCGv, TCGv, TCGv, TCGArg, MemOp), + MemOp mop) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); + TCGv val = gpr_src(ctx, a->rk, EXT_NONE); + + if (a->rd != 0 && (a->rj == a->rd || a->rk == a->rd)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Warning: source register overlaps destination register" + "in atomic insn at pc=0x" TARGET_FMT_lx "\n", + ctx->base.pc_next - 4); + return false; + } + + func(dest, addr, val, ctx->mem_idx, mop); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +TRANS(ll_w, gen_ll, MO_TESL) +TRANS(sc_w, gen_sc, MO_TESL) +TRANS(ll_d, gen_ll, MO_TEUQ) +TRANS(sc_d, gen_sc, MO_TEUQ) +TRANS(amswap_w, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) +TRANS(amswap_d, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) +TRANS(amadd_w, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) +TRANS(amadd_d, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) +TRANS(amand_w, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) +TRANS(amand_d, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) +TRANS(amor_w, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) +TRANS(amor_d, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) +TRANS(amxor_w, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) +TRANS(amxor_d, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) +TRANS(ammax_w, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) +TRANS(ammax_d, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) +TRANS(ammin_w, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) +TRANS(ammin_d, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) +TRANS(ammax_wu, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) +TRANS(ammax_du, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) +TRANS(ammin_wu, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) +TRANS(ammin_du, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) +TRANS(amswap_db_w, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) +TRANS(amswap_db_d, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) +TRANS(amadd_db_w, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) +TRANS(amadd_db_d, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) +TRANS(amand_db_w, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) +TRANS(amand_db_d, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) +TRANS(amor_db_w, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) +TRANS(amor_db_d, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) +TRANS(amxor_db_w, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) +TRANS(amxor_db_d, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) +TRANS(ammax_db_w, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) +TRANS(ammax_db_d, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) +TRANS(ammin_db_w, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) +TRANS(ammin_db_d, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) +TRANS(ammax_db_wu, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) +TRANS(ammax_db_du, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) +TRANS(ammin_db_wu, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) +TRANS(ammin_db_du, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) diff --git a/target/loongarch/insn_trans/trans_memory.c.inc b/target/loongarch/insn_trans/trans_memory.c.inc index 10914acf52..d5eb31147c 100644 --- a/target/loongarch/insn_trans/trans_memory.c.inc +++ b/target/loongarch/insn_trans/trans_memory.c.inc @@ -172,7 +172,7 @@ static bool gen_stptr(DisasContext *ctx, arg_rr_i *a, MemOp mop) if (a->imm) { temp = tcg_temp_new(); - tcg_gen_addi_tl(temp, addr, a->im); + tcg_gen_addi_tl(temp, addr, a->imm); addr = temp; } diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index 1156e6965c..8d247aa68c 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -193,3 +193,47 @@ stle_b 0011 10000111 11100 ..... ..... ..... @rrr stle_h 0011 10000111 11101 ..... ..... ..... @rrr stle_w 0011 10000111 11110 ..... ..... ..... @rrr stle_d 0011 10000111 11111 ..... ..... ..... @rrr + +# +# Fixed point atomic instruction +# +ll_w 0010 0000 .............. ..... ..... @rr_i14s2 +sc_w 0010 0001 .............. ..... ..... @rr_i14s2 +ll_d 0010 0010 .............. ..... ..... @rr_i14s2 +sc_d 0010 0011 .............. ..... ..... @rr_i14s2 +amswap_w 0011 10000110 00000 ..... ..... ..... @rrr +amswap_d 0011 10000110 00001 ..... ..... ..... @rrr +amadd_w 0011 10000110 00010 ..... ..... ..... @rrr +amadd_d 0011 10000110 00011 ..... ..... ..... @rrr +amand_w 0011 10000110 00100 ..... ..... ..... @rrr +amand_d 0011 10000110 00101 ..... ..... ..... @rrr +amor_w 0011 10000110 00110 ..... ..... ..... @rrr +amor_d 0011 10000110 00111 ..... ..... ..... @rrr +amxor_w 0011 10000110 01000 ..... ..... ..... @rrr +amxor_d 0011 10000110 01001 ..... ..... ..... @rrr +ammax_w 0011 10000110 01010 ..... ..... ..... @rrr +ammax_d 0011 10000110 01011 ..... ..... ..... @rrr +ammin_w 0011 10000110 01100 ..... ..... ..... @rrr +ammin_d 0011 10000110 01101 ..... ..... ..... @rrr +ammax_wu 0011 10000110 01110 ..... ..... ..... @rrr +ammax_du 0011 10000110 01111 ..... ..... ..... @rrr +ammin_wu 0011 10000110 10000 ..... ..... ..... @rrr +ammin_du 0011 10000110 10001 ..... ..... ..... @rrr +amswap_db_w 0011 10000110 10010 ..... ..... ..... @rrr +amswap_db_d 0011 10000110 10011 ..... ..... ..... @rrr +amadd_db_w 0011 10000110 10100 ..... ..... ..... @rrr +amadd_db_d 0011 10000110 10101 ..... ..... ..... @rrr +amand_db_w 0011 10000110 10110 ..... ..... ..... @rrr +amand_db_d 0011 10000110 10111 ..... ..... ..... @rrr +amor_db_w 0011 10000110 11000 ..... ..... ..... @rrr +amor_db_d 0011 10000110 11001 ..... ..... ..... @rrr +amxor_db_w 0011 10000110 11010 ..... ..... ..... @rrr +amxor_db_d 0011 10000110 11011 ..... ..... ..... @rrr +ammax_db_w 0011 10000110 11100 ..... ..... ..... @rrr +ammax_db_d 0011 10000110 11101 ..... ..... ..... @rrr +ammin_db_w 0011 10000110 11110 ..... ..... ..... @rrr +ammin_db_d 0011 10000110 11111 ..... ..... ..... @rrr +ammax_db_wu 0011 10000111 00000 ..... ..... ..... @rrr +ammax_db_du 0011 10000111 00001 ..... ..... ..... @rrr +ammin_db_wu 0011 10000111 00010 ..... ..... ..... @rrr +ammin_db_du 0011 10000111 00011 ..... ..... ..... @rrr diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index b8fed26699..01791bf1a2 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -154,6 +154,7 @@ static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext) #include "insn_trans/trans_shift.c.inc" #include "insn_trans/trans_bit.c.inc" #include "insn_trans/trans_memory.c.inc" +#include "insn_trans/trans_atomic.c.inc" static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { From 8708a04a6145b4c9289fed28358fb1273dcd6aea Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 6 Jun 2022 20:42:59 +0800 Subject: [PATCH 816/935] target/loongarch: Add fixed point extra instruction translation This includes: - CRC[C].W.{B/H/W/D}.W - SYSCALL - BREAK - ASRT{LE/GT}.D - RDTIME{L/H}.W, RDTIME.D - CPUCFG Signed-off-by: Song Gao Signed-off-by: Xiaojuan Yang Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-10-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/helper.h | 4 ++ target/loongarch/insn_trans/trans_extra.c.inc | 68 +++++++++++++++++++ target/loongarch/insns.decode | 19 ++++++ target/loongarch/op_helper.c | 26 +++++++ target/loongarch/translate.c | 1 + 5 files changed, 118 insertions(+) create mode 100644 target/loongarch/insn_trans/trans_extra.c.inc diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index 100622bfc2..638c2efc51 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -11,3 +11,7 @@ DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_3(asrtle_d, TCG_CALL_NO_WG, void, env, tl, tl) DEF_HELPER_FLAGS_3(asrtgt_d, TCG_CALL_NO_WG, void, env, tl, tl) + +DEF_HELPER_FLAGS_3(crc32, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl) +DEF_HELPER_FLAGS_3(crc32c, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl) +DEF_HELPER_FLAGS_2(cpucfg, TCG_CALL_NO_RWG_SE, tl, env, tl) diff --git a/target/loongarch/insn_trans/trans_extra.c.inc b/target/loongarch/insn_trans/trans_extra.c.inc new file mode 100644 index 0000000000..549f75a867 --- /dev/null +++ b/target/loongarch/insn_trans/trans_extra.c.inc @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +static bool trans_break(DisasContext *ctx, arg_break *a) +{ + generate_exception(ctx, EXCCODE_BRK); + return true; +} + +static bool trans_syscall(DisasContext *ctx, arg_syscall *a) +{ + generate_exception(ctx, EXCCODE_SYS); + return true; +} + +static bool trans_asrtle_d(DisasContext *ctx, arg_asrtle_d * a) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + + gen_helper_asrtle_d(cpu_env, src1, src2); + return true; +} + +static bool trans_asrtgt_d(DisasContext *ctx, arg_asrtgt_d * a) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + + gen_helper_asrtgt_d(cpu_env, src1, src2); + return true; +} + +static bool trans_cpucfg(DisasContext *ctx, arg_cpucfg *a) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + + gen_helper_cpucfg(dest, cpu_env, src1); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +static bool gen_crc(DisasContext *ctx, arg_rrr *a, + void (*func)(TCGv, TCGv, TCGv, TCGv), + TCGv tsz) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_SIGN); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + + func(dest, src2, src1, tsz); + gen_set_gpr(a->rd, dest, EXT_SIGN); + + return true; +} + +TRANS(crc_w_b_w, gen_crc, gen_helper_crc32, tcg_constant_tl(1)) +TRANS(crc_w_h_w, gen_crc, gen_helper_crc32, tcg_constant_tl(2)) +TRANS(crc_w_w_w, gen_crc, gen_helper_crc32, tcg_constant_tl(4)) +TRANS(crc_w_d_w, gen_crc, gen_helper_crc32, tcg_constant_tl(8)) +TRANS(crcc_w_b_w, gen_crc, gen_helper_crc32c, tcg_constant_tl(1)) +TRANS(crcc_w_h_w, gen_crc, gen_helper_crc32c, tcg_constant_tl(2)) +TRANS(crcc_w_w_w, gen_crc, gen_helper_crc32c, tcg_constant_tl(4)) +TRANS(crcc_w_d_w, gen_crc, gen_helper_crc32c, tcg_constant_tl(8)) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index 8d247aa68c..98774dbddb 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -17,6 +17,7 @@ &i imm &r_i rd imm &rr rd rj +&rr_jk rj rk &rrr rd rj rk &rr_i rd rj imm &hint_r_i hint rj imm @@ -28,6 +29,7 @@ # @i15 .... ........ ..... imm:15 &i @rr .... ........ ..... ..... rj:5 rd:5 &rr +@rr_jk .... ........ ..... rk:5 rj:5 ..... &rr_jk @rrr .... ........ ..... rk:5 rj:5 rd:5 &rrr @r_i20 .... ... imm:s20 rd:5 &r_i @rr_ui5 .... ........ ..... imm:5 rj:5 rd:5 &rr_i @@ -237,3 +239,20 @@ ammax_db_wu 0011 10000111 00000 ..... ..... ..... @rrr ammax_db_du 0011 10000111 00001 ..... ..... ..... @rrr ammin_db_wu 0011 10000111 00010 ..... ..... ..... @rrr ammin_db_du 0011 10000111 00011 ..... ..... ..... @rrr + +# +# Fixed point extra instruction +# +crc_w_b_w 0000 00000010 01000 ..... ..... ..... @rrr +crc_w_h_w 0000 00000010 01001 ..... ..... ..... @rrr +crc_w_w_w 0000 00000010 01010 ..... ..... ..... @rrr +crc_w_d_w 0000 00000010 01011 ..... ..... ..... @rrr +crcc_w_b_w 0000 00000010 01100 ..... ..... ..... @rrr +crcc_w_h_w 0000 00000010 01101 ..... ..... ..... @rrr +crcc_w_w_w 0000 00000010 01110 ..... ..... ..... @rrr +crcc_w_d_w 0000 00000010 01111 ..... ..... ..... @rrr +break 0000 00000010 10100 ............... @i15 +syscall 0000 00000010 10110 ............... @i15 +asrtle_d 0000 00000000 00010 ..... ..... 00000 @rr_jk +asrtgt_d 0000 00000000 00011 ..... ..... 00000 @rr_jk +cpucfg 0000 00000000 00000 11011 ..... ..... @rr diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c index bd2db783c9..18e565ce7f 100644 --- a/target/loongarch/op_helper.c +++ b/target/loongarch/op_helper.c @@ -13,6 +13,8 @@ #include "exec/exec-all.h" #include "exec/cpu_ldst.h" #include "internals.h" +#include "qemu/crc32c.h" +#include /* Exceptions helpers */ void helper_raise_exception(CPULoongArchState *env, uint32_t exception) @@ -55,3 +57,27 @@ void helper_asrtgt_d(CPULoongArchState *env, target_ulong rj, target_ulong rk) do_raise_exception(env, EXCCODE_ADEM, GETPC()); } } + +target_ulong helper_crc32(target_ulong val, target_ulong m, uint64_t sz) +{ + uint8_t buf[8]; + target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); + + m &= mask; + stq_le_p(buf, m); + return (int32_t) (crc32(val ^ 0xffffffff, buf, sz) ^ 0xffffffff); +} + +target_ulong helper_crc32c(target_ulong val, target_ulong m, uint64_t sz) +{ + uint8_t buf[8]; + target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); + m &= mask; + stq_le_p(buf, m); + return (int32_t) (crc32c(val, buf, sz) ^ 0xffffffff); +} + +target_ulong helper_cpucfg(CPULoongArchState *env, target_ulong rj) +{ + return rj > 21 ? 0 : env->cpucfg[rj]; +} diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 01791bf1a2..b946dc4d5f 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -155,6 +155,7 @@ static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext) #include "insn_trans/trans_bit.c.inc" #include "insn_trans/trans_memory.c.inc" #include "insn_trans/trans_atomic.c.inc" +#include "insn_trans/trans_extra.c.inc" static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { From d578ca6cbba6056f17901c869a6325d571bb124d Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 6 Jun 2022 20:43:00 +0800 Subject: [PATCH 817/935] target/loongarch: Add floating point arithmetic instruction translation This includes: - F{ADD/SUB/MUL/DIV}.{S/D} - F{MADD/MSUB/NMADD/NMSUB}.{S/D} - F{MAX/MIN}.{S/D} - F{MAXA/MINA}.{S/D} - F{ABS/NEG}.{S/D} - F{SQRT/RECIP/RSQRT}.{S/D} - F{SCALEB/LOGB/COPYSIGN}.{S/D} - FCLASS.{S/D} Signed-off-by: Song Gao Signed-off-by: Xiaojuan Yang Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-11-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/cpu.c | 1 + target/loongarch/fpu_helper.c | 403 ++++++++++++++++++ target/loongarch/helper.h | 37 ++ .../loongarch/insn_trans/trans_farith.c.inc | 105 +++++ target/loongarch/insns.decode | 52 +++ target/loongarch/internals.h | 2 + target/loongarch/translate.c | 11 + 7 files changed, 611 insertions(+) create mode 100644 target/loongarch/fpu_helper.c create mode 100644 target/loongarch/insn_trans/trans_farith.c.inc diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 1f8e37906a..95900be257 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -196,6 +196,7 @@ static void loongarch_cpu_reset(DeviceState *dev) env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3; env->fcsr0 = 0x0; + restore_fp_status(env); cs->exception_index = -1; } diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c new file mode 100644 index 0000000000..d7442cc188 --- /dev/null +++ b/target/loongarch/fpu_helper.c @@ -0,0 +1,403 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch float point emulation helpers for QEMU + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/helper-proto.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "fpu/softfloat.h" +#include "internals.h" + +#define FLOAT_TO_INT32_OVERFLOW 0x7fffffff +#define FLOAT_TO_INT64_OVERFLOW 0x7fffffffffffffffULL + +static inline uint64_t nanbox_s(float32 fp) +{ + return fp | MAKE_64BIT_MASK(32, 32); +} + +/* Convert loongarch rounding mode in fcsr0 to IEEE library */ +static const FloatRoundMode ieee_rm[4] = { + float_round_nearest_even, + float_round_to_zero, + float_round_up, + float_round_down +}; + +void restore_fp_status(CPULoongArchState *env) +{ + set_float_rounding_mode(ieee_rm[(env->fcsr0 >> FCSR0_RM) & 0x3], + &env->fp_status); + set_flush_to_zero(0, &env->fp_status); +} + +static int ieee_ex_to_loongarch(int xcpt) +{ + int ret = 0; + if (xcpt & float_flag_invalid) { + ret |= FP_INVALID; + } + if (xcpt & float_flag_overflow) { + ret |= FP_OVERFLOW; + } + if (xcpt & float_flag_underflow) { + ret |= FP_UNDERFLOW; + } + if (xcpt & float_flag_divbyzero) { + ret |= FP_DIV0; + } + if (xcpt & float_flag_inexact) { + ret |= FP_INEXACT; + } + return ret; +} + +static void update_fcsr0_mask(CPULoongArchState *env, uintptr_t pc, int mask) +{ + int flags = get_float_exception_flags(&env->fp_status); + + set_float_exception_flags(0, &env->fp_status); + + flags &= ~mask; + + if (!flags) { + SET_FP_CAUSE(env->fcsr0, flags); + return; + } else { + flags = ieee_ex_to_loongarch(flags); + SET_FP_CAUSE(env->fcsr0, flags); + } + + if (GET_FP_ENABLES(env->fcsr0) & flags) { + do_raise_exception(env, EXCCODE_FPE, pc); + } else { + UPDATE_FP_FLAGS(env->fcsr0, flags); + } +} + +static void update_fcsr0(CPULoongArchState *env, uintptr_t pc) +{ + update_fcsr0_mask(env, pc, 0); +} + +uint64_t helper_fadd_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = nanbox_s(float32_add((uint32_t)fj, (uint32_t)fk, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fadd_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = float64_add(fj, fk, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fsub_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = nanbox_s(float32_sub((uint32_t)fj, (uint32_t)fk, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fsub_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = float64_sub(fj, fk, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmul_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = nanbox_s(float32_mul((uint32_t)fj, (uint32_t)fk, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmul_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = float64_mul(fj, fk, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fdiv_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = nanbox_s(float32_div((uint32_t)fj, (uint32_t)fk, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fdiv_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = float64_div(fj, fk, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmax_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = nanbox_s(float32_maxnum((uint32_t)fj, (uint32_t)fk, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmax_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = float64_maxnum(fj, fk, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmin_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = nanbox_s(float32_minnum((uint32_t)fj, (uint32_t)fk, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmin_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = float64_minnum(fj, fk, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmaxa_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = nanbox_s(float32_maxnummag((uint32_t)fj, + (uint32_t)fk, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmaxa_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = float64_maxnummag(fj, fk, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmina_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = nanbox_s(float32_minnummag((uint32_t)fj, + (uint32_t)fk, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmina_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + + fd = float64_minnummag(fj, fk, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fscaleb_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + int32_t n = (int32_t)fk; + + fd = nanbox_s(float32_scalbn((uint32_t)fj, + n > 0x200 ? 0x200 : + n < -0x200 ? -0x200 : n, + &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fscaleb_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +{ + uint64_t fd; + int64_t n = (int64_t)fk; + + fd = float64_scalbn(fj, + n > 0x1000 ? 0x1000 : + n < -0x1000 ? -0x1000 : n, + &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fsqrt_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = nanbox_s(float32_sqrt((uint32_t)fj, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fsqrt_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = float64_sqrt(fj, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_frecip_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = nanbox_s(float32_div(float32_one, (uint32_t)fj, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_frecip_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = float64_div(float64_one, fj, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_frsqrt_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + uint32_t fp; + + fp = float32_sqrt((uint32_t)fj, &env->fp_status); + fd = nanbox_s(float32_div(float32_one, fp, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_frsqrt_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fp, fd; + + fp = float64_sqrt(fj, &env->fp_status); + fd = float64_div(float64_one, fp, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_flogb_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + uint32_t fp; + float_status *status = &env->fp_status; + FloatRoundMode old_mode = get_float_rounding_mode(status); + + set_float_rounding_mode(float_round_down, status); + fp = float32_log2((uint32_t)fj, status); + fd = nanbox_s(float32_round_to_int(fp, status)); + set_float_rounding_mode(old_mode, status); + update_fcsr0_mask(env, GETPC(), float_flag_inexact); + return fd; +} + +uint64_t helper_flogb_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + float_status *status = &env->fp_status; + FloatRoundMode old_mode = get_float_rounding_mode(status); + + set_float_rounding_mode(float_round_down, status); + fd = float64_log2(fj, status); + fd = float64_round_to_int(fd, status); + set_float_rounding_mode(old_mode, status); + update_fcsr0_mask(env, GETPC(), float_flag_inexact); + return fd; +} + +uint64_t helper_fclass_s(CPULoongArchState *env, uint64_t fj) +{ + float32 f = fj; + bool sign = float32_is_neg(f); + + if (float32_is_infinity(f)) { + return sign ? 1 << 2 : 1 << 6; + } else if (float32_is_zero(f)) { + return sign ? 1 << 5 : 1 << 9; + } else if (float32_is_zero_or_denormal(f)) { + return sign ? 1 << 4 : 1 << 8; + } else if (float32_is_any_nan(f)) { + float_status s = { }; /* for snan_bit_is_one */ + return float32_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0; + } else { + return sign ? 1 << 3 : 1 << 7; + } +} + +uint64_t helper_fclass_d(CPULoongArchState *env, uint64_t fj) +{ + float64 f = fj; + bool sign = float64_is_neg(f); + + if (float64_is_infinity(f)) { + return sign ? 1 << 2 : 1 << 6; + } else if (float64_is_zero(f)) { + return sign ? 1 << 5 : 1 << 9; + } else if (float64_is_zero_or_denormal(f)) { + return sign ? 1 << 4 : 1 << 8; + } else if (float64_is_any_nan(f)) { + float_status s = { }; /* for snan_bit_is_one */ + return float64_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0; + } else { + return sign ? 1 << 3 : 1 << 7; + } +} + +uint64_t helper_fmuladd_s(CPULoongArchState *env, uint64_t fj, + uint64_t fk, uint64_t fa, uint32_t flag) +{ + uint64_t fd; + + fd = nanbox_s(float32_muladd((uint32_t)fj, (uint32_t)fk, + (uint32_t)fa, flag, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fmuladd_d(CPULoongArchState *env, uint64_t fj, + uint64_t fk, uint64_t fa, uint32_t flag) +{ + uint64_t fd; + + fd = float64_muladd(fj, fk, fa, flag, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index 638c2efc51..840bad9b2f 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -15,3 +15,40 @@ DEF_HELPER_FLAGS_3(asrtgt_d, TCG_CALL_NO_WG, void, env, tl, tl) DEF_HELPER_FLAGS_3(crc32, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl) DEF_HELPER_FLAGS_3(crc32c, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl) DEF_HELPER_FLAGS_2(cpucfg, TCG_CALL_NO_RWG_SE, tl, env, tl) + +/* Floating-point helper */ +DEF_HELPER_FLAGS_3(fadd_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fadd_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fsub_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fsub_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmul_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmul_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fdiv_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fdiv_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmax_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmax_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmin_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmin_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmaxa_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmaxa_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmina_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmina_d, TCG_CALL_NO_WG, i64, env, i64, i64) + +DEF_HELPER_FLAGS_5(fmuladd_s, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i32) +DEF_HELPER_FLAGS_5(fmuladd_d, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i32) + +DEF_HELPER_FLAGS_3(fscaleb_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fscaleb_d, TCG_CALL_NO_WG, i64, env, i64, i64) + +DEF_HELPER_FLAGS_2(flogb_s, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(flogb_d, TCG_CALL_NO_WG, i64, env, i64) + +DEF_HELPER_FLAGS_2(fsqrt_s, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(fsqrt_d, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(frsqrt_s, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(frsqrt_d, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(frecip_s, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(frecip_d, TCG_CALL_NO_WG, i64, env, i64) + +DEF_HELPER_FLAGS_2(fclass_s, TCG_CALL_NO_RWG_SE, i64, env, i64) +DEF_HELPER_FLAGS_2(fclass_d, TCG_CALL_NO_RWG_SE, i64, env, i64) diff --git a/target/loongarch/insn_trans/trans_farith.c.inc b/target/loongarch/insn_trans/trans_farith.c.inc new file mode 100644 index 0000000000..65ad2ffab8 --- /dev/null +++ b/target/loongarch/insn_trans/trans_farith.c.inc @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +static bool gen_fff(DisasContext *ctx, arg_fff *a, + void (*func)(TCGv, TCGv_env, TCGv, TCGv)) +{ + func(cpu_fpr[a->fd], cpu_env, cpu_fpr[a->fj], cpu_fpr[a->fk]); + return true; +} + +static bool gen_ff(DisasContext *ctx, arg_ff *a, + void (*func)(TCGv, TCGv_env, TCGv)) +{ + func(cpu_fpr[a->fd], cpu_env, cpu_fpr[a->fj]); + return true; +} + +static bool gen_muladd(DisasContext *ctx, arg_ffff *a, + void (*func)(TCGv, TCGv_env, TCGv, TCGv, TCGv, TCGv_i32), + int flag) +{ + TCGv_i32 tflag = tcg_constant_i32(flag); + func(cpu_fpr[a->fd], cpu_env, cpu_fpr[a->fj], + cpu_fpr[a->fk], cpu_fpr[a->fa], tflag); + return true; +} + +static bool trans_fcopysign_s(DisasContext *ctx, arg_fcopysign_s *a) +{ + tcg_gen_deposit_i64(cpu_fpr[a->fd], cpu_fpr[a->fk], cpu_fpr[a->fj], 0, 31); + return true; +} + +static bool trans_fcopysign_d(DisasContext *ctx, arg_fcopysign_d *a) +{ + tcg_gen_deposit_i64(cpu_fpr[a->fd], cpu_fpr[a->fk], cpu_fpr[a->fj], 0, 63); + return true; +} + +static bool trans_fabs_s(DisasContext *ctx, arg_fabs_s *a) +{ + tcg_gen_andi_i64(cpu_fpr[a->fd], cpu_fpr[a->fj], MAKE_64BIT_MASK(0, 31)); + gen_nanbox_s(cpu_fpr[a->fd], cpu_fpr[a->fd]); + return true; +} + +static bool trans_fabs_d(DisasContext *ctx, arg_fabs_d *a) +{ + tcg_gen_andi_i64(cpu_fpr[a->fd], cpu_fpr[a->fj], MAKE_64BIT_MASK(0, 63)); + return true; +} + +static bool trans_fneg_s(DisasContext *ctx, arg_fneg_s *a) +{ + tcg_gen_xori_i64(cpu_fpr[a->fd], cpu_fpr[a->fj], 0x80000000); + gen_nanbox_s(cpu_fpr[a->fd], cpu_fpr[a->fd]); + return true; +} + +static bool trans_fneg_d(DisasContext *ctx, arg_fneg_d *a) +{ + tcg_gen_xori_i64(cpu_fpr[a->fd], cpu_fpr[a->fj], 0x8000000000000000LL); + return true; +} + +TRANS(fadd_s, gen_fff, gen_helper_fadd_s) +TRANS(fadd_d, gen_fff, gen_helper_fadd_d) +TRANS(fsub_s, gen_fff, gen_helper_fsub_s) +TRANS(fsub_d, gen_fff, gen_helper_fsub_d) +TRANS(fmul_s, gen_fff, gen_helper_fmul_s) +TRANS(fmul_d, gen_fff, gen_helper_fmul_d) +TRANS(fdiv_s, gen_fff, gen_helper_fdiv_s) +TRANS(fdiv_d, gen_fff, gen_helper_fdiv_d) +TRANS(fmax_s, gen_fff, gen_helper_fmax_s) +TRANS(fmax_d, gen_fff, gen_helper_fmax_d) +TRANS(fmin_s, gen_fff, gen_helper_fmin_s) +TRANS(fmin_d, gen_fff, gen_helper_fmin_d) +TRANS(fmaxa_s, gen_fff, gen_helper_fmaxa_s) +TRANS(fmaxa_d, gen_fff, gen_helper_fmaxa_d) +TRANS(fmina_s, gen_fff, gen_helper_fmina_s) +TRANS(fmina_d, gen_fff, gen_helper_fmina_d) +TRANS(fscaleb_s, gen_fff, gen_helper_fscaleb_s) +TRANS(fscaleb_d, gen_fff, gen_helper_fscaleb_d) +TRANS(fsqrt_s, gen_ff, gen_helper_fsqrt_s) +TRANS(fsqrt_d, gen_ff, gen_helper_fsqrt_d) +TRANS(frecip_s, gen_ff, gen_helper_frecip_s) +TRANS(frecip_d, gen_ff, gen_helper_frecip_d) +TRANS(frsqrt_s, gen_ff, gen_helper_frsqrt_s) +TRANS(frsqrt_d, gen_ff, gen_helper_frsqrt_d) +TRANS(flogb_s, gen_ff, gen_helper_flogb_s) +TRANS(flogb_d, gen_ff, gen_helper_flogb_d) +TRANS(fclass_s, gen_ff, gen_helper_fclass_s) +TRANS(fclass_d, gen_ff, gen_helper_fclass_d) +TRANS(fmadd_s, gen_muladd, gen_helper_fmuladd_s, 0) +TRANS(fmadd_d, gen_muladd, gen_helper_fmuladd_d, 0) +TRANS(fmsub_s, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_c) +TRANS(fmsub_d, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_c) +TRANS(fnmadd_s, gen_muladd, gen_helper_fmuladd_s, + float_muladd_negate_product | float_muladd_negate_c) +TRANS(fnmadd_d, gen_muladd, gen_helper_fmuladd_d, + float_muladd_negate_product | float_muladd_negate_c) +TRANS(fnmsub_s, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_product) +TRANS(fnmsub_d, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_product) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index 98774dbddb..6455e09ebe 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -23,6 +23,9 @@ &hint_r_i hint rj imm &rrr_sa rd rj rk sa &rr_ms_ls rd rj ms ls +&ff fd fj +&fff fd fj fk +&ffff fd fj fk fa # # Formats @@ -44,6 +47,9 @@ @rrr_sa3 .... ........ .. sa:3 rk:5 rj:5 rd:5 &rrr_sa @rr_2bw .... ....... ms:5 . ls:5 rj:5 rd:5 &rr_ms_ls @rr_2bd .... ...... ms:6 ls:6 rj:5 rd:5 &rr_ms_ls +@ff .... ........ ..... ..... fj:5 fd:5 &ff +@fff .... ........ ..... fk:5 fj:5 fd:5 &fff +@ffff .... ........ fa:5 fk:5 fj:5 fd:5 &ffff # # Fixed point arithmetic operation instruction @@ -256,3 +262,49 @@ syscall 0000 00000010 10110 ............... @i15 asrtle_d 0000 00000000 00010 ..... ..... 00000 @rr_jk asrtgt_d 0000 00000000 00011 ..... ..... 00000 @rr_jk cpucfg 0000 00000000 00000 11011 ..... ..... @rr + +# +# Floating point arithmetic operation instruction +# +fadd_s 0000 00010000 00001 ..... ..... ..... @fff +fadd_d 0000 00010000 00010 ..... ..... ..... @fff +fsub_s 0000 00010000 00101 ..... ..... ..... @fff +fsub_d 0000 00010000 00110 ..... ..... ..... @fff +fmul_s 0000 00010000 01001 ..... ..... ..... @fff +fmul_d 0000 00010000 01010 ..... ..... ..... @fff +fdiv_s 0000 00010000 01101 ..... ..... ..... @fff +fdiv_d 0000 00010000 01110 ..... ..... ..... @fff +fmadd_s 0000 10000001 ..... ..... ..... ..... @ffff +fmadd_d 0000 10000010 ..... ..... ..... ..... @ffff +fmsub_s 0000 10000101 ..... ..... ..... ..... @ffff +fmsub_d 0000 10000110 ..... ..... ..... ..... @ffff +fnmadd_s 0000 10001001 ..... ..... ..... ..... @ffff +fnmadd_d 0000 10001010 ..... ..... ..... ..... @ffff +fnmsub_s 0000 10001101 ..... ..... ..... ..... @ffff +fnmsub_d 0000 10001110 ..... ..... ..... ..... @ffff +fmax_s 0000 00010000 10001 ..... ..... ..... @fff +fmax_d 0000 00010000 10010 ..... ..... ..... @fff +fmin_s 0000 00010000 10101 ..... ..... ..... @fff +fmin_d 0000 00010000 10110 ..... ..... ..... @fff +fmaxa_s 0000 00010000 11001 ..... ..... ..... @fff +fmaxa_d 0000 00010000 11010 ..... ..... ..... @fff +fmina_s 0000 00010000 11101 ..... ..... ..... @fff +fmina_d 0000 00010000 11110 ..... ..... ..... @fff +fabs_s 0000 00010001 01000 00001 ..... ..... @ff +fabs_d 0000 00010001 01000 00010 ..... ..... @ff +fneg_s 0000 00010001 01000 00101 ..... ..... @ff +fneg_d 0000 00010001 01000 00110 ..... ..... @ff +fsqrt_s 0000 00010001 01000 10001 ..... ..... @ff +fsqrt_d 0000 00010001 01000 10010 ..... ..... @ff +frecip_s 0000 00010001 01000 10101 ..... ..... @ff +frecip_d 0000 00010001 01000 10110 ..... ..... @ff +frsqrt_s 0000 00010001 01000 11001 ..... ..... @ff +frsqrt_d 0000 00010001 01000 11010 ..... ..... @ff +fscaleb_s 0000 00010001 00001 ..... ..... ..... @fff +fscaleb_d 0000 00010001 00010 ..... ..... ..... @fff +flogb_s 0000 00010001 01000 01001 ..... ..... @ff +flogb_d 0000 00010001 01000 01010 ..... ..... @ff +fcopysign_s 0000 00010001 00101 ..... ..... ..... @fff +fcopysign_d 0000 00010001 00110 ..... ..... ..... @fff +fclass_s 0000 00010001 01000 01101 ..... ..... @ff +fclass_d 0000 00010001 01000 01110 ..... ..... @ff diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h index 9f02287a90..43b865ec21 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -18,4 +18,6 @@ void G_NORETURN do_raise_exception(CPULoongArchState *env, const char *loongarch_exception_name(int32_t exception); +void restore_fp_status(CPULoongArchState *env); + #endif diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index b946dc4d5f..050d5f2c3b 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -15,6 +15,7 @@ #include "exec/translator.h" #include "exec/log.h" #include "qemu/qemu-print.h" +#include "fpu/softfloat.h" #include "translate.h" #include "internals.h" @@ -36,6 +37,15 @@ static inline int shl_2(DisasContext *ctx, int x) return x << 2; } +/* + * LoongArch the upper 32 bits are undefined ("can be any value"). + * QEMU chooses to nanbox, because it is most likely to show guest bugs early. + */ +static void gen_nanbox_s(TCGv_i64 out, TCGv_i64 in) +{ + tcg_gen_ori_i64(out, in, MAKE_64BIT_MASK(32, 32)); +} + void generate_exception(DisasContext *ctx, int excp) { tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); @@ -156,6 +166,7 @@ static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext) #include "insn_trans/trans_memory.c.inc" #include "insn_trans/trans_atomic.c.inc" #include "insn_trans/trans_extra.c.inc" +#include "insn_trans/trans_farith.c.inc" static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { From 9b7410763aedcd99b7f2302c564c8778179ef347 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 6 Jun 2022 20:43:01 +0800 Subject: [PATCH 818/935] target/loongarch: Add floating point comparison instruction translation This includes: - FCMP.cond.{S/D} Signed-off-by: Song Gao Signed-off-by: Xiaojuan Yang Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-12-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/fpu_helper.c | 60 ++++++++++++++++++++ target/loongarch/helper.h | 9 +++ target/loongarch/insn_trans/trans_fcmp.c.inc | 56 ++++++++++++++++++ target/loongarch/insns.decode | 8 +++ target/loongarch/internals.h | 5 ++ target/loongarch/translate.c | 1 + 6 files changed, 139 insertions(+) create mode 100644 target/loongarch/insn_trans/trans_fcmp.c.inc diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c index d7442cc188..1e514cce74 100644 --- a/target/loongarch/fpu_helper.c +++ b/target/loongarch/fpu_helper.c @@ -401,3 +401,63 @@ uint64_t helper_fmuladd_d(CPULoongArchState *env, uint64_t fj, update_fcsr0(env, GETPC()); return fd; } + +static uint64_t fcmp_common(CPULoongArchState *env, FloatRelation cmp, + uint32_t flags) +{ + bool ret; + + switch (cmp) { + case float_relation_less: + ret = (flags & FCMP_LT); + break; + case float_relation_equal: + ret = (flags & FCMP_EQ); + break; + case float_relation_greater: + ret = (flags & FCMP_GT); + break; + case float_relation_unordered: + ret = (flags & FCMP_UN); + break; + default: + g_assert_not_reached(); + } + update_fcsr0(env, GETPC()); + + return ret; +} + +/* fcmp_cXXX_s */ +uint64_t helper_fcmp_c_s(CPULoongArchState *env, uint64_t fj, + uint64_t fk, uint32_t flags) +{ + FloatRelation cmp = float32_compare_quiet((uint32_t)fj, + (uint32_t)fk, &env->fp_status); + return fcmp_common(env, cmp, flags); +} + +/* fcmp_sXXX_s */ +uint64_t helper_fcmp_s_s(CPULoongArchState *env, uint64_t fj, + uint64_t fk, uint32_t flags) +{ + FloatRelation cmp = float32_compare((uint32_t)fj, + (uint32_t)fk, &env->fp_status); + return fcmp_common(env, cmp, flags); +} + +/* fcmp_cXXX_d */ +uint64_t helper_fcmp_c_d(CPULoongArchState *env, uint64_t fj, + uint64_t fk, uint32_t flags) +{ + FloatRelation cmp = float64_compare_quiet(fj, fk, &env->fp_status); + return fcmp_common(env, cmp, flags); +} + +/* fcmp_sXXX_d */ +uint64_t helper_fcmp_s_d(CPULoongArchState *env, uint64_t fj, + uint64_t fk, uint32_t flags) +{ + FloatRelation cmp = float64_compare(fj, fk, &env->fp_status); + return fcmp_common(env, cmp, flags); +} diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index 840bad9b2f..25a891bf8b 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -52,3 +52,12 @@ DEF_HELPER_FLAGS_2(frecip_d, TCG_CALL_NO_WG, i64, env, i64) DEF_HELPER_FLAGS_2(fclass_s, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_2(fclass_d, TCG_CALL_NO_RWG_SE, i64, env, i64) + +/* fcmp.cXXX.s */ +DEF_HELPER_4(fcmp_c_s, i64, env, i64, i64, i32) +/* fcmp.sXXX.s */ +DEF_HELPER_4(fcmp_s_s, i64, env, i64, i64, i32) +/* fcmp.cXXX.d */ +DEF_HELPER_4(fcmp_c_d, i64, env, i64, i64, i32) +/* fcmp.sXXX.d */ +DEF_HELPER_4(fcmp_s_d, i64, env, i64, i64, i32) diff --git a/target/loongarch/insn_trans/trans_fcmp.c.inc b/target/loongarch/insn_trans/trans_fcmp.c.inc new file mode 100644 index 0000000000..93a6a2230f --- /dev/null +++ b/target/loongarch/insn_trans/trans_fcmp.c.inc @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +/* bit0(signaling/quiet) bit1(lt) bit2(eq) bit3(un) bit4(neq) */ +static uint32_t get_fcmp_flags(int cond) +{ + uint32_t flags = 0; + + if (cond & 0x1) { + flags |= FCMP_LT; + } + if (cond & 0x2) { + flags |= FCMP_EQ; + } + if (cond & 0x4) { + flags |= FCMP_UN; + } + if (cond & 0x8) { + flags |= FCMP_GT | FCMP_LT; + } + return flags; +} + +static bool trans_fcmp_cond_s(DisasContext *ctx, arg_fcmp_cond_s *a) +{ + TCGv var = tcg_temp_new(); + uint32_t flags; + void (*fn)(TCGv, TCGv_env, TCGv, TCGv, TCGv_i32); + + fn = (a->fcond & 1 ? gen_helper_fcmp_s_s : gen_helper_fcmp_c_s); + flags = get_fcmp_flags(a->fcond >> 1); + + fn(var, cpu_env, cpu_fpr[a->fj], cpu_fpr[a->fk], tcg_constant_i32(flags)); + + tcg_gen_st8_tl(var, cpu_env, offsetof(CPULoongArchState, cf[a->cd])); + tcg_temp_free(var); + return true; +} + +static bool trans_fcmp_cond_d(DisasContext *ctx, arg_fcmp_cond_d *a) +{ + TCGv var = tcg_temp_new(); + uint32_t flags; + void (*fn)(TCGv, TCGv_env, TCGv, TCGv, TCGv_i32); + fn = (a->fcond & 1 ? gen_helper_fcmp_s_d : gen_helper_fcmp_c_d); + flags = get_fcmp_flags(a->fcond >> 1); + + fn(var, cpu_env, cpu_fpr[a->fj], cpu_fpr[a->fk], tcg_constant_i32(flags)); + + tcg_gen_st8_tl(var, cpu_env, offsetof(CPULoongArchState, cf[a->cd])); + + tcg_temp_free(var); + return true; +} diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index 6455e09ebe..d7ed80b0b9 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -26,6 +26,7 @@ &ff fd fj &fff fd fj fk &ffff fd fj fk fa +&cff_fcond cd fj fk fcond # # Formats @@ -50,6 +51,7 @@ @ff .... ........ ..... ..... fj:5 fd:5 &ff @fff .... ........ ..... fk:5 fj:5 fd:5 &fff @ffff .... ........ fa:5 fk:5 fj:5 fd:5 &ffff +@cff_fcond .... ........ fcond:5 fk:5 fj:5 .. cd:3 &cff_fcond # # Fixed point arithmetic operation instruction @@ -308,3 +310,9 @@ fcopysign_s 0000 00010001 00101 ..... ..... ..... @fff fcopysign_d 0000 00010001 00110 ..... ..... ..... @fff fclass_s 0000 00010001 01000 01101 ..... ..... @ff fclass_d 0000 00010001 01000 01110 ..... ..... @ff + +# +# Floating point compare instruction +# +fcmp_cond_s 0000 11000001 ..... ..... ..... 00 ... @cff_fcond +fcmp_cond_d 0000 11000010 ..... ..... ..... 00 ... @cff_fcond diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h index 43b865ec21..1a3b39e0be 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -8,6 +8,11 @@ #ifndef LOONGARCH_INTERNALS_H #define LOONGARCH_INTERNALS_H +#define FCMP_LT 0b0001 /* fp0 < fp1 */ +#define FCMP_EQ 0b0010 /* fp0 = fp1 */ +#define FCMP_UN 0b0100 /* unordered */ +#define FCMP_GT 0b1000 /* fp0 > fp1 */ + void loongarch_translate_init(void); void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags); diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 050d5f2c3b..a338db50b7 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -167,6 +167,7 @@ static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext) #include "insn_trans/trans_atomic.c.inc" #include "insn_trans/trans_extra.c.inc" #include "insn_trans/trans_farith.c.inc" +#include "insn_trans/trans_fcmp.c.inc" static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { From 7c1f88703d216cc6b2e30689fbc295423ca13d40 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 6 Jun 2022 20:43:02 +0800 Subject: [PATCH 819/935] target/loongarch: Add floating point conversion instruction translation This includes: - FCVT.S.D, FCVT.D.S - FFINT.{S/D}.{W/L}, FTINT.{W/L}.{S/D} - FTINT{RM/RP/RZ/RNE}.{W/L}.{S/D} - FRINT.{S/D} Signed-off-by: Song Gao Signed-off-by: Xiaojuan Yang Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-13-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/fpu_helper.c | 393 +++++++++++++++++++ target/loongarch/helper.h | 29 ++ target/loongarch/insn_trans/trans_fcnv.c.inc | 33 ++ target/loongarch/insns.decode | 32 ++ target/loongarch/translate.c | 1 + 5 files changed, 488 insertions(+) create mode 100644 target/loongarch/insn_trans/trans_fcnv.c.inc diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c index 1e514cce74..81466678eb 100644 --- a/target/loongarch/fpu_helper.c +++ b/target/loongarch/fpu_helper.c @@ -461,3 +461,396 @@ uint64_t helper_fcmp_s_d(CPULoongArchState *env, uint64_t fj, FloatRelation cmp = float64_compare(fj, fk, &env->fp_status); return fcmp_common(env, cmp, flags); } + +/* floating point conversion */ +uint64_t helper_fcvt_s_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = nanbox_s(float64_to_float32(fj, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_fcvt_d_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = float32_to_float64((uint32_t)fj, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ffint_s_w(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = nanbox_s(int32_to_float32((int32_t)fj, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ffint_s_l(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = nanbox_s(int64_to_float32(fj, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ffint_d_w(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = int32_to_float64((int32_t)fj, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ffint_d_l(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = int64_to_float64(fj, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_frint_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = (uint64_t)(float32_round_to_int((uint32_t)fj, &env->fp_status)); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_frint_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = float64_round_to_int(fj, &env->fp_status); + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrm_l_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_down, &env->fp_status); + fd = float64_to_int64(fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & + (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrm_l_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_down, &env->fp_status); + fd = float32_to_int64((uint32_t)fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & + (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrm_w_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_down, &env->fp_status); + fd = (uint64_t)float64_to_int32(fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & + (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrm_w_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_down, &env->fp_status); + fd = (uint64_t)float32_to_int32((uint32_t)fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & + (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrp_l_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_up, &env->fp_status); + fd = float64_to_int64(fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & + (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrp_l_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_up, &env->fp_status); + fd = float32_to_int64((uint32_t)fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & + (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrp_w_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_up, &env->fp_status); + fd = (uint64_t)float64_to_int32(fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & + (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrp_w_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_up, &env->fp_status); + fd = (uint64_t)float32_to_int32((uint32_t)fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & + (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrz_l_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + fd = float64_to_int64_round_to_zero(fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & + (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrz_l_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + fd = float32_to_int64_round_to_zero((uint32_t)fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & + (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrz_w_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + fd = (uint64_t)float64_to_int32_round_to_zero(fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & + (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrz_w_s(CPULoongArchState *env, uint64_t fj) +{ + uint32_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + fd = float32_to_int32_round_to_zero((uint32_t)fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & + (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return (uint64_t)fd; +} + +uint64_t helper_ftintrne_l_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + fd = float64_to_int64(fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & + (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrne_l_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + fd = float32_to_int64((uint32_t)fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & + (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrne_w_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + fd = (uint64_t)float64_to_int32(fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & + (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftintrne_w_s(CPULoongArchState *env, uint64_t fj) +{ + uint32_t fd; + FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); + + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + fd = float32_to_int32((uint32_t)fj, &env->fp_status); + set_float_rounding_mode(old_mode, &env->fp_status); + + if (get_float_exception_flags(&env->fp_status) & + (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return (uint64_t)fd; +} + +uint64_t helper_ftint_l_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = float64_to_int64(fj, &env->fp_status); + if (get_float_exception_flags(&env->fp_status) & + (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftint_l_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = float32_to_int64((uint32_t)fj, &env->fp_status); + if (get_float_exception_flags(&env->fp_status) & + (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftint_w_s(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = (uint64_t)float32_to_int32((uint32_t)fj, &env->fp_status); + if (get_float_exception_flags(&env->fp_status) + & (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return fd; +} + +uint64_t helper_ftint_w_d(CPULoongArchState *env, uint64_t fj) +{ + uint64_t fd; + + fd = (uint64_t)float64_to_int32(fj, &env->fp_status); + if (get_float_exception_flags(&env->fp_status) + & (float_flag_invalid | float_flag_overflow)) { + fd = FLOAT_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return fd; +} diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index 25a891bf8b..1e8749433a 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -61,3 +61,32 @@ DEF_HELPER_4(fcmp_s_s, i64, env, i64, i64, i32) DEF_HELPER_4(fcmp_c_d, i64, env, i64, i64, i32) /* fcmp.sXXX.d */ DEF_HELPER_4(fcmp_s_d, i64, env, i64, i64, i32) + +DEF_HELPER_2(fcvt_d_s, i64, env, i64) +DEF_HELPER_2(fcvt_s_d, i64, env, i64) +DEF_HELPER_2(ffint_d_w, i64, env, i64) +DEF_HELPER_2(ffint_d_l, i64, env, i64) +DEF_HELPER_2(ffint_s_w, i64, env, i64) +DEF_HELPER_2(ffint_s_l, i64, env, i64) +DEF_HELPER_2(ftintrm_l_s, i64, env, i64) +DEF_HELPER_2(ftintrm_l_d, i64, env, i64) +DEF_HELPER_2(ftintrm_w_s, i64, env, i64) +DEF_HELPER_2(ftintrm_w_d, i64, env, i64) +DEF_HELPER_2(ftintrp_l_s, i64, env, i64) +DEF_HELPER_2(ftintrp_l_d, i64, env, i64) +DEF_HELPER_2(ftintrp_w_s, i64, env, i64) +DEF_HELPER_2(ftintrp_w_d, i64, env, i64) +DEF_HELPER_2(ftintrz_l_s, i64, env, i64) +DEF_HELPER_2(ftintrz_l_d, i64, env, i64) +DEF_HELPER_2(ftintrz_w_s, i64, env, i64) +DEF_HELPER_2(ftintrz_w_d, i64, env, i64) +DEF_HELPER_2(ftintrne_l_s, i64, env, i64) +DEF_HELPER_2(ftintrne_l_d, i64, env, i64) +DEF_HELPER_2(ftintrne_w_s, i64, env, i64) +DEF_HELPER_2(ftintrne_w_d, i64, env, i64) +DEF_HELPER_2(ftint_l_s, i64, env, i64) +DEF_HELPER_2(ftint_l_d, i64, env, i64) +DEF_HELPER_2(ftint_w_s, i64, env, i64) +DEF_HELPER_2(ftint_w_d, i64, env, i64) +DEF_HELPER_2(frint_s, i64, env, i64) +DEF_HELPER_2(frint_d, i64, env, i64) diff --git a/target/loongarch/insn_trans/trans_fcnv.c.inc b/target/loongarch/insn_trans/trans_fcnv.c.inc new file mode 100644 index 0000000000..c1c6918ad1 --- /dev/null +++ b/target/loongarch/insn_trans/trans_fcnv.c.inc @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +TRANS(fcvt_s_d, gen_ff, gen_helper_fcvt_s_d) +TRANS(fcvt_d_s, gen_ff, gen_helper_fcvt_d_s) +TRANS(ftintrm_w_s, gen_ff, gen_helper_ftintrm_w_s) +TRANS(ftintrm_w_d, gen_ff, gen_helper_ftintrm_w_d) +TRANS(ftintrm_l_s, gen_ff, gen_helper_ftintrm_l_s) +TRANS(ftintrm_l_d, gen_ff, gen_helper_ftintrm_l_d) +TRANS(ftintrp_w_s, gen_ff, gen_helper_ftintrp_w_s) +TRANS(ftintrp_w_d, gen_ff, gen_helper_ftintrp_w_d) +TRANS(ftintrp_l_s, gen_ff, gen_helper_ftintrp_l_s) +TRANS(ftintrp_l_d, gen_ff, gen_helper_ftintrp_l_d) +TRANS(ftintrz_w_s, gen_ff, gen_helper_ftintrz_w_s) +TRANS(ftintrz_w_d, gen_ff, gen_helper_ftintrz_w_d) +TRANS(ftintrz_l_s, gen_ff, gen_helper_ftintrz_l_s) +TRANS(ftintrz_l_d, gen_ff, gen_helper_ftintrz_l_d) +TRANS(ftintrne_w_s, gen_ff, gen_helper_ftintrne_w_s) +TRANS(ftintrne_w_d, gen_ff, gen_helper_ftintrne_w_d) +TRANS(ftintrne_l_s, gen_ff, gen_helper_ftintrne_l_s) +TRANS(ftintrne_l_d, gen_ff, gen_helper_ftintrne_l_d) +TRANS(ftint_w_s, gen_ff, gen_helper_ftint_w_s) +TRANS(ftint_w_d, gen_ff, gen_helper_ftint_w_d) +TRANS(ftint_l_s, gen_ff, gen_helper_ftint_l_s) +TRANS(ftint_l_d, gen_ff, gen_helper_ftint_l_d) +TRANS(ffint_s_w, gen_ff, gen_helper_ffint_s_w) +TRANS(ffint_s_l, gen_ff, gen_helper_ffint_s_l) +TRANS(ffint_d_w, gen_ff, gen_helper_ffint_d_w) +TRANS(ffint_d_l, gen_ff, gen_helper_ffint_d_l) +TRANS(frint_s, gen_ff, gen_helper_frint_s) +TRANS(frint_d, gen_ff, gen_helper_frint_d) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index d7ed80b0b9..b9f135d36f 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -316,3 +316,35 @@ fclass_d 0000 00010001 01000 01110 ..... ..... @ff # fcmp_cond_s 0000 11000001 ..... ..... ..... 00 ... @cff_fcond fcmp_cond_d 0000 11000010 ..... ..... ..... 00 ... @cff_fcond + +# +# Floating point conversion instruction +# +fcvt_s_d 0000 00010001 10010 00110 ..... ..... @ff +fcvt_d_s 0000 00010001 10010 01001 ..... ..... @ff +ftintrm_w_s 0000 00010001 10100 00001 ..... ..... @ff +ftintrm_w_d 0000 00010001 10100 00010 ..... ..... @ff +ftintrm_l_s 0000 00010001 10100 01001 ..... ..... @ff +ftintrm_l_d 0000 00010001 10100 01010 ..... ..... @ff +ftintrp_w_s 0000 00010001 10100 10001 ..... ..... @ff +ftintrp_w_d 0000 00010001 10100 10010 ..... ..... @ff +ftintrp_l_s 0000 00010001 10100 11001 ..... ..... @ff +ftintrp_l_d 0000 00010001 10100 11010 ..... ..... @ff +ftintrz_w_s 0000 00010001 10101 00001 ..... ..... @ff +ftintrz_w_d 0000 00010001 10101 00010 ..... ..... @ff +ftintrz_l_s 0000 00010001 10101 01001 ..... ..... @ff +ftintrz_l_d 0000 00010001 10101 01010 ..... ..... @ff +ftintrne_w_s 0000 00010001 10101 10001 ..... ..... @ff +ftintrne_w_d 0000 00010001 10101 10010 ..... ..... @ff +ftintrne_l_s 0000 00010001 10101 11001 ..... ..... @ff +ftintrne_l_d 0000 00010001 10101 11010 ..... ..... @ff +ftint_w_s 0000 00010001 10110 00001 ..... ..... @ff +ftint_w_d 0000 00010001 10110 00010 ..... ..... @ff +ftint_l_s 0000 00010001 10110 01001 ..... ..... @ff +ftint_l_d 0000 00010001 10110 01010 ..... ..... @ff +ffint_s_w 0000 00010001 11010 00100 ..... ..... @ff +ffint_s_l 0000 00010001 11010 00110 ..... ..... @ff +ffint_d_w 0000 00010001 11010 01000 ..... ..... @ff +ffint_d_l 0000 00010001 11010 01010 ..... ..... @ff +frint_s 0000 00010001 11100 10001 ..... ..... @ff +frint_d 0000 00010001 11100 10010 ..... ..... @ff diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index a338db50b7..26ef1e366c 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -168,6 +168,7 @@ static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext) #include "insn_trans/trans_extra.c.inc" #include "insn_trans/trans_farith.c.inc" #include "insn_trans/trans_fcmp.c.inc" +#include "insn_trans/trans_fcnv.c.inc" static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { From b7dabd5624326b116d6147c659de22037f357cf8 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 6 Jun 2022 20:43:03 +0800 Subject: [PATCH 820/935] target/loongarch: Add floating point move instruction translation This includes: - FMOV.{S/D} - FSEL - MOVGR2FR.{W/D}, MOVGR2FRH.W - MOVFR2GR.{S/D}, MOVFRH2GR.S - MOVGR2FCSR, MOVFCSR2GR - MOVFR2CF, MOVCF2FR - MOVGR2CF, MOVCF2GR Signed-off-by: Song Gao Signed-off-by: Xiaojuan Yang Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-14-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/fpu_helper.c | 6 + target/loongarch/helper.h | 2 + target/loongarch/insn_trans/trans_fmov.c.inc | 157 +++++++++++++++++++ target/loongarch/insns.decode | 37 +++++ target/loongarch/translate.c | 1 + 5 files changed, 203 insertions(+) create mode 100644 target/loongarch/insn_trans/trans_fmov.c.inc diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c index 81466678eb..3d0cb8dd0d 100644 --- a/target/loongarch/fpu_helper.c +++ b/target/loongarch/fpu_helper.c @@ -854,3 +854,9 @@ uint64_t helper_ftint_w_d(CPULoongArchState *env, uint64_t fj) update_fcsr0(env, GETPC()); return fd; } + +void helper_set_rounding_mode(CPULoongArchState *env, uint32_t fcsr0) +{ + set_float_rounding_mode(ieee_rm[(fcsr0 >> FCSR0_RM) & 0x3], + &env->fp_status); +} diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index 1e8749433a..da1a2bced7 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -90,3 +90,5 @@ DEF_HELPER_2(ftint_w_s, i64, env, i64) DEF_HELPER_2(ftint_w_d, i64, env, i64) DEF_HELPER_2(frint_s, i64, env, i64) DEF_HELPER_2(frint_d, i64, env, i64) + +DEF_HELPER_FLAGS_2(set_rounding_mode, TCG_CALL_NO_RWG, void, env, i32) diff --git a/target/loongarch/insn_trans/trans_fmov.c.inc b/target/loongarch/insn_trans/trans_fmov.c.inc new file mode 100644 index 0000000000..24753d4568 --- /dev/null +++ b/target/loongarch/insn_trans/trans_fmov.c.inc @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +static const uint32_t fcsr_mask[4] = { + UINT32_MAX, FCSR0_M1, FCSR0_M2, FCSR0_M3 +}; + +static bool trans_fsel(DisasContext *ctx, arg_fsel *a) +{ + TCGv zero = tcg_constant_tl(0); + TCGv cond = tcg_temp_new(); + + tcg_gen_ld8u_tl(cond, cpu_env, offsetof(CPULoongArchState, cf[a->ca])); + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_fpr[a->fd], cond, zero, + cpu_fpr[a->fj], cpu_fpr[a->fk]); + tcg_temp_free(cond); + + return true; +} + +static bool gen_f2f(DisasContext *ctx, arg_ff *a, + void (*func)(TCGv, TCGv), bool nanbox) +{ + TCGv dest = cpu_fpr[a->fd]; + TCGv src = cpu_fpr[a->fj]; + + func(dest, src); + if (nanbox) { + gen_nanbox_s(cpu_fpr[a->fd], cpu_fpr[a->fd]); + } + + return true; +} + +static bool gen_r2f(DisasContext *ctx, arg_fr *a, + void (*func)(TCGv, TCGv)) +{ + TCGv src = gpr_src(ctx, a->rj, EXT_NONE); + + func(cpu_fpr[a->fd], src); + return true; +} + +static bool gen_f2r(DisasContext *ctx, arg_rf *a, + void (*func)(TCGv, TCGv)) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + + func(dest, cpu_fpr[a->fj]); + gen_set_gpr(a->rd, dest, EXT_NONE); + + return true; +} + +static bool trans_movgr2fcsr(DisasContext *ctx, arg_movgr2fcsr *a) +{ + uint32_t mask = fcsr_mask[a->fcsrd]; + TCGv Rj = gpr_src(ctx, a->rj, EXT_NONE); + + if (mask == UINT32_MAX) { + tcg_gen_extrl_i64_i32(cpu_fcsr0, Rj); + } else { + TCGv_i32 temp = tcg_temp_new_i32(); + + tcg_gen_extrl_i64_i32(temp, Rj); + tcg_gen_andi_i32(temp, temp, mask); + tcg_gen_andi_i32(cpu_fcsr0, cpu_fcsr0, ~mask); + tcg_gen_or_i32(cpu_fcsr0, cpu_fcsr0, temp); + tcg_temp_free_i32(temp); + + /* + * Install the new rounding mode to fpu_status, if changed. + * Note that FCSR3 is exactly the rounding mode field. + */ + if (mask != FCSR0_M3) { + return true; + } + } + gen_helper_set_rounding_mode(cpu_env, cpu_fcsr0); + + return true; +} + +static bool trans_movfcsr2gr(DisasContext *ctx, arg_movfcsr2gr *a) +{ + TCGv_i32 temp = tcg_temp_new_i32(); + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + + tcg_gen_andi_i32(temp, cpu_fcsr0, fcsr_mask[a->fcsrs]); + tcg_gen_ext_i32_i64(dest, temp); + gen_set_gpr(a->rd, dest, EXT_NONE); + tcg_temp_free_i32(temp); + + return true; +} + +static void gen_movgr2fr_w(TCGv dest, TCGv src) +{ + tcg_gen_deposit_i64(dest, dest, src, 0, 32); +} + +static void gen_movgr2frh_w(TCGv dest, TCGv src) +{ + tcg_gen_deposit_i64(dest, dest, src, 32, 32); +} + +static void gen_movfrh2gr_s(TCGv dest, TCGv src) +{ + tcg_gen_sextract_tl(dest, src, 32, 32); +} + +static bool trans_movfr2cf(DisasContext *ctx, arg_movfr2cf *a) +{ + TCGv t0 = tcg_temp_new(); + + tcg_gen_andi_tl(t0, cpu_fpr[a->fj], 0x1); + tcg_gen_st8_tl(t0, cpu_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); + tcg_temp_free(t0); + + return true; +} + +static bool trans_movcf2fr(DisasContext *ctx, arg_movcf2fr *a) +{ + tcg_gen_ld8u_tl(cpu_fpr[a->fd], cpu_env, + offsetof(CPULoongArchState, cf[a->cj & 0x7])); + return true; +} + +static bool trans_movgr2cf(DisasContext *ctx, arg_movgr2cf *a) +{ + TCGv t0 = tcg_temp_new(); + + tcg_gen_andi_tl(t0, gpr_src(ctx, a->rj, EXT_NONE), 0x1); + tcg_gen_st8_tl(t0, cpu_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); + tcg_temp_free(t0); + + return true; +} + +static bool trans_movcf2gr(DisasContext *ctx, arg_movcf2gr *a) +{ + tcg_gen_ld8u_tl(gpr_dst(ctx, a->rd, EXT_NONE), cpu_env, + offsetof(CPULoongArchState, cf[a->cj & 0x7])); + return true; +} + +TRANS(fmov_s, gen_f2f, tcg_gen_mov_tl, true) +TRANS(fmov_d, gen_f2f, tcg_gen_mov_tl, false) +TRANS(movgr2fr_w, gen_r2f, gen_movgr2fr_w) +TRANS(movgr2fr_d, gen_r2f, tcg_gen_mov_tl) +TRANS(movgr2frh_w, gen_r2f, gen_movgr2frh_w) +TRANS(movfr2gr_s, gen_f2r, tcg_gen_ext32s_tl) +TRANS(movfr2gr_d, gen_f2r, tcg_gen_mov_tl) +TRANS(movfrh2gr_s, gen_f2r, gen_movfrh2gr_s) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index b9f135d36f..c62a4f6dcd 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -27,6 +27,15 @@ &fff fd fj fk &ffff fd fj fk fa &cff_fcond cd fj fk fcond +&fffc fd fj fk ca +&fr fd rj +&rf rd fj +&fcsrd_r fcsrd rj +&r_fcsrs rd fcsrs +&cf cd fj +&fc fd cj +&cr cd rj +&rc rd cj # # Formats @@ -52,6 +61,15 @@ @fff .... ........ ..... fk:5 fj:5 fd:5 &fff @ffff .... ........ fa:5 fk:5 fj:5 fd:5 &ffff @cff_fcond .... ........ fcond:5 fk:5 fj:5 .. cd:3 &cff_fcond +@fffc .... ........ .. ca:3 fk:5 fj:5 fd:5 &fffc +@fr .... ........ ..... ..... rj:5 fd:5 &fr +@rf .... ........ ..... ..... fj:5 rd:5 &rf +@fcsrd_r .... ........ ..... ..... rj:5 fcsrd:5 &fcsrd_r +@r_fcsrs .... ........ ..... ..... fcsrs:5 rd:5 &r_fcsrs +@cf .... ........ ..... ..... fj:5 .. cd:3 &cf +@fc .... ........ ..... ..... .. cj:3 fd:5 &fc +@cr .... ........ ..... ..... rj:5 .. cd:3 &cr +@rc .... ........ ..... ..... .. cj:3 rd:5 &rc # # Fixed point arithmetic operation instruction @@ -348,3 +366,22 @@ ffint_d_w 0000 00010001 11010 01000 ..... ..... @ff ffint_d_l 0000 00010001 11010 01010 ..... ..... @ff frint_s 0000 00010001 11100 10001 ..... ..... @ff frint_d 0000 00010001 11100 10010 ..... ..... @ff + +# +# Floating point move instruction +# +fmov_s 0000 00010001 01001 00101 ..... ..... @ff +fmov_d 0000 00010001 01001 00110 ..... ..... @ff +fsel 0000 11010000 00 ... ..... ..... ..... @fffc +movgr2fr_w 0000 00010001 01001 01001 ..... ..... @fr +movgr2fr_d 0000 00010001 01001 01010 ..... ..... @fr +movgr2frh_w 0000 00010001 01001 01011 ..... ..... @fr +movfr2gr_s 0000 00010001 01001 01101 ..... ..... @rf +movfr2gr_d 0000 00010001 01001 01110 ..... ..... @rf +movfrh2gr_s 0000 00010001 01001 01111 ..... ..... @rf +movgr2fcsr 0000 00010001 01001 10000 ..... ..... @fcsrd_r +movfcsr2gr 0000 00010001 01001 10010 ..... ..... @r_fcsrs +movfr2cf 0000 00010001 01001 10100 ..... 00 ... @cf +movcf2fr 0000 00010001 01001 10101 00 ... ..... @fc +movgr2cf 0000 00010001 01001 10110 ..... 00 ... @cr +movcf2gr 0000 00010001 01001 10111 00 ... ..... @rc diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 26ef1e366c..26d60b50fd 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -169,6 +169,7 @@ static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext) #include "insn_trans/trans_farith.c.inc" #include "insn_trans/trans_fcmp.c.inc" #include "insn_trans/trans_fcnv.c.inc" +#include "insn_trans/trans_fmov.c.inc" static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { From e616bdfd0159965bd65f12be83ebf28dc8c44bae Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 6 Jun 2022 20:43:04 +0800 Subject: [PATCH 821/935] target/loongarch: Add floating point load/store instruction translation This includes: - FLD.{S/D}, FST.{S/D} - FLDX.{S/D}, FSTX.{S/D} - FLD{GT/LE}.{S/D}, FST{GT/LE}.{S/D} Signed-off-by: Song Gao Signed-off-by: Xiaojuan Yang Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-15-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- .../loongarch/insn_trans/trans_fmemory.c.inc | 153 ++++++++++++++++++ target/loongarch/insns.decode | 24 +++ target/loongarch/translate.c | 1 + 3 files changed, 178 insertions(+) create mode 100644 target/loongarch/insn_trans/trans_fmemory.c.inc diff --git a/target/loongarch/insn_trans/trans_fmemory.c.inc b/target/loongarch/insn_trans/trans_fmemory.c.inc new file mode 100644 index 0000000000..74ee98f63a --- /dev/null +++ b/target/loongarch/insn_trans/trans_fmemory.c.inc @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +static void maybe_nanbox_load(TCGv freg, MemOp mop) +{ + if ((mop & MO_SIZE) == MO_32) { + gen_nanbox_s(freg, freg); + } +} + +static bool gen_fload_i(DisasContext *ctx, arg_fr_i *a, MemOp mop) +{ + TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); + TCGv temp = NULL; + + if (a->imm) { + temp = tcg_temp_new(); + tcg_gen_addi_tl(temp, addr, a->imm); + addr = temp; + } + + tcg_gen_qemu_ld_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop); + maybe_nanbox_load(cpu_fpr[a->fd], mop); + + if (temp) { + tcg_temp_free(temp); + } + + return true; +} + +static bool gen_fstore_i(DisasContext *ctx, arg_fr_i *a, MemOp mop) +{ + TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); + TCGv temp = NULL; + + if (a->imm) { + temp = tcg_temp_new(); + tcg_gen_addi_tl(temp, addr, a->imm); + addr = temp; + } + + tcg_gen_qemu_st_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop); + + if (temp) { + tcg_temp_free(temp); + } + return true; +} + +static bool gen_floadx(DisasContext *ctx, arg_frr *a, MemOp mop) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + TCGv addr = tcg_temp_new(); + + tcg_gen_add_tl(addr, src1, src2); + tcg_gen_qemu_ld_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop); + maybe_nanbox_load(cpu_fpr[a->fd], mop); + tcg_temp_free(addr); + + return true; +} + +static bool gen_fstorex(DisasContext *ctx, arg_frr *a, MemOp mop) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + TCGv addr = tcg_temp_new(); + + tcg_gen_add_tl(addr, src1, src2); + tcg_gen_qemu_st_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop); + tcg_temp_free(addr); + + return true; +} + +static bool gen_fload_gt(DisasContext *ctx, arg_frr *a, MemOp mop) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + TCGv addr = tcg_temp_new(); + + gen_helper_asrtgt_d(cpu_env, src1, src2); + tcg_gen_add_tl(addr, src1, src2); + tcg_gen_qemu_ld_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop); + maybe_nanbox_load(cpu_fpr[a->fd], mop); + tcg_temp_free(addr); + + return true; +} + +static bool gen_fstore_gt(DisasContext *ctx, arg_frr *a, MemOp mop) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + TCGv addr = tcg_temp_new(); + + gen_helper_asrtgt_d(cpu_env, src1, src2); + tcg_gen_add_tl(addr, src1, src2); + tcg_gen_qemu_st_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop); + tcg_temp_free(addr); + + return true; +} + +static bool gen_fload_le(DisasContext *ctx, arg_frr *a, MemOp mop) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + TCGv addr = tcg_temp_new(); + + gen_helper_asrtle_d(cpu_env, src1, src2); + tcg_gen_add_tl(addr, src1, src2); + tcg_gen_qemu_ld_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop); + maybe_nanbox_load(cpu_fpr[a->fd], mop); + tcg_temp_free(addr); + + return true; +} + +static bool gen_fstore_le(DisasContext *ctx, arg_frr *a, MemOp mop) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + TCGv addr = tcg_temp_new(); + + gen_helper_asrtle_d(cpu_env, src1, src2); + tcg_gen_add_tl(addr, src1, src2); + tcg_gen_qemu_st_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop); + tcg_temp_free(addr); + + return true; +} + +TRANS(fld_s, gen_fload_i, MO_TEUL) +TRANS(fst_s, gen_fstore_i, MO_TEUL) +TRANS(fld_d, gen_fload_i, MO_TEUQ) +TRANS(fst_d, gen_fstore_i, MO_TEUQ) +TRANS(fldx_s, gen_floadx, MO_TEUL) +TRANS(fldx_d, gen_floadx, MO_TEUQ) +TRANS(fstx_s, gen_fstorex, MO_TEUL) +TRANS(fstx_d, gen_fstorex, MO_TEUQ) +TRANS(fldgt_s, gen_fload_gt, MO_TEUL) +TRANS(fldgt_d, gen_fload_gt, MO_TEUQ) +TRANS(fldle_s, gen_fload_le, MO_TEUL) +TRANS(fldle_d, gen_fload_le, MO_TEUQ) +TRANS(fstgt_s, gen_fstore_gt, MO_TEUL) +TRANS(fstgt_d, gen_fstore_gt, MO_TEUQ) +TRANS(fstle_s, gen_fstore_le, MO_TEUL) +TRANS(fstle_d, gen_fstore_le, MO_TEUQ) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index c62a4f6dcd..8f286e7233 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -36,6 +36,8 @@ &fc fd cj &cr cd rj &rc rd cj +&frr fd rj rk +&fr_i fd rj imm # # Formats @@ -70,6 +72,8 @@ @fc .... ........ ..... ..... .. cj:3 fd:5 &fc @cr .... ........ ..... ..... rj:5 .. cd:3 &cr @rc .... ........ ..... ..... .. cj:3 rd:5 &rc +@frr .... ........ ..... rk:5 rj:5 fd:5 &frr +@fr_i12 .... ...... imm:s12 rj:5 fd:5 &fr_i # # Fixed point arithmetic operation instruction @@ -385,3 +389,23 @@ movfr2cf 0000 00010001 01001 10100 ..... 00 ... @cf movcf2fr 0000 00010001 01001 10101 00 ... ..... @fc movgr2cf 0000 00010001 01001 10110 ..... 00 ... @cr movcf2gr 0000 00010001 01001 10111 00 ... ..... @rc + +# +# Floating point load/store instruction +# +fld_s 0010 101100 ............ ..... ..... @fr_i12 +fst_s 0010 101101 ............ ..... ..... @fr_i12 +fld_d 0010 101110 ............ ..... ..... @fr_i12 +fst_d 0010 101111 ............ ..... ..... @fr_i12 +fldx_s 0011 10000011 00000 ..... ..... ..... @frr +fldx_d 0011 10000011 01000 ..... ..... ..... @frr +fstx_s 0011 10000011 10000 ..... ..... ..... @frr +fstx_d 0011 10000011 11000 ..... ..... ..... @frr +fldgt_s 0011 10000111 01000 ..... ..... ..... @frr +fldgt_d 0011 10000111 01001 ..... ..... ..... @frr +fldle_s 0011 10000111 01010 ..... ..... ..... @frr +fldle_d 0011 10000111 01011 ..... ..... ..... @frr +fstgt_s 0011 10000111 01100 ..... ..... ..... @frr +fstgt_d 0011 10000111 01101 ..... ..... ..... @frr +fstle_s 0011 10000111 01110 ..... ..... ..... @frr +fstle_d 0011 10000111 01111 ..... ..... ..... @frr diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 26d60b50fd..daa77ade33 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -170,6 +170,7 @@ static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext) #include "insn_trans/trans_fcmp.c.inc" #include "insn_trans/trans_fcnv.c.inc" #include "insn_trans/trans_fmov.c.inc" +#include "insn_trans/trans_fmemory.c.inc" static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { From ee86bd58b85ce9afe727b6664ba597acc371bdf2 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 6 Jun 2022 20:43:05 +0800 Subject: [PATCH 822/935] target/loongarch: Add branch instruction translation This includes: - BEQ, BNE, BLT[U], BGE[U] - BEQZ, BNEZ - B - BL - JIRL - BCEQZ, BCNEZ Signed-off-by: Song Gao Signed-off-by: Xiaojuan Yang Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-16-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- .../loongarch/insn_trans/trans_branch.c.inc | 83 +++++++++++++++++++ target/loongarch/insns.decode | 28 +++++++ target/loongarch/translate.c | 1 + 3 files changed, 112 insertions(+) create mode 100644 target/loongarch/insn_trans/trans_branch.c.inc diff --git a/target/loongarch/insn_trans/trans_branch.c.inc b/target/loongarch/insn_trans/trans_branch.c.inc new file mode 100644 index 0000000000..65dbdff41e --- /dev/null +++ b/target/loongarch/insn_trans/trans_branch.c.inc @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +static bool trans_b(DisasContext *ctx, arg_b *a) +{ + gen_goto_tb(ctx, 0, ctx->base.pc_next + a->offs); + ctx->base.is_jmp = DISAS_NORETURN; + return true; +} + +static bool trans_bl(DisasContext *ctx, arg_bl *a) +{ + tcg_gen_movi_tl(cpu_gpr[1], ctx->base.pc_next + 4); + gen_goto_tb(ctx, 0, ctx->base.pc_next + a->offs); + ctx->base.is_jmp = DISAS_NORETURN; + return true; +} + +static bool trans_jirl(DisasContext *ctx, arg_jirl *a) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + + tcg_gen_addi_tl(cpu_pc, src1, a->offs); + tcg_gen_movi_tl(dest, ctx->base.pc_next + 4); + gen_set_gpr(a->rd, dest, EXT_NONE); + tcg_gen_lookup_and_goto_ptr(); + ctx->base.is_jmp = DISAS_NORETURN; + return true; +} + +static void gen_bc(DisasContext *ctx, TCGv src1, TCGv src2, + target_long offs, TCGCond cond) +{ + TCGLabel *l = gen_new_label(); + tcg_gen_brcond_tl(cond, src1, src2, l); + gen_goto_tb(ctx, 1, ctx->base.pc_next + 4); + gen_set_label(l); + gen_goto_tb(ctx, 0, ctx->base.pc_next + offs); + ctx->base.is_jmp = DISAS_NORETURN; +} + +static bool gen_rr_bc(DisasContext *ctx, arg_rr_offs *a, TCGCond cond) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = gpr_src(ctx, a->rd, EXT_NONE); + + gen_bc(ctx, src1, src2, a->offs, cond); + return true; +} + +static bool gen_rz_bc(DisasContext *ctx, arg_r_offs *a, TCGCond cond) +{ + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv src2 = tcg_constant_tl(0); + + gen_bc(ctx, src1, src2, a->offs, cond); + return true; +} + +static bool gen_cz_bc(DisasContext *ctx, arg_c_offs *a, TCGCond cond) +{ + TCGv src1 = tcg_temp_new(); + TCGv src2 = tcg_constant_tl(0); + + tcg_gen_ld8u_tl(src1, cpu_env, + offsetof(CPULoongArchState, cf[a->cj])); + gen_bc(ctx, src1, src2, a->offs, cond); + return true; +} + +TRANS(beq, gen_rr_bc, TCG_COND_EQ) +TRANS(bne, gen_rr_bc, TCG_COND_NE) +TRANS(blt, gen_rr_bc, TCG_COND_LT) +TRANS(bge, gen_rr_bc, TCG_COND_GE) +TRANS(bltu, gen_rr_bc, TCG_COND_LTU) +TRANS(bgeu, gen_rr_bc, TCG_COND_GEU) +TRANS(beqz, gen_rz_bc, TCG_COND_EQ) +TRANS(bnez, gen_rz_bc, TCG_COND_NE) +TRANS(bceqz, gen_cz_bc, TCG_COND_EQ) +TRANS(bcnez, gen_cz_bc, TCG_COND_NE) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index 8f286e7233..9b293dfdf9 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -10,6 +10,9 @@ # %i14s2 10:s14 !function=shl_2 %sa2p1 15:2 !function=plus_1 +%offs21 0:s5 10:16 !function=shl_2 +%offs16 10:s16 !function=shl_2 +%offs26 0:s10 10:16 !function=shl_2 # # Argument sets @@ -38,6 +41,10 @@ &rc rd cj &frr fd rj rk &fr_i fd rj imm +&r_offs rj offs +&c_offs cj offs +&offs offs +&rr_offs rj rd offs # # Formats @@ -74,6 +81,10 @@ @rc .... ........ ..... ..... .. cj:3 rd:5 &rc @frr .... ........ ..... rk:5 rj:5 fd:5 &frr @fr_i12 .... ...... imm:s12 rj:5 fd:5 &fr_i +@r_offs21 .... .. ................ rj:5 ..... &r_offs offs=%offs21 +@c_offs21 .... .. ................ .. cj:3 ..... &c_offs offs=%offs21 +@offs26 .... .. .......................... &offs offs=%offs26 +@rr_offs16 .... .. ................ rj:5 rd:5 &rr_offs offs=%offs16 # # Fixed point arithmetic operation instruction @@ -409,3 +420,20 @@ fstgt_s 0011 10000111 01100 ..... ..... ..... @frr fstgt_d 0011 10000111 01101 ..... ..... ..... @frr fstle_s 0011 10000111 01110 ..... ..... ..... @frr fstle_d 0011 10000111 01111 ..... ..... ..... @frr + +# +# Branch instructions +# +beqz 0100 00 ................ ..... ..... @r_offs21 +bnez 0100 01 ................ ..... ..... @r_offs21 +bceqz 0100 10 ................ 00 ... ..... @c_offs21 +bcnez 0100 10 ................ 01 ... ..... @c_offs21 +jirl 0100 11 ................ ..... ..... @rr_offs16 +b 0101 00 .......................... @offs26 +bl 0101 01 .......................... @offs26 +beq 0101 10 ................ ..... ..... @rr_offs16 +bne 0101 11 ................ ..... ..... @rr_offs16 +blt 0110 00 ................ ..... ..... @rr_offs16 +bge 0110 01 ................ ..... ..... @rr_offs16 +bltu 0110 10 ................ ..... ..... @rr_offs16 +bgeu 0110 11 ................ ..... ..... @rr_offs16 diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index daa77ade33..0ad6b7b2ee 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -171,6 +171,7 @@ static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext) #include "insn_trans/trans_fcnv.c.inc" #include "insn_trans/trans_fmov.c.inc" #include "insn_trans/trans_fmemory.c.inc" +#include "insn_trans/trans_branch.c.inc" static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { From aae1746c726d6cc54e555bcca21e1eb5b56c21bf Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 6 Jun 2022 20:43:06 +0800 Subject: [PATCH 823/935] target/loongarch: Add disassembler This patch adds support for disassembling via option '-d in_asm'. Signed-off-by: Song Gao Signed-off-by: Xiaojuan Yang Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-17-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- include/disas/dis-asm.h | 2 + meson.build | 1 + target/loongarch/disas.c | 610 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 613 insertions(+) create mode 100644 target/loongarch/disas.c diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h index fc7cb7af5a..64247ecb11 100644 --- a/include/disas/dis-asm.h +++ b/include/disas/dis-asm.h @@ -253,6 +253,7 @@ enum bfd_architecture #define bfd_mach_rx 0x75 #define bfd_mach_rx_v2 0x76 #define bfd_mach_rx_v3 0x77 + bfd_arch_loongarch, bfd_arch_last }; #define bfd_mach_s390_31 31 @@ -458,6 +459,7 @@ int print_insn_riscv64 (bfd_vma, disassemble_info*); int print_insn_riscv128 (bfd_vma, disassemble_info*); int print_insn_rx(bfd_vma, disassemble_info *); int print_insn_hexagon(bfd_vma, disassemble_info *); +int print_insn_loongarch(bfd_vma, disassemble_info *); #ifdef CONFIG_CAPSTONE bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size); diff --git a/meson.build b/meson.build index d738391810..21cd949082 100644 --- a/meson.build +++ b/meson.build @@ -2349,6 +2349,7 @@ disassemblers = { 'sh4' : ['CONFIG_SH4_DIS'], 'sparc' : ['CONFIG_SPARC_DIS'], 'xtensa' : ['CONFIG_XTENSA_DIS'], + 'loongarch' : ['CONFIG_LOONGARCH_DIS'], } if link_language == 'cpp' disassemblers += { diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c new file mode 100644 index 0000000000..9454ebb8e9 --- /dev/null +++ b/target/loongarch/disas.c @@ -0,0 +1,610 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch Disassembler + * + * Copyright (c) 2021 Loongson Technology Corporation Limited. + */ + +#include "qemu/osdep.h" +#include "disas/dis-asm.h" +#include "qemu/bitops.h" + +typedef struct { + disassemble_info *info; + uint64_t pc; + uint32_t insn; +} DisasContext; + +static inline int plus_1(DisasContext *ctx, int x) +{ + return x + 1; +} + +static inline int shl_2(DisasContext *ctx, int x) +{ + return x << 2; +} + +#define output(C, INSN, FMT, ...) \ +{ \ + (C)->info->fprintf_func((C)->info->stream, "%08x %-9s\t" FMT, \ + (C)->insn, INSN, ##__VA_ARGS__); \ +} + +#include "decode-insns.c.inc" + +int print_insn_loongarch(bfd_vma memaddr, struct disassemble_info *info) +{ + bfd_byte buffer[4]; + uint32_t insn; + int status; + + status = (*info->read_memory_func)(memaddr, buffer, 4, info); + if (status != 0) { + (*info->memory_error_func)(status, memaddr, info); + return -1; + } + insn = bfd_getl32(buffer); + DisasContext ctx = { + .info = info, + .pc = memaddr, + .insn = insn + }; + + if (!decode(&ctx, insn)) { + output(&ctx, "illegal", ""); + } + return 4; +} + +static void output_r_i(DisasContext *ctx, arg_r_i *a, const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, %d", a->rd, a->imm); +} + +static void output_rrr(DisasContext *ctx, arg_rrr *a, const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, r%d, r%d", a->rd, a->rj, a->rk); +} + +static void output_rr_i(DisasContext *ctx, arg_rr_i *a, const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, r%d, %d", a->rd, a->rj, a->imm); +} + +static void output_rrr_sa(DisasContext *ctx, arg_rrr_sa *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, r%d, r%d, %d", a->rd, a->rj, a->rk, a->sa); +} + +static void output_rr(DisasContext *ctx, arg_rr *a, const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, r%d", a->rd, a->rj); +} + +static void output_rr_ms_ls(DisasContext *ctx, arg_rr_ms_ls *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, r%d, %d, %d", a->rd, a->rj, a->ms, a->ls); +} + +static void output_hint_r_i(DisasContext *ctx, arg_hint_r_i *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "%d, r%d, %d", a->hint, a->rj, a->imm); +} + +static void output_i(DisasContext *ctx, arg_i *a, const char *mnemonic) +{ + output(ctx, mnemonic, "%d", a->imm); +} + +static void output_rr_jk(DisasContext *ctx, arg_rr_jk *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, r%d", a->rj, a->rk); +} + +static void output_ff(DisasContext *ctx, arg_ff *a, const char *mnemonic) +{ + output(ctx, mnemonic, "f%d, f%d", a->fd, a->fj); +} + +static void output_fff(DisasContext *ctx, arg_fff *a, const char *mnemonic) +{ + output(ctx, mnemonic, "f%d, f%d, f%d", a->fd, a->fj, a->fk); +} + +static void output_ffff(DisasContext *ctx, arg_ffff *a, const char *mnemonic) +{ + output(ctx, mnemonic, "f%d, f%d, f%d, f%d", a->fd, a->fj, a->fk, a->fa); +} + +static void output_fffc(DisasContext *ctx, arg_fffc *a, const char *mnemonic) +{ + output(ctx, mnemonic, "f%d, f%d, f%d, %d", a->fd, a->fj, a->fk, a->ca); +} + +static void output_fr(DisasContext *ctx, arg_fr *a, const char *mnemonic) +{ + output(ctx, mnemonic, "f%d, r%d", a->fd, a->rj); +} + +static void output_rf(DisasContext *ctx, arg_rf *a, const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, f%d", a->rd, a->fj); +} + +static void output_fcsrd_r(DisasContext *ctx, arg_fcsrd_r *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "fcsr%d, r%d", a->fcsrd, a->rj); +} + +static void output_r_fcsrs(DisasContext *ctx, arg_r_fcsrs *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, fcsr%d", a->rd, a->fcsrs); +} + +static void output_cf(DisasContext *ctx, arg_cf *a, const char *mnemonic) +{ + output(ctx, mnemonic, "fcc%d, f%d", a->cd, a->fj); +} + +static void output_fc(DisasContext *ctx, arg_fc *a, const char *mnemonic) +{ + output(ctx, mnemonic, "f%d, fcc%d", a->fd, a->cj); +} + +static void output_cr(DisasContext *ctx, arg_cr *a, const char *mnemonic) +{ + output(ctx, mnemonic, "fcc%d, r%d", a->cd, a->rj); +} + +static void output_rc(DisasContext *ctx, arg_rc *a, const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, fcc%d", a->rd, a->cj); +} + +static void output_frr(DisasContext *ctx, arg_frr *a, const char *mnemonic) +{ + output(ctx, mnemonic, "f%d, r%d, r%d", a->fd, a->rj, a->rk); +} + +static void output_fr_i(DisasContext *ctx, arg_fr_i *a, const char *mnemonic) +{ + output(ctx, mnemonic, "f%d, r%d, %d", a->fd, a->rj, a->imm); +} + +static void output_r_offs(DisasContext *ctx, arg_r_offs *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, %d # 0x%" PRIx64, a->rj, a->offs, + ctx->pc + a->offs); +} + +static void output_c_offs(DisasContext *ctx, arg_c_offs *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "fcc%d, %d # 0x%" PRIx64, a->cj, a->offs, + ctx->pc + a->offs); +} + +static void output_offs(DisasContext *ctx, arg_offs *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "%d # 0x%" PRIx64, a->offs, ctx->pc + a->offs); +} + +static void output_rr_offs(DisasContext *ctx, arg_rr_offs *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, r%d, %d # 0x%" PRIx64, a->rj, + a->rd, a->offs, ctx->pc + a->offs); +} + +#define INSN(insn, type) \ +static bool trans_##insn(DisasContext *ctx, arg_##type * a) \ +{ \ + output_##type(ctx, a, #insn); \ + return true; \ +} + +INSN(clo_w, rr) +INSN(clz_w, rr) +INSN(cto_w, rr) +INSN(ctz_w, rr) +INSN(clo_d, rr) +INSN(clz_d, rr) +INSN(cto_d, rr) +INSN(ctz_d, rr) +INSN(revb_2h, rr) +INSN(revb_4h, rr) +INSN(revb_2w, rr) +INSN(revb_d, rr) +INSN(revh_2w, rr) +INSN(revh_d, rr) +INSN(bitrev_4b, rr) +INSN(bitrev_8b, rr) +INSN(bitrev_w, rr) +INSN(bitrev_d, rr) +INSN(ext_w_h, rr) +INSN(ext_w_b, rr) +INSN(cpucfg, rr) +INSN(asrtle_d, rr_jk) +INSN(asrtgt_d, rr_jk) +INSN(alsl_w, rrr_sa) +INSN(alsl_wu, rrr_sa) +INSN(bytepick_w, rrr_sa) +INSN(bytepick_d, rrr_sa) +INSN(add_w, rrr) +INSN(add_d, rrr) +INSN(sub_w, rrr) +INSN(sub_d, rrr) +INSN(slt, rrr) +INSN(sltu, rrr) +INSN(maskeqz, rrr) +INSN(masknez, rrr) +INSN(nor, rrr) +INSN(and, rrr) +INSN(or, rrr) +INSN(xor, rrr) +INSN(orn, rrr) +INSN(andn, rrr) +INSN(sll_w, rrr) +INSN(srl_w, rrr) +INSN(sra_w, rrr) +INSN(sll_d, rrr) +INSN(srl_d, rrr) +INSN(sra_d, rrr) +INSN(rotr_w, rrr) +INSN(rotr_d, rrr) +INSN(mul_w, rrr) +INSN(mulh_w, rrr) +INSN(mulh_wu, rrr) +INSN(mul_d, rrr) +INSN(mulh_d, rrr) +INSN(mulh_du, rrr) +INSN(mulw_d_w, rrr) +INSN(mulw_d_wu, rrr) +INSN(div_w, rrr) +INSN(mod_w, rrr) +INSN(div_wu, rrr) +INSN(mod_wu, rrr) +INSN(div_d, rrr) +INSN(mod_d, rrr) +INSN(div_du, rrr) +INSN(mod_du, rrr) +INSN(crc_w_b_w, rrr) +INSN(crc_w_h_w, rrr) +INSN(crc_w_w_w, rrr) +INSN(crc_w_d_w, rrr) +INSN(crcc_w_b_w, rrr) +INSN(crcc_w_h_w, rrr) +INSN(crcc_w_w_w, rrr) +INSN(crcc_w_d_w, rrr) +INSN(break, i) +INSN(syscall, i) +INSN(alsl_d, rrr_sa) +INSN(slli_w, rr_i) +INSN(slli_d, rr_i) +INSN(srli_w, rr_i) +INSN(srli_d, rr_i) +INSN(srai_w, rr_i) +INSN(srai_d, rr_i) +INSN(rotri_w, rr_i) +INSN(rotri_d, rr_i) +INSN(bstrins_w, rr_ms_ls) +INSN(bstrpick_w, rr_ms_ls) +INSN(bstrins_d, rr_ms_ls) +INSN(bstrpick_d, rr_ms_ls) +INSN(fadd_s, fff) +INSN(fadd_d, fff) +INSN(fsub_s, fff) +INSN(fsub_d, fff) +INSN(fmul_s, fff) +INSN(fmul_d, fff) +INSN(fdiv_s, fff) +INSN(fdiv_d, fff) +INSN(fmax_s, fff) +INSN(fmax_d, fff) +INSN(fmin_s, fff) +INSN(fmin_d, fff) +INSN(fmaxa_s, fff) +INSN(fmaxa_d, fff) +INSN(fmina_s, fff) +INSN(fmina_d, fff) +INSN(fscaleb_s, fff) +INSN(fscaleb_d, fff) +INSN(fcopysign_s, fff) +INSN(fcopysign_d, fff) +INSN(fabs_s, ff) +INSN(fabs_d, ff) +INSN(fneg_s, ff) +INSN(fneg_d, ff) +INSN(flogb_s, ff) +INSN(flogb_d, ff) +INSN(fclass_s, ff) +INSN(fclass_d, ff) +INSN(fsqrt_s, ff) +INSN(fsqrt_d, ff) +INSN(frecip_s, ff) +INSN(frecip_d, ff) +INSN(frsqrt_s, ff) +INSN(frsqrt_d, ff) +INSN(fmov_s, ff) +INSN(fmov_d, ff) +INSN(movgr2fr_w, fr) +INSN(movgr2fr_d, fr) +INSN(movgr2frh_w, fr) +INSN(movfr2gr_s, rf) +INSN(movfr2gr_d, rf) +INSN(movfrh2gr_s, rf) +INSN(movgr2fcsr, fcsrd_r) +INSN(movfcsr2gr, r_fcsrs) +INSN(movfr2cf, cf) +INSN(movcf2fr, fc) +INSN(movgr2cf, cr) +INSN(movcf2gr, rc) +INSN(fcvt_s_d, ff) +INSN(fcvt_d_s, ff) +INSN(ftintrm_w_s, ff) +INSN(ftintrm_w_d, ff) +INSN(ftintrm_l_s, ff) +INSN(ftintrm_l_d, ff) +INSN(ftintrp_w_s, ff) +INSN(ftintrp_w_d, ff) +INSN(ftintrp_l_s, ff) +INSN(ftintrp_l_d, ff) +INSN(ftintrz_w_s, ff) +INSN(ftintrz_w_d, ff) +INSN(ftintrz_l_s, ff) +INSN(ftintrz_l_d, ff) +INSN(ftintrne_w_s, ff) +INSN(ftintrne_w_d, ff) +INSN(ftintrne_l_s, ff) +INSN(ftintrne_l_d, ff) +INSN(ftint_w_s, ff) +INSN(ftint_w_d, ff) +INSN(ftint_l_s, ff) +INSN(ftint_l_d, ff) +INSN(ffint_s_w, ff) +INSN(ffint_s_l, ff) +INSN(ffint_d_w, ff) +INSN(ffint_d_l, ff) +INSN(frint_s, ff) +INSN(frint_d, ff) +INSN(slti, rr_i) +INSN(sltui, rr_i) +INSN(addi_w, rr_i) +INSN(addi_d, rr_i) +INSN(lu52i_d, rr_i) +INSN(andi, rr_i) +INSN(ori, rr_i) +INSN(xori, rr_i) +INSN(fmadd_s, ffff) +INSN(fmadd_d, ffff) +INSN(fmsub_s, ffff) +INSN(fmsub_d, ffff) +INSN(fnmadd_s, ffff) +INSN(fnmadd_d, ffff) +INSN(fnmsub_s, ffff) +INSN(fnmsub_d, ffff) +INSN(fsel, fffc) +INSN(addu16i_d, rr_i) +INSN(lu12i_w, r_i) +INSN(lu32i_d, r_i) +INSN(pcaddi, r_i) +INSN(pcalau12i, r_i) +INSN(pcaddu12i, r_i) +INSN(pcaddu18i, r_i) +INSN(ll_w, rr_i) +INSN(sc_w, rr_i) +INSN(ll_d, rr_i) +INSN(sc_d, rr_i) +INSN(ldptr_w, rr_i) +INSN(stptr_w, rr_i) +INSN(ldptr_d, rr_i) +INSN(stptr_d, rr_i) +INSN(ld_b, rr_i) +INSN(ld_h, rr_i) +INSN(ld_w, rr_i) +INSN(ld_d, rr_i) +INSN(st_b, rr_i) +INSN(st_h, rr_i) +INSN(st_w, rr_i) +INSN(st_d, rr_i) +INSN(ld_bu, rr_i) +INSN(ld_hu, rr_i) +INSN(ld_wu, rr_i) +INSN(preld, hint_r_i) +INSN(fld_s, fr_i) +INSN(fst_s, fr_i) +INSN(fld_d, fr_i) +INSN(fst_d, fr_i) +INSN(ldx_b, rrr) +INSN(ldx_h, rrr) +INSN(ldx_w, rrr) +INSN(ldx_d, rrr) +INSN(stx_b, rrr) +INSN(stx_h, rrr) +INSN(stx_w, rrr) +INSN(stx_d, rrr) +INSN(ldx_bu, rrr) +INSN(ldx_hu, rrr) +INSN(ldx_wu, rrr) +INSN(fldx_s, frr) +INSN(fldx_d, frr) +INSN(fstx_s, frr) +INSN(fstx_d, frr) +INSN(amswap_w, rrr) +INSN(amswap_d, rrr) +INSN(amadd_w, rrr) +INSN(amadd_d, rrr) +INSN(amand_w, rrr) +INSN(amand_d, rrr) +INSN(amor_w, rrr) +INSN(amor_d, rrr) +INSN(amxor_w, rrr) +INSN(amxor_d, rrr) +INSN(ammax_w, rrr) +INSN(ammax_d, rrr) +INSN(ammin_w, rrr) +INSN(ammin_d, rrr) +INSN(ammax_wu, rrr) +INSN(ammax_du, rrr) +INSN(ammin_wu, rrr) +INSN(ammin_du, rrr) +INSN(amswap_db_w, rrr) +INSN(amswap_db_d, rrr) +INSN(amadd_db_w, rrr) +INSN(amadd_db_d, rrr) +INSN(amand_db_w, rrr) +INSN(amand_db_d, rrr) +INSN(amor_db_w, rrr) +INSN(amor_db_d, rrr) +INSN(amxor_db_w, rrr) +INSN(amxor_db_d, rrr) +INSN(ammax_db_w, rrr) +INSN(ammax_db_d, rrr) +INSN(ammin_db_w, rrr) +INSN(ammin_db_d, rrr) +INSN(ammax_db_wu, rrr) +INSN(ammax_db_du, rrr) +INSN(ammin_db_wu, rrr) +INSN(ammin_db_du, rrr) +INSN(dbar, i) +INSN(ibar, i) +INSN(fldgt_s, frr) +INSN(fldgt_d, frr) +INSN(fldle_s, frr) +INSN(fldle_d, frr) +INSN(fstgt_s, frr) +INSN(fstgt_d, frr) +INSN(fstle_s, frr) +INSN(fstle_d, frr) +INSN(ldgt_b, rrr) +INSN(ldgt_h, rrr) +INSN(ldgt_w, rrr) +INSN(ldgt_d, rrr) +INSN(ldle_b, rrr) +INSN(ldle_h, rrr) +INSN(ldle_w, rrr) +INSN(ldle_d, rrr) +INSN(stgt_b, rrr) +INSN(stgt_h, rrr) +INSN(stgt_w, rrr) +INSN(stgt_d, rrr) +INSN(stle_b, rrr) +INSN(stle_h, rrr) +INSN(stle_w, rrr) +INSN(stle_d, rrr) +INSN(beqz, r_offs) +INSN(bnez, r_offs) +INSN(bceqz, c_offs) +INSN(bcnez, c_offs) +INSN(jirl, rr_offs) +INSN(b, offs) +INSN(bl, offs) +INSN(beq, rr_offs) +INSN(bne, rr_offs) +INSN(blt, rr_offs) +INSN(bge, rr_offs) +INSN(bltu, rr_offs) +INSN(bgeu, rr_offs) + +#define output_fcmp(C, PREFIX, SUFFIX) \ +{ \ + (C)->info->fprintf_func((C)->info->stream, "%08x %s%s\tfcc%d, f%d, f%d", \ + (C)->insn, PREFIX, SUFFIX, a->cd, \ + a->fj, a->fk); \ +} + +static bool output_cff_fcond(DisasContext *ctx, arg_cff_fcond * a, + const char *suffix) +{ + bool ret = true; + switch (a->fcond) { + case 0x0: + output_fcmp(ctx, "fcmp_caf_", suffix); + break; + case 0x1: + output_fcmp(ctx, "fcmp_saf_", suffix); + break; + case 0x2: + output_fcmp(ctx, "fcmp_clt_", suffix); + break; + case 0x3: + output_fcmp(ctx, "fcmp_slt_", suffix); + break; + case 0x4: + output_fcmp(ctx, "fcmp_ceq_", suffix); + break; + case 0x5: + output_fcmp(ctx, "fcmp_seq_", suffix); + break; + case 0x6: + output_fcmp(ctx, "fcmp_cle_", suffix); + break; + case 0x7: + output_fcmp(ctx, "fcmp_sle_", suffix); + break; + case 0x8: + output_fcmp(ctx, "fcmp_cun_", suffix); + break; + case 0x9: + output_fcmp(ctx, "fcmp_sun_", suffix); + break; + case 0xA: + output_fcmp(ctx, "fcmp_cult_", suffix); + break; + case 0xB: + output_fcmp(ctx, "fcmp_sult_", suffix); + break; + case 0xC: + output_fcmp(ctx, "fcmp_cueq_", suffix); + break; + case 0xD: + output_fcmp(ctx, "fcmp_sueq_", suffix); + break; + case 0xE: + output_fcmp(ctx, "fcmp_cule_", suffix); + break; + case 0xF: + output_fcmp(ctx, "fcmp_sule_", suffix); + break; + case 0x10: + output_fcmp(ctx, "fcmp_cne_", suffix); + break; + case 0x11: + output_fcmp(ctx, "fcmp_sne_", suffix); + break; + case 0x14: + output_fcmp(ctx, "fcmp_cor_", suffix); + break; + case 0x15: + output_fcmp(ctx, "fcmp_sor_", suffix); + break; + case 0x18: + output_fcmp(ctx, "fcmp_cune_", suffix); + break; + case 0x19: + output_fcmp(ctx, "fcmp_sune_", suffix); + break; + default: + ret = false; + } + return ret; +} + +#define FCMP_INSN(suffix) \ +static bool trans_fcmp_cond_##suffix(DisasContext *ctx, \ + arg_cff_fcond * a) \ +{ \ + return output_cff_fcond(ctx, a, #suffix); \ +} + +FCMP_INSN(s) +FCMP_INSN(d) From 14f2b0b74188582c6f016f8659b24baa340d765a Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 6 Jun 2022 20:43:07 +0800 Subject: [PATCH 824/935] target/loongarch: Add target build suport MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Song Gao Signed-off-by: Xiaojuan Yang Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20220606124333.2060567-18-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/meson.build | 19 +++++++++++++++++++ target/meson.build | 1 + 2 files changed, 20 insertions(+) create mode 100644 target/loongarch/meson.build diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build new file mode 100644 index 0000000000..bcb076e55f --- /dev/null +++ b/target/loongarch/meson.build @@ -0,0 +1,19 @@ +gen = decodetree.process('insns.decode') + +loongarch_ss = ss.source_set() +loongarch_ss.add(files( + 'cpu.c', + 'disas.c', +)) +loongarch_tcg_ss = ss.source_set() +loongarch_tcg_ss.add(gen) +loongarch_tcg_ss.add(files( + 'fpu_helper.c', + 'op_helper.c', + 'translate.c', +)) +loongarch_tcg_ss.add(zlib) + +loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss]) + +target_arch += {'loongarch': loongarch_ss} diff --git a/target/meson.build b/target/meson.build index 2f6940255e..a53a60486f 100644 --- a/target/meson.build +++ b/target/meson.build @@ -5,6 +5,7 @@ subdir('cris') subdir('hexagon') subdir('hppa') subdir('i386') +subdir('loongarch') subdir('m68k') subdir('microblaze') subdir('mips') From d88b51dc26c0e29d012f52d0215ebef29329ca87 Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:08 +0800 Subject: [PATCH 825/935] target/loongarch: Add system emulation introduction Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-19-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- MAINTAINERS | 8 +++++ docs/system/loongarch/loongson3.rst | 41 ++++++++++++++++++++++ target/loongarch/README | 54 +++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 docs/system/loongarch/loongson3.rst diff --git a/MAINTAINERS b/MAINTAINERS index 319a5d805a..e3f875071a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1122,6 +1122,14 @@ F: include/hw/net/lasi_82596.h F: include/hw/pci-host/dino.h F: pc-bios/hppa-firmware.img +LoongArch Machines +------------------ +Virt +M: Xiaojuan Yang +M: Song Gao +S: Maintained +F: docs/system/loongarch/loongson3.rst + M68K Machines ------------- an5206 diff --git a/docs/system/loongarch/loongson3.rst b/docs/system/loongarch/loongson3.rst new file mode 100644 index 0000000000..fa3acd01c0 --- /dev/null +++ b/docs/system/loongarch/loongson3.rst @@ -0,0 +1,41 @@ +:orphan: + +========================================== +loongson3 virt generic platform (``virt``) +========================================== + +The ``virt`` machine use gpex host bridge, and there are some +emulated devices on virt board, such as loongson7a RTC device, +IOAPIC device, ACPI device and so on. + +Supported devices +----------------- + +The ``virt`` machine supports: +- Gpex host bridge +- Ls7a RTC device +- Ls7a IOAPIC device +- Ls7a ACPI device +- Fw_cfg device +- PCI/PCIe devices +- Memory device +- CPU device. Type: Loongson-3A5000. + +CPU and machine Type +-------------------- + +The ``qemu-system-loongarch64`` provides emulation for virt +machine. You can specify the machine type ``virt`` and +cpu type ``Loongson-3A5000``. + +Boot options +------------ + +Now the ``virt`` machine can run test program in ELF format and the +method of compiling is in target/loongarch/README. + +.. code-block:: bash + + $ qemu-system-loongarch64 -machine virt -m 4G -cpu Loongson-3A5000 \ + -smp 1 -kernel hello -monitor none -display none \ + -chardev file,path=hello.out,id=output -serial chardev:output diff --git a/target/loongarch/README b/target/loongarch/README index de141c1a58..4dcd0f1682 100644 --- a/target/loongarch/README +++ b/target/loongarch/README @@ -8,3 +8,57 @@ We can get the latest loongarch documents at https://github.com/loongson/LoongArch-Documentation/tags. + +- System emulation + + Mainly emulate a virt 3A5000 board and ls7a bridge that is not exactly the same as the host. + 3A5000 support multiple interrupt cascading while here we just emulate the extioi interrupt + cascading. LS7A1000 host bridge support multiple devices, such as sata, gmac, uart, rtc + and so on. But we just realize the rtc. Others use the qemu common devices. It does not affect + the general use. We also introduced the emulation of devices at docs/system/loongarch/loongson3.rst. + + This version only supports running binary files in ELF format, and does not depend on BIOS and kernel file. + You can compile the test program with 'make & make check-tcg' and run the test case with the following command: + + 1. Install LoongArch cross-tools on X86 machines. + + Download cross-tools. + + wget https://github.com/loongson/build-tools/releases/latest/download/loongarch64-clfs-20211202-cross-tools.tar.xz + + tar -vxf loongarch64-clfs-20211202-cross-tools.tar.xz -C /opt + + Config cross-tools env. + + . setenv.sh + + setenv.sh: + + #!/bin/sh + set -x + CC_PREFIX=/opt/cross-tools + + export PATH=$CC_PREFIX/bin:$PATH + export LD_LIBRARY_PATH=$CC_PREFIX/lib:$LD_LIBRARY_PATH + export LD_LIBRARY_PATH=$CC_PREFIX/loongarch64-unknown-linux-gnu/lib/:$LD_LIBRARY_PATH + set +x + + 2. Test tests/tcg/multiarch. + + ./configure --disable-rdma --disable-pvrdma --prefix=/usr \ + --target-list="loongarch64-softmmu" \ + --disable-libiscsi --disable-libnfs --disable-libpmem \ + --disable-glusterfs --enable-libusb --enable-usb-redir \ + --disable-opengl --disable-xen --enable-spice --disable-werror \ + --enable-debug --disable-capstone --disable-kvm --enable-profiler + + cd build/ + + make && make check-tcg + + or + + ./build/qemu-system-loongarch64 -machine virt -m 4G -cpu Loongson-3A5000 -smp 1 -kernel build/tests/tcg/loongarch64-softmmu/hello -monitor none -display none -chardev file,path=hello.out,id=output -serial chardev:output + +- Note. + We can get the latest LoongArch documents or LoongArch tools at https://github.com/loongson/ From 398cecb9c3e756afcbf5c5f2bfa9796be0324e2c Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:09 +0800 Subject: [PATCH 826/935] target/loongarch: Add CSRs definition Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-20-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/cpu-csr.h | 208 +++++++++++++++++++++++++++++++++++++ target/loongarch/cpu.c | 41 ++++++++ target/loongarch/cpu.h | 64 ++++++++++++ 3 files changed, 313 insertions(+) create mode 100644 target/loongarch/cpu-csr.h diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h new file mode 100644 index 0000000000..4c8ce7fed5 --- /dev/null +++ b/target/loongarch/cpu-csr.h @@ -0,0 +1,208 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch CSRs + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_CPU_CSR_H +#define LOONGARCH_CPU_CSR_H + +#include "hw/registerfields.h" + +/* Base on kernal definitions: arch/loongarch/include/asm/loongarch.h */ + +/* Basic CSRs */ +#define LOONGARCH_CSR_CRMD 0x0 /* Current mode info */ + +#define LOONGARCH_CSR_PRMD 0x1 /* Prev-exception mode info */ +FIELD(CSR_PRMD, PPLV, 0, 2) +FIELD(CSR_PRMD, PIE, 2, 1) +FIELD(CSR_PRMD, PWE, 3, 1) + +#define LOONGARCH_CSR_EUEN 0x2 /* Extended unit enable */ +FIELD(CSR_EUEN, FPE, 0, 1) +FIELD(CSR_EUEN, SXE, 1, 1) +FIELD(CSR_EUEN, ASXE, 2, 1) +FIELD(CSR_EUEN, BTE, 3, 1) + +#define LOONGARCH_CSR_MISC 0x3 /* Misc config */ +FIELD(CSR_MISC, VA32, 0, 4) +FIELD(CSR_MISC, DRDTL, 4, 4) +FIELD(CSR_MISC, RPCNTL, 8, 4) +FIELD(CSR_MISC, ALCL, 12, 4) +FIELD(CSR_MISC, DWPL, 16, 3) + +#define LOONGARCH_CSR_ECFG 0x4 /* Exception config */ +FIELD(CSR_ECFG, LIE, 0, 13) +FIELD(CSR_ECFG, VS, 16, 3) + +#define LOONGARCH_CSR_ESTAT 0x5 /* Exception status */ +FIELD(CSR_ESTAT, IS, 0, 13) +FIELD(CSR_ESTAT, ECODE, 16, 6) +FIELD(CSR_ESTAT, ESUBCODE, 22, 9) + +#define LOONGARCH_CSR_ERA 0x6 /* Exception return address */ + +#define LOONGARCH_CSR_BADV 0x7 /* Bad virtual address */ + +#define LOONGARCH_CSR_BADI 0x8 /* Bad instruction */ + +#define LOONGARCH_CSR_EENTRY 0xc /* Exception entry address */ + +/* TLB related CSRs */ +#define LOONGARCH_CSR_TLBIDX 0x10 /* TLB Index, EHINV, PageSize, NP */ +FIELD(CSR_TLBIDX, INDEX, 0, 12) +FIELD(CSR_TLBIDX, PS, 24, 6) +FIELD(CSR_TLBIDX, NE, 31, 1) + +#define LOONGARCH_CSR_TLBEHI 0x11 /* TLB EntryHi */ +FIELD(CSR_TLBEHI, VPPN, 13, 35) + +#define LOONGARCH_CSR_TLBELO0 0x12 /* TLB EntryLo0 */ +#define LOONGARCH_CSR_TLBELO1 0x13 /* TLB EntryLo1 */ +FIELD(TLBENTRY, V, 0, 1) +FIELD(TLBENTRY, D, 1, 1) +FIELD(TLBENTRY, PLV, 2, 2) +FIELD(TLBENTRY, MAT, 4, 2) +FIELD(TLBENTRY, G, 6, 1) +FIELD(TLBENTRY, PPN, 12, 36) +FIELD(TLBENTRY, NR, 61, 1) +FIELD(TLBENTRY, NX, 62, 1) +FIELD(TLBENTRY, RPLV, 63, 1) + +#define LOONGARCH_CSR_ASID 0x18 /* Address space identifier */ +FIELD(CSR_ASID, ASID, 0, 10) +FIELD(CSR_ASID, ASIDBITS, 16, 8) + +/* Page table base address when badv[47] = 0 */ +#define LOONGARCH_CSR_PGDL 0x19 +/* Page table base address when badv[47] = 1 */ +#define LOONGARCH_CSR_PGDH 0x1a + +#define LOONGARCH_CSR_PGD 0x1b /* Page table base address */ + +/* Page walk controller's low addr */ +#define LOONGARCH_CSR_PWCL 0x1c +FIELD(CSR_PWCL, PTBASE, 0, 5) +FIELD(CSR_PWCL, PTWIDTH, 5, 5) +FIELD(CSR_PWCL, DIR1_BASE, 10, 5) +FIELD(CSR_PWCL, DIR1_WIDTH, 15, 5) +FIELD(CSR_PWCL, DIR2_BASE, 20, 5) +FIELD(CSR_PWCL, DIR2_WIDTH, 25, 5) +FIELD(CSR_PWCL, PTEWIDTH, 30, 2) + +/* Page walk controller's high addr */ +#define LOONGARCH_CSR_PWCH 0x1d +FIELD(CSR_PWCH, DIR3_BASE, 0, 6) +FIELD(CSR_PWCH, DIR3_WIDTH, 6, 6) +FIELD(CSR_PWCH, DIR4_BASE, 12, 6) +FIELD(CSR_PWCH, DIR4_WIDTH, 18, 6) + +#define LOONGARCH_CSR_STLBPS 0x1e /* Stlb page size */ +FIELD(CSR_STLBPS, PS, 0, 5) + +#define LOONGARCH_CSR_RVACFG 0x1f /* Reduced virtual address config */ +FIELD(CSR_RVACFG, RBITS, 0, 4) + +/* Config CSRs */ +#define LOONGARCH_CSR_CPUID 0x20 /* CPU core id */ + +#define LOONGARCH_CSR_PRCFG1 0x21 /* Config1 */ +FIELD(CSR_PRCFG1, SAVE_NUM, 0, 4) +FIELD(CSR_PRCFG1, TIMER_BITS, 4, 8) +FIELD(CSR_PRCFG1, VSMAX, 12, 3) + +#define LOONGARCH_CSR_PRCFG2 0x22 /* Config2 */ + +#define LOONGARCH_CSR_PRCFG3 0x23 /* Config3 */ +FIELD(CSR_PRCFG3, TLB_TYPE, 0, 4) +FIELD(CSR_PRCFG3, MTLB_ENTRY, 4, 8) +FIELD(CSR_PRCFG3, STLB_WAYS, 12, 8) +FIELD(CSR_PRCFG3, STLB_SETS, 20, 8) + +/* + * Save registers count can read from PRCFG1.SAVE_NUM + * The Min count is 1. Max count is 15. + */ +#define LOONGARCH_CSR_SAVE(N) (0x30 + N) + +/* Timer CSRs */ +#define LOONGARCH_CSR_TID 0x40 /* Timer ID */ + +#define LOONGARCH_CSR_TCFG 0x41 /* Timer config */ +FIELD(CSR_TCFG, EN, 0, 1) +FIELD(CSR_TCFG, PERIODIC, 1, 1) +FIELD(CSR_TCFG, INIT_VAL, 2, 46) + +#define LOONGARCH_CSR_TVAL 0x42 /* Timer ticks remain */ + +#define LOONGARCH_CSR_CNTC 0x43 /* Timer offset */ + +#define LOONGARCH_CSR_TICLR 0x44 /* Timer interrupt clear */ + +/* LLBCTL CSRs */ +#define LOONGARCH_CSR_LLBCTL 0x60 /* LLBit control */ +FIELD(CSR_LLBCTL, ROLLB, 0, 1) +FIELD(CSR_LLBCTL, WCLLB, 1, 1) +FIELD(CSR_LLBCTL, KLO, 2, 1) + +/* Implement dependent */ +#define LOONGARCH_CSR_IMPCTL1 0x80 /* LoongArch config1 */ + +#define LOONGARCH_CSR_IMPCTL2 0x81 /* LoongArch config2*/ + +/* TLB Refill CSRs */ +#define LOONGARCH_CSR_TLBRENTRY 0x88 /* TLB refill exception address */ +#define LOONGARCH_CSR_TLBRBADV 0x89 /* TLB refill badvaddr */ +#define LOONGARCH_CSR_TLBRERA 0x8a /* TLB refill ERA */ +#define LOONGARCH_CSR_TLBRSAVE 0x8b /* KScratch for TLB refill */ +FIELD(CSR_TLBRERA, ISTLBR, 0, 1) +FIELD(CSR_TLBRERA, PC, 2, 62) +#define LOONGARCH_CSR_TLBRELO0 0x8c /* TLB refill entrylo0 */ +#define LOONGARCH_CSR_TLBRELO1 0x8d /* TLB refill entrylo1 */ +#define LOONGARCH_CSR_TLBREHI 0x8e /* TLB refill entryhi */ +FIELD(CSR_TLBREHI, PS, 0, 6) +FIELD(CSR_TLBREHI, VPPN, 13, 35) +#define LOONGARCH_CSR_TLBRPRMD 0x8f /* TLB refill mode info */ +FIELD(CSR_TLBRPRMD, PPLV, 0, 2) +FIELD(CSR_TLBRPRMD, PIE, 2, 1) +FIELD(CSR_TLBRPRMD, PWE, 4, 1) + +/* Machine Error CSRs */ +#define LOONGARCH_CSR_MERRCTL 0x90 /* ERRCTL */ +FIELD(CSR_MERRCTL, ISMERR, 0, 1) +#define LOONGARCH_CSR_MERRINFO1 0x91 +#define LOONGARCH_CSR_MERRINFO2 0x92 +#define LOONGARCH_CSR_MERRENTRY 0x93 /* MError exception base */ +#define LOONGARCH_CSR_MERRERA 0x94 /* MError exception PC */ +#define LOONGARCH_CSR_MERRSAVE 0x95 /* KScratch for error exception */ + +#define LOONGARCH_CSR_CTAG 0x98 /* TagLo + TagHi */ + +/* Direct map windows CSRs*/ +#define LOONGARCH_CSR_DMW(N) (0x180 + N) +FIELD(CSR_DMW, PLV0, 0, 1) +FIELD(CSR_DMW, PLV1, 1, 1) +FIELD(CSR_DMW, PLV2, 2, 1) +FIELD(CSR_DMW, PLV3, 3, 1) +FIELD(CSR_DMW, MAT, 4, 2) +FIELD(CSR_DMW, VSEG, 60, 4) + +#define dmw_va2pa(va) \ + (va & MAKE_64BIT_MASK(0, TARGET_VIRT_ADDR_SPACE_BITS)) + +/* Debug CSRs */ +#define LOONGARCH_CSR_DBG 0x500 /* debug config */ +FIELD(CSR_DBG, DST, 0, 1) +FIELD(CSR_DBG, DREV, 1, 7) +FIELD(CSR_DBG, DEI, 8, 1) +FIELD(CSR_DBG, DCL, 9, 1) +FIELD(CSR_DBG, DFW, 10, 1) +FIELD(CSR_DBG, DMW, 11, 1) +FIELD(CSR_DBG, ECODE, 16, 6) + +#define LOONGARCH_CSR_DERA 0x501 /* Debug era */ +#define LOONGARCH_CSR_DSAVE 0x502 /* Debug save */ + +#endif /* LOONGARCH_CPU_CSR_H */ diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 95900be257..33d9a9450d 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -16,6 +16,7 @@ #include "cpu.h" #include "internals.h" #include "fpu/softfloat-helpers.h" +#include "cpu-csr.h" const char * const regnames[32] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", @@ -167,6 +168,8 @@ static void loongarch_la464_initfn(Object *obj) data = FIELD_DP32(data, CPUCFG20, L3IU_SETS, 14); data = FIELD_DP32(data, CPUCFG20, L3IU_SETS, 6); env->cpucfg[20] = data; + + env->CSR_ASID = FIELD_DP64(0, CSR_ASID, ASIDBITS, 0xa); } static void loongarch_cpu_list_entry(gpointer data, gpointer user_data) @@ -196,6 +199,44 @@ static void loongarch_cpu_reset(DeviceState *dev) env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3; env->fcsr0 = 0x0; + int n; + /* Set csr registers value after reset */ + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 1); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 0); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATF, 1); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATM, 1); + + env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, FPE, 0); + env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, SXE, 0); + env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, ASXE, 0); + env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, BTE, 0); + + env->CSR_MISC = 0; + + env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, VS, 0); + env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, LIE, 0); + + env->CSR_ESTAT = env->CSR_ESTAT & (~MAKE_64BIT_MASK(0, 2)); + env->CSR_RVACFG = FIELD_DP64(env->CSR_RVACFG, CSR_RVACFG, RBITS, 0); + env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0); + env->CSR_LLBCTL = FIELD_DP64(env->CSR_LLBCTL, CSR_LLBCTL, KLO, 0); + env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0); + env->CSR_MERRCTL = FIELD_DP64(env->CSR_MERRCTL, CSR_MERRCTL, ISMERR, 0); + + env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, TLB_TYPE, 2); + env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, MTLB_ENTRY, 63); + env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_WAYS, 7); + env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_SETS, 8); + + for (n = 0; n < 4; n++) { + env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV0, 0); + env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV1, 0); + env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV2, 0); + env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV3, 0); + } + restore_fp_status(env); cs->exception_index = -1; } diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 3e8ba46377..3ec978f47c 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -172,6 +172,15 @@ FIELD(CPUCFG20, L3IU_WAYS, 0, 16) FIELD(CPUCFG20, L3IU_SETS, 16, 8) FIELD(CPUCFG20, L3IU_SIZE, 24, 7) +/*CSR_CRMD */ +FIELD(CSR_CRMD, PLV, 0, 2) +FIELD(CSR_CRMD, IE, 2, 1) +FIELD(CSR_CRMD, DA, 3, 1) +FIELD(CSR_CRMD, PG, 4, 1) +FIELD(CSR_CRMD, DATF, 5, 2) +FIELD(CSR_CRMD, DATM, 7, 2) +FIELD(CSR_CRMD, WE, 9, 1) + extern const char * const regnames[32]; extern const char * const fregnames[32]; @@ -192,6 +201,61 @@ typedef struct CPUArchState { uint64_t llval; uint64_t badaddr; + + /* LoongArch CSRs */ + uint64_t CSR_CRMD; + uint64_t CSR_PRMD; + uint64_t CSR_EUEN; + uint64_t CSR_MISC; + uint64_t CSR_ECFG; + uint64_t CSR_ESTAT; + uint64_t CSR_ERA; + uint64_t CSR_BADV; + uint64_t CSR_BADI; + uint64_t CSR_EENTRY; + uint64_t CSR_TLBIDX; + uint64_t CSR_TLBEHI; + uint64_t CSR_TLBELO0; + uint64_t CSR_TLBELO1; + uint64_t CSR_ASID; + uint64_t CSR_PGDL; + uint64_t CSR_PGDH; + uint64_t CSR_PGD; + uint64_t CSR_PWCL; + uint64_t CSR_PWCH; + uint64_t CSR_STLBPS; + uint64_t CSR_RVACFG; + uint64_t CSR_PRCFG1; + uint64_t CSR_PRCFG2; + uint64_t CSR_PRCFG3; + uint64_t CSR_SAVE[16]; + uint64_t CSR_TID; + uint64_t CSR_TCFG; + uint64_t CSR_TVAL; + uint64_t CSR_CNTC; + uint64_t CSR_TICLR; + uint64_t CSR_LLBCTL; + uint64_t CSR_IMPCTL1; + uint64_t CSR_IMPCTL2; + uint64_t CSR_TLBRENTRY; + uint64_t CSR_TLBRBADV; + uint64_t CSR_TLBRERA; + uint64_t CSR_TLBRSAVE; + uint64_t CSR_TLBRELO0; + uint64_t CSR_TLBRELO1; + uint64_t CSR_TLBREHI; + uint64_t CSR_TLBRPRMD; + uint64_t CSR_MERRCTL; + uint64_t CSR_MERRINFO1; + uint64_t CSR_MERRINFO2; + uint64_t CSR_MERRENTRY; + uint64_t CSR_MERRERA; + uint64_t CSR_MERRSAVE; + uint64_t CSR_CTAG; + uint64_t CSR_DMW[4]; + uint64_t CSR_DBG; + uint64_t CSR_DERA; + uint64_t CSR_DSAVE; } CPULoongArchState; /** From 67ebd42a4884b5d6f29391beada050823108bd4f Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:10 +0800 Subject: [PATCH 827/935] target/loongarch: Add basic vmstate description of CPU. Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-21-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/cpu.c | 1 + target/loongarch/internals.h | 2 + target/loongarch/machine.c | 85 ++++++++++++++++++++++++++++++++++++ target/loongarch/meson.build | 6 +++ 4 files changed, 94 insertions(+) create mode 100644 target/loongarch/machine.c diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 33d9a9450d..267d96c9a8 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -336,6 +336,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data) cc->class_by_name = loongarch_cpu_class_by_name; cc->dump_state = loongarch_cpu_dump_state; cc->set_pc = loongarch_cpu_set_pc; + dc->vmsd = &vmstate_loongarch_cpu; cc->disas_set_info = loongarch_cpu_disas_set_info; #ifdef CONFIG_TCG cc->tcg_ops = &loongarch_tcg_ops; diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h index 1a3b39e0be..39960dee27 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -25,4 +25,6 @@ const char *loongarch_exception_name(int32_t exception); void restore_fp_status(CPULoongArchState *env); +extern const VMStateDescription vmstate_loongarch_cpu; + #endif diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c new file mode 100644 index 0000000000..49a06fdf28 --- /dev/null +++ b/target/loongarch/machine.c @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch Machine State + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "migration/cpu.h" + +/* LoongArch CPU state */ + +const VMStateDescription vmstate_loongarch_cpu = { + .name = "cpu", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + + VMSTATE_UINTTL_ARRAY(env.gpr, LoongArchCPU, 32), + VMSTATE_UINTTL(env.pc, LoongArchCPU), + VMSTATE_UINT64_ARRAY(env.fpr, LoongArchCPU, 32), + VMSTATE_UINT32(env.fcsr0, LoongArchCPU), + VMSTATE_BOOL_ARRAY(env.cf, LoongArchCPU, 8), + + /* Remaining CSRs */ + VMSTATE_UINT64(env.CSR_CRMD, LoongArchCPU), + VMSTATE_UINT64(env.CSR_PRMD, LoongArchCPU), + VMSTATE_UINT64(env.CSR_EUEN, LoongArchCPU), + VMSTATE_UINT64(env.CSR_MISC, LoongArchCPU), + VMSTATE_UINT64(env.CSR_ECFG, LoongArchCPU), + VMSTATE_UINT64(env.CSR_ESTAT, LoongArchCPU), + VMSTATE_UINT64(env.CSR_ERA, LoongArchCPU), + VMSTATE_UINT64(env.CSR_BADV, LoongArchCPU), + VMSTATE_UINT64(env.CSR_BADI, LoongArchCPU), + VMSTATE_UINT64(env.CSR_EENTRY, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBIDX, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBEHI, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBELO0, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBELO1, LoongArchCPU), + VMSTATE_UINT64(env.CSR_ASID, LoongArchCPU), + VMSTATE_UINT64(env.CSR_PGDL, LoongArchCPU), + VMSTATE_UINT64(env.CSR_PGDH, LoongArchCPU), + VMSTATE_UINT64(env.CSR_PGD, LoongArchCPU), + VMSTATE_UINT64(env.CSR_PWCL, LoongArchCPU), + VMSTATE_UINT64(env.CSR_PWCH, LoongArchCPU), + VMSTATE_UINT64(env.CSR_STLBPS, LoongArchCPU), + VMSTATE_UINT64(env.CSR_RVACFG, LoongArchCPU), + VMSTATE_UINT64(env.CSR_PRCFG1, LoongArchCPU), + VMSTATE_UINT64(env.CSR_PRCFG2, LoongArchCPU), + VMSTATE_UINT64(env.CSR_PRCFG3, LoongArchCPU), + VMSTATE_UINT64_ARRAY(env.CSR_SAVE, LoongArchCPU, 16), + VMSTATE_UINT64(env.CSR_TID, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TCFG, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TVAL, LoongArchCPU), + VMSTATE_UINT64(env.CSR_CNTC, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TICLR, LoongArchCPU), + VMSTATE_UINT64(env.CSR_LLBCTL, LoongArchCPU), + VMSTATE_UINT64(env.CSR_IMPCTL1, LoongArchCPU), + VMSTATE_UINT64(env.CSR_IMPCTL2, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBRENTRY, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBRBADV, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBRERA, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBRSAVE, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBRELO0, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBRELO1, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBREHI, LoongArchCPU), + VMSTATE_UINT64(env.CSR_TLBRPRMD, LoongArchCPU), + VMSTATE_UINT64(env.CSR_MERRCTL, LoongArchCPU), + VMSTATE_UINT64(env.CSR_MERRINFO1, LoongArchCPU), + VMSTATE_UINT64(env.CSR_MERRINFO2, LoongArchCPU), + VMSTATE_UINT64(env.CSR_MERRENTRY, LoongArchCPU), + VMSTATE_UINT64(env.CSR_MERRERA, LoongArchCPU), + VMSTATE_UINT64(env.CSR_MERRSAVE, LoongArchCPU), + VMSTATE_UINT64(env.CSR_CTAG, LoongArchCPU), + VMSTATE_UINT64_ARRAY(env.CSR_DMW, LoongArchCPU, 4), + + /* Debug CSRs */ + VMSTATE_UINT64(env.CSR_DBG, LoongArchCPU), + VMSTATE_UINT64(env.CSR_DERA, LoongArchCPU), + VMSTATE_UINT64(env.CSR_DSAVE, LoongArchCPU), + + VMSTATE_END_OF_LIST() + }, +}; diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build index bcb076e55f..103f36ee15 100644 --- a/target/loongarch/meson.build +++ b/target/loongarch/meson.build @@ -14,6 +14,12 @@ loongarch_tcg_ss.add(files( )) loongarch_tcg_ss.add(zlib) +loongarch_softmmu_ss = ss.source_set() +loongarch_softmmu_ss.add(files( + 'machine.c', +)) + loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss]) target_arch += {'loongarch': loongarch_ss} +target_softmmu_arch += {'loongarch': loongarch_softmmu_ss} From 425876f5d8110d5c004843d104a1cb1b90b35542 Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:11 +0800 Subject: [PATCH 828/935] target/loongarch: Implement qmp_query_cpu_definitions() Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-22-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- qapi/machine-target.json | 6 ++++-- target/loongarch/cpu.c | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/qapi/machine-target.json b/qapi/machine-target.json index 06b0d2ca61..2e267fa458 100644 --- a/qapi/machine-target.json +++ b/qapi/machine-target.json @@ -323,7 +323,8 @@ 'TARGET_ARM', 'TARGET_I386', 'TARGET_S390X', - 'TARGET_MIPS' ] } } + 'TARGET_MIPS', + 'TARGET_LOONGARCH64' ] } } ## # @query-cpu-definitions: @@ -339,4 +340,5 @@ 'TARGET_ARM', 'TARGET_I386', 'TARGET_S390X', - 'TARGET_MIPS' ] } } + 'TARGET_MIPS', + 'TARGET_LOONGARCH64' ] } } diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 267d96c9a8..aa0e1f9167 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -365,3 +365,29 @@ static const TypeInfo loongarch_cpu_type_infos[] = { }; DEFINE_TYPES(loongarch_cpu_type_infos) + +static void loongarch_cpu_add_definition(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + CpuDefinitionInfoList **cpu_list = user_data; + CpuDefinitionInfo *info = g_new0(CpuDefinitionInfo, 1); + const char *typename = object_class_get_name(oc); + + info->name = g_strndup(typename, + strlen(typename) - strlen("-" TYPE_LOONGARCH_CPU)); + info->q_typename = g_strdup(typename); + + QAPI_LIST_PREPEND(*cpu_list, info); +} + +CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) +{ + CpuDefinitionInfoList *cpu_list = NULL; + GSList *list; + + list = object_class_get_list(TYPE_LOONGARCH_CPU, false); + g_slist_foreach(list, loongarch_cpu_add_definition, &cpu_list); + g_slist_free(list); + + return cpu_list; +} From 7e1c521e2a108a4ffceecd8bec846625c956c8f8 Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:12 +0800 Subject: [PATCH 829/935] target/loongarch: Add MMU support for LoongArch CPU. Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-23-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/cpu-param.h | 2 +- target/loongarch/cpu.c | 24 +++ target/loongarch/cpu.h | 51 ++++++ target/loongarch/internals.h | 9 + target/loongarch/machine.c | 17 ++ target/loongarch/meson.build | 1 + target/loongarch/tlb_helper.c | 315 ++++++++++++++++++++++++++++++++++ 7 files changed, 418 insertions(+), 1 deletion(-) create mode 100644 target/loongarch/tlb_helper.c diff --git a/target/loongarch/cpu-param.h b/target/loongarch/cpu-param.h index 9a769b67e0..414d8fff46 100644 --- a/target/loongarch/cpu-param.h +++ b/target/loongarch/cpu-param.h @@ -13,6 +13,6 @@ #define TARGET_VIRT_ADDR_SPACE_BITS 48 #define TARGET_PAGE_BITS 14 -#define NB_MMU_MODES 4 +#define NB_MMU_MODES 5 #endif diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index aa0e1f9167..9a5cabbf4c 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -303,6 +303,21 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) } } + qemu_fprintf(f, "CRMD=%016" PRIx64 "\n", env->CSR_CRMD); + qemu_fprintf(f, "PRMD=%016" PRIx64 "\n", env->CSR_PRMD); + qemu_fprintf(f, "EUEN=%016" PRIx64 "\n", env->CSR_EUEN); + qemu_fprintf(f, "ESTAT=%016" PRIx64 "\n", env->CSR_ESTAT); + qemu_fprintf(f, "ERA=%016" PRIx64 "\n", env->CSR_ERA); + qemu_fprintf(f, "BADV=%016" PRIx64 "\n", env->CSR_BADV); + qemu_fprintf(f, "BADI=%016" PRIx64 "\n", env->CSR_BADI); + qemu_fprintf(f, "EENTRY=%016" PRIx64 "\n", env->CSR_EENTRY); + qemu_fprintf(f, "PRCFG1=%016" PRIx64 ", PRCFG2=%016" PRIx64 "," + " PRCFG3=%016" PRIx64 "\n", + env->CSR_PRCFG1, env->CSR_PRCFG3, env->CSR_PRCFG3); + qemu_fprintf(f, "TLBRENTRY=%016" PRIx64 "\n", env->CSR_TLBRENTRY); + qemu_fprintf(f, "TLBRBADV=%016" PRIx64 "\n", env->CSR_TLBRBADV); + qemu_fprintf(f, "TLBRERA=%016" PRIx64 "\n", env->CSR_TLBRERA); + /* fpr */ if (flags & CPU_DUMP_FPU) { for (i = 0; i < 32; i++) { @@ -320,9 +335,17 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) static struct TCGCPUOps loongarch_tcg_ops = { .initialize = loongarch_translate_init, .synchronize_from_tb = loongarch_cpu_synchronize_from_tb, + + .tlb_fill = loongarch_cpu_tlb_fill, }; #endif /* CONFIG_TCG */ +#include "hw/core/sysemu-cpu-ops.h" + +static const struct SysemuCPUOps loongarch_sysemu_ops = { + .get_phys_page_debug = loongarch_cpu_get_phys_page_debug, +}; + static void loongarch_cpu_class_init(ObjectClass *c, void *data) { LoongArchCPUClass *lacc = LOONGARCH_CPU_CLASS(c); @@ -337,6 +360,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data) cc->dump_state = loongarch_cpu_dump_state; cc->set_pc = loongarch_cpu_set_pc; dc->vmsd = &vmstate_loongarch_cpu; + cc->sysemu_ops = &loongarch_sysemu_ops; cc->disas_set_info = loongarch_cpu_disas_set_info; #ifdef CONFIG_TCG cc->tcg_ops = &loongarch_tcg_ops; diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 3ec978f47c..e0415d8929 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -184,6 +184,26 @@ FIELD(CSR_CRMD, WE, 9, 1) extern const char * const regnames[32]; extern const char * const fregnames[32]; +#define LOONGARCH_STLB 2048 /* 2048 STLB */ +#define LOONGARCH_MTLB 64 /* 64 MTLB */ +#define LOONGARCH_TLB_MAX (LOONGARCH_STLB + LOONGARCH_MTLB) + +/* + * define the ASID PS E VPPN field of TLB + */ +FIELD(TLB_MISC, E, 0, 1) +FIELD(TLB_MISC, ASID, 1, 10) +FIELD(TLB_MISC, VPPN, 13, 35) +FIELD(TLB_MISC, PS, 48, 6) + +struct LoongArchTLB { + uint64_t tlb_misc; + /* Fields corresponding to CSR_TLBELO0/1 */ + uint64_t tlb_entry0; + uint64_t tlb_entry1; +}; +typedef struct LoongArchTLB LoongArchTLB; + typedef struct CPUArchState { uint64_t gpr[32]; uint64_t pc; @@ -256,6 +276,8 @@ typedef struct CPUArchState { uint64_t CSR_DBG; uint64_t CSR_DERA; uint64_t CSR_DSAVE; + + LoongArchTLB tlb[LOONGARCH_TLB_MAX]; } CPULoongArchState; /** @@ -294,6 +316,35 @@ struct LoongArchCPUClass { DeviceReset parent_reset; }; +/* + * LoongArch CPUs has 4 privilege levels. + * 0 for kernel mode, 3 for user mode. + * Define an extra index for DA(direct addressing) mode. + */ +#define MMU_KERNEL_IDX 0 +#define MMU_USER_IDX 3 +#define MMU_DA_IDX 4 + +static inline int cpu_mmu_index(CPULoongArchState *env, bool ifetch) +{ + uint8_t pg = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG); + + if (!pg) { + return MMU_DA_IDX; + } + return FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV); +} + +static inline void cpu_get_tb_cpu_state(CPULoongArchState *env, + target_ulong *pc, + target_ulong *cs_base, + uint32_t *flags) +{ + *pc = env->pc; + *cs_base = 0; + *flags = cpu_mmu_index(env, false); +} + void loongarch_cpu_list(void); #define cpu_list loongarch_cpu_list diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h index 39960dee27..2fed768653 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -13,6 +13,9 @@ #define FCMP_UN 0b0100 /* unordered */ #define FCMP_GT 0b1000 /* fp0 > fp1 */ +#define TARGET_PHYS_MASK MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS) +#define TARGET_VIRT_MASK MAKE_64BIT_MASK(0, TARGET_VIRT_ADDR_SPACE_BITS) + void loongarch_translate_init(void); void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags); @@ -27,4 +30,10 @@ void restore_fp_status(CPULoongArchState *env); extern const VMStateDescription vmstate_loongarch_cpu; +bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr); + +hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); + #endif diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c index 49a06fdf28..b1e523ea72 100644 --- a/target/loongarch/machine.c +++ b/target/loongarch/machine.c @@ -8,6 +8,20 @@ #include "qemu/osdep.h" #include "cpu.h" #include "migration/cpu.h" +#include "internals.h" + +/* TLB state */ +const VMStateDescription vmstate_tlb = { + .name = "cpu/tlb", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT64(tlb_misc, LoongArchTLB), + VMSTATE_UINT64(tlb_entry0, LoongArchTLB), + VMSTATE_UINT64(tlb_entry1, LoongArchTLB), + VMSTATE_END_OF_LIST() + } +}; /* LoongArch CPU state */ @@ -79,6 +93,9 @@ const VMStateDescription vmstate_loongarch_cpu = { VMSTATE_UINT64(env.CSR_DBG, LoongArchCPU), VMSTATE_UINT64(env.CSR_DERA, LoongArchCPU), VMSTATE_UINT64(env.CSR_DSAVE, LoongArchCPU), + /* TLB */ + VMSTATE_STRUCT_ARRAY(env.tlb, LoongArchCPU, LOONGARCH_TLB_MAX, + 0, vmstate_tlb, LoongArchTLB), VMSTATE_END_OF_LIST() }, diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build index 103f36ee15..435cc75999 100644 --- a/target/loongarch/meson.build +++ b/target/loongarch/meson.build @@ -17,6 +17,7 @@ loongarch_tcg_ss.add(zlib) loongarch_softmmu_ss = ss.source_set() loongarch_softmmu_ss.add(files( 'machine.c', + 'tlb_helper.c', )) loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss]) diff --git a/target/loongarch/tlb_helper.c b/target/loongarch/tlb_helper.c new file mode 100644 index 0000000000..fad8bc7746 --- /dev/null +++ b/target/loongarch/tlb_helper.c @@ -0,0 +1,315 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch TLB helpers + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + */ + +#include "qemu/osdep.h" + +#include "cpu.h" +#include "internals.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "exec/log.h" +#include "cpu-csr.h" + +enum { + TLBRET_MATCH = 0, + TLBRET_BADADDR = 1, + TLBRET_NOMATCH = 2, + TLBRET_INVALID = 3, + TLBRET_DIRTY = 4, + TLBRET_RI = 5, + TLBRET_XI = 6, + TLBRET_PE = 7, +}; + +static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical, + int *prot, target_ulong address, + int access_type, int index, int mmu_idx) +{ + LoongArchTLB *tlb = &env->tlb[index]; + uint64_t plv = mmu_idx; + uint64_t tlb_entry, tlb_ppn; + uint8_t tlb_ps, n, tlb_v, tlb_d, tlb_plv, tlb_nx, tlb_nr, tlb_rplv; + + if (index >= LOONGARCH_STLB) { + tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); + } else { + tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); + } + n = (address >> tlb_ps) & 0x1;/* Odd or even */ + + tlb_entry = n ? tlb->tlb_entry1 : tlb->tlb_entry0; + tlb_v = FIELD_EX64(tlb_entry, TLBENTRY, V); + tlb_d = FIELD_EX64(tlb_entry, TLBENTRY, D); + tlb_plv = FIELD_EX64(tlb_entry, TLBENTRY, PLV); + tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY, PPN); + tlb_nx = FIELD_EX64(tlb_entry, TLBENTRY, NX); + tlb_nr = FIELD_EX64(tlb_entry, TLBENTRY, NR); + tlb_rplv = FIELD_EX64(tlb_entry, TLBENTRY, RPLV); + + /* Check access rights */ + if (!tlb_v) { + return TLBRET_INVALID; + } + + if (access_type == MMU_INST_FETCH && tlb_nx) { + return TLBRET_XI; + } + + if (access_type == MMU_DATA_LOAD && tlb_nr) { + return TLBRET_RI; + } + + if (((tlb_rplv == 0) && (plv > tlb_plv)) || + ((tlb_rplv == 1) && (plv != tlb_plv))) { + return TLBRET_PE; + } + + if ((access_type == MMU_DATA_STORE) && !tlb_d) { + return TLBRET_DIRTY; + } + + /* + * tlb_entry contains ppn[47:12] while 16KiB ppn is [47:15] + * need adjust. + */ + *physical = (tlb_ppn << R_TLBENTRY_PPN_SHIFT) | + (address & MAKE_64BIT_MASK(0, tlb_ps)); + *prot = PAGE_READ; + if (tlb_d) { + *prot |= PAGE_WRITE; + } + if (!tlb_nx) { + *prot |= PAGE_EXEC; + } + return TLBRET_MATCH; +} + +/* + * One tlb entry holds an adjacent odd/even pair, the vpn is the + * content of the virtual page number divided by 2. So the + * compare vpn is bit[47:15] for 16KiB page. while the vppn + * field in tlb entry contains bit[47:13], so need adjust. + * virt_vpn = vaddr[47:13] + */ +static bool loongarch_tlb_search(CPULoongArchState *env, target_ulong vaddr, + int *index) +{ + LoongArchTLB *tlb; + uint16_t csr_asid, tlb_asid, stlb_idx; + uint8_t tlb_e, tlb_ps, tlb_g, stlb_ps; + int i, compare_shift; + uint64_t vpn, tlb_vppn; + + csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID); + stlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); + vpn = (vaddr & TARGET_VIRT_MASK) >> (stlb_ps + 1); + stlb_idx = vpn & 0xff; /* VA[25:15] <==> TLBIDX.index for 16KiB Page */ + compare_shift = stlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; + + /* Search STLB */ + for (i = 0; i < 8; ++i) { + tlb = &env->tlb[i * 256 + stlb_idx]; + tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); + if (tlb_e) { + tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); + tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); + tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + + if ((tlb_g == 1 || tlb_asid == csr_asid) && + (vpn == (tlb_vppn >> compare_shift))) { + *index = i * 256 + stlb_idx; + return true; + } + } + } + + /* Search MTLB */ + for (i = LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; ++i) { + tlb = &env->tlb[i]; + tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); + if (tlb_e) { + tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); + tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); + tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); + tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; + vpn = (vaddr & TARGET_VIRT_MASK) >> (tlb_ps + 1); + if ((tlb_g == 1 || tlb_asid == csr_asid) && + (vpn == (tlb_vppn >> compare_shift))) { + *index = i; + return true; + } + } + } + return false; +} + +static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical, + int *prot, target_ulong address, + MMUAccessType access_type, int mmu_idx) +{ + int index, match; + + match = loongarch_tlb_search(env, address, &index); + if (match) { + return loongarch_map_tlb_entry(env, physical, prot, + address, access_type, index, mmu_idx); + } + + return TLBRET_NOMATCH; +} + +static int get_physical_address(CPULoongArchState *env, hwaddr *physical, + int *prot, target_ulong address, + MMUAccessType access_type, int mmu_idx) +{ + int user_mode = mmu_idx == MMU_USER_IDX; + int kernel_mode = mmu_idx == MMU_KERNEL_IDX; + uint32_t plv, base_c, base_v; + int64_t addr_high; + uint8_t da = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, DA); + uint8_t pg = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG); + + /* Check PG and DA */ + if (da & !pg) { + *physical = address & TARGET_PHYS_MASK; + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + return TLBRET_MATCH; + } + + plv = kernel_mode | (user_mode << R_CSR_DMW_PLV3_SHIFT); + base_v = address >> TARGET_VIRT_ADDR_SPACE_BITS; + /* Check direct map window */ + for (int i = 0; i < 4; i++) { + base_c = env->CSR_DMW[i] >> TARGET_VIRT_ADDR_SPACE_BITS; + if ((plv & env->CSR_DMW[i]) && (base_c == base_v)) { + *physical = dmw_va2pa(address); + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + return TLBRET_MATCH; + } + } + + /* Check valid extension */ + addr_high = sextract64(address, TARGET_VIRT_ADDR_SPACE_BITS, 16); + if (!(addr_high == 0 || addr_high == -1)) { + return TLBRET_BADADDR; + } + + /* Mapped address */ + return loongarch_map_address(env, physical, prot, address, + access_type, mmu_idx); +} + +hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + hwaddr phys_addr; + int prot; + + if (get_physical_address(env, &phys_addr, &prot, addr, MMU_DATA_LOAD, + cpu_mmu_index(env, false)) != 0) { + return -1; + } + return phys_addr; +} + +static void raise_mmu_exception(CPULoongArchState *env, target_ulong address, + MMUAccessType access_type, int tlb_error) +{ + CPUState *cs = env_cpu(env); + + switch (tlb_error) { + default: + case TLBRET_BADADDR: + cs->exception_index = EXCCODE_ADEM; + break; + case TLBRET_NOMATCH: + /* No TLB match for a mapped address */ + if (access_type == MMU_DATA_LOAD) { + cs->exception_index = EXCCODE_PIL; + } else if (access_type == MMU_DATA_STORE) { + cs->exception_index = EXCCODE_PIS; + } else if (access_type == MMU_INST_FETCH) { + cs->exception_index = EXCCODE_PIF; + } + env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 1); + break; + case TLBRET_INVALID: + /* TLB match with no valid bit */ + if (access_type == MMU_DATA_LOAD) { + cs->exception_index = EXCCODE_PIL; + } else if (access_type == MMU_DATA_STORE) { + cs->exception_index = EXCCODE_PIS; + } else if (access_type == MMU_INST_FETCH) { + cs->exception_index = EXCCODE_PIF; + } + break; + case TLBRET_DIRTY: + /* TLB match but 'D' bit is cleared */ + cs->exception_index = EXCCODE_PME; + break; + case TLBRET_XI: + /* Execute-Inhibit Exception */ + cs->exception_index = EXCCODE_PNX; + break; + case TLBRET_RI: + /* Read-Inhibit Exception */ + cs->exception_index = EXCCODE_PNR; + break; + case TLBRET_PE: + /* Privileged Exception */ + cs->exception_index = EXCCODE_PPI; + break; + } + + if (tlb_error == TLBRET_NOMATCH) { + env->CSR_TLBRBADV = address; + env->CSR_TLBREHI = FIELD_DP64(env->CSR_TLBREHI, CSR_TLBREHI, VPPN, + extract64(address, 13, 35)); + } else { + if (!FIELD_EX64(env->CSR_DBG, CSR_DBG, DST)) { + env->CSR_BADV = address; + } + env->CSR_TLBEHI = address & (TARGET_PAGE_MASK << 1); + } +} + +bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + hwaddr physical; + int prot; + int ret = TLBRET_BADADDR; + + /* Data access */ + ret = get_physical_address(env, &physical, &prot, address, + access_type, mmu_idx); + + if (ret == TLBRET_MATCH) { + tlb_set_page(cs, address & TARGET_PAGE_MASK, + physical & TARGET_PAGE_MASK, prot, + mmu_idx, TARGET_PAGE_SIZE); + qemu_log_mask(CPU_LOG_MMU, + "%s address=%" VADDR_PRIx " physical " TARGET_FMT_plx + " prot %d\n", __func__, address, physical, prot); + return true; + } else { + qemu_log_mask(CPU_LOG_MMU, + "%s address=%" VADDR_PRIx " ret %d\n", __func__, address, + ret); + } + if (probe) { + return false; + } + raise_mmu_exception(env, address, access_type, ret); + cpu_loop_exit_restore(cs, retaddr); +} From f757a2cd6948344b8303e375f6f9d72887abf1f4 Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:13 +0800 Subject: [PATCH 830/935] target/loongarch: Add LoongArch interrupt and exception handle Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-24-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/cpu.c | 230 +++++++++++++++++++++++++++++++++++ target/loongarch/cpu.h | 2 + target/loongarch/internals.h | 2 + 3 files changed, 234 insertions(+) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 9a5cabbf4c..01a0b4878a 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -80,6 +80,215 @@ static void loongarch_cpu_set_pc(CPUState *cs, vaddr value) env->pc = value; } +void loongarch_cpu_set_irq(void *opaque, int irq, int level) +{ + LoongArchCPU *cpu = opaque; + CPULoongArchState *env = &cpu->env; + CPUState *cs = CPU(cpu); + + if (irq < 0 || irq >= N_IRQS) { + return; + } + + env->CSR_ESTAT = deposit64(env->CSR_ESTAT, irq, 1, level != 0); + + if (FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS)) { + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } +} + +static inline bool cpu_loongarch_hw_interrupts_enabled(CPULoongArchState *env) +{ + bool ret = 0; + + ret = (FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE) && + !(FIELD_EX64(env->CSR_DBG, CSR_DBG, DST))); + + return ret; +} + +/* Check if there is pending and not masked out interrupt */ +static inline bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env) +{ + uint32_t pending; + uint32_t status; + bool r; + + pending = FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS); + status = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, LIE); + + r = (pending & status) != 0; + return r; +} + +static void loongarch_cpu_do_interrupt(CPUState *cs) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + bool update_badinstr = 1; + int cause = -1; + const char *name; + bool tlbfill = FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR); + uint32_t vec_size = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, VS); + + if (cs->exception_index != EXCCODE_INT) { + if (cs->exception_index < 0 || + cs->exception_index > ARRAY_SIZE(excp_names)) { + name = "unknown"; + } else { + name = excp_names[cs->exception_index]; + } + + qemu_log_mask(CPU_LOG_INT, + "%s enter: pc " TARGET_FMT_lx " ERA " TARGET_FMT_lx + " TLBRERA " TARGET_FMT_lx " %s exception\n", __func__, + env->pc, env->CSR_ERA, env->CSR_TLBRERA, name); + } + + switch (cs->exception_index) { + case EXCCODE_DBP: + env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DCL, 1); + env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, ECODE, 0xC); + goto set_DERA; + set_DERA: + env->CSR_DERA = env->pc; + env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DST, 1); + env->pc = env->CSR_EENTRY + 0x480; + break; + case EXCCODE_INT: + if (FIELD_EX64(env->CSR_DBG, CSR_DBG, DST)) { + env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DEI, 1); + goto set_DERA; + } + QEMU_FALLTHROUGH; + case EXCCODE_PIF: + cause = cs->exception_index; + update_badinstr = 0; + break; + case EXCCODE_ADEM: + case EXCCODE_SYS: + case EXCCODE_BRK: + case EXCCODE_PIL: + case EXCCODE_PIS: + case EXCCODE_PME: + case EXCCODE_PNR: + case EXCCODE_PNX: + case EXCCODE_PPI: + case EXCCODE_INE: + case EXCCODE_IPE: + case EXCCODE_FPE: + cause = cs->exception_index; + break; + default: + qemu_log("Error: exception(%d) '%s' has not been supported\n", + cs->exception_index, excp_names[cs->exception_index]); + abort(); + } + + if (update_badinstr) { + env->CSR_BADI = cpu_ldl_code(env, env->pc); + } + + /* Save PLV and IE */ + if (tlbfill) { + env->CSR_TLBRPRMD = FIELD_DP64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PPLV, + FIELD_EX64(env->CSR_CRMD, + CSR_CRMD, PLV)); + env->CSR_TLBRPRMD = FIELD_DP64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PIE, + FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE)); + /* set the DA mode */ + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 1); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 0); + env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, + PC, (env->pc >> 2)); + } else { + env->CSR_ESTAT = FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, ECODE, cause); + env->CSR_PRMD = FIELD_DP64(env->CSR_PRMD, CSR_PRMD, PPLV, + FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV)); + env->CSR_PRMD = FIELD_DP64(env->CSR_PRMD, CSR_PRMD, PIE, + FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE)); + env->CSR_ERA = env->pc; + } + + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0); + + if (cs->exception_index == EXCCODE_INT) { + /* Interrupt */ + uint32_t vector = 0; + uint32_t pending = FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS); + pending &= FIELD_EX64(env->CSR_ECFG, CSR_ECFG, LIE); + + /* Find the highest-priority interrupt. */ + vector = 31 - clz32(pending); + env->pc = env->CSR_EENTRY + (EXCCODE_EXTERNAL_INT + vector) * vec_size; + qemu_log_mask(CPU_LOG_INT, + "%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx + " cause %d\n" " A " TARGET_FMT_lx " D " + TARGET_FMT_lx " vector = %d ExC " TARGET_FMT_lx "ExS" + TARGET_FMT_lx "\n", + __func__, env->pc, env->CSR_ERA, + cause, env->CSR_BADV, env->CSR_DERA, vector, + env->CSR_ECFG, env->CSR_ESTAT); + } else { + if (tlbfill) { + env->pc = env->CSR_TLBRENTRY; + } else { + env->pc = env->CSR_EENTRY; + env->pc += cause * vec_size; + } + qemu_log_mask(CPU_LOG_INT, + "%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx + " cause %d%s\n, ESTAT " TARGET_FMT_lx + " EXCFG " TARGET_FMT_lx " BADVA " TARGET_FMT_lx + "BADI " TARGET_FMT_lx " SYS_NUM " TARGET_FMT_lu + " cpu %d asid " TARGET_FMT_lx "\n", __func__, env->pc, + tlbfill ? env->CSR_TLBRERA : env->CSR_ERA, + cause, tlbfill ? "(refill)" : "", env->CSR_ESTAT, + env->CSR_ECFG, + tlbfill ? env->CSR_TLBRBADV : env->CSR_BADV, + env->CSR_BADI, env->gpr[11], cs->cpu_index, + env->CSR_ASID); + } + cs->exception_index = -1; +} + +static void loongarch_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, + vaddr addr, unsigned size, + MMUAccessType access_type, + int mmu_idx, MemTxAttrs attrs, + MemTxResult response, + uintptr_t retaddr) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + if (access_type == MMU_INST_FETCH) { + do_raise_exception(env, EXCCODE_ADEF, retaddr); + } else { + do_raise_exception(env, EXCCODE_ADEM, retaddr); + } +} + +static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ + if (interrupt_request & CPU_INTERRUPT_HARD) { + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + if (cpu_loongarch_hw_interrupts_enabled(env) && + cpu_loongarch_hw_interrupts_pending(env)) { + /* Raise it */ + cs->exception_index = EXCCODE_INT; + loongarch_cpu_do_interrupt(cs); + return true; + } + } + return false; +} + #ifdef CONFIG_TCG static void loongarch_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) @@ -91,6 +300,20 @@ static void loongarch_cpu_synchronize_from_tb(CPUState *cs, } #endif /* CONFIG_TCG */ +static bool loongarch_cpu_has_work(CPUState *cs) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + bool has_work = false; + + if ((cs->interrupt_request & CPU_INTERRUPT_HARD) && + cpu_loongarch_hw_interrupts_pending(env)) { + has_work = true; + } + + return has_work; +} + static void loongarch_la464_initfn(Object *obj) { LoongArchCPU *cpu = LOONGARCH_CPU(obj); @@ -237,6 +460,8 @@ static void loongarch_cpu_reset(DeviceState *dev) env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV3, 0); } + env->pc = 0x1c000000; + restore_fp_status(env); cs->exception_index = -1; } @@ -269,6 +494,7 @@ static void loongarch_cpu_init(Object *obj) LoongArchCPU *cpu = LOONGARCH_CPU(obj); cpu_set_cpustate_pointers(cpu); + qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS); } static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model) @@ -337,6 +563,9 @@ static struct TCGCPUOps loongarch_tcg_ops = { .synchronize_from_tb = loongarch_cpu_synchronize_from_tb, .tlb_fill = loongarch_cpu_tlb_fill, + .cpu_exec_interrupt = loongarch_cpu_exec_interrupt, + .do_interrupt = loongarch_cpu_do_interrupt, + .do_transaction_failed = loongarch_cpu_do_transaction_failed, }; #endif /* CONFIG_TCG */ @@ -357,6 +586,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data) device_class_set_parent_reset(dc, loongarch_cpu_reset, &lacc->parent_reset); cc->class_by_name = loongarch_cpu_class_by_name; + cc->has_work = loongarch_cpu_has_work; cc->dump_state = loongarch_cpu_dump_state; cc->set_pc = loongarch_cpu_set_pc; dc->vmsd = &vmstate_loongarch_cpu; diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index e0415d8929..b983ce241c 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -184,6 +184,8 @@ FIELD(CSR_CRMD, WE, 9, 1) extern const char * const regnames[32]; extern const char * const fregnames[32]; +#define N_IRQS 13 + #define LOONGARCH_STLB 2048 /* 2048 STLB */ #define LOONGARCH_MTLB 64 /* 64 MTLB */ #define LOONGARCH_TLB_MAX (LOONGARCH_STLB + LOONGARCH_MTLB) diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h index 2fed768653..69183e8bb5 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -30,6 +30,8 @@ void restore_fp_status(CPULoongArchState *env); extern const VMStateDescription vmstate_loongarch_cpu; +void loongarch_cpu_set_irq(void *opaque, int irq, int level); + bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); From dd615fa48da89b2308a907cc4e4956771c75d68f Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:14 +0800 Subject: [PATCH 831/935] target/loongarch: Add constant timer support Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-25-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/constant_timer.c | 64 +++++++++++++++++++++++++++++++ target/loongarch/cpu.c | 2 + target/loongarch/cpu.h | 4 ++ target/loongarch/internals.h | 6 +++ target/loongarch/meson.build | 1 + 5 files changed, 77 insertions(+) create mode 100644 target/loongarch/constant_timer.c diff --git a/target/loongarch/constant_timer.c b/target/loongarch/constant_timer.c new file mode 100644 index 0000000000..1851f53fd6 --- /dev/null +++ b/target/loongarch/constant_timer.c @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch constant timer support + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qemu/timer.h" +#include "cpu.h" +#include "internals.h" +#include "cpu-csr.h" + +#define TIMER_PERIOD 10 /* 10 ns period for 100 MHz frequency */ +#define CONSTANT_TIMER_TICK_MASK 0xfffffffffffcUL +#define CONSTANT_TIMER_ENABLE 0x1UL + +uint64_t cpu_loongarch_get_constant_timer_counter(LoongArchCPU *cpu) +{ + return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD; +} + +uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArchCPU *cpu) +{ + uint64_t now, expire; + + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + expire = timer_expire_time_ns(&cpu->timer); + + return (expire - now) / TIMER_PERIOD; +} + +void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu, + uint64_t value) +{ + CPULoongArchState *env = &cpu->env; + uint64_t now, next; + + env->CSR_TCFG = value; + if (value & CONSTANT_TIMER_ENABLE) { + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + next = now + (value & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD; + timer_mod(&cpu->timer, next); + } else { + timer_del(&cpu->timer); + } +} + +void loongarch_constant_timer_cb(void *opaque) +{ + LoongArchCPU *cpu = opaque; + CPULoongArchState *env = &cpu->env; + uint64_t now, next; + + if (FIELD_EX64(env->CSR_TCFG, CSR_TCFG, PERIODIC)) { + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + next = now + (env->CSR_TCFG & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD; + timer_mod(&cpu->timer, next); + } else { + env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0); + } + + loongarch_cpu_set_irq(opaque, IRQ_TIMER, 1); +} diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 01a0b4878a..5ec0ba1cfa 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -495,6 +495,8 @@ static void loongarch_cpu_init(Object *obj) cpu_set_cpustate_pointers(cpu); qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS); + timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL, + &loongarch_constant_timer_cb, cpu); } static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model) diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index b983ce241c..2081902f2e 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -11,6 +11,7 @@ #include "exec/cpu-defs.h" #include "fpu/softfloat-types.h" #include "hw/registerfields.h" +#include "qemu/timer.h" #define TCG_GUEST_DEFAULT_MO (0) @@ -185,6 +186,8 @@ extern const char * const regnames[32]; extern const char * const fregnames[32]; #define N_IRQS 13 +#define IRQ_TIMER 11 +#define IRQ_IPI 12 #define LOONGARCH_STLB 2048 /* 2048 STLB */ #define LOONGARCH_MTLB 64 /* 64 MTLB */ @@ -295,6 +298,7 @@ struct ArchCPU { CPUNegativeOffsetState neg; CPULoongArchState env; + QEMUTimer timer; }; #define TYPE_LOONGARCH_CPU "loongarch-cpu" diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h index 69183e8bb5..4b1bcd7c0f 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -32,6 +32,12 @@ extern const VMStateDescription vmstate_loongarch_cpu; void loongarch_cpu_set_irq(void *opaque, int irq, int level); +void loongarch_constant_timer_cb(void *opaque); +uint64_t cpu_loongarch_get_constant_timer_counter(LoongArchCPU *cpu); +uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArchCPU *cpu); +void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu, + uint64_t value); + bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build index 435cc75999..04e15ba1e3 100644 --- a/target/loongarch/meson.build +++ b/target/loongarch/meson.build @@ -18,6 +18,7 @@ loongarch_softmmu_ss = ss.source_set() loongarch_softmmu_ss.add(files( 'machine.c', 'tlb_helper.c', + 'constant_timer.c', )) loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss]) From 5b1dedfe848b61521aa5b46b81a4cc676e9e7c1b Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:15 +0800 Subject: [PATCH 832/935] target/loongarch: Add LoongArch CSR instruction This includes: - CSRRD - CSRWR - CSRXCHG Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-26-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/csr_helper.c | 87 ++++++ target/loongarch/disas.c | 101 +++++++ target/loongarch/helper.h | 8 + .../insn_trans/trans_privileged.c.inc | 264 ++++++++++++++++++ target/loongarch/insns.decode | 13 + target/loongarch/meson.build | 1 + target/loongarch/translate.c | 11 +- 7 files changed, 484 insertions(+), 1 deletion(-) create mode 100644 target/loongarch/csr_helper.c create mode 100644 target/loongarch/insn_trans/trans_privileged.c.inc diff --git a/target/loongarch/csr_helper.c b/target/loongarch/csr_helper.c new file mode 100644 index 0000000000..24a9389364 --- /dev/null +++ b/target/loongarch/csr_helper.c @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch emulation helpers for CSRs + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "cpu.h" +#include "internals.h" +#include "qemu/host-utils.h" +#include "exec/helper-proto.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "hw/irq.h" +#include "cpu-csr.h" +#include "tcg/tcg-ldst.h" + +target_ulong helper_csrrd_pgd(CPULoongArchState *env) +{ + int64_t v; + + if (env->CSR_TLBRERA & 0x1) { + v = env->CSR_TLBRBADV; + } else { + v = env->CSR_BADV; + } + + if ((v >> 63) & 0x1) { + v = env->CSR_PGDH; + } else { + v = env->CSR_PGDL; + } + + return v; +} + +target_ulong helper_csrrd_tval(CPULoongArchState *env) +{ + LoongArchCPU *cpu = env_archcpu(env); + + return cpu_loongarch_get_constant_timer_ticks(cpu); +} + +target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val) +{ + int64_t old_v = env->CSR_ESTAT; + + /* Only IS[1:0] can be written */ + env->CSR_ESTAT = deposit64(env->CSR_ESTAT, 0, 2, val); + + return old_v; +} + +target_ulong helper_csrwr_asid(CPULoongArchState *env, target_ulong val) +{ + int64_t old_v = env->CSR_ASID; + + /* Only ASID filed of CSR_ASID can be written */ + env->CSR_ASID = deposit64(env->CSR_ASID, 0, 10, val); + if (old_v != env->CSR_ASID) { + tlb_flush(env_cpu(env)); + } + return old_v; +} + +target_ulong helper_csrwr_tcfg(CPULoongArchState *env, target_ulong val) +{ + LoongArchCPU *cpu = env_archcpu(env); + int64_t old_v = env->CSR_TCFG; + + cpu_loongarch_store_constant_timer_config(cpu, val); + + return old_v; +} + +target_ulong helper_csrwr_ticlr(CPULoongArchState *env, target_ulong val) +{ + LoongArchCPU *cpu = env_archcpu(env); + int64_t old_v = 0; + + if (val & 0x1) { + loongarch_cpu_set_irq(cpu, IRQ_TIMER, 0); + } + return old_v; +} diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c index 9454ebb8e9..11a704ff7c 100644 --- a/target/loongarch/disas.c +++ b/target/loongarch/disas.c @@ -8,6 +8,7 @@ #include "qemu/osdep.h" #include "disas/dis-asm.h" #include "qemu/bitops.h" +#include "cpu-csr.h" typedef struct { disassemble_info *info; @@ -25,6 +26,90 @@ static inline int shl_2(DisasContext *ctx, int x) return x << 2; } +#define CSR_NAME(REG) \ + [LOONGARCH_CSR_##REG] = (#REG) + +static const char * const csr_names[] = { + CSR_NAME(CRMD), + CSR_NAME(PRMD), + CSR_NAME(EUEN), + CSR_NAME(MISC), + CSR_NAME(ECFG), + CSR_NAME(ESTAT), + CSR_NAME(ERA), + CSR_NAME(BADV), + CSR_NAME(BADI), + CSR_NAME(EENTRY), + CSR_NAME(TLBIDX), + CSR_NAME(TLBEHI), + CSR_NAME(TLBELO0), + CSR_NAME(TLBELO1), + CSR_NAME(ASID), + CSR_NAME(PGDL), + CSR_NAME(PGDH), + CSR_NAME(PGD), + CSR_NAME(PWCL), + CSR_NAME(PWCH), + CSR_NAME(STLBPS), + CSR_NAME(RVACFG), + CSR_NAME(CPUID), + CSR_NAME(PRCFG1), + CSR_NAME(PRCFG2), + CSR_NAME(PRCFG3), + CSR_NAME(SAVE(0)), + CSR_NAME(SAVE(1)), + CSR_NAME(SAVE(2)), + CSR_NAME(SAVE(3)), + CSR_NAME(SAVE(4)), + CSR_NAME(SAVE(5)), + CSR_NAME(SAVE(6)), + CSR_NAME(SAVE(7)), + CSR_NAME(SAVE(8)), + CSR_NAME(SAVE(9)), + CSR_NAME(SAVE(10)), + CSR_NAME(SAVE(11)), + CSR_NAME(SAVE(12)), + CSR_NAME(SAVE(13)), + CSR_NAME(SAVE(14)), + CSR_NAME(SAVE(15)), + CSR_NAME(TID), + CSR_NAME(TCFG), + CSR_NAME(TVAL), + CSR_NAME(CNTC), + CSR_NAME(TICLR), + CSR_NAME(LLBCTL), + CSR_NAME(IMPCTL1), + CSR_NAME(IMPCTL2), + CSR_NAME(TLBRENTRY), + CSR_NAME(TLBRBADV), + CSR_NAME(TLBRERA), + CSR_NAME(TLBRSAVE), + CSR_NAME(TLBRELO0), + CSR_NAME(TLBRELO1), + CSR_NAME(TLBREHI), + CSR_NAME(TLBRPRMD), + CSR_NAME(MERRCTL), + CSR_NAME(MERRINFO1), + CSR_NAME(MERRINFO2), + CSR_NAME(MERRENTRY), + CSR_NAME(MERRERA), + CSR_NAME(MERRSAVE), + CSR_NAME(CTAG), + CSR_NAME(DMW(0)), + CSR_NAME(DMW(1)), + CSR_NAME(DMW(2)), + CSR_NAME(DMW(3)), + CSR_NAME(DBG), + CSR_NAME(DERA), + CSR_NAME(DSAVE), +}; + +static const char *get_csr_name(unsigned num) +{ + return ((num < ARRAY_SIZE(csr_names)) && (csr_names[num] != NULL)) ? + csr_names[num] : "Undefined CSR"; +} + #define output(C, INSN, FMT, ...) \ { \ (C)->info->fprintf_func((C)->info->stream, "%08x %-9s\t" FMT, \ @@ -205,6 +290,19 @@ static void output_rr_offs(DisasContext *ctx, arg_rr_offs *a, a->rd, a->offs, ctx->pc + a->offs); } +static void output_r_csr(DisasContext *ctx, arg_r_csr *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, %d # %s", a->rd, a->csr, get_csr_name(a->csr)); +} + +static void output_rr_csr(DisasContext *ctx, arg_rr_csr *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, r%d, %d # %s", + a->rd, a->rj, a->csr, get_csr_name(a->csr)); +} + #define INSN(insn, type) \ static bool trans_##insn(DisasContext *ctx, arg_##type * a) \ { \ @@ -514,6 +612,9 @@ INSN(blt, rr_offs) INSN(bge, rr_offs) INSN(bltu, rr_offs) INSN(bgeu, rr_offs) +INSN(csrrd, r_csr) +INSN(csrwr, r_csr) +INSN(csrxchg, rr_csr) #define output_fcmp(C, PREFIX, SUFFIX) \ { \ diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index da1a2bced7..5a6754eb65 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -92,3 +92,11 @@ DEF_HELPER_2(frint_s, i64, env, i64) DEF_HELPER_2(frint_d, i64, env, i64) DEF_HELPER_FLAGS_2(set_rounding_mode, TCG_CALL_NO_RWG, void, env, i32) + +/* CSRs helper */ +DEF_HELPER_1(csrrd_pgd, i64, env) +DEF_HELPER_1(csrrd_tval, i64, env) +DEF_HELPER_2(csrwr_estat, i64, env, tl) +DEF_HELPER_2(csrwr_asid, i64, env, tl) +DEF_HELPER_2(csrwr_tcfg, i64, env, tl) +DEF_HELPER_2(csrwr_ticlr, i64, env, tl) diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc b/target/loongarch/insn_trans/trans_privileged.c.inc new file mode 100644 index 0000000000..f984e3f68e --- /dev/null +++ b/target/loongarch/insn_trans/trans_privileged.c.inc @@ -0,0 +1,264 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * LoongArch translation routines for the privileged instructions. + */ + +#include "cpu-csr.h" + +typedef void (*GenCSRRead)(TCGv dest, TCGv_ptr env); +typedef void (*GenCSRWrite)(TCGv dest, TCGv_ptr env, TCGv src); + +typedef struct { + int offset; + int flags; + GenCSRRead readfn; + GenCSRWrite writefn; +} CSRInfo; + +enum { + CSRFL_READONLY = (1 << 0), + CSRFL_EXITTB = (1 << 1), + CSRFL_IO = (1 << 2), +}; + +#define CSR_OFF_FUNCS(NAME, FL, RD, WR) \ + [LOONGARCH_CSR_##NAME] = { \ + .offset = offsetof(CPULoongArchState, CSR_##NAME), \ + .flags = FL, .readfn = RD, .writefn = WR \ + } + +#define CSR_OFF_ARRAY(NAME, N) \ + [LOONGARCH_CSR_##NAME(N)] = { \ + .offset = offsetof(CPULoongArchState, CSR_##NAME[N]), \ + .flags = 0, .readfn = NULL, .writefn = NULL \ + } + +#define CSR_OFF_FLAGS(NAME, FL) \ + CSR_OFF_FUNCS(NAME, FL, NULL, NULL) + +#define CSR_OFF(NAME) \ + CSR_OFF_FLAGS(NAME, 0) + +static const CSRInfo csr_info[] = { + CSR_OFF_FLAGS(CRMD, CSRFL_EXITTB), + CSR_OFF(PRMD), + CSR_OFF_FLAGS(EUEN, CSRFL_EXITTB), + CSR_OFF_FLAGS(MISC, CSRFL_READONLY), + CSR_OFF(ECFG), + CSR_OFF_FUNCS(ESTAT, CSRFL_EXITTB, NULL, gen_helper_csrwr_estat), + CSR_OFF(ERA), + CSR_OFF(BADV), + CSR_OFF_FLAGS(BADI, CSRFL_READONLY), + CSR_OFF(EENTRY), + CSR_OFF(TLBIDX), + CSR_OFF(TLBEHI), + CSR_OFF(TLBELO0), + CSR_OFF(TLBELO1), + CSR_OFF_FUNCS(ASID, CSRFL_EXITTB, NULL, gen_helper_csrwr_asid), + CSR_OFF(PGDL), + CSR_OFF(PGDH), + CSR_OFF_FUNCS(PGD, CSRFL_READONLY, gen_helper_csrrd_pgd, NULL), + CSR_OFF(PWCL), + CSR_OFF(PWCH), + CSR_OFF(STLBPS), + CSR_OFF(RVACFG), + [LOONGARCH_CSR_CPUID] = { + .offset = (int)offsetof(CPUState, cpu_index) + - (int)offsetof(LoongArchCPU, env), + .flags = CSRFL_READONLY, + .readfn = NULL, + .writefn = NULL + }, + CSR_OFF_FLAGS(PRCFG1, CSRFL_READONLY), + CSR_OFF_FLAGS(PRCFG2, CSRFL_READONLY), + CSR_OFF_FLAGS(PRCFG3, CSRFL_READONLY), + CSR_OFF_ARRAY(SAVE, 0), + CSR_OFF_ARRAY(SAVE, 1), + CSR_OFF_ARRAY(SAVE, 2), + CSR_OFF_ARRAY(SAVE, 3), + CSR_OFF_ARRAY(SAVE, 4), + CSR_OFF_ARRAY(SAVE, 5), + CSR_OFF_ARRAY(SAVE, 6), + CSR_OFF_ARRAY(SAVE, 7), + CSR_OFF_ARRAY(SAVE, 8), + CSR_OFF_ARRAY(SAVE, 9), + CSR_OFF_ARRAY(SAVE, 10), + CSR_OFF_ARRAY(SAVE, 11), + CSR_OFF_ARRAY(SAVE, 12), + CSR_OFF_ARRAY(SAVE, 13), + CSR_OFF_ARRAY(SAVE, 14), + CSR_OFF_ARRAY(SAVE, 15), + CSR_OFF(TID), + CSR_OFF_FUNCS(TCFG, CSRFL_IO, NULL, gen_helper_csrwr_tcfg), + CSR_OFF_FUNCS(TVAL, CSRFL_READONLY | CSRFL_IO, gen_helper_csrrd_tval, NULL), + CSR_OFF(CNTC), + CSR_OFF_FUNCS(TICLR, CSRFL_IO, NULL, gen_helper_csrwr_ticlr), + CSR_OFF(LLBCTL), + CSR_OFF(IMPCTL1), + CSR_OFF(IMPCTL2), + CSR_OFF(TLBRENTRY), + CSR_OFF(TLBRBADV), + CSR_OFF(TLBRERA), + CSR_OFF(TLBRSAVE), + CSR_OFF(TLBRELO0), + CSR_OFF(TLBRELO1), + CSR_OFF(TLBREHI), + CSR_OFF(TLBRPRMD), + CSR_OFF(MERRCTL), + CSR_OFF(MERRINFO1), + CSR_OFF(MERRINFO2), + CSR_OFF(MERRENTRY), + CSR_OFF(MERRERA), + CSR_OFF(MERRSAVE), + CSR_OFF(CTAG), + CSR_OFF_ARRAY(DMW, 0), + CSR_OFF_ARRAY(DMW, 1), + CSR_OFF_ARRAY(DMW, 2), + CSR_OFF_ARRAY(DMW, 3), + CSR_OFF(DBG), + CSR_OFF(DERA), + CSR_OFF(DSAVE), +}; + +static bool check_plv(DisasContext *ctx) +{ + if (ctx->base.tb->flags == MMU_USER_IDX) { + generate_exception(ctx, EXCCODE_IPE); + return true; + } + return false; +} + +static const CSRInfo *get_csr(unsigned csr_num) +{ + const CSRInfo *csr; + + if (csr_num >= ARRAY_SIZE(csr_info)) { + return NULL; + } + csr = &csr_info[csr_num]; + if (csr->offset == 0) { + return NULL; + } + return csr; +} + +static bool check_csr_flags(DisasContext *ctx, const CSRInfo *csr, bool write) +{ + if ((csr->flags & CSRFL_READONLY) && write) { + return false; + } + if ((csr->flags & CSRFL_IO) && + (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT)) { + gen_io_start(); + ctx->base.is_jmp = DISAS_EXIT_UPDATE; + } else if ((csr->flags & CSRFL_EXITTB) && write) { + ctx->base.is_jmp = DISAS_EXIT_UPDATE; + } + return true; +} + +static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a) +{ + TCGv dest; + const CSRInfo *csr; + + if (check_plv(ctx)) { + return false; + } + csr = get_csr(a->csr); + if (csr == NULL) { + /* CSR is undefined: read as 0. */ + dest = tcg_constant_tl(0); + } else { + check_csr_flags(ctx, csr, false); + dest = gpr_dst(ctx, a->rd, EXT_NONE); + if (csr->readfn) { + csr->readfn(dest, cpu_env); + } else { + tcg_gen_ld_tl(dest, cpu_env, csr->offset); + } + } + gen_set_gpr(a->rd, dest, EXT_NONE); + return true; +} + +static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a) +{ + TCGv dest, src1; + const CSRInfo *csr; + + if (check_plv(ctx)) { + return false; + } + csr = get_csr(a->csr); + if (csr == NULL) { + /* CSR is undefined: write ignored, read old_value as 0. */ + gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE); + return true; + } + if (!check_csr_flags(ctx, csr, true)) { + /* CSR is readonly: trap. */ + return false; + } + src1 = gpr_src(ctx, a->rd, EXT_NONE); + if (csr->writefn) { + dest = gpr_dst(ctx, a->rd, EXT_NONE); + csr->writefn(dest, cpu_env, src1); + } else { + dest = temp_new(ctx); + tcg_gen_ld_tl(dest, cpu_env, csr->offset); + tcg_gen_st_tl(src1, cpu_env, csr->offset); + } + gen_set_gpr(a->rd, dest, EXT_NONE); + return true; +} + +static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a) +{ + TCGv src1, mask, oldv, newv, temp; + const CSRInfo *csr; + + if (check_plv(ctx)) { + return false; + } + csr = get_csr(a->csr); + if (csr == NULL) { + /* CSR is undefined: write ignored, read old_value as 0. */ + gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE); + return true; + } + + if (!check_csr_flags(ctx, csr, true)) { + /* CSR is readonly: trap. */ + return false; + } + + /* So far only readonly csrs have readfn. */ + assert(csr->readfn == NULL); + + src1 = gpr_src(ctx, a->rd, EXT_NONE); + mask = gpr_src(ctx, a->rj, EXT_NONE); + oldv = tcg_temp_new(); + newv = tcg_temp_new(); + temp = tcg_temp_new(); + + tcg_gen_ld_tl(oldv, cpu_env, csr->offset); + tcg_gen_and_tl(newv, src1, mask); + tcg_gen_andc_tl(temp, oldv, mask); + tcg_gen_or_tl(newv, newv, temp); + + if (csr->writefn) { + csr->writefn(oldv, cpu_env, newv); + } else { + tcg_gen_st_tl(newv, cpu_env, csr->offset); + } + gen_set_gpr(a->rd, oldv, EXT_NONE); + + tcg_temp_free(temp); + tcg_temp_free(newv); + tcg_temp_free(oldv); + return true; +} diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index 9b293dfdf9..43005ca283 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -45,6 +45,8 @@ &c_offs cj offs &offs offs &rr_offs rj rd offs +&r_csr rd csr +&rr_csr rd rj csr # # Formats @@ -85,6 +87,8 @@ @c_offs21 .... .. ................ .. cj:3 ..... &c_offs offs=%offs21 @offs26 .... .. .......................... &offs offs=%offs26 @rr_offs16 .... .. ................ rj:5 rd:5 &rr_offs offs=%offs16 +@r_csr .... .... csr:14 ..... rd:5 &r_csr +@rr_csr .... .... csr:14 rj:5 rd:5 &rr_csr # # Fixed point arithmetic operation instruction @@ -437,3 +441,12 @@ blt 0110 00 ................ ..... ..... @rr_offs16 bge 0110 01 ................ ..... ..... @rr_offs16 bltu 0110 10 ................ ..... ..... @rr_offs16 bgeu 0110 11 ................ ..... ..... @rr_offs16 + +# +# Core instructions +# +{ + csrrd 0000 0100 .............. 00000 ..... @r_csr + csrwr 0000 0100 .............. 00001 ..... @r_csr + csrxchg 0000 0100 .............. ..... ..... @rr_csr +} diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build index 04e15ba1e3..d11829a6cc 100644 --- a/target/loongarch/meson.build +++ b/target/loongarch/meson.build @@ -19,6 +19,7 @@ loongarch_softmmu_ss.add(files( 'machine.c', 'tlb_helper.c', 'constant_timer.c', + 'csr_helper.c', )) loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss]) diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 0ad6b7b2ee..0f098924a3 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -25,7 +25,9 @@ static TCGv cpu_lladdr, cpu_llval; TCGv_i32 cpu_fcsr0; TCGv_i64 cpu_fpr[32]; -#define DISAS_STOP DISAS_TARGET_0 +#define DISAS_STOP DISAS_TARGET_0 +#define DISAS_EXIT DISAS_TARGET_1 +#define DISAS_EXIT_UPDATE DISAS_TARGET_2 static inline int plus_1(DisasContext *ctx, int x) { @@ -172,6 +174,7 @@ static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext) #include "insn_trans/trans_fmov.c.inc" #include "insn_trans/trans_fmemory.c.inc" #include "insn_trans/trans_branch.c.inc" +#include "insn_trans/trans_privileged.c.inc" static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { @@ -210,6 +213,12 @@ static void loongarch_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) break; case DISAS_NORETURN: break; + case DISAS_EXIT_UPDATE: + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); + QEMU_FALLTHROUGH; + case DISAS_EXIT: + tcg_gen_exit_tb(NULL, 0); + break; default: g_assert_not_reached(); } From f84a2aacf5d1679b1d1cceabb6006e02864232f3 Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:16 +0800 Subject: [PATCH 833/935] target/loongarch: Add LoongArch IOCSR instruction This includes: - IOCSR{RD/WR}.{B/H/W/D} Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-27-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/cpu.c | 44 ++++++++++++ target/loongarch/cpu.h | 25 +++++++ target/loongarch/disas.c | 8 +++ target/loongarch/helper.h | 8 +++ .../insn_trans/trans_privileged.c.inc | 35 ++++++++++ target/loongarch/insns.decode | 9 +++ target/loongarch/iocsr_helper.c | 67 +++++++++++++++++++ target/loongarch/meson.build | 1 + 8 files changed, 197 insertions(+) create mode 100644 target/loongarch/iocsr_helper.c diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 5ec0ba1cfa..b846bd1a8b 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -17,6 +17,8 @@ #include "internals.h" #include "fpu/softfloat-helpers.h" #include "cpu-csr.h" +#include "sysemu/reset.h" +#include "hw/loader.h" const char * const regnames[32] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", @@ -489,14 +491,56 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) lacc->parent_realize(dev, errp); } +static void loongarch_qemu_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ +} + +static uint64_t loongarch_qemu_read(void *opaque, hwaddr addr, unsigned size) +{ + switch (addr) { + case FEATURE_REG: + return 1ULL << IOCSRF_MSI | 1ULL << IOCSRF_EXTIOI | + 1ULL << IOCSRF_CSRIPI; + case VENDOR_REG: + return 0x6e6f73676e6f6f4cULL; /* "Loongson" */ + case CPUNAME_REG: + return 0x303030354133ULL; /* "3A5000" */ + case MISC_FUNC_REG: + return 1ULL << IOCSRM_EXTIOI_EN; + } + return 0ULL; +} + +static const MemoryRegionOps loongarch_qemu_ops = { + .read = loongarch_qemu_read, + .write = loongarch_qemu_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 8, + .max_access_size = 8, + }, +}; + static void loongarch_cpu_init(Object *obj) { LoongArchCPU *cpu = LOONGARCH_CPU(obj); + CPULoongArchState *env = &cpu->env; cpu_set_cpustate_pointers(cpu); qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS); timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL, &loongarch_constant_timer_cb, cpu); + memory_region_init_io(&env->system_iocsr, OBJECT(cpu), NULL, + env, "iocsr", UINT64_MAX); + address_space_init(&env->address_space_iocsr, &env->system_iocsr, "IOCSR"); + memory_region_init_io(&env->iocsr_mem, OBJECT(cpu), &loongarch_qemu_ops, + NULL, "iocsr_misc", 0x428); + memory_region_add_subregion(&env->system_iocsr, 0, &env->iocsr_mem); } static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model) diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 2081902f2e..03cc96ee9b 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -12,6 +12,27 @@ #include "fpu/softfloat-types.h" #include "hw/registerfields.h" #include "qemu/timer.h" +#include "exec/memory.h" +#include "hw/sysbus.h" + +#define IOCSRF_TEMP 0 +#define IOCSRF_NODECNT 1 +#define IOCSRF_MSI 2 +#define IOCSRF_EXTIOI 3 +#define IOCSRF_CSRIPI 4 +#define IOCSRF_FREQCSR 5 +#define IOCSRF_FREQSCALE 6 +#define IOCSRF_DVFSV1 7 +#define IOCSRF_GMOD 9 +#define IOCSRF_VM 11 + +#define FEATURE_REG 0x8 +#define VENDOR_REG 0x10 +#define CPUNAME_REG 0x20 +#define MISC_FUNC_REG 0x420 +#define IOCSRM_EXTIOI_EN 48 + +#define IOCSR_MEM_SIZE 0x428 #define TCG_GUEST_DEFAULT_MO (0) @@ -283,6 +304,10 @@ typedef struct CPUArchState { uint64_t CSR_DSAVE; LoongArchTLB tlb[LOONGARCH_TLB_MAX]; + + AddressSpace address_space_iocsr; + MemoryRegion system_iocsr; + MemoryRegion iocsr_mem; } CPULoongArchState; /** diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c index 11a704ff7c..ea26aea728 100644 --- a/target/loongarch/disas.c +++ b/target/loongarch/disas.c @@ -615,6 +615,14 @@ INSN(bgeu, rr_offs) INSN(csrrd, r_csr) INSN(csrwr, r_csr) INSN(csrxchg, rr_csr) +INSN(iocsrrd_b, rr) +INSN(iocsrrd_h, rr) +INSN(iocsrrd_w, rr) +INSN(iocsrrd_d, rr) +INSN(iocsrwr_b, rr) +INSN(iocsrwr_h, rr) +INSN(iocsrwr_w, rr) +INSN(iocsrwr_d, rr) #define output_fcmp(C, PREFIX, SUFFIX) \ { \ diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index 5a6754eb65..4664a02dcf 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -100,3 +100,11 @@ DEF_HELPER_2(csrwr_estat, i64, env, tl) DEF_HELPER_2(csrwr_asid, i64, env, tl) DEF_HELPER_2(csrwr_tcfg, i64, env, tl) DEF_HELPER_2(csrwr_ticlr, i64, env, tl) +DEF_HELPER_2(iocsrrd_b, i64, env, tl) +DEF_HELPER_2(iocsrrd_h, i64, env, tl) +DEF_HELPER_2(iocsrrd_w, i64, env, tl) +DEF_HELPER_2(iocsrrd_d, i64, env, tl) +DEF_HELPER_3(iocsrwr_b, void, env, tl, tl) +DEF_HELPER_3(iocsrwr_h, void, env, tl, tl) +DEF_HELPER_3(iocsrwr_w, void, env, tl, tl) +DEF_HELPER_3(iocsrwr_d, void, env, tl, tl) diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc b/target/loongarch/insn_trans/trans_privileged.c.inc index f984e3f68e..3e50cd3ac6 100644 --- a/target/loongarch/insn_trans/trans_privileged.c.inc +++ b/target/loongarch/insn_trans/trans_privileged.c.inc @@ -262,3 +262,38 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a) tcg_temp_free(oldv); return true; } + +static bool gen_iocsrrd(DisasContext *ctx, arg_rr *a, + void (*func)(TCGv, TCGv_ptr, TCGv)) +{ + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + + if (check_plv(ctx)) { + return false; + } + func(dest, cpu_env, src1); + return true; +} + +static bool gen_iocsrwr(DisasContext *ctx, arg_rr *a, + void (*func)(TCGv_ptr, TCGv, TCGv)) +{ + TCGv val = gpr_src(ctx, a->rd, EXT_NONE); + TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); + + if (check_plv(ctx)) { + return false; + } + func(cpu_env, addr, val); + return true; +} + +TRANS(iocsrrd_b, gen_iocsrrd, gen_helper_iocsrrd_b) +TRANS(iocsrrd_h, gen_iocsrrd, gen_helper_iocsrrd_h) +TRANS(iocsrrd_w, gen_iocsrrd, gen_helper_iocsrrd_w) +TRANS(iocsrrd_d, gen_iocsrrd, gen_helper_iocsrrd_d) +TRANS(iocsrwr_b, gen_iocsrwr, gen_helper_iocsrwr_b) +TRANS(iocsrwr_h, gen_iocsrwr, gen_helper_iocsrwr_h) +TRANS(iocsrwr_w, gen_iocsrwr, gen_helper_iocsrwr_w) +TRANS(iocsrwr_d, gen_iocsrwr, gen_helper_iocsrwr_d) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index 43005ca283..2b436d3cd6 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -450,3 +450,12 @@ bgeu 0110 11 ................ ..... ..... @rr_offs16 csrwr 0000 0100 .............. 00001 ..... @r_csr csrxchg 0000 0100 .............. ..... ..... @rr_csr } + +iocsrrd_b 0000 01100100 10000 00000 ..... ..... @rr +iocsrrd_h 0000 01100100 10000 00001 ..... ..... @rr +iocsrrd_w 0000 01100100 10000 00010 ..... ..... @rr +iocsrrd_d 0000 01100100 10000 00011 ..... ..... @rr +iocsrwr_b 0000 01100100 10000 00100 ..... ..... @rr +iocsrwr_h 0000 01100100 10000 00101 ..... ..... @rr +iocsrwr_w 0000 01100100 10000 00110 ..... ..... @rr +iocsrwr_d 0000 01100100 10000 00111 ..... ..... @rr diff --git a/target/loongarch/iocsr_helper.c b/target/loongarch/iocsr_helper.c new file mode 100644 index 0000000000..0e9c537dc7 --- /dev/null +++ b/target/loongarch/iocsr_helper.c @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * Helpers for IOCSR reads/writes + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "cpu.h" +#include "qemu/host-utils.h" +#include "exec/helper-proto.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "tcg/tcg-ldst.h" + +uint64_t helper_iocsrrd_b(CPULoongArchState *env, target_ulong r_addr) +{ + return address_space_ldub(&env->address_space_iocsr, r_addr, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +uint64_t helper_iocsrrd_h(CPULoongArchState *env, target_ulong r_addr) +{ + return address_space_lduw(&env->address_space_iocsr, r_addr, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +uint64_t helper_iocsrrd_w(CPULoongArchState *env, target_ulong r_addr) +{ + return address_space_ldl(&env->address_space_iocsr, r_addr, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +uint64_t helper_iocsrrd_d(CPULoongArchState *env, target_ulong r_addr) +{ + return address_space_ldq(&env->address_space_iocsr, r_addr, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +void helper_iocsrwr_b(CPULoongArchState *env, target_ulong w_addr, + target_ulong val) +{ + address_space_stb(&env->address_space_iocsr, w_addr, + val, MEMTXATTRS_UNSPECIFIED, NULL); +} + +void helper_iocsrwr_h(CPULoongArchState *env, target_ulong w_addr, + target_ulong val) +{ + address_space_stw(&env->address_space_iocsr, w_addr, + val, MEMTXATTRS_UNSPECIFIED, NULL); +} + +void helper_iocsrwr_w(CPULoongArchState *env, target_ulong w_addr, + target_ulong val) +{ + address_space_stl(&env->address_space_iocsr, w_addr, + val, MEMTXATTRS_UNSPECIFIED, NULL); +} + +void helper_iocsrwr_d(CPULoongArchState *env, target_ulong w_addr, + target_ulong val) +{ + address_space_stq(&env->address_space_iocsr, w_addr, + val, MEMTXATTRS_UNSPECIFIED, NULL); +} diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build index d11829a6cc..74e5f3b2a7 100644 --- a/target/loongarch/meson.build +++ b/target/loongarch/meson.build @@ -20,6 +20,7 @@ loongarch_softmmu_ss.add(files( 'tlb_helper.c', 'constant_timer.c', 'csr_helper.c', + 'iocsr_helper.c', )) loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss]) From fcbbeb8ecd8b755e9244e12f2f0d7579350ab23e Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:17 +0800 Subject: [PATCH 834/935] target/loongarch: Add TLB instruction support This includes: - TLBSRCH - TLBRD - TLBWR - TLBFILL - TLBCLR - TLBFLUSH - INVTLB Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-28-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/disas.c | 18 + target/loongarch/helper.h | 13 + .../insn_trans/trans_privileged.c.inc | 102 +++++ target/loongarch/insns.decode | 11 + target/loongarch/tlb_helper.c | 355 ++++++++++++++++++ 5 files changed, 499 insertions(+) diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c index ea26aea728..6a56607302 100644 --- a/target/loongarch/disas.c +++ b/target/loongarch/disas.c @@ -303,6 +303,17 @@ static void output_rr_csr(DisasContext *ctx, arg_rr_csr *a, a->rd, a->rj, a->csr, get_csr_name(a->csr)); } +static void output_empty(DisasContext *ctx, arg_empty *a, + const char *mnemonic) +{ + output(ctx, mnemonic, ""); +} + +static void output_i_rr(DisasContext *ctx, arg_i_rr *a, const char *mnemonic) +{ + output(ctx, mnemonic, "%d, r%d, r%d", a->imm, a->rj, a->rk); +} + #define INSN(insn, type) \ static bool trans_##insn(DisasContext *ctx, arg_##type * a) \ { \ @@ -623,6 +634,13 @@ INSN(iocsrwr_b, rr) INSN(iocsrwr_h, rr) INSN(iocsrwr_w, rr) INSN(iocsrwr_d, rr) +INSN(tlbsrch, empty) +INSN(tlbrd, empty) +INSN(tlbwr, empty) +INSN(tlbfill, empty) +INSN(tlbclr, empty) +INSN(tlbflush, empty) +INSN(invtlb, i_rr) #define output_fcmp(C, PREFIX, SUFFIX) \ { \ diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index 4664a02dcf..b092ca75fe 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -108,3 +108,16 @@ DEF_HELPER_3(iocsrwr_b, void, env, tl, tl) DEF_HELPER_3(iocsrwr_h, void, env, tl, tl) DEF_HELPER_3(iocsrwr_w, void, env, tl, tl) DEF_HELPER_3(iocsrwr_d, void, env, tl, tl) + +/* TLB helper */ +DEF_HELPER_1(tlbwr, void, env) +DEF_HELPER_1(tlbfill, void, env) +DEF_HELPER_1(tlbsrch, void, env) +DEF_HELPER_1(tlbrd, void, env) +DEF_HELPER_1(tlbclr, void, env) +DEF_HELPER_1(tlbflush, void, env) +DEF_HELPER_1(invtlb_all, void, env) +DEF_HELPER_2(invtlb_all_g, void, env, i32) +DEF_HELPER_2(invtlb_all_asid, void, env, tl) +DEF_HELPER_3(invtlb_page_asid, void, env, tl, tl) +DEF_HELPER_3(invtlb_page_asid_or_g, void, env, tl, tl) diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc b/target/loongarch/insn_trans/trans_privileged.c.inc index 3e50cd3ac6..d47918785b 100644 --- a/target/loongarch/insn_trans/trans_privileged.c.inc +++ b/target/loongarch/insn_trans/trans_privileged.c.inc @@ -297,3 +297,105 @@ TRANS(iocsrwr_b, gen_iocsrwr, gen_helper_iocsrwr_b) TRANS(iocsrwr_h, gen_iocsrwr, gen_helper_iocsrwr_h) TRANS(iocsrwr_w, gen_iocsrwr, gen_helper_iocsrwr_w) TRANS(iocsrwr_d, gen_iocsrwr, gen_helper_iocsrwr_d) + +static void check_mmu_idx(DisasContext *ctx) +{ + if (ctx->mem_idx != MMU_DA_IDX) { + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4); + ctx->base.is_jmp = DISAS_EXIT; + } +} + +static bool trans_tlbsrch(DisasContext *ctx, arg_tlbsrch *a) +{ + if (check_plv(ctx)) { + return false; + } + gen_helper_tlbsrch(cpu_env); + return true; +} + +static bool trans_tlbrd(DisasContext *ctx, arg_tlbrd *a) +{ + if (check_plv(ctx)) { + return false; + } + gen_helper_tlbrd(cpu_env); + return true; +} + +static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a) +{ + if (check_plv(ctx)) { + return false; + } + gen_helper_tlbwr(cpu_env); + check_mmu_idx(ctx); + return true; +} + +static bool trans_tlbfill(DisasContext *ctx, arg_tlbfill *a) +{ + if (check_plv(ctx)) { + return false; + } + gen_helper_tlbfill(cpu_env); + check_mmu_idx(ctx); + return true; +} + +static bool trans_tlbclr(DisasContext *ctx, arg_tlbclr *a) +{ + if (check_plv(ctx)) { + return false; + } + gen_helper_tlbclr(cpu_env); + check_mmu_idx(ctx); + return true; +} + +static bool trans_tlbflush(DisasContext *ctx, arg_tlbflush *a) +{ + if (check_plv(ctx)) { + return false; + } + gen_helper_tlbflush(cpu_env); + check_mmu_idx(ctx); + return true; +} + +static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a) +{ + TCGv rj = gpr_src(ctx, a->rj, EXT_NONE); + TCGv rk = gpr_src(ctx, a->rk, EXT_NONE); + + if (check_plv(ctx)) { + return false; + } + + switch (a->imm) { + case 0: + case 1: + gen_helper_invtlb_all(cpu_env); + break; + case 2: + gen_helper_invtlb_all_g(cpu_env, tcg_constant_i32(1)); + break; + case 3: + gen_helper_invtlb_all_g(cpu_env, tcg_constant_i32(0)); + break; + case 4: + gen_helper_invtlb_all_asid(cpu_env, rj); + break; + case 5: + gen_helper_invtlb_page_asid(cpu_env, rj, rk); + break; + case 6: + gen_helper_invtlb_page_asid_or_g(cpu_env, rj, rk); + break; + default: + return false; + } + ctx->base.is_jmp = DISAS_STOP; + return true; +} diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index 2b436d3cd6..f8ed11d83e 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -47,6 +47,8 @@ &rr_offs rj rd offs &r_csr rd csr &rr_csr rd rj csr +&empty +&i_rr imm rj rk # # Formats @@ -89,6 +91,8 @@ @rr_offs16 .... .. ................ rj:5 rd:5 &rr_offs offs=%offs16 @r_csr .... .... csr:14 ..... rd:5 &r_csr @rr_csr .... .... csr:14 rj:5 rd:5 &rr_csr +@empty .... ........ ..... ..... ..... ..... &empty +@i_rr ...... ...... ..... rk:5 rj:5 imm:5 &i_rr # # Fixed point arithmetic operation instruction @@ -459,3 +463,10 @@ iocsrwr_b 0000 01100100 10000 00100 ..... ..... @rr iocsrwr_h 0000 01100100 10000 00101 ..... ..... @rr iocsrwr_w 0000 01100100 10000 00110 ..... ..... @rr iocsrwr_d 0000 01100100 10000 00111 ..... ..... @rr +tlbsrch 0000 01100100 10000 01010 00000 00000 @empty +tlbrd 0000 01100100 10000 01011 00000 00000 @empty +tlbwr 0000 01100100 10000 01100 00000 00000 @empty +tlbfill 0000 01100100 10000 01101 00000 00000 @empty +tlbclr 0000 01100100 10000 01000 00000 00000 @empty +tlbflush 0000 01100100 10000 01001 00000 00000 @empty +invtlb 0000 01100100 10011 ..... ..... ..... @i_rr diff --git a/target/loongarch/tlb_helper.c b/target/loongarch/tlb_helper.c index fad8bc7746..4f84ef3e4b 100644 --- a/target/loongarch/tlb_helper.c +++ b/target/loongarch/tlb_helper.c @@ -7,9 +7,11 @@ */ #include "qemu/osdep.h" +#include "qemu/guest-random.h" #include "cpu.h" #include "internals.h" +#include "exec/helper-proto.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" #include "exec/log.h" @@ -280,6 +282,359 @@ static void raise_mmu_exception(CPULoongArchState *env, target_ulong address, } } +static void invalidate_tlb_entry(CPULoongArchState *env, int index) +{ + target_ulong addr, mask, pagesize; + uint8_t tlb_ps; + LoongArchTLB *tlb = &env->tlb[index]; + + int mmu_idx = cpu_mmu_index(env, false); + uint8_t tlb_v0 = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, V); + uint8_t tlb_v1 = FIELD_EX64(tlb->tlb_entry1, TLBENTRY, V); + uint64_t tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); + + if (index >= LOONGARCH_STLB) { + tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); + } else { + tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); + } + pagesize = 1 << tlb_ps; + mask = MAKE_64BIT_MASK(0, tlb_ps + 1); + + if (tlb_v0) { + addr = (tlb_vppn << R_TLB_MISC_VPPN_SHIFT) & ~mask; /* even */ + tlb_flush_range_by_mmuidx(env_cpu(env), addr, pagesize, + mmu_idx, TARGET_LONG_BITS); + } + + if (tlb_v1) { + addr = (tlb_vppn << R_TLB_MISC_VPPN_SHIFT) & pagesize; /* odd */ + tlb_flush_range_by_mmuidx(env_cpu(env), addr, pagesize, + mmu_idx, TARGET_LONG_BITS); + } +} + +static void invalidate_tlb(CPULoongArchState *env, int index) +{ + LoongArchTLB *tlb; + uint16_t csr_asid, tlb_asid, tlb_g; + + csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID); + tlb = &env->tlb[index]; + tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); + tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + if (tlb_g == 0 && tlb_asid != csr_asid) { + return; + } + invalidate_tlb_entry(env, index); +} + +static void fill_tlb_entry(CPULoongArchState *env, int index) +{ + LoongArchTLB *tlb = &env->tlb[index]; + uint64_t lo0, lo1, csr_vppn; + uint16_t csr_asid; + uint8_t csr_ps; + + if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { + csr_ps = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI, PS); + csr_vppn = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI, VPPN); + lo0 = env->CSR_TLBRELO0; + lo1 = env->CSR_TLBRELO1; + } else { + csr_ps = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, PS); + csr_vppn = FIELD_EX64(env->CSR_TLBEHI, CSR_TLBEHI, VPPN); + lo0 = env->CSR_TLBELO0; + lo1 = env->CSR_TLBELO1; + } + + if (csr_ps == 0) { + qemu_log_mask(CPU_LOG_MMU, "page size is 0\n"); + } + + /* Only MTLB has the ps fields */ + if (index >= LOONGARCH_STLB) { + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, PS, csr_ps); + } + + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, VPPN, csr_vppn); + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 1); + csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID); + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, ASID, csr_asid); + + tlb->tlb_entry0 = lo0; + tlb->tlb_entry1 = lo1; +} + +/* Return an random value between low and high */ +static uint32_t get_random_tlb(uint32_t low, uint32_t high) +{ + uint32_t val; + + qemu_guest_getrandom_nofail(&val, sizeof(val)); + return val % (high - low + 1) + low; +} + +void helper_tlbsrch(CPULoongArchState *env) +{ + int index, match; + + if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { + match = loongarch_tlb_search(env, env->CSR_TLBREHI, &index); + } else { + match = loongarch_tlb_search(env, env->CSR_TLBEHI, &index); + } + + if (match) { + env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX, index); + env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 0); + return; + } + + env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 1); +} + +void helper_tlbrd(CPULoongArchState *env) +{ + LoongArchTLB *tlb; + int index; + uint8_t tlb_ps, tlb_e; + + index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX); + tlb = &env->tlb[index]; + + if (index >= LOONGARCH_STLB) { + tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); + } else { + tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); + } + tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); + + if (!tlb_e) { + /* Invalid TLB entry */ + env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 1); + env->CSR_ASID = FIELD_DP64(env->CSR_ASID, CSR_ASID, ASID, 0); + env->CSR_TLBEHI = 0; + env->CSR_TLBELO0 = 0; + env->CSR_TLBELO1 = 0; + env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, PS, 0); + } else { + /* Valid TLB entry */ + env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 0); + env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, + PS, (tlb_ps & 0x3f)); + env->CSR_TLBEHI = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN) << + R_TLB_MISC_VPPN_SHIFT; + env->CSR_TLBELO0 = tlb->tlb_entry0; + env->CSR_TLBELO1 = tlb->tlb_entry1; + } +} + +void helper_tlbwr(CPULoongArchState *env) +{ + int index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX); + + invalidate_tlb(env, index); + + if (FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, NE)) { + env->tlb[index].tlb_misc = FIELD_DP64(env->tlb[index].tlb_misc, + TLB_MISC, E, 0); + return; + } + + fill_tlb_entry(env, index); +} + +void helper_tlbfill(CPULoongArchState *env) +{ + uint64_t address, entryhi; + int index, set, stlb_idx; + uint16_t pagesize, stlb_ps; + + if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { + entryhi = env->CSR_TLBREHI; + pagesize = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI, PS); + } else { + entryhi = env->CSR_TLBEHI; + pagesize = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, PS); + } + + stlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); + + if (pagesize == stlb_ps) { + /* Only write into STLB bits [47:13] */ + address = entryhi & ~MAKE_64BIT_MASK(0, R_CSR_TLBEHI_VPPN_SHIFT); + + /* Choose one set ramdomly */ + set = get_random_tlb(0, 7); + + /* Index in one set */ + stlb_idx = (address >> (stlb_ps + 1)) & 0xff; /* [0,255] */ + + index = set * 256 + stlb_idx; + } else { + /* Only write into MTLB */ + index = get_random_tlb(LOONGARCH_STLB, LOONGARCH_TLB_MAX - 1); + } + + invalidate_tlb(env, index); + fill_tlb_entry(env, index); +} + +void helper_tlbclr(CPULoongArchState *env) +{ + LoongArchTLB *tlb; + int i, index; + uint16_t csr_asid, tlb_asid, tlb_g; + + csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID); + index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX); + + if (index < LOONGARCH_STLB) { + /* STLB. One line per operation */ + for (i = 0; i < 8; i++) { + tlb = &env->tlb[i * 256 + (index % 256)]; + tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); + tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + if (!tlb_g && tlb_asid == csr_asid) { + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); + } + } + } else if (index < LOONGARCH_TLB_MAX) { + /* All MTLB entries */ + for (i = LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; i++) { + tlb = &env->tlb[i]; + tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); + tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + if (!tlb_g && tlb_asid == csr_asid) { + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); + } + } + } + + tlb_flush(env_cpu(env)); +} + +void helper_tlbflush(CPULoongArchState *env) +{ + int i, index; + + index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX); + + if (index < LOONGARCH_STLB) { + /* STLB. One line per operation */ + for (i = 0; i < 8; i++) { + int s_idx = i * 256 + (index % 256); + env->tlb[s_idx].tlb_misc = FIELD_DP64(env->tlb[s_idx].tlb_misc, + TLB_MISC, E, 0); + } + } else if (index < LOONGARCH_TLB_MAX) { + /* All MTLB entries */ + for (i = LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; i++) { + env->tlb[i].tlb_misc = FIELD_DP64(env->tlb[i].tlb_misc, + TLB_MISC, E, 0); + } + } + + tlb_flush(env_cpu(env)); +} + +void helper_invtlb_all(CPULoongArchState *env) +{ + for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { + env->tlb[i].tlb_misc = FIELD_DP64(env->tlb[i].tlb_misc, + TLB_MISC, E, 0); + } + tlb_flush(env_cpu(env)); +} + +void helper_invtlb_all_g(CPULoongArchState *env, uint32_t g) +{ + for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { + LoongArchTLB *tlb = &env->tlb[i]; + uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + + if (tlb_g == g) { + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); + } + } + tlb_flush(env_cpu(env)); +} + +void helper_invtlb_all_asid(CPULoongArchState *env, target_ulong info) +{ + uint16_t asid = info & R_CSR_ASID_ASID_MASK; + + for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { + LoongArchTLB *tlb = &env->tlb[i]; + uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + uint16_t tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); + + if (!tlb_g && (tlb_asid == asid)) { + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); + } + } + tlb_flush(env_cpu(env)); +} + +void helper_invtlb_page_asid(CPULoongArchState *env, target_ulong info, + target_ulong addr) +{ + uint16_t asid = info & 0x3ff; + + for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { + LoongArchTLB *tlb = &env->tlb[i]; + uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + uint16_t tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); + uint64_t vpn, tlb_vppn; + uint8_t tlb_ps, compare_shift; + + if (i >= LOONGARCH_STLB) { + tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); + } else { + tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); + } + tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); + vpn = (addr & TARGET_VIRT_MASK) >> (tlb_ps + 1); + compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; + + if (!tlb_g && (tlb_asid == asid) && + (vpn == (tlb_vppn >> compare_shift))) { + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); + } + } + tlb_flush(env_cpu(env)); +} + +void helper_invtlb_page_asid_or_g(CPULoongArchState *env, + target_ulong info, target_ulong addr) +{ + uint16_t asid = info & 0x3ff; + + for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { + LoongArchTLB *tlb = &env->tlb[i]; + uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + uint16_t tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); + uint64_t vpn, tlb_vppn; + uint8_t tlb_ps, compare_shift; + + if (i >= LOONGARCH_STLB) { + tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); + } else { + tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); + } + tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); + vpn = (addr & TARGET_VIRT_MASK) >> (tlb_ps + 1); + compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; + + if ((tlb_g || (tlb_asid == asid)) && + (vpn == (tlb_vppn >> compare_shift))) { + tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); + } + } + tlb_flush(env_cpu(env)); +} + bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr) From d2cba6f7cea9d55aa0567fa8efdeaf2028e1de5e Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:18 +0800 Subject: [PATCH 835/935] target/loongarch: Add other core instructions support This includes: -CACOP -LDDIR -LDPTE -ERTN -DBCL -IDLE Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-29-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/disas.c | 17 ++++ target/loongarch/helper.h | 5 + .../insn_trans/trans_privileged.c.inc | 65 +++++++++++++ target/loongarch/insns.decode | 11 +++ target/loongarch/internals.h | 5 + target/loongarch/op_helper.c | 37 ++++++++ target/loongarch/tlb_helper.c | 93 +++++++++++++++++++ 7 files changed, 233 insertions(+) diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c index 6a56607302..9d790b172c 100644 --- a/target/loongarch/disas.c +++ b/target/loongarch/disas.c @@ -314,6 +314,17 @@ static void output_i_rr(DisasContext *ctx, arg_i_rr *a, const char *mnemonic) output(ctx, mnemonic, "%d, r%d, r%d", a->imm, a->rj, a->rk); } +static void output_cop_r_i(DisasContext *ctx, arg_cop_r_i *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "%d, r%d, %d", a->cop, a->rj, a->imm); +} + +static void output_j_i(DisasContext *ctx, arg_j_i *a, const char *mnemonic) +{ + output(ctx, mnemonic, "r%d, %d", a->rj, a->imm); +} + #define INSN(insn, type) \ static bool trans_##insn(DisasContext *ctx, arg_##type * a) \ { \ @@ -641,6 +652,12 @@ INSN(tlbfill, empty) INSN(tlbclr, empty) INSN(tlbflush, empty) INSN(invtlb, i_rr) +INSN(cacop, cop_r_i) +INSN(lddir, rr_i) +INSN(ldpte, j_i) +INSN(ertn, empty) +INSN(idle, i) +INSN(dbcl, i) #define output_fcmp(C, PREFIX, SUFFIX) \ { \ diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index b092ca75fe..626fc32e1e 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -121,3 +121,8 @@ DEF_HELPER_2(invtlb_all_g, void, env, i32) DEF_HELPER_2(invtlb_all_asid, void, env, tl) DEF_HELPER_3(invtlb_page_asid, void, env, tl, tl) DEF_HELPER_3(invtlb_page_asid_or_g, void, env, tl, tl) + +DEF_HELPER_4(lddir, tl, env, tl, tl, i32) +DEF_HELPER_4(ldpte, void, env, tl, tl, i32) +DEF_HELPER_1(ertn, void, env) +DEF_HELPER_1(idle, void, env) diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc b/target/loongarch/insn_trans/trans_privileged.c.inc index d47918785b..53596c4f77 100644 --- a/target/loongarch/insn_trans/trans_privileged.c.inc +++ b/target/loongarch/insn_trans/trans_privileged.c.inc @@ -399,3 +399,68 @@ static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a) ctx->base.is_jmp = DISAS_STOP; return true; } + +static bool trans_cacop(DisasContext *ctx, arg_cacop *a) +{ + /* Treat the cacop as a nop */ + if (check_plv(ctx)) { + return false; + } + return true; +} + +static bool trans_ldpte(DisasContext *ctx, arg_ldpte *a) +{ + TCGv_i32 mem_idx = tcg_constant_i32(ctx->mem_idx); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + + if (check_plv(ctx)) { + return false; + } + gen_helper_ldpte(cpu_env, src1, tcg_constant_tl(a->imm), mem_idx); + return true; +} + +static bool trans_lddir(DisasContext *ctx, arg_lddir *a) +{ + TCGv_i32 mem_idx = tcg_constant_i32(ctx->mem_idx); + TCGv src = gpr_src(ctx, a->rj, EXT_NONE); + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + + if (check_plv(ctx)) { + return false; + } + gen_helper_lddir(dest, cpu_env, src, tcg_constant_tl(a->imm), mem_idx); + return true; +} + +static bool trans_ertn(DisasContext *ctx, arg_ertn *a) +{ + if (check_plv(ctx)) { + return false; + } + gen_helper_ertn(cpu_env); + ctx->base.is_jmp = DISAS_EXIT; + return true; +} + +static bool trans_dbcl(DisasContext *ctx, arg_dbcl *a) +{ + if (check_plv(ctx)) { + return false; + } + generate_exception(ctx, EXCCODE_DBP); + return true; +} + +static bool trans_idle(DisasContext *ctx, arg_idle *a) +{ + if (check_plv(ctx)) { + return false; + } + + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4); + gen_helper_idle(cpu_env); + ctx->base.is_jmp = DISAS_NORETURN; + return true; +} diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index f8ed11d83e..ebd3d505fb 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -49,6 +49,8 @@ &rr_csr rd rj csr &empty &i_rr imm rj rk +&cop_r_i cop rj imm +&j_i rj imm # # Formats @@ -60,6 +62,7 @@ @r_i20 .... ... imm:s20 rd:5 &r_i @rr_ui5 .... ........ ..... imm:5 rj:5 rd:5 &rr_i @rr_ui6 .... ........ .... imm:6 rj:5 rd:5 &rr_i +@rr_ui8 .. ........ .... imm:8 rj:5 rd:5 &rr_i @rr_i12 .... ...... imm:s12 rj:5 rd:5 &rr_i @rr_ui12 .... ...... imm:12 rj:5 rd:5 &rr_i @rr_i14s2 .... .... .............. rj:5 rd:5 &rr_i imm=%i14s2 @@ -93,6 +96,8 @@ @rr_csr .... .... csr:14 rj:5 rd:5 &rr_csr @empty .... ........ ..... ..... ..... ..... &empty @i_rr ...... ...... ..... rk:5 rj:5 imm:5 &i_rr +@cop_r_i .... ...... imm:s12 rj:5 cop:5 &cop_r_i +@j_i .... ........ .. imm:8 rj:5 ..... &j_i # # Fixed point arithmetic operation instruction @@ -470,3 +475,9 @@ tlbfill 0000 01100100 10000 01101 00000 00000 @empty tlbclr 0000 01100100 10000 01000 00000 00000 @empty tlbflush 0000 01100100 10000 01001 00000 00000 @empty invtlb 0000 01100100 10011 ..... ..... ..... @i_rr +cacop 0000 011000 ............ ..... ..... @cop_r_i +lddir 0000 01100100 00 ........ ..... ..... @rr_ui8 +ldpte 0000 01100100 01 ........ ..... 00000 @j_i +ertn 0000 01100100 10000 01110 00000 00000 @empty +idle 0000 01100100 10001 ............... @i15 +dbcl 0000 00000010 10101 ............... @i15 diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h index 4b1bcd7c0f..a410c41c37 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -16,6 +16,11 @@ #define TARGET_PHYS_MASK MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS) #define TARGET_VIRT_MASK MAKE_64BIT_MASK(0, TARGET_VIRT_ADDR_SPACE_BITS) +/* Global bit used for lddir/ldpte */ +#define LOONGARCH_PAGE_HUGE_SHIFT 6 +/* Global bit for huge page */ +#define LOONGARCH_HGLOBAL_SHIFT 12 + void loongarch_translate_init(void); void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags); diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c index 18e565ce7f..a9ba72d5b2 100644 --- a/target/loongarch/op_helper.c +++ b/target/loongarch/op_helper.c @@ -6,6 +6,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "qemu/main-loop.h" #include "cpu.h" #include "qemu/host-utils.h" @@ -15,6 +16,7 @@ #include "internals.h" #include "qemu/crc32c.h" #include +#include "cpu-csr.h" /* Exceptions helpers */ void helper_raise_exception(CPULoongArchState *env, uint32_t exception) @@ -81,3 +83,38 @@ target_ulong helper_cpucfg(CPULoongArchState *env, target_ulong rj) { return rj > 21 ? 0 : env->cpucfg[rj]; } + +void helper_ertn(CPULoongArchState *env) +{ + uint64_t csr_pplv, csr_pie; + if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { + csr_pplv = FIELD_EX64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PPLV); + csr_pie = FIELD_EX64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PIE); + + env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 0); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 1); + env->pc = env->CSR_TLBRERA; + qemu_log_mask(CPU_LOG_INT, "%s: TLBRERA " TARGET_FMT_lx "\n", + __func__, env->CSR_TLBRERA); + } else { + csr_pplv = FIELD_EX64(env->CSR_PRMD, CSR_PRMD, PPLV); + csr_pie = FIELD_EX64(env->CSR_PRMD, CSR_PRMD, PIE); + + env->pc = env->CSR_ERA; + qemu_log_mask(CPU_LOG_INT, "%s: ERA " TARGET_FMT_lx "\n", + __func__, env->CSR_ERA); + } + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, csr_pplv); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, csr_pie); + + env->lladdr = 1; +} + +void helper_idle(CPULoongArchState *env) +{ + CPUState *cs = env_cpu(env); + + cs->halted = 1; + do_raise_exception(env, EXCP_HLT, 0); +} diff --git a/target/loongarch/tlb_helper.c b/target/loongarch/tlb_helper.c index 4f84ef3e4b..bab19c7e05 100644 --- a/target/loongarch/tlb_helper.c +++ b/target/loongarch/tlb_helper.c @@ -668,3 +668,96 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, raise_mmu_exception(env, address, access_type, ret); cpu_loop_exit_restore(cs, retaddr); } + +target_ulong helper_lddir(CPULoongArchState *env, target_ulong base, + target_ulong level, uint32_t mem_idx) +{ + CPUState *cs = env_cpu(env); + target_ulong badvaddr, index, phys, ret; + int shift; + uint64_t dir_base, dir_width; + bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1; + + badvaddr = env->CSR_TLBRBADV; + base = base & TARGET_PHYS_MASK; + + /* 0:64bit, 1:128bit, 2:192bit, 3:256bit */ + shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH); + shift = (shift + 1) * 3; + + if (huge) { + return base; + } + switch (level) { + case 1: + dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_BASE); + dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_WIDTH); + break; + case 2: + dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_BASE); + dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_WIDTH); + break; + case 3: + dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_BASE); + dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_WIDTH); + break; + case 4: + dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_BASE); + dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_WIDTH); + break; + default: + do_raise_exception(env, EXCCODE_INE, GETPC()); + return 0; + } + index = (badvaddr >> dir_base) & ((1 << dir_width) - 1); + phys = base | index << shift; + ret = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK; + return ret; +} + +void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd, + uint32_t mem_idx) +{ + CPUState *cs = env_cpu(env); + target_ulong phys, tmp0, ptindex, ptoffset0, ptoffset1, ps, badv; + int shift; + bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1; + uint64_t ptbase = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE); + uint64_t ptwidth = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTWIDTH); + + base = base & TARGET_PHYS_MASK; + + if (huge) { + /* Huge Page. base is paddr */ + tmp0 = base ^ (1 << LOONGARCH_PAGE_HUGE_SHIFT); + /* Move Global bit */ + tmp0 = ((tmp0 & (1 << LOONGARCH_HGLOBAL_SHIFT)) >> + LOONGARCH_HGLOBAL_SHIFT) << R_TLBENTRY_G_SHIFT | + (tmp0 & (~(1 << R_TLBENTRY_G_SHIFT))); + ps = ptbase + ptwidth - 1; + if (odd) { + tmp0 += (1 << ps); + } + } else { + /* 0:64bit, 1:128bit, 2:192bit, 3:256bit */ + shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH); + shift = (shift + 1) * 3; + badv = env->CSR_TLBRBADV; + + ptindex = (badv >> ptbase) & ((1 << ptwidth) - 1); + ptindex = ptindex & ~0x1; /* clear bit 0 */ + ptoffset0 = ptindex << shift; + ptoffset1 = (ptindex + 1) << shift; + + phys = base | (odd ? ptoffset1 : ptoffset0); + tmp0 = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK; + ps = ptbase; + } + + if (odd) { + env->CSR_TLBRELO1 = tmp0; + } else { + env->CSR_TLBRELO0 = tmp0; + } + env->CSR_TLBREHI = FIELD_DP64(env->CSR_TLBREHI, CSR_TLBREHI, PS, ps); +} From f9bf50745f29c85e531857898ed7927b6db7c763 Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:19 +0800 Subject: [PATCH 836/935] target/loongarch: Add timer related instructions support. This includes: -RDTIME{L/H}.W -RDTIME.D Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-30-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- target/loongarch/disas.c | 3 ++ target/loongarch/helper.h | 2 ++ target/loongarch/insn_trans/trans_extra.c.inc | 33 +++++++++++++++++++ target/loongarch/insns.decode | 3 ++ target/loongarch/op_helper.c | 13 ++++++++ target/loongarch/translate.c | 2 ++ 6 files changed, 56 insertions(+) diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c index 9d790b172c..858dfcc53a 100644 --- a/target/loongarch/disas.c +++ b/target/loongarch/disas.c @@ -352,6 +352,9 @@ INSN(bitrev_w, rr) INSN(bitrev_d, rr) INSN(ext_w_h, rr) INSN(ext_w_b, rr) +INSN(rdtimel_w, rr) +INSN(rdtimeh_w, rr) +INSN(rdtime_d, rr) INSN(cpucfg, rr) INSN(asrtle_d, rr_jk) INSN(asrtgt_d, rr_jk) diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index 626fc32e1e..85c11a60d4 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -93,6 +93,8 @@ DEF_HELPER_2(frint_d, i64, env, i64) DEF_HELPER_FLAGS_2(set_rounding_mode, TCG_CALL_NO_RWG, void, env, i32) +DEF_HELPER_1(rdtime_d, i64, env) + /* CSRs helper */ DEF_HELPER_1(csrrd_pgd, i64, env) DEF_HELPER_1(csrrd_tval, i64, env) diff --git a/target/loongarch/insn_trans/trans_extra.c.inc b/target/loongarch/insn_trans/trans_extra.c.inc index 549f75a867..ad713cd61e 100644 --- a/target/loongarch/insn_trans/trans_extra.c.inc +++ b/target/loongarch/insn_trans/trans_extra.c.inc @@ -33,6 +33,39 @@ static bool trans_asrtgt_d(DisasContext *ctx, arg_asrtgt_d * a) return true; } +static bool gen_rdtime(DisasContext *ctx, arg_rr *a, + bool word, bool high) +{ + TCGv dst1 = gpr_dst(ctx, a->rd, EXT_NONE); + TCGv dst2 = gpr_dst(ctx, a->rj, EXT_NONE); + + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } + gen_helper_rdtime_d(dst1, cpu_env); + if (word) { + tcg_gen_sextract_tl(dst1, dst1, high ? 32 : 0, 32); + } + tcg_gen_ld_i64(dst2, cpu_env, offsetof(CPULoongArchState, CSR_TID)); + + return true; +} + +static bool trans_rdtimel_w(DisasContext *ctx, arg_rdtimel_w *a) +{ + return gen_rdtime(ctx, a, 1, 0); +} + +static bool trans_rdtimeh_w(DisasContext *ctx, arg_rdtimeh_w *a) +{ + return gen_rdtime(ctx, a, 1, 1); +} + +static bool trans_rdtime_d(DisasContext *ctx, arg_rdtime_d *a) +{ + return gen_rdtime(ctx, a, 0, 0); +} + static bool trans_cpucfg(DisasContext *ctx, arg_cpucfg *a) { TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index ebd3d505fb..3fdc6e148c 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -309,6 +309,9 @@ break 0000 00000010 10100 ............... @i15 syscall 0000 00000010 10110 ............... @i15 asrtle_d 0000 00000000 00010 ..... ..... 00000 @rr_jk asrtgt_d 0000 00000000 00011 ..... ..... 00000 @rr_jk +rdtimel_w 0000 00000000 00000 11000 ..... ..... @rr +rdtimeh_w 0000 00000000 00000 11001 ..... ..... @rr +rdtime_d 0000 00000000 00000 11010 ..... ..... @rr cpucfg 0000 00000000 00000 11011 ..... ..... @rr # diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c index a9ba72d5b2..d87049851f 100644 --- a/target/loongarch/op_helper.c +++ b/target/loongarch/op_helper.c @@ -84,6 +84,19 @@ target_ulong helper_cpucfg(CPULoongArchState *env, target_ulong rj) return rj > 21 ? 0 : env->cpucfg[rj]; } +uint64_t helper_rdtime_d(CPULoongArchState *env) +{ + uint64_t plv; + LoongArchCPU *cpu = env_archcpu(env); + + plv = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV); + if (extract64(env->CSR_MISC, R_CSR_MISC_DRDTL_SHIFT + plv, 1)) { + do_raise_exception(env, EXCCODE_IPE, GETPC()); + } + + return cpu_loongarch_get_constant_timer_counter(cpu); +} + void helper_ertn(CPULoongArchState *env) { uint64_t csr_pplv, csr_pie; diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 0f098924a3..c9afd11420 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -25,6 +25,8 @@ static TCGv cpu_lladdr, cpu_llval; TCGv_i32 cpu_fcsr0; TCGv_i64 cpu_fpr[32]; +#include "exec/gen-icount.h" + #define DISAS_STOP DISAS_TARGET_0 #define DISAS_EXIT DISAS_TARGET_1 #define DISAS_EXIT_UPDATE DISAS_TARGET_2 From a8a506c3907093a064dd2d475564e677fb1bf148 Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:20 +0800 Subject: [PATCH 837/935] hw/loongarch: Add support loongson3 virt machine type. Emulate a 3A5000 board use the new loongarch instruction. 3A5000 belongs to the Loongson3 series processors. The board consists of a 3A5000 cpu model and the virt bridge. The host 3A5000 board is really complicated and contains many functions.Now for the tcg softmmu mode only part functions are emulated. More detailed info you can see https://github.com/loongson/LoongArch-Documentation Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-31-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- MAINTAINERS | 4 + .../devices/loongarch64-softmmu/default.mak | 3 + configs/targets/loongarch64-softmmu.mak | 3 + hw/Kconfig | 1 + hw/loongarch/Kconfig | 4 + hw/loongarch/loongson3.c | 94 +++++++++++++++++++ hw/loongarch/meson.build | 4 + hw/meson.build | 1 + include/exec/poison.h | 2 + include/hw/loongarch/virt.h | 31 ++++++ include/sysemu/arch_init.h | 1 + qapi/machine.json | 2 +- target/Kconfig | 1 + target/loongarch/Kconfig | 2 + target/loongarch/cpu.c | 2 + 15 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 configs/devices/loongarch64-softmmu/default.mak create mode 100644 configs/targets/loongarch64-softmmu.mak create mode 100644 hw/loongarch/Kconfig create mode 100644 hw/loongarch/loongson3.c create mode 100644 hw/loongarch/meson.build create mode 100644 include/hw/loongarch/virt.h create mode 100644 target/loongarch/Kconfig diff --git a/MAINTAINERS b/MAINTAINERS index e3f875071a..0c54c03cef 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1129,6 +1129,10 @@ M: Xiaojuan Yang M: Song Gao S: Maintained F: docs/system/loongarch/loongson3.rst +F: configs/targets/loongarch64-softmmu.mak +F: configs/devices/loongarch64-softmmu/default.mak +F: hw/loongarch/ +F: include/hw/loongarch/virt.h M68K Machines ------------- diff --git a/configs/devices/loongarch64-softmmu/default.mak b/configs/devices/loongarch64-softmmu/default.mak new file mode 100644 index 0000000000..928bc117ef --- /dev/null +++ b/configs/devices/loongarch64-softmmu/default.mak @@ -0,0 +1,3 @@ +# Default configuration for loongarch64-softmmu + +CONFIG_LOONGARCH_VIRT=y diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak new file mode 100644 index 0000000000..666154022f --- /dev/null +++ b/configs/targets/loongarch64-softmmu.mak @@ -0,0 +1,3 @@ +TARGET_ARCH=loongarch64 +TARGET_BASE_ARCH=loongarch +TARGET_SUPPORTS_MTTCG=y diff --git a/hw/Kconfig b/hw/Kconfig index 50e0952889..38233bbb0f 100644 --- a/hw/Kconfig +++ b/hw/Kconfig @@ -50,6 +50,7 @@ source avr/Kconfig source cris/Kconfig source hppa/Kconfig source i386/Kconfig +source loongarch/Kconfig source m68k/Kconfig source microblaze/Kconfig source mips/Kconfig diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig new file mode 100644 index 0000000000..13e8501897 --- /dev/null +++ b/hw/loongarch/Kconfig @@ -0,0 +1,4 @@ +config LOONGARCH_VIRT + bool + select PCI + select PCI_EXPRESS_GENERIC_BRIDGE diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c new file mode 100644 index 0000000000..7df32f777e --- /dev/null +++ b/hw/loongarch/loongson3.c @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU loongson 3a5000 develop board emulation + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qemu/datadir.h" +#include "qapi/error.h" +#include "hw/boards.h" +#include "sysemu/sysemu.h" +#include "sysemu/qtest.h" +#include "sysemu/runstate.h" +#include "sysemu/reset.h" +#include "sysemu/rtc.h" +#include "hw/loongarch/virt.h" +#include "exec/address-spaces.h" +#include "target/loongarch/cpu.h" + +static void loongarch_init(MachineState *machine) +{ + const char *cpu_model = machine->cpu_type; + ram_addr_t offset = 0; + ram_addr_t ram_size = machine->ram_size; + uint64_t highram_size = 0; + MemoryRegion *address_space_mem = get_system_memory(); + LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); + int i; + + if (!cpu_model) { + cpu_model = LOONGARCH_CPU_TYPE_NAME("la464"); + } + + if (!strstr(cpu_model, "la464")) { + error_report("LoongArch/TCG needs cpu type la464"); + exit(1); + } + + if (ram_size < 1 * GiB) { + error_report("ram_size must be greater than 1G."); + exit(1); + } + + /* Init CPUs */ + for (i = 0; i < machine->smp.cpus; i++) { + cpu_create(machine->cpu_type); + } + + /* Add memory region */ + memory_region_init_alias(&lams->lowmem, NULL, "loongarch.lowram", + machine->ram, 0, 256 * MiB); + memory_region_add_subregion(address_space_mem, offset, &lams->lowmem); + offset += 256 * MiB; + + highram_size = ram_size - 256 * MiB; + memory_region_init_alias(&lams->highmem, NULL, "loongarch.highmem", + machine->ram, offset, highram_size); + memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem); + + /* Add isa io region */ + memory_region_init_alias(&lams->isa_io, NULL, "isa-io", + get_system_io(), 0, LOONGARCH_ISA_IO_SIZE); + memory_region_add_subregion(address_space_mem, LOONGARCH_ISA_IO_BASE, + &lams->isa_io); +} + +static void loongarch_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Loongson-3A5000 LS7A1000 machine"; + mc->init = loongarch_init; + mc->default_ram_size = 1 * GiB; + mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464"); + mc->default_ram_id = "loongarch.ram"; + mc->max_cpus = LOONGARCH_MAX_VCPUS; + mc->is_default = 1; + mc->default_kernel_irqchip_split = false; + mc->block_default_type = IF_VIRTIO; + mc->default_boot_order = "c"; + mc->no_cdrom = 1; +} + +static const TypeInfo loongarch_machine_types[] = { + { + .name = TYPE_LOONGARCH_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(LoongArchMachineState), + .class_init = loongarch_class_init, + } +}; + +DEFINE_TYPES(loongarch_machine_types) diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build new file mode 100644 index 0000000000..cecb1a5d65 --- /dev/null +++ b/hw/loongarch/meson.build @@ -0,0 +1,4 @@ +loongarch_ss = ss.source_set() +loongarch_ss.add(when: 'CONFIG_LOONGARCH_VIRT', if_true: files('loongson3.c')) + +hw_arch += {'loongarch': loongarch_ss} diff --git a/hw/meson.build b/hw/meson.build index 9992c5101e..c7ac7d3d75 100644 --- a/hw/meson.build +++ b/hw/meson.build @@ -50,6 +50,7 @@ subdir('avr') subdir('cris') subdir('hppa') subdir('i386') +subdir('loongarch') subdir('m68k') subdir('microblaze') subdir('mips') diff --git a/include/exec/poison.h b/include/exec/poison.h index 9f1ca3409c..bbb82cf9ec 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -14,6 +14,7 @@ #pragma GCC poison TARGET_CRIS #pragma GCC poison TARGET_HEXAGON #pragma GCC poison TARGET_HPPA +#pragma GCC poison TARGET_LOONGARCH64 #pragma GCC poison TARGET_M68K #pragma GCC poison TARGET_MICROBLAZE #pragma GCC poison TARGET_MIPS @@ -71,6 +72,7 @@ #pragma GCC poison CONFIG_HPPA_DIS #pragma GCC poison CONFIG_I386_DIS #pragma GCC poison CONFIG_HEXAGON_DIS +#pragma GCC poison CONFIG_LOONGARCH_DIS #pragma GCC poison CONFIG_M68K_DIS #pragma GCC poison CONFIG_MICROBLAZE_DIS #pragma GCC poison CONFIG_MIPS_DIS diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h new file mode 100644 index 0000000000..4a4bb3f51f --- /dev/null +++ b/include/hw/loongarch/virt.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Definitions for loongarch board emulation. + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#ifndef HW_LOONGARCH_H +#define HW_LOONGARCH_H + +#include "target/loongarch/cpu.h" +#include "hw/boards.h" +#include "qemu/queue.h" + +#define LOONGARCH_MAX_VCPUS 4 + +#define LOONGARCH_ISA_IO_BASE 0x18000000UL +#define LOONGARCH_ISA_IO_SIZE 0x0004000 + +struct LoongArchMachineState { + /*< private >*/ + MachineState parent_obj; + + MemoryRegion lowmem; + MemoryRegion highmem; + MemoryRegion isa_io; +}; + +#define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("virt") +OBJECT_DECLARE_SIMPLE_TYPE(LoongArchMachineState, LOONGARCH_MACHINE) +#endif diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index 79c2591425..8850cb1a14 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -24,6 +24,7 @@ enum { QEMU_ARCH_RX = (1 << 20), QEMU_ARCH_AVR = (1 << 21), QEMU_ARCH_HEXAGON = (1 << 22), + QEMU_ARCH_LOONGARCH = (1 << 23), }; extern const uint32_t arch_type; diff --git a/qapi/machine.json b/qapi/machine.json index 883ce3f9ea..f750a16396 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -30,7 +30,7 @@ ## { 'enum' : 'SysEmuTarget', 'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386', - 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64', + 'loongarch64', 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64', 'mips64el', 'mipsel', 'nios2', 'or1k', 'ppc', 'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4', 'sh4eb', 'sparc', 'sparc64', 'tricore', diff --git a/target/Kconfig b/target/Kconfig index ae7f24fc66..83da0bd293 100644 --- a/target/Kconfig +++ b/target/Kconfig @@ -4,6 +4,7 @@ source avr/Kconfig source cris/Kconfig source hppa/Kconfig source i386/Kconfig +source loongarch/Kconfig source m68k/Kconfig source microblaze/Kconfig source mips/Kconfig diff --git a/target/loongarch/Kconfig b/target/loongarch/Kconfig new file mode 100644 index 0000000000..46b26b1a85 --- /dev/null +++ b/target/loongarch/Kconfig @@ -0,0 +1,2 @@ +config LOONGARCH64 + bool diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index b846bd1a8b..3b7d6289d2 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -82,6 +82,8 @@ static void loongarch_cpu_set_pc(CPUState *cs, vaddr value) env->pc = value; } +#include "hw/loongarch/virt.h" + void loongarch_cpu_set_irq(void *opaque, int irq, int level) { LoongArchCPU *cpu = opaque; From f6783e34380955e9ec0656c7b9fb8936b9733a6a Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:21 +0800 Subject: [PATCH 838/935] hw/loongarch: Add LoongArch ipi interrupt support(IPI) This patch realize the IPI interrupt controller. Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-32-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- MAINTAINERS | 2 + hw/intc/Kconfig | 3 + hw/intc/loongarch_ipi.c | 242 ++++++++++++++++++++++++++++++++ hw/intc/meson.build | 1 + hw/intc/trace-events | 4 + hw/loongarch/Kconfig | 1 + include/hw/intc/loongarch_ipi.h | 52 +++++++ include/hw/loongarch/virt.h | 2 + 8 files changed, 307 insertions(+) create mode 100644 hw/intc/loongarch_ipi.c create mode 100644 include/hw/intc/loongarch_ipi.h diff --git a/MAINTAINERS b/MAINTAINERS index 0c54c03cef..271eb89e2a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1133,6 +1133,8 @@ F: configs/targets/loongarch64-softmmu.mak F: configs/devices/loongarch64-softmmu/default.mak F: hw/loongarch/ F: include/hw/loongarch/virt.h +F: include/hw/intc/loongarch_*.h +F: hw/intc/loongarch_*.c M68K Machines ------------- diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig index eded1b557e..1122c33cec 100644 --- a/hw/intc/Kconfig +++ b/hw/intc/Kconfig @@ -87,3 +87,6 @@ config M68K_IRQC config NIOS2_VIC bool + +config LOONGARCH_IPI + bool diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c new file mode 100644 index 0000000000..66bee93675 --- /dev/null +++ b/hw/intc/loongarch_ipi.c @@ -0,0 +1,242 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch ipi interrupt support + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/intc/loongarch_ipi.h" +#include "hw/irq.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "exec/address-spaces.h" +#include "hw/loongarch/virt.h" +#include "migration/vmstate.h" +#include "target/loongarch/internals.h" +#include "trace.h" + +static uint64_t loongarch_ipi_readl(void *opaque, hwaddr addr, unsigned size) +{ + IPICore *s = opaque; + uint64_t ret = 0; + int index = 0; + + addr &= 0xff; + switch (addr) { + case CORE_STATUS_OFF: + ret = s->status; + break; + case CORE_EN_OFF: + ret = s->en; + break; + case CORE_SET_OFF: + ret = 0; + break; + case CORE_CLEAR_OFF: + ret = 0; + break; + case CORE_BUF_20 ... CORE_BUF_38 + 4: + index = (addr - CORE_BUF_20) >> 2; + ret = s->buf[index]; + break; + default: + qemu_log_mask(LOG_UNIMP, "invalid read: %x", (uint32_t)addr); + break; + } + + trace_loongarch_ipi_read(size, (uint64_t)addr, ret); + return ret; +} + +static int get_ipi_data(target_ulong val) +{ + int i, mask, data; + + data = val >> 32; + mask = (val >> 27) & 0xf; + + for (i = 0; i < 4; i++) { + if ((mask >> i) & 1) { + data &= ~(0xff << (i * 8)); + } + } + return data; +} + +static void ipi_send(uint64_t val) +{ + int cpuid, data; + CPULoongArchState *env; + + cpuid = (val >> 16) & 0x3ff; + /* IPI status vector */ + data = 1 << (val & 0x1f); + qemu_mutex_lock_iothread(); + CPUState *cs = qemu_get_cpu(cpuid); + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + env = &cpu->env; + loongarch_cpu_set_irq(cpu, IRQ_IPI, 1); + qemu_mutex_unlock_iothread(); + address_space_stl(&env->address_space_iocsr, 0x1008, + data, MEMTXATTRS_UNSPECIFIED, NULL); + +} + +static void mail_send(uint64_t val) +{ + int cpuid, data; + hwaddr addr; + CPULoongArchState *env; + + cpuid = (val >> 16) & 0x3ff; + addr = 0x1020 + (val & 0x1c); + CPUState *cs = qemu_get_cpu(cpuid); + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + env = &cpu->env; + data = get_ipi_data(val); + address_space_stl(&env->address_space_iocsr, addr, + data, MEMTXATTRS_UNSPECIFIED, NULL); +} + +static void any_send(uint64_t val) +{ + int cpuid, data; + hwaddr addr; + CPULoongArchState *env; + + cpuid = (val >> 16) & 0x3ff; + addr = val & 0xffff; + CPUState *cs = qemu_get_cpu(cpuid); + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + env = &cpu->env; + data = get_ipi_data(val); + address_space_stl(&env->address_space_iocsr, addr, + data, MEMTXATTRS_UNSPECIFIED, NULL); +} + +static void loongarch_ipi_writel(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + IPICore *s = opaque; + int index = 0; + + addr &= 0xff; + trace_loongarch_ipi_write(size, (uint64_t)addr, val); + switch (addr) { + case CORE_STATUS_OFF: + qemu_log_mask(LOG_GUEST_ERROR, "can not be written"); + break; + case CORE_EN_OFF: + s->en = val; + break; + case CORE_SET_OFF: + s->status |= val; + if (s->status != 0 && (s->status & s->en) != 0) { + qemu_irq_raise(s->irq); + } + break; + case CORE_CLEAR_OFF: + s->status &= ~val; + if (s->status == 0 && s->en != 0) { + qemu_irq_lower(s->irq); + } + break; + case CORE_BUF_20 ... CORE_BUF_38 + 4: + index = (addr - CORE_BUF_20) >> 2; + s->buf[index] = val; + break; + case IOCSR_IPI_SEND: + ipi_send(val); + break; + case IOCSR_MAIL_SEND: + mail_send(val); + break; + case IOCSR_ANY_SEND: + any_send(val); + break; + default: + qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr); + break; + } +} + +static const MemoryRegionOps loongarch_ipi_ops = { + .read = loongarch_ipi_readl, + .write = loongarch_ipi_writel, + .impl.min_access_size = 4, + .impl.max_access_size = 4, + .valid.min_access_size = 4, + .valid.max_access_size = 8, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void loongarch_ipi_init(Object *obj) +{ + int cpu; + LoongArchMachineState *lams; + LoongArchIPI *s = LOONGARCH_IPI(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + Object *machine = qdev_get_machine(); + ObjectClass *mc = object_get_class(machine); + /* 'lams' should be initialized */ + if (!strcmp(MACHINE_CLASS(mc)->name, "none")) { + return; + } + lams = LOONGARCH_MACHINE(machine); + for (cpu = 0; cpu < MAX_IPI_CORE_NUM; cpu++) { + memory_region_init_io(&s->ipi_iocsr_mem[cpu], obj, &loongarch_ipi_ops, + &lams->ipi_core[cpu], "loongarch_ipi_iocsr", 0x100); + sysbus_init_mmio(sbd, &s->ipi_iocsr_mem[cpu]); + qdev_init_gpio_out(DEVICE(obj), &lams->ipi_core[cpu].irq, 1); + } +} + +static const VMStateDescription vmstate_ipi_core = { + .name = "ipi-single", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(status, IPICore), + VMSTATE_UINT32(en, IPICore), + VMSTATE_UINT32(set, IPICore), + VMSTATE_UINT32(clear, IPICore), + VMSTATE_UINT32_ARRAY(buf, IPICore, MAX_IPI_MBX_NUM * 2), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_loongarch_ipi = { + .name = TYPE_LOONGARCH_IPI, + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_STRUCT_ARRAY(ipi_core, LoongArchMachineState, + MAX_IPI_CORE_NUM, 0, + vmstate_ipi_core, IPICore), + VMSTATE_END_OF_LIST() + } +}; + +static void loongarch_ipi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_loongarch_ipi; +} + +static const TypeInfo loongarch_ipi_info = { + .name = TYPE_LOONGARCH_IPI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(LoongArchIPI), + .instance_init = loongarch_ipi_init, + .class_init = loongarch_ipi_class_init, +}; + +static void loongarch_ipi_register_types(void) +{ + type_register_static(&loongarch_ipi_info); +} + +type_init(loongarch_ipi_register_types) diff --git a/hw/intc/meson.build b/hw/intc/meson.build index 8b35139f82..57af7fb33f 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -63,3 +63,4 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'], specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c')) specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c')) specific_ss.add(when: 'CONFIG_NIOS2_VIC', if_true: files('nios2_vic.c')) +specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c')) diff --git a/hw/intc/trace-events b/hw/intc/trace-events index 5271590304..36774662af 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -287,3 +287,7 @@ sh_intc_register(const char *s, int id, unsigned short v, int c, int m) "%s %u - sh_intc_read(unsigned size, uint64_t offset, unsigned long val) "size %u 0x%" PRIx64 " -> 0x%lx" sh_intc_write(unsigned size, uint64_t offset, unsigned long val) "size %u 0x%" PRIx64 " <- 0x%lx" sh_intc_set(int id, int enable) "setting interrupt group %d to %d" + +# loongarch_ipi.c +loongarch_ipi_read(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64 +loongarch_ipi_write(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64 diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig index 13e8501897..f0dad3329a 100644 --- a/hw/loongarch/Kconfig +++ b/hw/loongarch/Kconfig @@ -2,3 +2,4 @@ config LOONGARCH_VIRT bool select PCI select PCI_EXPRESS_GENERIC_BRIDGE + select LOONGARCH_IPI diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h new file mode 100644 index 0000000000..996ed7ea93 --- /dev/null +++ b/include/hw/intc/loongarch_ipi.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch ipi interrupt header files + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#ifndef HW_LOONGARCH_IPI_H +#define HW_LOONGARCH_IPI_H + +#include "hw/sysbus.h" + +/* Mainy used by iocsr read and write */ +#define SMP_IPI_MAILBOX 0x1000ULL +#define CORE_STATUS_OFF 0x0 +#define CORE_EN_OFF 0x4 +#define CORE_SET_OFF 0x8 +#define CORE_CLEAR_OFF 0xc +#define CORE_BUF_20 0x20 +#define CORE_BUF_28 0x28 +#define CORE_BUF_30 0x30 +#define CORE_BUF_38 0x38 +#define IOCSR_IPI_SEND 0x40 +#define IOCSR_MAIL_SEND 0x48 +#define IOCSR_ANY_SEND 0x158 + +/* IPI system memory address */ +#define IPI_SYSTEM_MEM 0x1fe01000 + +#define MAX_IPI_CORE_NUM 4 +#define MAX_IPI_MBX_NUM 4 + +#define TYPE_LOONGARCH_IPI "loongarch_ipi" +OBJECT_DECLARE_SIMPLE_TYPE(LoongArchIPI, LOONGARCH_IPI) + +typedef struct IPICore { + uint32_t status; + uint32_t en; + uint32_t set; + uint32_t clear; + /* 64bit buf divide into 2 32bit buf */ + uint32_t buf[MAX_IPI_MBX_NUM * 2]; + qemu_irq irq; +} IPICore; + +struct LoongArchIPI { + SysBusDevice parent_obj; + MemoryRegion ipi_iocsr_mem[MAX_IPI_CORE_NUM]; + MemoryRegion ipi_system_mem[MAX_IPI_CORE_NUM]; +}; + +#endif diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h index 4a4bb3f51f..09a816191c 100644 --- a/include/hw/loongarch/virt.h +++ b/include/hw/loongarch/virt.h @@ -11,6 +11,7 @@ #include "target/loongarch/cpu.h" #include "hw/boards.h" #include "qemu/queue.h" +#include "hw/intc/loongarch_ipi.h" #define LOONGARCH_MAX_VCPUS 4 @@ -21,6 +22,7 @@ struct LoongArchMachineState { /*< private >*/ MachineState parent_obj; + IPICore ipi_core[MAX_IPI_CORE_NUM]; MemoryRegion lowmem; MemoryRegion highmem; MemoryRegion isa_io; From 0f4fcf1845fe188901d4ff4cc807bd78690dddd0 Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:22 +0800 Subject: [PATCH 839/935] hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC) This patch realize the PCH-PIC interrupt controller. Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-33-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- MAINTAINERS | 1 + hw/intc/Kconfig | 4 + hw/intc/loongarch_pch_pic.c | 431 ++++++++++++++++++++++++++++ hw/intc/meson.build | 1 + hw/intc/trace-events | 9 + hw/loongarch/Kconfig | 1 + include/hw/intc/loongarch_pch_pic.h | 69 +++++ include/hw/pci-host/ls7a.h | 30 ++ 8 files changed, 546 insertions(+) create mode 100644 hw/intc/loongarch_pch_pic.c create mode 100644 include/hw/intc/loongarch_pch_pic.h create mode 100644 include/hw/pci-host/ls7a.h diff --git a/MAINTAINERS b/MAINTAINERS index 271eb89e2a..3ce5674da5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1135,6 +1135,7 @@ F: hw/loongarch/ F: include/hw/loongarch/virt.h F: include/hw/intc/loongarch_*.h F: hw/intc/loongarch_*.c +F: include/hw/pci-host/ls7a.h M68K Machines ------------- diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig index 1122c33cec..362980ca8c 100644 --- a/hw/intc/Kconfig +++ b/hw/intc/Kconfig @@ -90,3 +90,7 @@ config NIOS2_VIC config LOONGARCH_IPI bool + +config LOONGARCH_PCH_PIC + bool + select UNIMP diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c new file mode 100644 index 0000000000..3c9814a3b4 --- /dev/null +++ b/hw/intc/loongarch_pch_pic.c @@ -0,0 +1,431 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU Loongson 7A1000 I/O interrupt controller. + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/loongarch/virt.h" +#include "hw/irq.h" +#include "hw/intc/loongarch_pch_pic.h" +#include "migration/vmstate.h" +#include "trace.h" + +static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level) +{ + unsigned long val; + int irq; + + if (level) { + val = mask & s->intirr & ~s->int_mask; + if (val) { + irq = find_first_bit(&val, 64); + s->intisr |= 0x1ULL << irq; + qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1); + } + } else { + val = mask & s->intisr; + if (val) { + irq = find_first_bit(&val, 64); + s->intisr &= ~(0x1ULL << irq); + qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0); + } + } +} + +static void pch_pic_irq_handler(void *opaque, int irq, int level) +{ + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); + uint64_t mask = 1ULL << irq; + + assert(irq < PCH_PIC_IRQ_NUM); + trace_loongarch_pch_pic_irq_handler(irq, level); + + if (s->intedge & mask) { + /* Edge triggered */ + if (level) { + if ((s->last_intirr & mask) == 0) { + s->intirr |= mask; + } + s->last_intirr |= mask; + } else { + s->last_intirr &= ~mask; + } + } else { + /* Level triggered */ + if (level) { + s->intirr |= mask; + s->last_intirr |= mask; + } else { + s->intirr &= ~mask; + s->last_intirr &= ~mask; + } + } + pch_pic_update_irq(s, mask, level); +} + +static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr, + unsigned size) +{ + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); + uint64_t val = 0; + uint32_t offset = addr & 0xfff; + + switch (offset) { + case PCH_PIC_INT_ID_LO: + val = PCH_PIC_INT_ID_VAL; + break; + case PCH_PIC_INT_ID_HI: + val = PCH_PIC_INT_ID_NUM; + break; + case PCH_PIC_INT_MASK_LO: + val = (uint32_t)s->int_mask; + break; + case PCH_PIC_INT_MASK_HI: + val = s->int_mask >> 32; + break; + case PCH_PIC_INT_EDGE_LO: + val = (uint32_t)s->intedge; + break; + case PCH_PIC_INT_EDGE_HI: + val = s->intedge >> 32; + break; + case PCH_PIC_HTMSI_EN_LO: + val = (uint32_t)s->htmsi_en; + break; + case PCH_PIC_HTMSI_EN_HI: + val = s->htmsi_en >> 32; + break; + case PCH_PIC_AUTO_CTRL0_LO: + case PCH_PIC_AUTO_CTRL0_HI: + case PCH_PIC_AUTO_CTRL1_LO: + case PCH_PIC_AUTO_CTRL1_HI: + break; + default: + break; + } + + trace_loongarch_pch_pic_low_readw(size, addr, val); + return val; +} + +static uint64_t get_writew_val(uint64_t value, uint32_t target, bool hi) +{ + uint64_t mask = 0xffffffff00000000; + uint64_t data = target; + + return hi ? (value & ~mask) | (data << 32) : (value & mask) | data; +} + +static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); + uint32_t offset, old_valid, data = (uint32_t)value; + uint64_t old, int_mask; + offset = addr & 0xfff; + + trace_loongarch_pch_pic_low_writew(size, addr, data); + + switch (offset) { + case PCH_PIC_INT_MASK_LO: + old = s->int_mask; + s->int_mask = get_writew_val(old, data, 0); + old_valid = (uint32_t)old; + if (old_valid & ~data) { + pch_pic_update_irq(s, (old_valid & ~data), 1); + } + if (~old_valid & data) { + pch_pic_update_irq(s, (~old_valid & data), 0); + } + break; + case PCH_PIC_INT_MASK_HI: + old = s->int_mask; + s->int_mask = get_writew_val(old, data, 1); + old_valid = (uint32_t)(old >> 32); + int_mask = old_valid & ~data; + if (int_mask) { + pch_pic_update_irq(s, int_mask << 32, 1); + } + int_mask = ~old_valid & data; + if (int_mask) { + pch_pic_update_irq(s, int_mask << 32, 0); + } + break; + case PCH_PIC_INT_EDGE_LO: + s->intedge = get_writew_val(s->intedge, data, 0); + break; + case PCH_PIC_INT_EDGE_HI: + s->intedge = get_writew_val(s->intedge, data, 1); + break; + case PCH_PIC_INT_CLEAR_LO: + if (s->intedge & data) { + s->intirr &= (~data); + pch_pic_update_irq(s, data, 0); + s->intisr &= (~data); + } + break; + case PCH_PIC_INT_CLEAR_HI: + value <<= 32; + if (s->intedge & value) { + s->intirr &= (~value); + pch_pic_update_irq(s, value, 0); + s->intisr &= (~value); + } + break; + case PCH_PIC_HTMSI_EN_LO: + s->htmsi_en = get_writew_val(s->htmsi_en, data, 0); + break; + case PCH_PIC_HTMSI_EN_HI: + s->htmsi_en = get_writew_val(s->htmsi_en, data, 1); + break; + case PCH_PIC_AUTO_CTRL0_LO: + case PCH_PIC_AUTO_CTRL0_HI: + case PCH_PIC_AUTO_CTRL1_LO: + case PCH_PIC_AUTO_CTRL1_HI: + break; + default: + break; + } +} + +static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr, + unsigned size) +{ + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); + uint64_t val = 0; + uint32_t offset = addr & 0xfff; + + switch (offset) { + case STATUS_LO_START: + val = (uint32_t)(s->intisr & (~s->int_mask)); + break; + case STATUS_HI_START: + val = (s->intisr & (~s->int_mask)) >> 32; + break; + case POL_LO_START: + val = (uint32_t)s->int_polarity; + break; + case POL_HI_START: + val = s->int_polarity >> 32; + break; + default: + break; + } + + trace_loongarch_pch_pic_high_readw(size, addr, val); + return val; +} + +static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); + uint32_t offset, data = (uint32_t)value; + offset = addr & 0xfff; + + trace_loongarch_pch_pic_high_writew(size, addr, data); + + switch (offset) { + case STATUS_LO_START: + s->intisr = get_writew_val(s->intisr, data, 0); + break; + case STATUS_HI_START: + s->intisr = get_writew_val(s->intisr, data, 1); + break; + case POL_LO_START: + s->int_polarity = get_writew_val(s->int_polarity, data, 0); + break; + case POL_HI_START: + s->int_polarity = get_writew_val(s->int_polarity, data, 1); + break; + default: + break; + } +} + +static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr, + unsigned size) +{ + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); + uint64_t val = 0; + uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET; + int64_t offset_tmp; + + switch (offset) { + case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END: + offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET; + if (offset_tmp >= 0 && offset_tmp < 64) { + val = s->htmsi_vector[offset_tmp]; + } + break; + case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END: + offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET; + if (offset_tmp >= 0 && offset_tmp < 64) { + val = s->route_entry[offset_tmp]; + } + break; + default: + break; + } + + trace_loongarch_pch_pic_readb(size, addr, val); + return val; +} + +static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); + int32_t offset_tmp; + uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET; + + trace_loongarch_pch_pic_writeb(size, addr, data); + + switch (offset) { + case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END: + offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET; + if (offset_tmp >= 0 && offset_tmp < 64) { + s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff); + } + break; + case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END: + offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET; + if (offset_tmp >= 0 && offset_tmp < 64) { + s->route_entry[offset_tmp] = (uint8_t)(data & 0xff); + } + break; + default: + break; + } +} + +static const MemoryRegionOps loongarch_pch_pic_reg32_low_ops = { + .read = loongarch_pch_pic_low_readw, + .write = loongarch_pch_pic_low_writew, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static const MemoryRegionOps loongarch_pch_pic_reg32_high_ops = { + .read = loongarch_pch_pic_high_readw, + .write = loongarch_pch_pic_high_writew, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static const MemoryRegionOps loongarch_pch_pic_reg8_ops = { + .read = loongarch_pch_pic_readb, + .write = loongarch_pch_pic_writeb, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void loongarch_pch_pic_reset(DeviceState *d) +{ + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(d); + int i; + + s->int_mask = -1; + s->htmsi_en = 0x0; + s->intedge = 0x0; + s->intclr = 0x0; + s->auto_crtl0 = 0x0; + s->auto_crtl1 = 0x0; + for (i = 0; i < 64; i++) { + s->route_entry[i] = 0x1; + s->htmsi_vector[i] = 0x0; + } + s->intirr = 0x0; + s->intisr = 0x0; + s->last_intirr = 0x0; + s->int_polarity = 0x0; +} + +static void loongarch_pch_pic_init(Object *obj) +{ + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem32_low, obj, + &loongarch_pch_pic_reg32_low_ops, + s, PCH_PIC_NAME(.reg32_part1), 0x100); + memory_region_init_io(&s->iomem8, obj, &loongarch_pch_pic_reg8_ops, + s, PCH_PIC_NAME(.reg8), 0x2a0); + memory_region_init_io(&s->iomem32_high, obj, + &loongarch_pch_pic_reg32_high_ops, + s, PCH_PIC_NAME(.reg32_part2), 0xc60); + sysbus_init_mmio(sbd, &s->iomem32_low); + sysbus_init_mmio(sbd, &s->iomem8); + sysbus_init_mmio(sbd, &s->iomem32_high); + + qdev_init_gpio_out(DEVICE(obj), s->parent_irq, PCH_PIC_IRQ_NUM); + qdev_init_gpio_in(DEVICE(obj), pch_pic_irq_handler, PCH_PIC_IRQ_NUM); +} + +static const VMStateDescription vmstate_loongarch_pch_pic = { + .name = TYPE_LOONGARCH_PCH_PIC, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(int_mask, LoongArchPCHPIC), + VMSTATE_UINT64(htmsi_en, LoongArchPCHPIC), + VMSTATE_UINT64(intedge, LoongArchPCHPIC), + VMSTATE_UINT64(intclr, LoongArchPCHPIC), + VMSTATE_UINT64(auto_crtl0, LoongArchPCHPIC), + VMSTATE_UINT64(auto_crtl1, LoongArchPCHPIC), + VMSTATE_UINT8_ARRAY(route_entry, LoongArchPCHPIC, 64), + VMSTATE_UINT8_ARRAY(htmsi_vector, LoongArchPCHPIC, 64), + VMSTATE_UINT64(last_intirr, LoongArchPCHPIC), + VMSTATE_UINT64(intirr, LoongArchPCHPIC), + VMSTATE_UINT64(intisr, LoongArchPCHPIC), + VMSTATE_UINT64(int_polarity, LoongArchPCHPIC), + VMSTATE_END_OF_LIST() + } +}; + +static void loongarch_pch_pic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = loongarch_pch_pic_reset; + dc->vmsd = &vmstate_loongarch_pch_pic; +} + +static const TypeInfo loongarch_pch_pic_info = { + .name = TYPE_LOONGARCH_PCH_PIC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(LoongArchPCHPIC), + .instance_init = loongarch_pch_pic_init, + .class_init = loongarch_pch_pic_class_init, +}; + +static void loongarch_pch_pic_register_types(void) +{ + type_register_static(&loongarch_pch_pic_info); +} + +type_init(loongarch_pch_pic_register_types) diff --git a/hw/intc/meson.build b/hw/intc/meson.build index 57af7fb33f..03f13f1c49 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -64,3 +64,4 @@ specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c')) specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c')) specific_ss.add(when: 'CONFIG_NIOS2_VIC', if_true: files('nios2_vic.c')) specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c')) +specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c')) diff --git a/hw/intc/trace-events b/hw/intc/trace-events index 36774662af..4cdbc01a07 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -291,3 +291,12 @@ sh_intc_set(int id, int enable) "setting interrupt group %d to %d" # loongarch_ipi.c loongarch_ipi_read(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64 loongarch_ipi_write(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64 + +# loongarch_pch_pic.c +loongarch_pch_pic_irq_handler(int irq, int level) "irq %d level %d" +loongarch_pch_pic_low_readw(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 +loongarch_pch_pic_low_writew(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 +loongarch_pch_pic_high_readw(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 +loongarch_pch_pic_high_writew(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 +loongarch_pch_pic_readb(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 +loongarch_pch_pic_writeb(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig index f0dad3329a..2df45f7e8f 100644 --- a/hw/loongarch/Kconfig +++ b/hw/loongarch/Kconfig @@ -3,3 +3,4 @@ config LOONGARCH_VIRT select PCI select PCI_EXPRESS_GENERIC_BRIDGE select LOONGARCH_IPI + select LOONGARCH_PCH_PIC diff --git a/include/hw/intc/loongarch_pch_pic.h b/include/hw/intc/loongarch_pch_pic.h new file mode 100644 index 0000000000..2d4aa9ed6f --- /dev/null +++ b/include/hw/intc/loongarch_pch_pic.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch 7A1000 I/O interrupt controller definitions + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic" +#define PCH_PIC_NAME(name) TYPE_LOONGARCH_PCH_PIC#name +OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHPIC, LOONGARCH_PCH_PIC) + +#define PCH_PIC_IRQ_START 0 +#define PCH_PIC_IRQ_END 63 +#define PCH_PIC_IRQ_NUM 64 +#define PCH_PIC_INT_ID_VAL 0x7000000UL +#define PCH_PIC_INT_ID_NUM 0x3f0001UL + +#define PCH_PIC_INT_ID_LO 0x00 +#define PCH_PIC_INT_ID_HI 0x04 +#define PCH_PIC_INT_MASK_LO 0x20 +#define PCH_PIC_INT_MASK_HI 0x24 +#define PCH_PIC_HTMSI_EN_LO 0x40 +#define PCH_PIC_HTMSI_EN_HI 0x44 +#define PCH_PIC_INT_EDGE_LO 0x60 +#define PCH_PIC_INT_EDGE_HI 0x64 +#define PCH_PIC_INT_CLEAR_LO 0x80 +#define PCH_PIC_INT_CLEAR_HI 0x84 +#define PCH_PIC_AUTO_CTRL0_LO 0xc0 +#define PCH_PIC_AUTO_CTRL0_HI 0xc4 +#define PCH_PIC_AUTO_CTRL1_LO 0xe0 +#define PCH_PIC_AUTO_CTRL1_HI 0xe4 +#define PCH_PIC_ROUTE_ENTRY_OFFSET 0x100 +#define PCH_PIC_ROUTE_ENTRY_END 0x13f +#define PCH_PIC_HTMSI_VEC_OFFSET 0x200 +#define PCH_PIC_HTMSI_VEC_END 0x23f +#define PCH_PIC_INT_STATUS_LO 0x3a0 +#define PCH_PIC_INT_STATUS_HI 0x3a4 +#define PCH_PIC_INT_POL_LO 0x3e0 +#define PCH_PIC_INT_POL_HI 0x3e4 + +#define STATUS_LO_START 0 +#define STATUS_HI_START 0x4 +#define POL_LO_START 0x40 +#define POL_HI_START 0x44 +struct LoongArchPCHPIC { + SysBusDevice parent_obj; + qemu_irq parent_irq[64]; + uint64_t int_mask; /*0x020 interrupt mask register*/ + uint64_t htmsi_en; /*0x040 1=msi*/ + uint64_t intedge; /*0x060 edge=1 level =0*/ + uint64_t intclr; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/ + uint64_t auto_crtl0; /*0x0c0*/ + uint64_t auto_crtl1; /*0x0e0*/ + uint64_t last_intirr; /* edge detection */ + uint64_t intirr; /* 0x380 interrupt request register */ + uint64_t intisr; /* 0x3a0 interrupt service register */ + /* + * 0x3e0 interrupt level polarity selection + * register 0 for high level trigger + */ + uint64_t int_polarity; + + uint8_t route_entry[64]; /*0x100 - 0x138*/ + uint8_t htmsi_vector[64]; /*0x200 - 0x238*/ + + MemoryRegion iomem32_low; + MemoryRegion iomem32_high; + MemoryRegion iomem8; +}; diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h new file mode 100644 index 0000000000..bf80e99ce1 --- /dev/null +++ b/include/hw/pci-host/ls7a.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch CPU + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef HW_LS7A_H +#define HW_LS7A_H + +#include "hw/pci/pci.h" +#include "hw/pci/pcie_host.h" +#include "hw/pci-host/pam.h" +#include "qemu/units.h" +#include "qemu/range.h" +#include "qom/object.h" + +#define LS7A_PCH_REG_BASE 0x10000000UL +#define LS7A_IOAPIC_REG_BASE (LS7A_PCH_REG_BASE) +#define LS7A_PCH_MSI_ADDR_LOW 0x2FF00000UL + +/* + * According to the kernel pch irq start from 64 offset + * 0 ~ 16 irqs used for non-pci device while 16 ~ 64 irqs + * used for pci device. + */ +#define PCH_PIC_IRQ_OFFSET 64 +#define LS7A_DEVICE_IRQS 16 +#define LS7A_PCI_IRQS 48 +#endif From 249ad85a4b4ba6e949bba3c5b9932c389e07249c Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:23 +0800 Subject: [PATCH 840/935] hw/intc: Add LoongArch ls7a msi interrupt controller support(PCH-MSI) This patch realize PCH-MSI interrupt controller. Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-34-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- hw/intc/Kconfig | 5 ++ hw/intc/loongarch_pch_msi.c | 73 +++++++++++++++++++++++++++++ hw/intc/meson.build | 1 + hw/intc/trace-events | 3 ++ hw/loongarch/Kconfig | 1 + include/hw/intc/loongarch_pch_msi.h | 20 ++++++++ include/hw/pci-host/ls7a.h | 3 ++ 7 files changed, 106 insertions(+) create mode 100644 hw/intc/loongarch_pch_msi.c create mode 100644 include/hw/intc/loongarch_pch_msi.h diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig index 362980ca8c..58f550b865 100644 --- a/hw/intc/Kconfig +++ b/hw/intc/Kconfig @@ -94,3 +94,8 @@ config LOONGARCH_IPI config LOONGARCH_PCH_PIC bool select UNIMP + +config LOONGARCH_PCH_MSI + select MSI_NONBROKEN + bool + select UNIMP diff --git a/hw/intc/loongarch_pch_msi.c b/hw/intc/loongarch_pch_msi.c new file mode 100644 index 0000000000..74bcdbdb48 --- /dev/null +++ b/hw/intc/loongarch_pch_msi.c @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU Loongson 7A1000 msi interrupt controller. + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/intc/loongarch_pch_msi.h" +#include "hw/intc/loongarch_pch_pic.h" +#include "hw/pci/msi.h" +#include "hw/misc/unimp.h" +#include "migration/vmstate.h" +#include "trace.h" + +static uint64_t loongarch_msi_mem_read(void *opaque, hwaddr addr, unsigned size) +{ + return 0; +} + +static void loongarch_msi_mem_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(opaque); + int irq_num = val & 0xff; + + trace_loongarch_msi_set_irq(irq_num); + assert(irq_num < PCH_MSI_IRQ_NUM); + qemu_set_irq(s->pch_msi_irq[irq_num], 1); +} + +static const MemoryRegionOps loongarch_pch_msi_ops = { + .read = loongarch_msi_mem_read, + .write = loongarch_msi_mem_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void pch_msi_irq_handler(void *opaque, int irq, int level) +{ + LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(opaque); + + qemu_set_irq(s->pch_msi_irq[irq], level); +} + +static void loongarch_pch_msi_init(Object *obj) +{ + LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->msi_mmio, obj, &loongarch_pch_msi_ops, + s, TYPE_LOONGARCH_PCH_MSI, 0x8); + sysbus_init_mmio(sbd, &s->msi_mmio); + msi_nonbroken = true; + + qdev_init_gpio_out(DEVICE(obj), s->pch_msi_irq, PCH_MSI_IRQ_NUM); + qdev_init_gpio_in(DEVICE(obj), pch_msi_irq_handler, PCH_MSI_IRQ_NUM); +} + +static const TypeInfo loongarch_pch_msi_info = { + .name = TYPE_LOONGARCH_PCH_MSI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(LoongArchPCHMSI), + .instance_init = loongarch_pch_msi_init, +}; + +static void loongarch_pch_msi_register_types(void) +{ + type_register_static(&loongarch_pch_msi_info); +} + +type_init(loongarch_pch_msi_register_types) diff --git a/hw/intc/meson.build b/hw/intc/meson.build index 03f13f1c49..1d407c046d 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -65,3 +65,4 @@ specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c')) specific_ss.add(when: 'CONFIG_NIOS2_VIC', if_true: files('nios2_vic.c')) specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c')) specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c')) +specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c')) diff --git a/hw/intc/trace-events b/hw/intc/trace-events index 4cdbc01a07..63c9851923 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -300,3 +300,6 @@ loongarch_pch_pic_high_readw(unsigned size, uint64_t addr, uint64_t val) "size: loongarch_pch_pic_high_writew(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 loongarch_pch_pic_readb(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 loongarch_pch_pic_writeb(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64 + +# loongarch_pch_msi.c +loongarch_msi_set_irq(int irq_num) "set msi irq %d" diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig index 2df45f7e8f..d814fc6103 100644 --- a/hw/loongarch/Kconfig +++ b/hw/loongarch/Kconfig @@ -4,3 +4,4 @@ config LOONGARCH_VIRT select PCI_EXPRESS_GENERIC_BRIDGE select LOONGARCH_IPI select LOONGARCH_PCH_PIC + select LOONGARCH_PCH_MSI diff --git a/include/hw/intc/loongarch_pch_msi.h b/include/hw/intc/loongarch_pch_msi.h new file mode 100644 index 0000000000..f668bfca7a --- /dev/null +++ b/include/hw/intc/loongarch_pch_msi.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch 7A1000 I/O interrupt controller definitions + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#define TYPE_LOONGARCH_PCH_MSI "loongarch_pch_msi" +OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHMSI, LOONGARCH_PCH_MSI) + +/* Msi irq start start from 64 to 255 */ +#define PCH_MSI_IRQ_START 64 +#define PCH_MSI_IRQ_END 255 +#define PCH_MSI_IRQ_NUM 192 + +struct LoongArchPCHMSI { + SysBusDevice parent_obj; + qemu_irq pch_msi_irq[PCH_MSI_IRQ_NUM]; + MemoryRegion msi_mmio; +}; diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h index bf80e99ce1..089d3e5438 100644 --- a/include/hw/pci-host/ls7a.h +++ b/include/hw/pci-host/ls7a.h @@ -15,6 +15,9 @@ #include "qemu/range.h" #include "qom/object.h" +#define LS7A_PCI_MEM_BASE 0x40000000UL +#define LS7A_PCI_MEM_SIZE 0x40000000UL + #define LS7A_PCH_REG_BASE 0x10000000UL #define LS7A_IOAPIC_REG_BASE (LS7A_PCH_REG_BASE) #define LS7A_PCH_MSI_ADDR_LOW 0x2FF00000UL From cbff2db1e92f8759db0f0716a41a3e11b18f2eee Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:24 +0800 Subject: [PATCH 841/935] hw/intc: Add LoongArch extioi interrupt controller(EIOINTC) This patch realize the EIOINTC interrupt controller. Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-35-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- hw/intc/Kconfig | 3 + hw/intc/loongarch_extioi.c | 312 +++++++++++++++++++++++++++++ hw/intc/meson.build | 1 + hw/intc/trace-events | 6 + hw/loongarch/Kconfig | 1 + include/hw/intc/loongarch_extioi.h | 62 ++++++ 6 files changed, 385 insertions(+) create mode 100644 hw/intc/loongarch_extioi.c create mode 100644 include/hw/intc/loongarch_extioi.h diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig index 58f550b865..ecd2883ceb 100644 --- a/hw/intc/Kconfig +++ b/hw/intc/Kconfig @@ -99,3 +99,6 @@ config LOONGARCH_PCH_MSI select MSI_NONBROKEN bool select UNIMP + +config LOONGARCH_EXTIOI + bool diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c new file mode 100644 index 0000000000..22803969bc --- /dev/null +++ b/hw/intc/loongarch_extioi.c @@ -0,0 +1,312 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Loongson 3A5000 ext interrupt controller emulation + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/log.h" +#include "hw/irq.h" +#include "hw/sysbus.h" +#include "hw/loongarch/virt.h" +#include "hw/qdev-properties.h" +#include "exec/address-spaces.h" +#include "hw/intc/loongarch_extioi.h" +#include "migration/vmstate.h" +#include "trace.h" + + +static void extioi_update_irq(LoongArchExtIOI *s, int irq, int level) +{ + int ipnum, cpu, found, irq_index, irq_mask; + + ipnum = s->sw_ipmap[irq / 32]; + cpu = s->sw_coremap[irq]; + irq_index = irq / 32; + irq_mask = 1 << (irq & 0x1f); + + if (level) { + /* if not enable return false */ + if (((s->enable[irq_index]) & irq_mask) == 0) { + return; + } + s->coreisr[cpu][irq_index] |= irq_mask; + found = find_first_bit(s->sw_isr[cpu][ipnum], EXTIOI_IRQS); + set_bit(irq, s->sw_isr[cpu][ipnum]); + if (found < EXTIOI_IRQS) { + /* other irq is handling, need not update parent irq level */ + return; + } + } else { + s->coreisr[cpu][irq_index] &= ~irq_mask; + clear_bit(irq, s->sw_isr[cpu][ipnum]); + found = find_first_bit(s->sw_isr[cpu][ipnum], EXTIOI_IRQS); + if (found < EXTIOI_IRQS) { + /* other irq is handling, need not update parent irq level */ + return; + } + } + qemu_set_irq(s->parent_irq[cpu][ipnum], level); +} + +static void extioi_setirq(void *opaque, int irq, int level) +{ + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque); + trace_loongarch_extioi_setirq(irq, level); + if (level) { + /* + * s->isr should be used in vmstate structure, + * but it not support 'unsigned long', + * so we have to switch it. + */ + set_bit(irq, (unsigned long *)s->isr); + } else { + clear_bit(irq, (unsigned long *)s->isr); + } + extioi_update_irq(s, irq, level); +} + +static uint64_t extioi_readw(void *opaque, hwaddr addr, unsigned size) +{ + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque); + unsigned long offset = addr & 0xffff; + uint32_t index, cpu, ret = 0; + + switch (offset) { + case EXTIOI_NODETYPE_START ... EXTIOI_NODETYPE_END - 1: + index = (offset - EXTIOI_NODETYPE_START) >> 2; + ret = s->nodetype[index]; + break; + case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END - 1: + index = (offset - EXTIOI_IPMAP_START) >> 2; + ret = s->ipmap[index]; + break; + case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END - 1: + index = (offset - EXTIOI_ENABLE_START) >> 2; + ret = s->enable[index]; + break; + case EXTIOI_BOUNCE_START ... EXTIOI_BOUNCE_END - 1: + index = (offset - EXTIOI_BOUNCE_START) >> 2; + ret = s->bounce[index]; + break; + case EXTIOI_COREISR_START ... EXTIOI_COREISR_END - 1: + index = ((offset - EXTIOI_COREISR_START) & 0x1f) >> 2; + cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3; + ret = s->coreisr[cpu][index]; + break; + case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END - 1: + index = (offset - EXTIOI_COREMAP_START) >> 2; + ret = s->coremap[index]; + break; + default: + break; + } + + trace_loongarch_extioi_readw(addr, ret); + return ret; +} + +static inline void extioi_enable_irq(LoongArchExtIOI *s, int index,\ + uint32_t mask, int level) +{ + uint32_t val; + int irq; + + val = mask & s->isr[index]; + irq = ctz32(val); + while (irq != 32) { + /* + * enable bit change from 0 to 1, + * need to update irq by pending bits + */ + extioi_update_irq(s, irq + index * 32, level); + val &= ~(1 << irq); + irq = ctz32(val); + } +} + +static void extioi_writew(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque); + int i, cpu, index, old_data, irq; + uint32_t offset; + + trace_loongarch_extioi_writew(addr, val); + offset = addr & 0xffff; + + switch (offset) { + case EXTIOI_NODETYPE_START ... EXTIOI_NODETYPE_END - 1: + index = (offset - EXTIOI_NODETYPE_START) >> 2; + s->nodetype[index] = val; + break; + case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END - 1: + /* + * ipmap cannot be set at runtime, can be set only at the beginning + * of intr driver, need not update upper irq level + */ + index = (offset - EXTIOI_IPMAP_START) >> 2; + s->ipmap[index] = val; + /* + * loongarch only support little endian, + * so we paresd the value with little endian. + */ + val = cpu_to_le64(val); + for (i = 0; i < 4; i++) { + uint8_t ipnum; + ipnum = val & 0xff; + ipnum = ctz32(ipnum); + ipnum = (ipnum >= 4) ? 0 : ipnum; + s->sw_ipmap[index * 4 + i] = ipnum; + val = val >> 8; + } + + break; + case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END - 1: + index = (offset - EXTIOI_ENABLE_START) >> 2; + old_data = s->enable[index]; + s->enable[index] = val; + + /* unmask irq */ + val = s->enable[index] & ~old_data; + extioi_enable_irq(s, index, val, 1); + + /* mask irq */ + val = ~s->enable[index] & old_data; + extioi_enable_irq(s, index, val, 0); + break; + case EXTIOI_BOUNCE_START ... EXTIOI_BOUNCE_END - 1: + /* do not emulate hw bounced irq routing */ + index = (offset - EXTIOI_BOUNCE_START) >> 2; + s->bounce[index] = val; + break; + case EXTIOI_COREISR_START ... EXTIOI_COREISR_END - 1: + index = ((offset - EXTIOI_COREISR_START) & 0x1f) >> 2; + cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3; + old_data = s->coreisr[cpu][index]; + s->coreisr[cpu][index] = old_data & ~val; + /* write 1 to clear interrrupt */ + old_data &= val; + irq = ctz32(old_data); + while (irq != 32) { + extioi_update_irq(s, irq + index * 32, 0); + old_data &= ~(1 << irq); + irq = ctz32(old_data); + } + break; + case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END - 1: + irq = offset - EXTIOI_COREMAP_START; + index = irq / 4; + s->coremap[index] = val; + /* + * loongarch only support little endian, + * so we paresd the value with little endian. + */ + val = cpu_to_le64(val); + + for (i = 0; i < 4; i++) { + cpu = val & 0xff; + cpu = ctz32(cpu); + cpu = (cpu >= 4) ? 0 : cpu; + val = val >> 8; + + if (s->sw_coremap[irq + i] == cpu) { + continue; + } + + if (test_bit(irq, (unsigned long *)s->isr)) { + /* + * lower irq at old cpu and raise irq at new cpu + */ + extioi_update_irq(s, irq + i, 0); + s->sw_coremap[irq + i] = cpu; + extioi_update_irq(s, irq + i, 1); + } else { + s->sw_coremap[irq + i] = cpu; + } + } + break; + default: + break; + } +} + +static const MemoryRegionOps extioi_ops = { + .read = extioi_readw, + .write = extioi_writew, + .impl.min_access_size = 4, + .impl.max_access_size = 4, + .valid.min_access_size = 4, + .valid.max_access_size = 8, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static const VMStateDescription vmstate_loongarch_extioi = { + .name = TYPE_LOONGARCH_EXTIOI, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(bounce, LoongArchExtIOI, EXTIOI_IRQS_GROUP_COUNT), + VMSTATE_UINT32_2DARRAY(coreisr, LoongArchExtIOI, LOONGARCH_MAX_VCPUS, + EXTIOI_IRQS_GROUP_COUNT), + VMSTATE_UINT32_ARRAY(nodetype, LoongArchExtIOI, + EXTIOI_IRQS_NODETYPE_COUNT / 2), + VMSTATE_UINT32_ARRAY(enable, LoongArchExtIOI, EXTIOI_IRQS / 32), + VMSTATE_UINT32_ARRAY(isr, LoongArchExtIOI, EXTIOI_IRQS / 32), + VMSTATE_UINT32_ARRAY(ipmap, LoongArchExtIOI, EXTIOI_IRQS_IPMAP_SIZE / 4), + VMSTATE_UINT32_ARRAY(coremap, LoongArchExtIOI, EXTIOI_IRQS / 4), + VMSTATE_UINT8_ARRAY(sw_ipmap, LoongArchExtIOI, EXTIOI_IRQS_IPMAP_SIZE), + VMSTATE_UINT8_ARRAY(sw_coremap, LoongArchExtIOI, EXTIOI_IRQS), + + VMSTATE_END_OF_LIST() + } +}; + +static void loongarch_extioi_instance_init(Object *obj) +{ + SysBusDevice *dev = SYS_BUS_DEVICE(obj); + LoongArchExtIOI *s = LOONGARCH_EXTIOI(obj); + int i, cpu, pin; + + for (i = 0; i < EXTIOI_IRQS; i++) { + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]); + } + + qdev_init_gpio_in(DEVICE(obj), extioi_setirq, EXTIOI_IRQS); + + for (cpu = 0; cpu < LOONGARCH_MAX_VCPUS; cpu++) { + memory_region_init_io(&s->extioi_iocsr_mem[cpu], OBJECT(s), &extioi_ops, + s, "extioi_iocsr", 0x900); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->extioi_iocsr_mem[cpu]); + for (pin = 0; pin < LS3A_INTC_IP; pin++) { + qdev_init_gpio_out(DEVICE(obj), &s->parent_irq[cpu][pin], 1); + } + } + memory_region_init_io(&s->extioi_system_mem, OBJECT(s), &extioi_ops, + s, "extioi_system_mem", 0x900); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->extioi_system_mem); +} + +static void loongarch_extioi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_loongarch_extioi; +} + +static const TypeInfo loongarch_extioi_info = { + .name = TYPE_LOONGARCH_EXTIOI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = loongarch_extioi_instance_init, + .instance_size = sizeof(struct LoongArchExtIOI), + .class_init = loongarch_extioi_class_init, +}; + +static void loongarch_extioi_register_types(void) +{ + type_register_static(&loongarch_extioi_info); +} + +type_init(loongarch_extioi_register_types) diff --git a/hw/intc/meson.build b/hw/intc/meson.build index 1d407c046d..bcbf22ff51 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -66,3 +66,4 @@ specific_ss.add(when: 'CONFIG_NIOS2_VIC', if_true: files('nios2_vic.c')) specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c')) specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c')) specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c')) +specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c')) diff --git a/hw/intc/trace-events b/hw/intc/trace-events index 63c9851923..0a90c1cdec 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -303,3 +303,9 @@ loongarch_pch_pic_writeb(unsigned size, uint64_t addr, uint64_t val) "size: %u a # loongarch_pch_msi.c loongarch_msi_set_irq(int irq_num) "set msi irq %d" + +# loongarch_extioi.c +loongarch_extioi_setirq(int irq, int level) "set extirq irq %d level %d" +loongarch_extioi_readw(uint64_t addr, uint32_t val) "addr: 0x%"PRIx64 "val: 0x%x" +loongarch_extioi_writew(uint64_t addr, uint64_t val) "addr: 0x%"PRIx64 "val: 0x%" PRIx64 + diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig index d814fc6103..f779087416 100644 --- a/hw/loongarch/Kconfig +++ b/hw/loongarch/Kconfig @@ -5,3 +5,4 @@ config LOONGARCH_VIRT select LOONGARCH_IPI select LOONGARCH_PCH_PIC select LOONGARCH_PCH_MSI + select LOONGARCH_EXTIOI diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h new file mode 100644 index 0000000000..15b8c999f6 --- /dev/null +++ b/include/hw/intc/loongarch_extioi.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch 3A5000 ext interrupt controller definitions + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#include "hw/sysbus.h" +#include "hw/loongarch/virt.h" + +#ifndef LOONGARCH_EXTIOI_H +#define LOONGARCH_EXTIOI_H + +#define LS3A_INTC_IP 8 +#define EXTIOI_IRQS (256) +#define EXTIOI_IRQS_BITMAP_SIZE (256 / 8) +/* map to ipnum per 32 irqs */ +#define EXTIOI_IRQS_IPMAP_SIZE (256 / 32) +#define EXTIOI_IRQS_COREMAP_SIZE 256 +#define EXTIOI_IRQS_NODETYPE_COUNT 16 +#define EXTIOI_IRQS_GROUP_COUNT 8 + +#define APIC_OFFSET 0x400 +#define APIC_BASE (0x1000ULL + APIC_OFFSET) + +#define EXTIOI_NODETYPE_START (0x4a0 - APIC_OFFSET) +#define EXTIOI_NODETYPE_END (0x4c0 - APIC_OFFSET) +#define EXTIOI_IPMAP_START (0x4c0 - APIC_OFFSET) +#define EXTIOI_IPMAP_END (0x4c8 - APIC_OFFSET) +#define EXTIOI_ENABLE_START (0x600 - APIC_OFFSET) +#define EXTIOI_ENABLE_END (0x620 - APIC_OFFSET) +#define EXTIOI_BOUNCE_START (0x680 - APIC_OFFSET) +#define EXTIOI_BOUNCE_END (0x6a0 - APIC_OFFSET) +#define EXTIOI_ISR_START (0x700 - APIC_OFFSET) +#define EXTIOI_ISR_END (0x720 - APIC_OFFSET) +#define EXTIOI_COREISR_START (0x800 - APIC_OFFSET) +#define EXTIOI_COREISR_END (0xB20 - APIC_OFFSET) +#define EXTIOI_COREMAP_START (0xC00 - APIC_OFFSET) +#define EXTIOI_COREMAP_END (0xD00 - APIC_OFFSET) + +#define TYPE_LOONGARCH_EXTIOI "loongarch.extioi" +OBJECT_DECLARE_SIMPLE_TYPE(LoongArchExtIOI, LOONGARCH_EXTIOI) +struct LoongArchExtIOI { + SysBusDevice parent_obj; + /* hardware state */ + uint32_t nodetype[EXTIOI_IRQS_NODETYPE_COUNT / 2]; + uint32_t bounce[EXTIOI_IRQS_GROUP_COUNT]; + uint32_t isr[EXTIOI_IRQS / 32]; + uint32_t coreisr[LOONGARCH_MAX_VCPUS][EXTIOI_IRQS_GROUP_COUNT]; + uint32_t enable[EXTIOI_IRQS / 32]; + uint32_t ipmap[EXTIOI_IRQS_IPMAP_SIZE / 4]; + uint32_t coremap[EXTIOI_IRQS / 4]; + uint32_t sw_pending[EXTIOI_IRQS / 32]; + DECLARE_BITMAP(sw_isr[LOONGARCH_MAX_VCPUS][LS3A_INTC_IP], EXTIOI_IRQS); + uint8_t sw_ipmap[EXTIOI_IRQS_IPMAP_SIZE]; + uint8_t sw_coremap[EXTIOI_IRQS]; + qemu_irq parent_irq[LOONGARCH_MAX_VCPUS][LS3A_INTC_IP]; + qemu_irq irq[EXTIOI_IRQS]; + MemoryRegion extioi_iocsr_mem[LOONGARCH_MAX_VCPUS]; + MemoryRegion extioi_system_mem; +}; +#endif /* LOONGARCH_EXTIOI_H */ From 69d9c74fa9143b58073772cd5a8a7dd2b1d8ffcf Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:25 +0800 Subject: [PATCH 842/935] hw/loongarch: Add irq hierarchy for the system This patch add the irq hierarchy for the virt board. Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-36-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- hw/loongarch/loongson3.c | 104 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c index 7df32f777e..7a5c61e2df 100644 --- a/hw/loongarch/loongson3.c +++ b/hw/loongarch/loongson3.c @@ -16,8 +16,110 @@ #include "sysemu/rtc.h" #include "hw/loongarch/virt.h" #include "exec/address-spaces.h" +#include "hw/intc/loongarch_ipi.h" +#include "hw/intc/loongarch_extioi.h" +#include "hw/intc/loongarch_pch_pic.h" +#include "hw/intc/loongarch_pch_msi.h" +#include "hw/pci-host/ls7a.h" + #include "target/loongarch/cpu.h" +static void loongarch_irq_init(LoongArchMachineState *lams) +{ + MachineState *ms = MACHINE(lams); + DeviceState *pch_pic, *pch_msi, *cpudev; + DeviceState *ipi, *extioi; + SysBusDevice *d; + LoongArchCPU *lacpu; + CPULoongArchState *env; + CPUState *cpu_state; + int cpu, pin, i; + + ipi = qdev_new(TYPE_LOONGARCH_IPI); + sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal); + + extioi = qdev_new(TYPE_LOONGARCH_EXTIOI); + sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal); + + /* + * The connection of interrupts: + * +-----+ +---------+ +-------+ + * | IPI |--> | CPUINTC | <-- | Timer | + * +-----+ +---------+ +-------+ + * ^ + * | + * +---------+ + * | EIOINTC | + * +---------+ + * ^ ^ + * | | + * +---------+ +---------+ + * | PCH-PIC | | PCH-MSI | + * +---------+ +---------+ + * ^ ^ ^ + * | | | + * +--------+ +---------+ +---------+ + * | UARTs | | Devices | | Devices | + * +--------+ +---------+ +---------+ + */ + for (cpu = 0; cpu < ms->smp.cpus; cpu++) { + cpu_state = qemu_get_cpu(cpu); + cpudev = DEVICE(cpu_state); + lacpu = LOONGARCH_CPU(cpu_state); + env = &(lacpu->env); + + /* connect ipi irq to cpu irq */ + qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI)); + /* IPI iocsr memory region */ + memory_region_add_subregion(&env->system_iocsr, SMP_IPI_MAILBOX, + sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), + cpu)); + /* extioi iocsr memory region */ + memory_region_add_subregion(&env->system_iocsr, APIC_BASE, + sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), + cpu)); + } + + /* + * connect ext irq to the cpu irq + * cpu_pin[9:2] <= intc_pin[7:0] + */ + for (cpu = 0; cpu < ms->smp.cpus; cpu++) { + cpudev = DEVICE(qemu_get_cpu(cpu)); + for (pin = 0; pin < LS3A_INTC_IP; pin++) { + qdev_connect_gpio_out(extioi, (cpu * 8 + pin), + qdev_get_gpio_in(cpudev, pin + 2)); + } + } + + pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC); + d = SYS_BUS_DEVICE(pch_pic); + sysbus_realize_and_unref(d, &error_fatal); + memory_region_add_subregion(get_system_memory(), LS7A_IOAPIC_REG_BASE, + sysbus_mmio_get_region(d, 0)); + memory_region_add_subregion(get_system_memory(), + LS7A_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY_OFFSET, + sysbus_mmio_get_region(d, 1)); + memory_region_add_subregion(get_system_memory(), + LS7A_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO, + sysbus_mmio_get_region(d, 2)); + + /* Connect 64 pch_pic irqs to extioi */ + for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) { + qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i)); + } + + pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI); + d = SYS_BUS_DEVICE(pch_msi); + sysbus_realize_and_unref(d, &error_fatal); + sysbus_mmio_map(d, 0, LS7A_PCH_MSI_ADDR_LOW); + for (i = 0; i < PCH_MSI_IRQ_NUM; i++) { + /* Connect 192 pch_msi irqs to extioi */ + qdev_connect_gpio_out(DEVICE(d), i, + qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START)); + } +} + static void loongarch_init(MachineState *machine) { const char *cpu_model = machine->cpu_type; @@ -63,6 +165,8 @@ static void loongarch_init(MachineState *machine) get_system_io(), 0, LOONGARCH_ISA_IO_SIZE); memory_region_add_subregion(address_space_mem, LOONGARCH_ISA_IO_BASE, &lams->isa_io); + /* Initialize the IO interrupt subsystem */ + loongarch_irq_init(lams); } static void loongarch_class_init(ObjectClass *oc, void *data) From 256309e1884898a9cedb44abab0f15c4843e06f6 Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:26 +0800 Subject: [PATCH 843/935] Enable common virtio pci support for LoongArch Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-37-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- softmmu/qdev-monitor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c index 12fe60c467..bb5897fc76 100644 --- a/softmmu/qdev-monitor.c +++ b/softmmu/qdev-monitor.c @@ -60,7 +60,8 @@ typedef struct QDevAlias QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \ QEMU_ARCH_MIPS | QEMU_ARCH_PPC | \ QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \ - QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA) + QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \ + QEMU_ARCH_LOONGARCH) #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X) #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K) From dc93b8df8a166d2df0c007affd49bcfd93e77391 Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:27 +0800 Subject: [PATCH 844/935] hw/loongarch: Add some devices support for 3A5000. 1.Add uart,virtio-net,vga and usb for 3A5000. 2.Add irq set and map for the pci host. Non pci device use irq 0-16, pci device use 16-64. 3.Add some unimplented device to emulate guest unused memory space. Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Acked-by: Richard Henderson Message-Id: <20220606124333.2060567-38-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- hw/loongarch/Kconfig | 7 ++++ hw/loongarch/loongson3.c | 77 ++++++++++++++++++++++++++++++++++++++ include/hw/pci-host/ls7a.h | 7 ++++ 3 files changed, 91 insertions(+) diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig index f779087416..8552ff4bee 100644 --- a/hw/loongarch/Kconfig +++ b/hw/loongarch/Kconfig @@ -2,6 +2,13 @@ config LOONGARCH_VIRT bool select PCI select PCI_EXPRESS_GENERIC_BRIDGE + imply VGA_PCI + imply VIRTIO_VGA + imply PCI_DEVICES + select ISA_BUS + select SERIAL + select SERIAL_ISA + select VIRTIO_PCI select LOONGARCH_IPI select LOONGARCH_PCH_PIC select LOONGARCH_PCH_MSI diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c index 7a5c61e2df..7bc17113dc 100644 --- a/hw/loongarch/loongson3.c +++ b/hw/loongarch/loongson3.c @@ -9,6 +9,7 @@ #include "qemu/datadir.h" #include "qapi/error.h" #include "hw/boards.h" +#include "hw/char/serial.h" #include "sysemu/sysemu.h" #include "sysemu/qtest.h" #include "sysemu/runstate.h" @@ -16,14 +17,88 @@ #include "sysemu/rtc.h" #include "hw/loongarch/virt.h" #include "exec/address-spaces.h" +#include "hw/irq.h" +#include "net/net.h" #include "hw/intc/loongarch_ipi.h" #include "hw/intc/loongarch_extioi.h" #include "hw/intc/loongarch_pch_pic.h" #include "hw/intc/loongarch_pch_msi.h" #include "hw/pci-host/ls7a.h" +#include "hw/pci-host/gpex.h" +#include "hw/misc/unimp.h" #include "target/loongarch/cpu.h" +static void loongarch_devices_init(DeviceState *pch_pic) +{ + DeviceState *gpex_dev; + SysBusDevice *d; + PCIBus *pci_bus; + MemoryRegion *ecam_alias, *ecam_reg, *pio_alias, *pio_reg; + MemoryRegion *mmio_alias, *mmio_reg; + int i; + + gpex_dev = qdev_new(TYPE_GPEX_HOST); + d = SYS_BUS_DEVICE(gpex_dev); + sysbus_realize_and_unref(d, &error_fatal); + pci_bus = PCI_HOST_BRIDGE(gpex_dev)->bus; + + /* Map only part size_ecam bytes of ECAM space */ + ecam_alias = g_new0(MemoryRegion, 1); + ecam_reg = sysbus_mmio_get_region(d, 0); + memory_region_init_alias(ecam_alias, OBJECT(gpex_dev), "pcie-ecam", + ecam_reg, 0, LS_PCIECFG_SIZE); + memory_region_add_subregion(get_system_memory(), LS_PCIECFG_BASE, + ecam_alias); + + /* Map PCI mem space */ + mmio_alias = g_new0(MemoryRegion, 1); + mmio_reg = sysbus_mmio_get_region(d, 1); + memory_region_init_alias(mmio_alias, OBJECT(gpex_dev), "pcie-mmio", + mmio_reg, LS7A_PCI_MEM_BASE, LS7A_PCI_MEM_SIZE); + memory_region_add_subregion(get_system_memory(), LS7A_PCI_MEM_BASE, + mmio_alias); + + /* Map PCI IO port space. */ + pio_alias = g_new0(MemoryRegion, 1); + pio_reg = sysbus_mmio_get_region(d, 2); + memory_region_init_alias(pio_alias, OBJECT(gpex_dev), "pcie-io", pio_reg, + LS7A_PCI_IO_OFFSET, LS7A_PCI_IO_SIZE); + memory_region_add_subregion(get_system_memory(), LS7A_PCI_IO_BASE, + pio_alias); + + for (i = 0; i < GPEX_NUM_IRQS; i++) { + sysbus_connect_irq(d, i, + qdev_get_gpio_in(pch_pic, 16 + i)); + gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i); + } + + serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0, + qdev_get_gpio_in(pch_pic, + LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET), + 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN); + + /* Network init */ + for (i = 0; i < nb_nics; i++) { + NICInfo *nd = &nd_table[i]; + + if (!nd->model) { + nd->model = g_strdup("virtio"); + } + + pci_nic_init_nofail(nd, pci_bus, nd->model, NULL); + } + + /* VGA setup */ + pci_vga_init(pci_bus); + + /* + * There are some invalid guest memory access. + * Create some unimplemented devices to emulate this. + */ + create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4); +} + static void loongarch_irq_init(LoongArchMachineState *lams) { MachineState *ms = MACHINE(lams); @@ -118,6 +193,8 @@ static void loongarch_irq_init(LoongArchMachineState *lams) qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START)); } + + loongarch_devices_init(pch_pic); } static void loongarch_init(MachineState *machine) diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h index 089d3e5438..5c653527f0 100644 --- a/include/hw/pci-host/ls7a.h +++ b/include/hw/pci-host/ls7a.h @@ -17,6 +17,11 @@ #define LS7A_PCI_MEM_BASE 0x40000000UL #define LS7A_PCI_MEM_SIZE 0x40000000UL +#define LS7A_PCI_IO_OFFSET 0x4000 +#define LS_PCIECFG_BASE 0x20000000 +#define LS_PCIECFG_SIZE 0x08000000 +#define LS7A_PCI_IO_BASE 0x18004000UL +#define LS7A_PCI_IO_SIZE 0xC000 #define LS7A_PCH_REG_BASE 0x10000000UL #define LS7A_IOAPIC_REG_BASE (LS7A_PCH_REG_BASE) @@ -30,4 +35,6 @@ #define PCH_PIC_IRQ_OFFSET 64 #define LS7A_DEVICE_IRQS 16 #define LS7A_PCI_IRQS 48 +#define LS7A_UART_IRQ (PCH_PIC_IRQ_OFFSET + 2) +#define LS7A_UART_BASE 0x1fe001e0 #endif From c117f68a46f4b3fa363635fd610873707d4899fa Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:28 +0800 Subject: [PATCH 845/935] hw/loongarch: Add LoongArch ls7a rtc device support This patch add ls7a rtc device support. Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-39-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- MAINTAINERS | 1 + hw/loongarch/Kconfig | 1 + hw/loongarch/loongson3.c | 3 + hw/rtc/Kconfig | 3 + hw/rtc/ls7a_rtc.c | 528 +++++++++++++++++++++++++++++++++++++ hw/rtc/meson.build | 1 + include/hw/pci-host/ls7a.h | 4 + 7 files changed, 541 insertions(+) create mode 100644 hw/rtc/ls7a_rtc.c diff --git a/MAINTAINERS b/MAINTAINERS index 3ce5674da5..e8938db694 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1136,6 +1136,7 @@ F: include/hw/loongarch/virt.h F: include/hw/intc/loongarch_*.h F: hw/intc/loongarch_*.c F: include/hw/pci-host/ls7a.h +F: hw/rtc/ls7a_rtc.c M68K Machines ------------- diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig index 8552ff4bee..35b6680772 100644 --- a/hw/loongarch/Kconfig +++ b/hw/loongarch/Kconfig @@ -13,3 +13,4 @@ config LOONGARCH_VIRT select LOONGARCH_PCH_PIC select LOONGARCH_PCH_MSI select LOONGARCH_EXTIOI + select LS7A_RTC diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c index 7bc17113dc..95984c9086 100644 --- a/hw/loongarch/loongson3.c +++ b/hw/loongarch/loongson3.c @@ -97,6 +97,9 @@ static void loongarch_devices_init(DeviceState *pch_pic) * Create some unimplemented devices to emulate this. */ create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4); + sysbus_create_simple("ls7a_rtc", LS7A_RTC_REG_BASE, + qdev_get_gpio_in(pch_pic, + LS7A_RTC_IRQ - PCH_PIC_IRQ_OFFSET)); } static void loongarch_irq_init(LoongArchMachineState *lams) diff --git a/hw/rtc/Kconfig b/hw/rtc/Kconfig index 730c272bc5..d0d8dda084 100644 --- a/hw/rtc/Kconfig +++ b/hw/rtc/Kconfig @@ -27,3 +27,6 @@ config SUN4V_RTC config GOLDFISH_RTC bool + +config LS7A_RTC + bool diff --git a/hw/rtc/ls7a_rtc.c b/hw/rtc/ls7a_rtc.c new file mode 100644 index 0000000000..fe6710310f --- /dev/null +++ b/hw/rtc/ls7a_rtc.c @@ -0,0 +1,528 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Loongarch LS7A Real Time Clock emulation + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "include/hw/register.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" +#include "qemu/cutils.h" +#include "qemu/log.h" +#include "migration/vmstate.h" +#include "hw/misc/unimp.h" +#include "sysemu/rtc.h" +#include "hw/registerfields.h" + +#define SYS_TOYTRIM 0x20 +#define SYS_TOYWRITE0 0x24 +#define SYS_TOYWRITE1 0x28 +#define SYS_TOYREAD0 0x2C +#define SYS_TOYREAD1 0x30 +#define SYS_TOYMATCH0 0x34 +#define SYS_TOYMATCH1 0x38 +#define SYS_TOYMATCH2 0x3C +#define SYS_RTCCTRL 0x40 +#define SYS_RTCTRIM 0x60 +#define SYS_RTCWRTIE0 0x64 +#define SYS_RTCREAD0 0x68 +#define SYS_RTCMATCH0 0x6C +#define SYS_RTCMATCH1 0x70 +#define SYS_RTCMATCH2 0x74 + +#define LS7A_RTC_FREQ 32768 +#define TIMER_NUMS 3 +/* + * Shift bits and filed mask + */ + +FIELD(TOY, MON, 26, 6) +FIELD(TOY, DAY, 21, 5) +FIELD(TOY, HOUR, 16, 5) +FIELD(TOY, MIN, 10, 6) +FIELD(TOY, SEC, 4, 6) +FIELD(TOY, MSEC, 0, 4) + +FIELD(TOY_MATCH, YEAR, 26, 6) +FIELD(TOY_MATCH, MON, 22, 4) +FIELD(TOY_MATCH, DAY, 17, 5) +FIELD(TOY_MATCH, HOUR, 12, 5) +FIELD(TOY_MATCH, MIN, 6, 6) +FIELD(TOY_MATCH, SEC, 0, 6) + +FIELD(RTC_CTRL, RTCEN, 13, 1) +FIELD(RTC_CTRL, TOYEN, 11, 1) +FIELD(RTC_CTRL, EO, 8, 1) + +#define TYPE_LS7A_RTC "ls7a_rtc" +OBJECT_DECLARE_SIMPLE_TYPE(LS7ARtcState, LS7A_RTC) + +struct LS7ARtcState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + /* + * Needed to preserve the tick_count across migration, even if the + * absolute value of the rtc_clock is different on the source and + * destination. + */ + int64_t offset_toy; + int64_t offset_rtc; + uint64_t save_toy_mon; + uint64_t save_toy_year; + uint64_t save_rtc; + int64_t data; + int tidx; + uint32_t toymatch[3]; + uint32_t toytrim; + uint32_t cntrctl; + uint32_t rtctrim; + uint32_t rtccount; + uint32_t rtcmatch[3]; + QEMUTimer *toy_timer[TIMER_NUMS]; + QEMUTimer *rtc_timer[TIMER_NUMS]; + qemu_irq irq; +}; + +/* switch nanoseconds time to rtc ticks */ +static inline uint64_t ls7a_rtc_ticks(void) +{ + return qemu_clock_get_ns(rtc_clock) * LS7A_RTC_FREQ / NANOSECONDS_PER_SECOND; +} + +/* switch rtc ticks to nanoseconds */ +static inline uint64_t ticks_to_ns(uint64_t ticks) +{ + return ticks * NANOSECONDS_PER_SECOND / LS7A_RTC_FREQ; +} + +static inline bool toy_enabled(LS7ARtcState *s) +{ + return FIELD_EX32(s->cntrctl, RTC_CTRL, TOYEN) && + FIELD_EX32(s->cntrctl, RTC_CTRL, EO); +} + +static inline bool rtc_enabled(LS7ARtcState *s) +{ + return FIELD_EX32(s->cntrctl, RTC_CTRL, RTCEN) && + FIELD_EX32(s->cntrctl, RTC_CTRL, EO); +} + +/* parse toy value to struct tm */ +static inline void toy_val_to_time_mon(uint64_t toy_val, struct tm *tm) +{ + tm->tm_sec = FIELD_EX32(toy_val, TOY, SEC); + tm->tm_min = FIELD_EX32(toy_val, TOY, MIN); + tm->tm_hour = FIELD_EX32(toy_val, TOY, HOUR); + tm->tm_mday = FIELD_EX32(toy_val, TOY, DAY); + tm->tm_mon = FIELD_EX32(toy_val, TOY, MON) - 1; +} + +static inline void toy_val_to_time_year(uint64_t toy_year, struct tm *tm) +{ + tm->tm_year = toy_year; +} + +/* parse struct tm to toy value */ +static inline uint64_t toy_time_to_val_mon(struct tm tm) +{ + uint64_t val = 0; + + val = FIELD_DP32(val, TOY, MON, tm.tm_mon + 1); + val = FIELD_DP32(val, TOY, DAY, tm.tm_mday); + val = FIELD_DP32(val, TOY, HOUR, tm.tm_hour); + val = FIELD_DP32(val, TOY, MIN, tm.tm_min); + val = FIELD_DP32(val, TOY, SEC, tm.tm_sec); + return val; +} + +static inline uint64_t toy_time_to_val_year(struct tm tm) +{ + uint64_t year; + + year = tm.tm_year; + return year; +} + +static inline void toymatch_val_to_time(uint64_t val, struct tm *tm) +{ + tm->tm_sec = FIELD_EX32(val, TOY_MATCH, SEC); + tm->tm_min = FIELD_EX32(val, TOY_MATCH, MIN); + tm->tm_hour = FIELD_EX32(val, TOY_MATCH, HOUR); + tm->tm_mday = FIELD_EX32(val, TOY_MATCH, DAY); + tm->tm_mon = FIELD_EX32(val, TOY_MATCH, MON) - 1; + tm->tm_year += (FIELD_EX32(val, TOY_MATCH, YEAR) - (tm->tm_year & 0x3f)); +} + +static void toymatch_write(LS7ARtcState *s, struct tm *tm, uint64_t val, int num) +{ + int64_t now, expire_time; + + /* it do not support write when toy disabled */ + if (toy_enabled(s)) { + s->toymatch[num] = val; + /* caculate expire time */ + now = qemu_clock_get_ms(rtc_clock); + toymatch_val_to_time(val, tm); + expire_time = now + (qemu_timedate_diff(tm) - s->offset_toy) * 1000; + timer_mod(s->toy_timer[num], expire_time); + } +} + +static void rtcmatch_write(LS7ARtcState *s, uint64_t val, int num) +{ + uint64_t expire_ns; + + /* it do not support write when toy disabled */ + if (rtc_enabled(s)) { + s->rtcmatch[num] = val; + /* caculate expire time */ + expire_ns = ticks_to_ns(val) - ticks_to_ns(s->offset_rtc); + timer_mod_ns(s->rtc_timer[num], expire_ns); + } +} + +static void ls7a_toy_stop(LS7ARtcState *s) +{ + int i; + struct tm tm; + /* + * save time when disabled toy, + * because toy time not add counters. + */ + qemu_get_timedate(&tm, s->offset_toy); + s->save_toy_mon = toy_time_to_val_mon(tm); + s->save_toy_year = toy_time_to_val_year(tm); + + /* delete timers, and when re-enabled, recaculate expire time */ + for (i = 0; i < TIMER_NUMS; i++) { + timer_del(s->toy_timer[i]); + } +} + +static void ls7a_rtc_stop(LS7ARtcState *s) +{ + int i; + uint64_t time; + + /* save rtc time */ + time = ls7a_rtc_ticks() + s->offset_rtc; + s->save_rtc = time; + + /* delete timers, and when re-enabled, recaculate expire time */ + for (i = 0; i < TIMER_NUMS; i++) { + timer_del(s->rtc_timer[i]); + } +} + +static void ls7a_toy_start(LS7ARtcState *s) +{ + int i; + uint64_t expire_time, now; + struct tm tm; + /* + * need to recaculate toy offset + * and expire time when enable it. + */ + toy_val_to_time_mon(s->save_toy_mon, &tm); + toy_val_to_time_year(s->save_toy_year, &tm); + + s->offset_toy = qemu_timedate_diff(&tm); + now = qemu_clock_get_ms(rtc_clock); + + /* recaculate expire time and enable timer */ + for (i = 0; i < TIMER_NUMS; i++) { + toymatch_val_to_time(s->toymatch[i], &tm); + expire_time = now + (qemu_timedate_diff(&tm) - s->offset_toy) * 1000; + timer_mod(s->toy_timer[i], expire_time); + } +} + +static void ls7a_rtc_start(LS7ARtcState *s) +{ + int i; + uint64_t expire_time, now; + + /* + * need to recaculate rtc offset + * and expire time when enable it. + */ + now = ls7a_rtc_ticks(); + s->offset_rtc = s->save_rtc - now; + + /* recaculate expire time and enable timer */ + for (i = 0; i < TIMER_NUMS; i++) { + expire_time = ticks_to_ns(s->rtcmatch[i]) - ticks_to_ns(s->offset_rtc); + timer_mod_ns(s->rtc_timer[i], expire_time); + } +} + +static uint64_t ls7a_rtc_read(void *opaque, hwaddr addr, unsigned size) +{ + LS7ARtcState *s = LS7A_RTC(opaque); + struct tm tm; + int val = 0; + + switch (addr) { + case SYS_TOYREAD0: + /* if toy disabled, read save toy time */ + if (toy_enabled(s)) { + qemu_get_timedate(&tm, s->offset_toy); + val = toy_time_to_val_mon(tm); + } else { + /* read save mon val */ + val = s->save_toy_mon; + } + break; + case SYS_TOYREAD1: + /* if toy disabled, read save toy time */ + if (toy_enabled(s)) { + qemu_get_timedate(&tm, s->offset_toy); + val = tm.tm_year; + } else { + /* read save year val */ + val = s->save_toy_year; + } + break; + case SYS_TOYMATCH0: + val = s->toymatch[0]; + break; + case SYS_TOYMATCH1: + val = s->toymatch[1]; + break; + case SYS_TOYMATCH2: + val = s->toymatch[2]; + break; + case SYS_RTCCTRL: + val = s->cntrctl; + break; + case SYS_RTCREAD0: + /* if rtc disabled, read save rtc time */ + if (rtc_enabled(s)) { + val = ls7a_rtc_ticks() + s->offset_rtc; + } else { + val = s->save_rtc; + } + break; + case SYS_RTCMATCH0: + val = s->rtcmatch[0]; + break; + case SYS_RTCMATCH1: + val = s->rtcmatch[1]; + break; + case SYS_RTCMATCH2: + val = s->rtcmatch[2]; + break; + default: + val = 0; + break; + } + return val; +} + +static void ls7a_rtc_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + int old_toyen, old_rtcen, new_toyen, new_rtcen; + LS7ARtcState *s = LS7A_RTC(opaque); + struct tm tm; + + switch (addr) { + case SYS_TOYWRITE0: + /* it do not support write when toy disabled */ + if (toy_enabled(s)) { + qemu_get_timedate(&tm, s->offset_toy); + tm.tm_sec = FIELD_EX32(val, TOY, SEC); + tm.tm_min = FIELD_EX32(val, TOY, MIN); + tm.tm_hour = FIELD_EX32(val, TOY, HOUR); + tm.tm_mday = FIELD_EX32(val, TOY, DAY); + tm.tm_mon = FIELD_EX32(val, TOY, MON) - 1; + s->offset_toy = qemu_timedate_diff(&tm); + } + break; + case SYS_TOYWRITE1: + if (toy_enabled(s)) { + qemu_get_timedate(&tm, s->offset_toy); + tm.tm_year = val; + s->offset_toy = qemu_timedate_diff(&tm); + } + break; + case SYS_TOYMATCH0: + toymatch_write(s, &tm, val, 0); + break; + case SYS_TOYMATCH1: + toymatch_write(s, &tm, val, 1); + break; + case SYS_TOYMATCH2: + toymatch_write(s, &tm, val, 2); + break; + case SYS_RTCCTRL: + /* get old ctrl */ + old_toyen = toy_enabled(s); + old_rtcen = rtc_enabled(s); + + s->cntrctl = val; + /* get new ctrl */ + new_toyen = toy_enabled(s); + new_rtcen = rtc_enabled(s); + + /* + * we do not consider if EO changed, as it always set at most time. + * toy or rtc enabled should start timer. otherwise, stop timer + */ + if (old_toyen != new_toyen) { + if (new_toyen) { + ls7a_toy_start(s); + } else { + ls7a_toy_stop(s); + } + } + if (old_rtcen != new_rtcen) { + if (new_rtcen) { + ls7a_rtc_start(s); + } else { + ls7a_rtc_stop(s); + } + } + break; + case SYS_RTCWRTIE0: + if (rtc_enabled(s)) { + s->offset_rtc = val - ls7a_rtc_ticks(); + } + break; + case SYS_RTCMATCH0: + rtcmatch_write(s, val, 0); + break; + case SYS_RTCMATCH1: + rtcmatch_write(s, val, 1); + break; + case SYS_RTCMATCH2: + rtcmatch_write(s, val, 2); + break; + default: + break; + } +} + +static const MemoryRegionOps ls7a_rtc_ops = { + .read = ls7a_rtc_read, + .write = ls7a_rtc_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static void toy_timer_cb(void *opaque) +{ + LS7ARtcState *s = opaque; + + if (toy_enabled(s)) { + qemu_irq_pulse(s->irq); + } +} + +static void rtc_timer_cb(void *opaque) +{ + LS7ARtcState *s = opaque; + + if (rtc_enabled(s)) { + qemu_irq_pulse(s->irq); + } +} + +static void ls7a_rtc_realize(DeviceState *dev, Error **errp) +{ + int i; + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + LS7ARtcState *d = LS7A_RTC(sbd); + memory_region_init_io(&d->iomem, NULL, &ls7a_rtc_ops, + (void *)d, "ls7a_rtc", 0x100); + + sysbus_init_irq(sbd, &d->irq); + + sysbus_init_mmio(sbd, &d->iomem); + for (i = 0; i < TIMER_NUMS; i++) { + d->toymatch[i] = 0; + d->rtcmatch[i] = 0; + d->toy_timer[i] = timer_new_ms(rtc_clock, toy_timer_cb, d); + d->rtc_timer[i] = timer_new_ms(rtc_clock, rtc_timer_cb, d); + } + d->offset_toy = 0; + d->offset_rtc = 0; + d->save_toy_mon = 0; + d->save_toy_year = 0; + d->save_rtc = 0; + + create_unimplemented_device("mmio fallback 1", 0x10013ffc, 0x4); +} + +static int ls7a_rtc_pre_save(void *opaque) +{ + LS7ARtcState *s = LS7A_RTC(opaque); + + ls7a_toy_stop(s); + ls7a_rtc_stop(s); + + return 0; +} + +static int ls7a_rtc_post_load(void *opaque, int version_id) +{ + LS7ARtcState *s = LS7A_RTC(opaque); + if (toy_enabled(s)) { + ls7a_toy_start(s); + } + + if (rtc_enabled(s)) { + ls7a_rtc_start(s); + } + + return 0; +} + +static const VMStateDescription vmstate_ls7a_rtc = { + .name = "ls7a_rtc", + .version_id = 1, + .minimum_version_id = 1, + .pre_save = ls7a_rtc_pre_save, + .post_load = ls7a_rtc_post_load, + .fields = (VMStateField[]) { + VMSTATE_INT64(offset_toy, LS7ARtcState), + VMSTATE_INT64(offset_rtc, LS7ARtcState), + VMSTATE_UINT64(save_toy_mon, LS7ARtcState), + VMSTATE_UINT64(save_toy_year, LS7ARtcState), + VMSTATE_UINT64(save_rtc, LS7ARtcState), + VMSTATE_UINT32_ARRAY(toymatch, LS7ARtcState, TIMER_NUMS), + VMSTATE_UINT32_ARRAY(rtcmatch, LS7ARtcState, TIMER_NUMS), + VMSTATE_UINT32(cntrctl, LS7ARtcState), + VMSTATE_END_OF_LIST() + } +}; + +static void ls7a_rtc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->vmsd = &vmstate_ls7a_rtc; + dc->realize = ls7a_rtc_realize; + dc->desc = "ls7a rtc"; +} + +static const TypeInfo ls7a_rtc_info = { + .name = TYPE_LS7A_RTC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(LS7ARtcState), + .class_init = ls7a_rtc_class_init, +}; + +static void ls7a_rtc_register_types(void) +{ + type_register_static(&ls7a_rtc_info); +} + +type_init(ls7a_rtc_register_types) diff --git a/hw/rtc/meson.build b/hw/rtc/meson.build index 7cecdee5dd..dc33973384 100644 --- a/hw/rtc/meson.build +++ b/hw/rtc/meson.build @@ -11,6 +11,7 @@ softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_rtc.c')) softmmu_ss.add(when: 'CONFIG_SUN4V_RTC', if_true: files('sun4v-rtc.c')) softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_rtc.c')) softmmu_ss.add(when: 'CONFIG_GOLDFISH_RTC', if_true: files('goldfish_rtc.c')) +softmmu_ss.add(when: 'CONFIG_LS7A_RTC', if_true: files('ls7a_rtc.c')) softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-rtc.c')) specific_ss.add(when: 'CONFIG_MC146818RTC', if_true: files('mc146818rtc.c')) diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h index 5c653527f0..08c5f78be2 100644 --- a/include/hw/pci-host/ls7a.h +++ b/include/hw/pci-host/ls7a.h @@ -37,4 +37,8 @@ #define LS7A_PCI_IRQS 48 #define LS7A_UART_IRQ (PCH_PIC_IRQ_OFFSET + 2) #define LS7A_UART_BASE 0x1fe001e0 +#define LS7A_RTC_IRQ (PCH_PIC_IRQ_OFFSET + 3) +#define LS7A_MISC_REG_BASE (LS7A_PCH_REG_BASE + 0x00080000) +#define LS7A_RTC_REG_BASE (LS7A_MISC_REG_BASE + 0x00050100) +#define LS7A_RTC_LEN 0x100 #endif From 6a6f26f481204bb95d855aa0427389ef10073e62 Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:29 +0800 Subject: [PATCH 846/935] hw/loongarch: Add LoongArch load elf function. Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-40-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- hw/loongarch/loongson3.c | 61 ++++++++++++++++++++++++++++++++++++++-- target/loongarch/cpu.h | 2 ++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c index 95984c9086..3c8fcb828c 100644 --- a/hw/loongarch/loongson3.c +++ b/hw/loongarch/loongson3.c @@ -19,6 +19,8 @@ #include "exec/address-spaces.h" #include "hw/irq.h" #include "net/net.h" +#include "hw/loader.h" +#include "elf.h" #include "hw/intc/loongarch_ipi.h" #include "hw/intc/loongarch_extioi.h" #include "hw/intc/loongarch_pch_pic.h" @@ -29,6 +31,36 @@ #include "target/loongarch/cpu.h" +static struct _loaderparams { + uint64_t ram_size; + const char *kernel_filename; +} loaderparams; + +static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr) +{ + return addr & 0x1fffffffll; +} + +static int64_t load_kernel_info(void) +{ + uint64_t kernel_entry, kernel_low, kernel_high; + ssize_t kernel_size; + + kernel_size = load_elf(loaderparams.kernel_filename, NULL, + cpu_loongarch_virt_to_phys, NULL, + &kernel_entry, &kernel_low, + &kernel_high, NULL, 0, + EM_LOONGARCH, 1, 0); + + if (kernel_size < 0) { + error_report("could not load kernel '%s': %s", + loaderparams.kernel_filename, + load_elf_strerror(kernel_size)); + exit(1); + } + return kernel_entry; +} + static void loongarch_devices_init(DeviceState *pch_pic) { DeviceState *gpex_dev; @@ -200,15 +232,29 @@ static void loongarch_irq_init(LoongArchMachineState *lams) loongarch_devices_init(pch_pic); } +static void reset_load_elf(void *opaque) +{ + LoongArchCPU *cpu = opaque; + CPULoongArchState *env = &cpu->env; + + cpu_reset(CPU(cpu)); + if (env->load_elf) { + cpu_set_pc(CPU(cpu), env->elf_address); + } +} + static void loongarch_init(MachineState *machine) { const char *cpu_model = machine->cpu_type; + const char *kernel_filename = machine->kernel_filename; ram_addr_t offset = 0; ram_addr_t ram_size = machine->ram_size; uint64_t highram_size = 0; MemoryRegion *address_space_mem = get_system_memory(); LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); + LoongArchCPU *lacpu; int i; + int64_t kernel_addr = 0; if (!cpu_model) { cpu_model = LOONGARCH_CPU_TYPE_NAME("la464"); @@ -234,17 +280,28 @@ static void loongarch_init(MachineState *machine) machine->ram, 0, 256 * MiB); memory_region_add_subregion(address_space_mem, offset, &lams->lowmem); offset += 256 * MiB; - highram_size = ram_size - 256 * MiB; memory_region_init_alias(&lams->highmem, NULL, "loongarch.highmem", machine->ram, offset, highram_size); memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem); - /* Add isa io region */ memory_region_init_alias(&lams->isa_io, NULL, "isa-io", get_system_io(), 0, LOONGARCH_ISA_IO_SIZE); memory_region_add_subregion(address_space_mem, LOONGARCH_ISA_IO_BASE, &lams->isa_io); + if (kernel_filename) { + loaderparams.ram_size = ram_size; + loaderparams.kernel_filename = kernel_filename; + kernel_addr = load_kernel_info(); + if (!machine->firmware) { + for (i = 0; i < machine->smp.cpus; i++) { + lacpu = LOONGARCH_CPU(qemu_get_cpu(i)); + lacpu->env.load_elf = true; + lacpu->env.elf_address = kernel_addr; + qemu_register_reset(reset_load_elf, lacpu); + } + } + } /* Initialize the IO interrupt subsystem */ loongarch_irq_init(lams); } diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 03cc96ee9b..71a5036c3c 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -308,6 +308,8 @@ typedef struct CPUArchState { AddressSpace address_space_iocsr; MemoryRegion system_iocsr; MemoryRegion iocsr_mem; + bool load_elf; + uint64_t elf_address; } CPULoongArchState; /** From 9e6602d65704dc8d2a3fbcd76bfad1bb22fc3d72 Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:30 +0800 Subject: [PATCH 847/935] hw/loongarch: Add LoongArch virt power manager support. This is a placeholder for missing ACPI, and will eventually be replaced. Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Acked-by: Richard Henderson Message-Id: <20220606124333.2060567-41-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- hw/loongarch/loongson3.c | 49 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c index 3c8fcb828c..bd20ebbb78 100644 --- a/hw/loongarch/loongson3.c +++ b/hw/loongarch/loongson3.c @@ -31,6 +31,48 @@ #include "target/loongarch/cpu.h" +#define PM_BASE 0x10080000 +#define PM_SIZE 0x100 +#define PM_CTRL 0x10 + +/* + * This is a placeholder for missing ACPI, + * and will eventually be replaced. + */ +static uint64_t loongarch_virt_pm_read(void *opaque, hwaddr addr, unsigned size) +{ + return 0; +} + +static void loongarch_virt_pm_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + if (addr != PM_CTRL) { + return; + } + + switch (val) { + case 0x00: + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + return; + case 0xff: + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); + return; + default: + return; + } +} + +static const MemoryRegionOps loongarch_virt_pm_ops = { + .read = loongarch_virt_pm_read, + .write = loongarch_virt_pm_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1 + } +}; + static struct _loaderparams { uint64_t ram_size; const char *kernel_filename; @@ -67,7 +109,7 @@ static void loongarch_devices_init(DeviceState *pch_pic) SysBusDevice *d; PCIBus *pci_bus; MemoryRegion *ecam_alias, *ecam_reg, *pio_alias, *pio_reg; - MemoryRegion *mmio_alias, *mmio_reg; + MemoryRegion *mmio_alias, *mmio_reg, *pm_mem; int i; gpex_dev = qdev_new(TYPE_GPEX_HOST); @@ -132,6 +174,11 @@ static void loongarch_devices_init(DeviceState *pch_pic) sysbus_create_simple("ls7a_rtc", LS7A_RTC_REG_BASE, qdev_get_gpio_in(pch_pic, LS7A_RTC_IRQ - PCH_PIC_IRQ_OFFSET)); + + pm_mem = g_new(MemoryRegion, 1); + memory_region_init_io(pm_mem, NULL, &loongarch_virt_pm_ops, + NULL, "loongarch_virt_pm", PM_SIZE); + memory_region_add_subregion(get_system_memory(), PM_BASE, pm_mem); } static void loongarch_irq_init(LoongArchMachineState *lams) From ca61e75071c647cf93b3161a228c6a54178cd58c Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:31 +0800 Subject: [PATCH 848/935] target/loongarch: Add gdb support. Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-42-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- MAINTAINERS | 1 + configs/targets/loongarch64-softmmu.mak | 1 + gdb-xml/loongarch-base64.xml | 44 ++++++++++++++ gdb-xml/loongarch-fpu64.xml | 57 +++++++++++++++++ target/loongarch/cpu.c | 9 +++ target/loongarch/gdbstub.c | 81 +++++++++++++++++++++++++ target/loongarch/internals.h | 4 ++ target/loongarch/meson.build | 1 + 8 files changed, 198 insertions(+) create mode 100644 gdb-xml/loongarch-base64.xml create mode 100644 gdb-xml/loongarch-fpu64.xml create mode 100644 target/loongarch/gdbstub.c diff --git a/MAINTAINERS b/MAINTAINERS index e8938db694..954fb95218 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1137,6 +1137,7 @@ F: include/hw/intc/loongarch_*.h F: hw/intc/loongarch_*.c F: include/hw/pci-host/ls7a.h F: hw/rtc/ls7a_rtc.c +F: gdb-xml/loongarch*.xml M68K Machines ------------- diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak index 666154022f..7bc06c850c 100644 --- a/configs/targets/loongarch64-softmmu.mak +++ b/configs/targets/loongarch64-softmmu.mak @@ -1,3 +1,4 @@ TARGET_ARCH=loongarch64 TARGET_BASE_ARCH=loongarch TARGET_SUPPORTS_MTTCG=y +TARGET_XML_FILES= gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu64.xml diff --git a/gdb-xml/loongarch-base64.xml b/gdb-xml/loongarch-base64.xml new file mode 100644 index 0000000000..4962bdbd28 --- /dev/null +++ b/gdb-xml/loongarch-base64.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb-xml/loongarch-fpu64.xml b/gdb-xml/loongarch-fpu64.xml new file mode 100644 index 0000000000..e52cf89fbc --- /dev/null +++ b/gdb-xml/loongarch-fpu64.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 3b7d6289d2..4c8f96bc3a 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -487,6 +487,8 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) return; } + loongarch_cpu_register_gdb_regs_for_features(cs); + cpu_reset(cs); qemu_init_vcpu(cs); @@ -640,6 +642,13 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data) dc->vmsd = &vmstate_loongarch_cpu; cc->sysemu_ops = &loongarch_sysemu_ops; cc->disas_set_info = loongarch_cpu_disas_set_info; + cc->gdb_read_register = loongarch_cpu_gdb_read_register; + cc->gdb_write_register = loongarch_cpu_gdb_write_register; + cc->disas_set_info = loongarch_cpu_disas_set_info; + cc->gdb_num_core_regs = 34; + cc->gdb_core_xml_file = "loongarch-base64.xml"; + cc->gdb_stop_before_watchpoint = true; + #ifdef CONFIG_TCG cc->tcg_ops = &loongarch_tcg_ops; #endif diff --git a/target/loongarch/gdbstub.c b/target/loongarch/gdbstub.c new file mode 100644 index 0000000000..0c48834201 --- /dev/null +++ b/target/loongarch/gdbstub.c @@ -0,0 +1,81 @@ +/* + * LOONGARCH gdb server stub + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "internals.h" +#include "exec/gdbstub.h" + +int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + if (0 <= n && n < 32) { + return gdb_get_regl(mem_buf, env->gpr[n]); + } else if (n == 32) { + return gdb_get_regl(mem_buf, env->pc); + } else if (n == 33) { + return gdb_get_regl(mem_buf, env->badaddr); + } + return 0; +} + +int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + target_ulong tmp = ldtul_p(mem_buf); + int length = 0; + + if (0 <= n && n < 32) { + env->gpr[n] = tmp; + length = sizeof(target_ulong); + } else if (n == 32) { + env->pc = tmp; + length = sizeof(target_ulong); + } + return length; +} + +static int loongarch_gdb_get_fpu(CPULoongArchState *env, + GByteArray *mem_buf, int n) +{ + if (0 <= n && n < 32) { + return gdb_get_reg64(mem_buf, env->fpr[n]); + } else if (32 <= n && n < 40) { + return gdb_get_reg8(mem_buf, env->cf[n - 32]); + } else if (n == 40) { + return gdb_get_reg32(mem_buf, env->fcsr0); + } + return 0; +} + +static int loongarch_gdb_set_fpu(CPULoongArchState *env, + uint8_t *mem_buf, int n) +{ + int length = 0; + + if (0 <= n && n < 32) { + env->fpr[n] = ldq_p(mem_buf); + length = 8; + } else if (32 <= n && n < 40) { + env->cf[n - 32] = ldub_p(mem_buf); + length = 1; + } else if (n == 40) { + env->fcsr0 = ldl_p(mem_buf); + length = 4; + } + return length; +} + +void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs) +{ + gdb_register_coprocessor(cs, loongarch_gdb_get_fpu, loongarch_gdb_set_fpu, + 41, "loongarch-fpu64.xml", 0); +} diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h index a410c41c37..9d50fbdd81 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -49,4 +49,8 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n); +int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n); +void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs); + #endif diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build index 74e5f3b2a7..6376f9e84b 100644 --- a/target/loongarch/meson.build +++ b/target/loongarch/meson.build @@ -11,6 +11,7 @@ loongarch_tcg_ss.add(files( 'fpu_helper.c', 'op_helper.c', 'translate.c', + 'gdbstub.c', )) loongarch_tcg_ss.add(zlib) From c4293333982e9303699dab25140b2d63dfc9a179 Mon Sep 17 00:00:00 2001 From: Xiaojuan Yang Date: Mon, 6 Jun 2022 20:43:32 +0800 Subject: [PATCH 849/935] tests/tcg/loongarch64: Add hello/memory test in loongarch64 system - We write a very minimal softmmu harness. - This is a very simple smoke test with no need to run a full Linux/kernel. - The Makefile.softmmu-target record the rule to run. Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20220606124333.2060567-43-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- MAINTAINERS | 1 + tests/tcg/loongarch64/Makefile.softmmu-target | 33 +++++++ tests/tcg/loongarch64/system/boot.S | 56 ++++++++++++ tests/tcg/loongarch64/system/kernel.ld | 30 +++++++ tests/tcg/loongarch64/system/regdef.h | 86 +++++++++++++++++++ 5 files changed, 206 insertions(+) create mode 100644 tests/tcg/loongarch64/Makefile.softmmu-target create mode 100644 tests/tcg/loongarch64/system/boot.S create mode 100644 tests/tcg/loongarch64/system/kernel.ld create mode 100644 tests/tcg/loongarch64/system/regdef.h diff --git a/MAINTAINERS b/MAINTAINERS index 954fb95218..5580a36b68 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -217,6 +217,7 @@ M: Song Gao M: Xiaojuan Yang S: Maintained F: target/loongarch/ +F: tests/tcg/loongarch64/ M68K TCG CPUs M: Laurent Vivier diff --git a/tests/tcg/loongarch64/Makefile.softmmu-target b/tests/tcg/loongarch64/Makefile.softmmu-target new file mode 100644 index 0000000000..908f3a8c0f --- /dev/null +++ b/tests/tcg/loongarch64/Makefile.softmmu-target @@ -0,0 +1,33 @@ +# +# Loongarch64 system tests +# + +LOONGARCH64_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/loongarch64/system +VPATH+=$(LOONGARCH64_SYSTEM_SRC) + +# These objects provide the basic boot code and helper functions for all tests +CRT_OBJS=boot.o + +LOONGARCH64_TEST_SRCS=$(wildcard $(LOONGARCH64_SYSTEM_SRC)/*.c) +LOONGARCH64_TESTS = $(patsubst $(LOONGARCH64_SYSTEM_SRC)/%.c, %, $(LOONGARCH64_TEST_SRCS)) + +CRT_PATH=$(LOONGARCH64_SYSTEM_SRC) +LINK_SCRIPT=$(LOONGARCH64_SYSTEM_SRC)/kernel.ld +LDFLAGS=-Wl,-T$(LINK_SCRIPT) +TESTS+=$(LOONGARCH64_TESTS) $(MULTIARCH_TESTS) +CFLAGS+=-nostdlib -g -O1 -march=loongarch64 -mabi=lp64d $(MINILIB_INC) +LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc + +# building head blobs +.PRECIOUS: $(CRT_OBJS) + +%.o: $(CRT_PATH)/%.S + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -c $< -o $@ + +# Build and link the tests +%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS) + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) + +memory: CFLAGS+=-DCHECK_UNALIGNED=0 +# Running +QEMU_OPTS+=-serial chardev:output -kernel diff --git a/tests/tcg/loongarch64/system/boot.S b/tests/tcg/loongarch64/system/boot.S new file mode 100644 index 0000000000..67eb1c04ce --- /dev/null +++ b/tests/tcg/loongarch64/system/boot.S @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Minimal LoongArch system boot code. + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "regdef.h" + + .global _start + .align 16 +_start: + la.local t0, stack_end + move sp, t0 + bl main + + .type _start 2 + .size _start, .-_start + + .global _exit + .align 16 +_exit: +2: /* QEMU ACPI poweroff */ + li.w t0, 0xff + li.w t1, 0x10080010 + st.w t0, t1, 0 + idle 0 + bl 2b + + .type _exit 2 + .size _exit, .-_exit + + .global __sys_outc +__sys_outc: + li.d t1, 1000000 +loop: + lu12i.w t2, 0x1fe00 + ori t0, t2, 0x1e5 + ld.bu t0, t0, 0 + andi t0, t0, 0x20 + ext.w.b t0, t0 + bnez t0, in + addi.w t1, t1, -1 + bnez t1, loop +in: + ext.w.b a0, a0 + lu12i.w t0, 0x1fe00 + ori t0, t0, 0x1e0 + st.b a0, t0, 0 + jirl $r0, ra, 0 + + .data + .align 4 +stack: + .space 65536 +stack_end: diff --git a/tests/tcg/loongarch64/system/kernel.ld b/tests/tcg/loongarch64/system/kernel.ld new file mode 100644 index 0000000000..f1a7c0168c --- /dev/null +++ b/tests/tcg/loongarch64/system/kernel.ld @@ -0,0 +1,30 @@ +ENTRY(_start) + +SECTIONS +{ + /* Linux kernel legacy start address. */ + . = 0x9000000000200000; + _text = .; + .text : { + *(.text) + } + .rodata : { + *(.rodata) + } + _etext = .; + + . = ALIGN(8192); + _data = .; + .got : { + *(.got) + } + .data : { + *(.sdata) + *(.data) + } + _edata = .; + .bss : { + *(.bss) + } + _end = .; +} diff --git a/tests/tcg/loongarch64/system/regdef.h b/tests/tcg/loongarch64/system/regdef.h new file mode 100644 index 0000000000..faa09b2377 --- /dev/null +++ b/tests/tcg/loongarch64/system/regdef.h @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ +#ifndef _ASM_REGDEF_H +#define _ASM_REGDEF_H + +#define zero $r0 /* wired zero */ +#define ra $r1 /* return address */ +#define tp $r2 +#define sp $r3 /* stack pointer */ +#define v0 $r4 /* return value - caller saved */ +#define v1 $r5 +#define a0 $r4 /* argument registers */ +#define a1 $r5 +#define a2 $r6 +#define a3 $r7 +#define a4 $r8 +#define a5 $r9 +#define a6 $r10 +#define a7 $r11 +#define t0 $r12 /* caller saved */ +#define t1 $r13 +#define t2 $r14 +#define t3 $r15 +#define t4 $r16 +#define t5 $r17 +#define t6 $r18 +#define t7 $r19 +#define t8 $r20 + /* $r21: Temporarily reserved */ +#define fp $r22 /* frame pointer */ +#define s0 $r23 /* callee saved */ +#define s1 $r24 +#define s2 $r25 +#define s3 $r26 +#define s4 $r27 +#define s5 $r28 +#define s6 $r29 +#define s7 $r30 +#define s8 $r31 + +#define gr0 $r0 +#define gr1 $r1 +#define gr2 $r2 +#define gr3 $r3 +#define gr4 $r4 +#define gr5 $r5 +#define gr6 $r6 +#define gr7 $r7 +#define gr8 $r8 +#define gr9 $r9 +#define gr10 $r10 +#define gr11 $r11 +#define gr12 $r12 +#define gr13 $r13 +#define gr14 $r14 +#define gr15 $r15 +#define gr16 $r16 +#define gr17 $r17 +#define gr18 $r18 +#define gr19 $r19 +#define gr20 $r20 +#define gr21 $r21 +#define gr22 $r22 +#define gr23 $r23 +#define gr24 $r24 +#define gr25 $r25 +#define gr26 $r26 +#define gr27 $r27 +#define gr28 $r28 +#define gr29 $r29 +#define gr30 $r30 +#define gr31 $r31 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_COMMON 5 +#define STT_TLS 6 + +#define ASM_NL ; + +#endif /* _ASM_REGDEF_H */ From 34bb43b074906a7cd642ccf03e2b7bea63b53d95 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 6 Jun 2022 20:43:33 +0800 Subject: [PATCH 850/935] target/loongarch: 'make check-tcg' support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Song Gao Signed-off-by: Xiaojuan Yang Reviewed-by: Richard Henderson Acked-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20220606124333.2060567-44-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson --- configure | 1 + 1 file changed, 1 insertion(+) diff --git a/configure b/configure index ac18ed4f3a..e69537c756 100755 --- a/configure +++ b/configure @@ -1831,6 +1831,7 @@ fi : ${cross_prefix_arm="arm-linux-gnueabihf-"} : ${cross_prefix_armeb="$cross_prefix_arm"} : ${cross_prefix_hexagon="hexagon-unknown-linux-musl-"} +: ${cross_prefix_loongarch64="loongarch64-unknown-linux-gnu-"} : ${cross_prefix_hppa="hppa-linux-gnu-"} : ${cross_prefix_i386="i686-linux-gnu-"} : ${cross_prefix_m68k="m68k-linux-gnu-"} From e37a0ef4605e5d2041785ff3fc89ca6021faf7a0 Mon Sep 17 00:00:00 2001 From: Anthony PERARD Date: Mon, 11 Apr 2022 15:47:49 +0100 Subject: [PATCH 851/935] tpm_crb: mark command buffer as dirty on request completion At the moment, there doesn't seems to be any way to know that QEMU made modification to the command buffer. This is potentially an issue on Xen while migrating a guest, as modification to the buffer after the migration as started could be ignored and not transfered to the destination. Mark the memory region of the command buffer as dirty once a request is completed. Signed-off-by: Anthony PERARD Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger Message-id: 20220411144749.47185-1-anthony.perard@citrix.com --- hw/tpm/tpm_crb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index aa9c00aad3..67db594c48 100644 --- a/hw/tpm/tpm_crb.c +++ b/hw/tpm/tpm_crb.c @@ -197,6 +197,7 @@ static void tpm_crb_request_completed(TPMIf *ti, int ret) ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS, tpmSts, 1); /* fatal error */ } + memory_region_set_dirty(&s->cmdmem, 0, CRB_CTRL_CMD_SIZE); } static enum TPMVersion tpm_crb_get_version(TPMIf *ti) From ec6600be0dc16982181c7ad80d94c143c0807dd2 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 24 May 2022 05:14:05 -0400 Subject: [PATCH 852/935] vfio/common: remove spurious warning on vfio_listener_region_del 851d6d1a0f ("vfio/common: remove spurious tpm-crb-cmd misalignment warning") removed the warning on vfio_listener_region_add() path. However the same warning also hits on region_del path. Let's remove it and reword the dynamic trace as this can be called on both map and unmap path. Signed-off-by: Eric Auger Reviewed-by: Cornelia Huck Link: https://lore.kernel.org/r/20220524091405.416256-1-eric.auger@redhat.com Fixes: 851d6d1a0ff2 ("vfio/common: remove spurious tpm-crb-cmd misalignment warning") Signed-off-by: Alex Williamson --- hw/vfio/common.c | 10 +++++++++- hw/vfio/trace-events | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 29982c7af8..ace9562a9b 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1145,7 +1145,15 @@ static void vfio_listener_region_del(MemoryListener *listener, if (unlikely((section->offset_within_address_space & ~qemu_real_host_page_mask()) != (section->offset_within_region & ~qemu_real_host_page_mask()))) { - error_report("%s received unaligned region", __func__); + if (!vfio_known_safe_misalignment(section)) { + error_report("%s received unaligned region %s iova=0x%"PRIx64 + " offset_within_region=0x%"PRIx64 + " qemu_real_host_page_size=0x%"PRIxPTR, + __func__, memory_region_name(section->mr), + section->offset_within_address_space, + section->offset_within_region, + qemu_real_host_page_size()); + } return; } diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index 582882db91..73dffe9e00 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -100,7 +100,7 @@ vfio_listener_region_add_skip(uint64_t start, uint64_t end) "SKIPPING region_add vfio_spapr_group_attach(int groupfd, int tablefd) "Attached groupfd %d to liobn fd %d" vfio_listener_region_add_iommu(uint64_t start, uint64_t end) "region_add [iommu] 0x%"PRIx64" - 0x%"PRIx64 vfio_listener_region_add_ram(uint64_t iova_start, uint64_t iova_end, void *vaddr) "region_add [ram] 0x%"PRIx64" - 0x%"PRIx64" [%p]" -vfio_known_safe_misalignment(const char *name, uint64_t iova, uint64_t offset_within_region, uintptr_t page_size) "Region \"%s\" iova=0x%"PRIx64" offset_within_region=0x%"PRIx64" qemu_real_host_page_size=0x%"PRIxPTR ": cannot be mapped for DMA" +vfio_known_safe_misalignment(const char *name, uint64_t iova, uint64_t offset_within_region, uintptr_t page_size) "Region \"%s\" iova=0x%"PRIx64" offset_within_region=0x%"PRIx64" qemu_real_host_page_size=0x%"PRIxPTR vfio_listener_region_add_no_dma_map(const char *name, uint64_t iova, uint64_t size, uint64_t page_size) "Region \"%s\" 0x%"PRIx64" size=0x%"PRIx64" is not aligned to 0x%"PRIx64" and cannot be mapped for DMA" vfio_listener_region_del_skip(uint64_t start, uint64_t end) "SKIPPING region_del 0x%"PRIx64" - 0x%"PRIx64 vfio_listener_region_del(uint64_t start, uint64_t end) "region_del 0x%"PRIx64" - 0x%"PRIx64 From d507bc3b0541581fc9960f157968e80c02247255 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 8 Jun 2022 19:38:46 +0100 Subject: [PATCH 853/935] target/arm: Declare support for FEAT_RASv1p1 The architectural feature RASv1p1 introduces the following new features: * new registers ERXPFGCDN_EL1, ERXPFGCTL_EL1 and ERXPFGF_EL1 * new bits in the fine-grained trap registers that control traps for these new registers * new trap bits HCR_EL2.FIEN and SCR_EL3.FIEN that control traps for ERXPFGCDN_EL1, ERXPFGCTL_EL1, ERXPFGP_EL1 * a larger number of the ERXMISC_EL1 registers * the format of ERRSTATUS registers changes The architecture permits that if ERRIDR_EL1.NUM is 0 (as it is for QEMU) then all these new registers may UNDEF, and the HCR_EL2.FIEN and SCR_EL3.FIEN bits may be RES0. We don't have any ERRSTATUS registers (again, because ERRIDR_EL1.NUM is 0). QEMU does not yet implement the fine-grained-trap extension. So there is nothing we need to implement to be compliant with the feature spec. Make the 'max' CPU report the feature in its ID registers, and document it. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220531114258.855804-1-peter.maydell@linaro.org --- docs/system/arm/emulation.rst | 1 + target/arm/cpu64.c | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index 49cc3e8340..81467f02ce 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -52,6 +52,7 @@ the following architecture extensions: - FEAT_PMUv3p1 (PMU Extensions v3.1) - FEAT_PMUv3p4 (PMU Extensions v3.4) - FEAT_RAS (Reliability, availability, and serviceability) +- FEAT_RASv1p1 (RAS Extension v1.1) - FEAT_RDM (Advanced SIMD rounding double multiply accumulate instructions) - FEAT_RNG (Random number generator) - FEAT_S2FWB (Stage 2 forced Write-Back) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 3ff9219ca3..bd1c62a342 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -916,6 +916,7 @@ static void aarch64_max_initfn(Object *obj) * we do for EL2 with the virtualization=on property. */ t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); /* FEAT_MTE3 */ + t = FIELD_DP64(t, ID_AA64PFR1, RAS_FRAC, 1); /* FEAT_RASv1p1 */ t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_2 */ cpu->isar.id_aa64pfr1 = t; From 7ac610206a0049460c392c9559b51246af0afd6d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 8 Jun 2022 19:38:46 +0100 Subject: [PATCH 854/935] target/arm: Implement FEAT_DoubleFault The FEAT_DoubleFault extension adds the following: * All external aborts on instruction fetches and translation table walks for instruction fetches must be synchronous. For QEMU this is already true. * SCR_EL3 has a new bit NMEA which disables the masking of SError interrupts by PSTATE.A when the SError interrupt is taken to EL3. For QEMU we only need to make the bit writable, because we have no sources of SError interrupts. * SCR_EL3 has a new bit EASE which causes synchronous external aborts taken to EL3 to be taken at the same entry point as SError. (Note that this does not mean that they are SErrors for purposes of PSTATE.A masking or that the syndrome register reports them as SErrors: it just means that the vector offset is different.) * The existing SCTLR_EL3.IESB has an effective value of 1 when SCR_EL3.NMEA is 1. For QEMU this is a no-op because we don't need different behaviour based on IESB (we don't need to do anything to ensure that error exceptions are synchronized). So for QEMU the things we need to change are: * Make SCR_EL3.{NMEA,EASE} writable * When taking a synchronous external abort at EL3, adjust the vector entry point if SCR_EL3.EASE is set * Advertise the feature in the ID registers Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220531151431.949322-1-peter.maydell@linaro.org --- docs/system/arm/emulation.rst | 1 + target/arm/cpu.h | 5 +++++ target/arm/cpu64.c | 4 ++-- target/arm/helper.c | 36 +++++++++++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index 81467f02ce..83b4410065 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -23,6 +23,7 @@ the following architecture extensions: - FEAT_Debugv8p2 (Debug changes for v8.2) - FEAT_Debugv8p4 (Debug changes for v8.4) - FEAT_DotProd (Advanced SIMD dot product instructions) +- FEAT_DoubleFault (Double Fault Extension) - FEAT_FCMA (Floating-point complex number instructions) - FEAT_FHM (Floating-point half-precision multiplication instructions) - FEAT_FP16 (Half-precision floating-point data processing) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index c1865ad5da..0ee1705a4f 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3952,6 +3952,11 @@ static inline bool isar_feature_aa64_ras(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RAS) != 0; } +static inline bool isar_feature_aa64_doublefault(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RAS) >= 2; +} + static inline bool isar_feature_aa64_sve(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SVE) != 0; diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index bd1c62a342..cce68dd82a 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -899,7 +899,7 @@ static void aarch64_max_initfn(Object *obj) t = cpu->isar.id_aa64pfr0; t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); /* FEAT_FP16 */ t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); /* FEAT_FP16 */ - t = FIELD_DP64(t, ID_AA64PFR0, RAS, 1); /* FEAT_RAS */ + t = FIELD_DP64(t, ID_AA64PFR0, RAS, 2); /* FEAT_RASv1p1 + FEAT_DoubleFault */ t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); /* FEAT_SEL2 */ t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); /* FEAT_DIT */ @@ -916,7 +916,7 @@ static void aarch64_max_initfn(Object *obj) * we do for EL2 with the virtualization=on property. */ t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); /* FEAT_MTE3 */ - t = FIELD_DP64(t, ID_AA64PFR1, RAS_FRAC, 1); /* FEAT_RASv1p1 */ + t = FIELD_DP64(t, ID_AA64PFR1, RAS_FRAC, 0); /* FEAT_RASv1p1 + FEAT_DoubleFault */ t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_2 */ cpu->isar.id_aa64pfr1 = t; diff --git a/target/arm/helper.c b/target/arm/helper.c index 40da63913c..7f2c14bea9 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -1776,6 +1776,9 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) if (cpu_isar_feature(aa64_scxtnum, cpu)) { valid_mask |= SCR_ENSCXT; } + if (cpu_isar_feature(aa64_doublefault, cpu)) { + valid_mask |= SCR_EASE | SCR_NMEA; + } } else { valid_mask &= ~(SCR_RW | SCR_ST); if (cpu_isar_feature(aa32_ras, cpu)) { @@ -10113,6 +10116,31 @@ static uint32_t cpsr_read_for_spsr_elx(CPUARMState *env) return ret; } +static bool syndrome_is_sync_extabt(uint32_t syndrome) +{ + /* Return true if this syndrome value is a synchronous external abort */ + switch (syn_get_ec(syndrome)) { + case EC_INSNABORT: + case EC_INSNABORT_SAME_EL: + case EC_DATAABORT: + case EC_DATAABORT_SAME_EL: + /* Look at fault status code for all the synchronous ext abort cases */ + switch (syndrome & 0x3f) { + case 0x10: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + return true; + default: + return false; + } + default: + return false; + } +} + /* Handle exception entry to a target EL which is using AArch64 */ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) { @@ -10168,6 +10196,14 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) switch (cs->exception_index) { case EXCP_PREFETCH_ABORT: case EXCP_DATA_ABORT: + /* + * FEAT_DoubleFault allows synchronous external aborts taken to EL3 + * to be taken to the SError vector entrypoint. + */ + if (new_el == 3 && (env->cp15.scr_el3 & SCR_EASE) && + syndrome_is_sync_extabt(env->exception.syndrome)) { + addr += 0x180; + } env->cp15.far_el[new_el] = env->exception.vaddress; qemu_log_mask(CPU_LOG_INT, "...with FAR 0x%" PRIx64 "\n", env->cp15.far_el[new_el]); From 9323e79f10e5f5d8fffc3b307776173ca11faeae Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 8 Jun 2022 19:38:47 +0100 Subject: [PATCH 855/935] Fix 'writeable' typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have about 30 instances of the typo/variant spelling 'writeable', and over 500 of the more common 'writable'. Standardize on the latter. Change produced with: sed -i -e 's/\([Ww][Rr][Ii][Tt]\)[Ee]\([Aa][Bb][Ll][Ee]\)/\1\2/g' $(git grep -il writeable) and then hand-undoing the instance in linux-headers/linux/kvm.h. Most of these changes are in comments or documentation; the exceptions are: * a local variable in accel/hvf/hvf-accel-ops.c * a local variable in accel/kvm/kvm-all.c * the PMCR_WRITABLE_MASK macro in target/arm/internals.h * the EPT_VIOLATION_GPA_WRITABLE macro in target/i386/hvf/vmcs.h (which is never used anywhere) * the AR_TYPE_WRITABLE_MASK macro in target/i386/hvf/vmx.h (which is never used anywhere) Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Weil Message-id: 20220505095015.2714666-1-peter.maydell@linaro.org --- accel/hvf/hvf-accel-ops.c | 4 ++-- accel/kvm/kvm-all.c | 4 ++-- accel/tcg/user-exec.c | 6 +++--- docs/interop/vhost-user.rst | 2 +- docs/specs/vmgenid.txt | 4 ++-- hw/acpi/ghes.c | 2 +- hw/intc/arm_gicv3_cpuif.c | 2 +- hw/intc/arm_gicv3_dist.c | 2 +- hw/intc/arm_gicv3_redist.c | 4 ++-- hw/intc/riscv_aclint.c | 2 +- hw/intc/riscv_aplic.c | 2 +- hw/pci/shpc.c | 2 +- hw/scsi/mfi.h | 2 +- hw/sparc64/sun4u_iommu.c | 2 +- hw/timer/sse-timer.c | 2 +- python/qemu/machine/machine.py | 2 +- target/arm/gdbstub.c | 2 +- target/arm/helper.c | 4 ++-- target/arm/hvf/hvf.c | 4 ++-- target/arm/internals.h | 4 ++-- target/i386/cpu-sysemu.c | 2 +- target/i386/hvf/vmcs.h | 2 +- target/i386/hvf/vmx.h | 2 +- target/s390x/ioinst.c | 2 +- tests/tcg/x86_64/system/boot.S | 2 +- 25 files changed, 34 insertions(+), 34 deletions(-) diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c index a70e2eb375..24913ca9c4 100644 --- a/accel/hvf/hvf-accel-ops.c +++ b/accel/hvf/hvf-accel-ops.c @@ -120,12 +120,12 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add) { hvf_slot *mem; MemoryRegion *area = section->mr; - bool writeable = !area->readonly && !area->rom_device; + bool writable = !area->readonly && !area->rom_device; hv_memory_flags_t flags; uint64_t page_size = qemu_real_host_page_size(); if (!memory_region_is_ram(area)) { - if (writeable) { + if (writable) { return; } else if (!memory_region_is_romd(area)) { /* diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 32e177bd26..a4c4863f53 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -1346,13 +1346,13 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, KVMSlot *mem; int err; MemoryRegion *mr = section->mr; - bool writeable = !mr->readonly && !mr->rom_device; + bool writable = !mr->readonly && !mr->rom_device; hwaddr start_addr, size, slot_size, mr_offset; ram_addr_t ram_start_offset; void *ram; if (!memory_region_is_ram(mr)) { - if (writeable || !kvm_readonly_mem_allowed) { + if (writable || !kvm_readonly_mem_allowed) { return; } else if (!mr->romd_mode) { /* If the memory device is not in romd_mode, then we actually want diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index ac57324d4f..20ada5472b 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -101,10 +101,10 @@ MMUAccessType adjust_signal_pc(uintptr_t *pc, bool is_write) * Return true if the write fault has been handled, and should be re-tried. * * Note that it is important that we don't call page_unprotect() unless - * this is really a "write to nonwriteable page" fault, because + * this is really a "write to nonwritable page" fault, because * page_unprotect() assumes that if it is called for an access to - * a page that's writeable this means we had two threads racing and - * another thread got there first and already made the page writeable; + * a page that's writable this means we had two threads racing and + * another thread got there first and already made the page writable; * so we will retry the access. If we were to call page_unprotect() * for some other kind of fault that should really be passed to the * guest, we'd end up in an infinite loop of retrying the faulting access. diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst index a99ba4433c..d7cf904f7f 100644 --- a/docs/interop/vhost-user.rst +++ b/docs/interop/vhost-user.rst @@ -222,7 +222,7 @@ Virtio device config space :size: a 32-bit configuration space access size in bytes :flags: a 32-bit value: - - 0: Vhost front-end messages used for writeable fields + - 0: Vhost front-end messages used for writable fields - 1: Vhost front-end messages used for live migration :payload: Size bytes array holding the contents of the virtio diff --git a/docs/specs/vmgenid.txt b/docs/specs/vmgenid.txt index aa9f518676..80ff69f31c 100644 --- a/docs/specs/vmgenid.txt +++ b/docs/specs/vmgenid.txt @@ -153,7 +153,7 @@ change the contents of the memory at runtime, specifically when starting a backed-up or snapshotted image. In order to do this, QEMU must know the address that has been allocated. -The mechanism chosen for this memory sharing is writeable fw_cfg blobs. +The mechanism chosen for this memory sharing is writable fw_cfg blobs. These are data object that are visible to both QEMU and guests, and are addressable as sequential files. @@ -164,7 +164,7 @@ Two fw_cfg blobs are used in this case: /etc/vmgenid_guid - contains the actual VM Generation ID GUID - read-only to the guest /etc/vmgenid_addr - contains the address of the downloaded vmgenid blob - - writeable by the guest + - writable by the guest QEMU sends the following commands to the guest at startup: diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c index 45d9a809cc..e9511d9b8f 100644 --- a/hw/acpi/ghes.c +++ b/hw/acpi/ghes.c @@ -249,7 +249,7 @@ void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker) for (i = 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) { /* * Initialize the value of read_ack_register to 1, so GHES can be - * writeable after (re)boot. + * writable after (re)boot. * ACPI 6.2: 18.3.2.8 Generic Hardware Error Source version 2 * (GHESv2 - Type 10) */ diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index 8867e2e496..8ca630e5ad 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -2047,7 +2047,7 @@ static void icc_ctlr_el3_write(CPUARMState *env, const ARMCPRegInfo *ri, cs->icc_ctlr_el1[GICV3_S] |= ICC_CTLR_EL1_CBPR; } - /* The only bit stored in icc_ctlr_el3 which is writeable is EOIMODE_EL3: */ + /* The only bit stored in icc_ctlr_el3 which is writable is EOIMODE_EL3: */ mask = ICC_CTLR_EL3_EOIMODE_EL3; cs->icc_ctlr_el3 &= ~mask; diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c index b9ed955e36..eea0368118 100644 --- a/hw/intc/arm_gicv3_dist.c +++ b/hw/intc/arm_gicv3_dist.c @@ -611,7 +611,7 @@ static bool gicd_writel(GICv3State *s, hwaddr offset, if (value & mask & GICD_CTLR_DS) { /* We just set DS, so the ARE_NS and EnG1S bits are now RES0. * Note that this is a one-way transition because if DS is set - * then it's not writeable, so it can only go back to 0 with a + * then it's not writable, so it can only go back to 0 with a * hardware reset. */ s->gicd_ctlr &= ~(GICD_CTLR_EN_GRP1S | GICD_CTLR_ARE_NS); diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c index c3d4cdd66b..f1ecb2502b 100644 --- a/hw/intc/arm_gicv3_redist.c +++ b/hw/intc/arm_gicv3_redist.c @@ -257,7 +257,7 @@ static void gicr_write_vpendbaser(GICv3CPUState *cs, uint64_t newval) /* * The DIRTY bit is read-only and for us is always zero; - * other fields are writeable. + * other fields are writable. */ newval &= R_GICR_VPENDBASER_INNERCACHE_MASK | R_GICR_VPENDBASER_SHAREABILITY_MASK | @@ -491,7 +491,7 @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset, /* RAZ/WI for our implementation */ return MEMTX_OK; case GICR_WAKER: - /* Only the ProcessorSleep bit is writeable. When the guest sets + /* Only the ProcessorSleep bit is writable. When the guest sets * it it requests that we transition the channel between the * redistributor and the cpu interface to quiescent, and that * we set the ChildrenAsleep bit once the inteface has reached the diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c index e6bceceefd..e7942c4e5a 100644 --- a/hw/intc/riscv_aclint.c +++ b/hw/intc/riscv_aclint.c @@ -463,7 +463,7 @@ static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp) /* Claim software interrupt bits */ for (i = 0; i < swi->num_harts; i++) { RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(swi->hartid_base + i)); - /* We don't claim mip.SSIP because it is writeable by software */ + /* We don't claim mip.SSIP because it is writable by software */ if (riscv_cpu_claim_interrupts(cpu, swi->sswi ? 0 : MIP_MSIP) < 0) { error_report("MSIP already claimed"); exit(1); diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c index e7809fb6b2..cfd007e629 100644 --- a/hw/intc/riscv_aplic.c +++ b/hw/intc/riscv_aplic.c @@ -646,7 +646,7 @@ static void riscv_aplic_write(void *opaque, hwaddr addr, uint64_t value, } if (addr == APLIC_DOMAINCFG) { - /* Only IE bit writeable at the moment */ + /* Only IE bit writable at the moment */ value &= APLIC_DOMAINCFG_IE; aplic->domaincfg = value; } else if ((APLIC_SOURCECFG_BASE <= addr) && diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c index 28e62174c4..f822f18b98 100644 --- a/hw/pci/shpc.c +++ b/hw/pci/shpc.c @@ -456,7 +456,7 @@ static int shpc_cap_add_config(PCIDevice *d, Error **errp) pci_set_byte(config + SHPC_CAP_CxP, 0); pci_set_long(config + SHPC_CAP_DWORD_DATA, 0); d->shpc->cap = config_offset; - /* Make dword select and data writeable. */ + /* Make dword select and data writable. */ pci_set_byte(d->wmask + config_offset + SHPC_CAP_DWORD_SELECT, 0xff); pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xffffffff); return 0; diff --git a/hw/scsi/mfi.h b/hw/scsi/mfi.h index e67a5c0b47..0b4ee53dfc 100644 --- a/hw/scsi/mfi.h +++ b/hw/scsi/mfi.h @@ -633,7 +633,7 @@ struct mfi_ctrl_props { * metadata and user data * 1=5%, 2=10%, 3=15% and so on */ - uint8_t viewSpace; /* snapshot writeable VIEWs + uint8_t viewSpace; /* snapshot writable VIEWs * capacity as a % of source LD * capacity. 0=READ only * 1=5%, 2=10%, 3=15% and so on diff --git a/hw/sparc64/sun4u_iommu.c b/hw/sparc64/sun4u_iommu.c index 9178277f82..1c1dca712e 100644 --- a/hw/sparc64/sun4u_iommu.c +++ b/hw/sparc64/sun4u_iommu.c @@ -165,7 +165,7 @@ static IOMMUTLBEntry sun4u_translate_iommu(IOMMUMemoryRegion *iommu, } if (tte & IOMMU_TTE_DATA_W) { - /* Writeable */ + /* Writable */ ret.perm = IOMMU_RW; } else { ret.perm = IOMMU_RO; diff --git a/hw/timer/sse-timer.c b/hw/timer/sse-timer.c index f959cb9d60..e92e83747d 100644 --- a/hw/timer/sse-timer.c +++ b/hw/timer/sse-timer.c @@ -324,7 +324,7 @@ static void sse_timer_write(void *opaque, hwaddr offset, uint64_t value, { uint32_t old_ctl = s->cntp_aival_ctl; - /* EN bit is writeable; CLR bit is write-0-to-clear, write-1-ignored */ + /* EN bit is writable; CLR bit is write-0-to-clear, write-1-ignored */ s->cntp_aival_ctl &= ~R_CNTP_AIVAL_CTL_EN_MASK; s->cntp_aival_ctl |= value & R_CNTP_AIVAL_CTL_EN_MASK; if (!(value & R_CNTP_AIVAL_CTL_CLR_MASK)) { diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py index 07ac5a710b..37191f433b 100644 --- a/python/qemu/machine/machine.py +++ b/python/qemu/machine/machine.py @@ -495,7 +495,7 @@ class QEMUMachine: """ # If we keep the console socket open, we may deadlock waiting # for QEMU to exit, while QEMU is waiting for the socket to - # become writeable. + # become writable. if self._console_socket is not None: self._console_socket.close() self._console_socket = None diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c index f5b35cd55f..2f806512d0 100644 --- a/target/arm/gdbstub.c +++ b/target/arm/gdbstub.c @@ -118,7 +118,7 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) /* * Don't allow writing to XPSR.Exception as it can cause * a transition into or out of handler mode (it's not - * writeable via the MSR insn so this is a reasonable + * writable via the MSR insn so this is a reasonable * restriction). Other fields are safe to update. */ xpsr_write(env, tmp, ~XPSR_EXCP); diff --git a/target/arm/helper.c b/target/arm/helper.c index 7f2c14bea9..5727ead5e4 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -1411,8 +1411,8 @@ static void pmcr_write(CPUARMState *env, const ARMCPRegInfo *ri, } } - env->cp15.c9_pmcr &= ~PMCR_WRITEABLE_MASK; - env->cp15.c9_pmcr |= (value & PMCR_WRITEABLE_MASK); + env->cp15.c9_pmcr &= ~PMCR_WRITABLE_MASK; + env->cp15.c9_pmcr |= (value & PMCR_WRITABLE_MASK); pmu_op_finish(env); } diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 1fdc5eef92..060aa0ccf4 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -978,8 +978,8 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val) } } - env->cp15.c9_pmcr &= ~PMCR_WRITEABLE_MASK; - env->cp15.c9_pmcr |= (val & PMCR_WRITEABLE_MASK); + env->cp15.c9_pmcr &= ~PMCR_WRITABLE_MASK; + env->cp15.c9_pmcr |= (val & PMCR_WRITABLE_MASK); pmu_op_finish(env); break; diff --git a/target/arm/internals.h b/target/arm/internals.h index b654bee468..1e4887b2dd 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1280,10 +1280,10 @@ enum MVEECIState { #define PMCRP 0x2 #define PMCRE 0x1 /* - * Mask of PMCR bits writeable by guest (not including WO bits like C, P, + * Mask of PMCR bits writable by guest (not including WO bits like C, P, * which can be written as 1 to trigger behaviour but which stay RAZ). */ -#define PMCR_WRITEABLE_MASK (PMCRLC | PMCRDP | PMCRX | PMCRD | PMCRE) +#define PMCR_WRITABLE_MASK (PMCRLC | PMCRDP | PMCRX | PMCRD | PMCRE) #define PMXEVTYPER_P 0x80000000 #define PMXEVTYPER_U 0x40000000 diff --git a/target/i386/cpu-sysemu.c b/target/i386/cpu-sysemu.c index e254d8ba10..a6f47b7d11 100644 --- a/target/i386/cpu-sysemu.c +++ b/target/i386/cpu-sysemu.c @@ -103,7 +103,7 @@ static void x86_cpu_to_dict(X86CPU *cpu, QDict *props) /* Convert CPU model data from X86CPU object to a property dictionary * that can recreate exactly the same CPU model, including every - * writeable QOM property. + * writable QOM property. */ static void x86_cpu_to_dict_full(X86CPU *cpu, QDict *props) { diff --git a/target/i386/hvf/vmcs.h b/target/i386/hvf/vmcs.h index 42de7ebc3a..b4692f63f6 100644 --- a/target/i386/hvf/vmcs.h +++ b/target/i386/hvf/vmcs.h @@ -330,7 +330,7 @@ #define EPT_VIOLATION_DATA_WRITE (1UL << 1) #define EPT_VIOLATION_INST_FETCH (1UL << 2) #define EPT_VIOLATION_GPA_READABLE (1UL << 3) -#define EPT_VIOLATION_GPA_WRITEABLE (1UL << 4) +#define EPT_VIOLATION_GPA_WRITABLE (1UL << 4) #define EPT_VIOLATION_GPA_EXECUTABLE (1UL << 5) #define EPT_VIOLATION_GLA_VALID (1UL << 7) #define EPT_VIOLATION_XLAT_VALID (1UL << 8) diff --git a/target/i386/hvf/vmx.h b/target/i386/hvf/vmx.h index 573ddc33c0..fcd9a95e5b 100644 --- a/target/i386/hvf/vmx.h +++ b/target/i386/hvf/vmx.h @@ -80,7 +80,7 @@ static inline uint64_t cap2ctrl(uint64_t cap, uint64_t ctrl) #define AR_TYPE_ACCESSES_MASK 1 #define AR_TYPE_READABLE_MASK (1 << 1) -#define AR_TYPE_WRITEABLE_MASK (1 << 2) +#define AR_TYPE_WRITABLE_MASK (1 << 2) #define AR_TYPE_CODE_MASK (1 << 3) #define AR_TYPE_MASK 0x0f #define AR_TYPE_BUSY_64_TSS 11 diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c index bdae5090bc..b12f18d346 100644 --- a/target/s390x/ioinst.c +++ b/target/s390x/ioinst.c @@ -284,7 +284,7 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, g_assert(!s390_is_pv()); /* * As operand exceptions have a lower priority than access exceptions, - * we check whether the memory area is writeable (injecting the + * we check whether the memory area is writable (injecting the * access execption if it is not) first. */ if (!s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib))) { diff --git a/tests/tcg/x86_64/system/boot.S b/tests/tcg/x86_64/system/boot.S index f8a2fcc839..ed0f638406 100644 --- a/tests/tcg/x86_64/system/boot.S +++ b/tests/tcg/x86_64/system/boot.S @@ -56,7 +56,7 @@ * * - `ebx`: contains the physical memory address where the loader has placed * the boot start info structure. - * - `cr0`: bit 0 (PE) must be set. All the other writeable bits are cleared. + * - `cr0`: bit 0 (PE) must be set. All the other writable bits are cleared. * - `cr4`: all bits are cleared. * - `cs `: must be a 32-bit read/execute code segment with a base of ‘0’ * and a limit of ‘0xFFFFFFFF’. The selector value is unspecified. From d2008b3355061ab0cca823739cd98045e769a809 Mon Sep 17 00:00:00 2001 From: Frederic Konrad Date: Wed, 8 Jun 2022 19:38:47 +0100 Subject: [PATCH 856/935] xlnx_dp: fix the wrong register size The core and the vblend registers size are wrong, they should respectively be 0x3B0 and 0x1E0 according to: https://www.xilinx.com/htmldocs/registers/ug1087/ug1087-zynq-ultrascale-registers.html. Let's fix that and use macros when creating the mmio region. Fixes: 58ac482a66d ("introduce xlnx-dp") Signed-off-by: Frederic Konrad Reviewed-by: Edgar E. Iglesias Acked-by: Alistair Francis Message-id: 20220601172353.3220232-2-fkonrad@xilinx.com Signed-off-by: Peter Maydell --- hw/display/xlnx_dp.c | 17 ++++++++++------- include/hw/display/xlnx_dp.h | 9 +++++++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index 9bb781e312..0378570459 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -1219,19 +1219,22 @@ static void xlnx_dp_init(Object *obj) SysBusDevice *sbd = SYS_BUS_DEVICE(obj); XlnxDPState *s = XLNX_DP(obj); - memory_region_init(&s->container, obj, TYPE_XLNX_DP, 0xC050); + memory_region_init(&s->container, obj, TYPE_XLNX_DP, DP_CONTAINER_SIZE); memory_region_init_io(&s->core_iomem, obj, &dp_ops, s, TYPE_XLNX_DP - ".core", 0x3AF); - memory_region_add_subregion(&s->container, 0x0000, &s->core_iomem); + ".core", sizeof(s->core_registers)); + memory_region_add_subregion(&s->container, DP_CORE_REG_OFFSET, + &s->core_iomem); memory_region_init_io(&s->vblend_iomem, obj, &vblend_ops, s, TYPE_XLNX_DP - ".v_blend", 0x1DF); - memory_region_add_subregion(&s->container, 0xA000, &s->vblend_iomem); + ".v_blend", sizeof(s->vblend_registers)); + memory_region_add_subregion(&s->container, DP_VBLEND_REG_OFFSET, + &s->vblend_iomem); memory_region_init_io(&s->avbufm_iomem, obj, &avbufm_ops, s, TYPE_XLNX_DP - ".av_buffer_manager", 0x238); - memory_region_add_subregion(&s->container, 0xB000, &s->avbufm_iomem); + ".av_buffer_manager", sizeof(s->avbufm_registers)); + memory_region_add_subregion(&s->container, DP_AVBUF_REG_OFFSET, + &s->avbufm_iomem); memory_region_init_io(&s->audio_iomem, obj, &audio_ops, s, TYPE_XLNX_DP ".audio", sizeof(s->audio_registers)); diff --git a/include/hw/display/xlnx_dp.h b/include/hw/display/xlnx_dp.h index 8ab4733bb8..1ef5a89ee7 100644 --- a/include/hw/display/xlnx_dp.h +++ b/include/hw/display/xlnx_dp.h @@ -39,10 +39,15 @@ #define AUD_CHBUF_MAX_DEPTH (32 * KiB) #define MAX_QEMU_BUFFER_SIZE (4 * KiB) -#define DP_CORE_REG_ARRAY_SIZE (0x3AF >> 2) +#define DP_CORE_REG_OFFSET (0x0000) +#define DP_CORE_REG_ARRAY_SIZE (0x3B0 >> 2) +#define DP_AVBUF_REG_OFFSET (0xB000) #define DP_AVBUF_REG_ARRAY_SIZE (0x238 >> 2) -#define DP_VBLEND_REG_ARRAY_SIZE (0x1DF >> 2) +#define DP_VBLEND_REG_OFFSET (0xA000) +#define DP_VBLEND_REG_ARRAY_SIZE (0x1E0 >> 2) +#define DP_AUDIO_REG_OFFSET (0xC000) #define DP_AUDIO_REG_ARRAY_SIZE (0x50 >> 2) +#define DP_CONTAINER_SIZE (0xC050) struct PixmanPlane { pixman_format_code_t format; From 759ae1b47e7e0203eb6881304b4bbf0d935fd550 Mon Sep 17 00:00:00 2001 From: Sai Pavan Boddu Date: Wed, 8 Jun 2022 19:38:47 +0100 Subject: [PATCH 857/935] xlnx_dp: Introduce a vblank signal Add a periodic timer which raises vblank at a frequency of 30Hz. Note that this is a migration compatibility break for the xlnx-zcu102 board type. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias Signed-off-by: Frederic Konrad Acked-by: Alistair Francis Message-id: 20220601172353.3220232-3-fkonrad@xilinx.com Changes by fkonrad: - Switched to transaction-based ptimer API. - Added the DP_INT_VBLNK_START macro. Signed-off-by: Frederic Konrad [PMM: bump vmstate version, add commit message note about compat break] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/display/xlnx_dp.c | 30 ++++++++++++++++++++++++++---- include/hw/display/xlnx_dp.h | 3 +++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index 0378570459..ed856b596d 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -114,6 +114,7 @@ #define DP_TX_N_AUD (0x032C >> 2) #define DP_TX_AUDIO_EXT_DATA(n) ((0x0330 + 4 * n) >> 2) #define DP_INT_STATUS (0x03A0 >> 2) +#define DP_INT_VBLNK_START (1 << 13) #define DP_INT_MASK (0x03A4 >> 2) #define DP_INT_EN (0x03A8 >> 2) #define DP_INT_DS (0x03AC >> 2) @@ -260,7 +261,7 @@ typedef enum DPVideoFmt DPVideoFmt; static const VMStateDescription vmstate_dp = { .name = TYPE_XLNX_DP, - .version_id = 1, + .version_id = 2, .fields = (VMStateField[]){ VMSTATE_UINT32_ARRAY(core_registers, XlnxDPState, DP_CORE_REG_ARRAY_SIZE), @@ -270,10 +271,15 @@ static const VMStateDescription vmstate_dp = { DP_VBLEND_REG_ARRAY_SIZE), VMSTATE_UINT32_ARRAY(audio_registers, XlnxDPState, DP_AUDIO_REG_ARRAY_SIZE), + VMSTATE_PTIMER(vblank, XlnxDPState), VMSTATE_END_OF_LIST() } }; +#define DP_VBLANK_PTIMER_POLICY (PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD | \ + PTIMER_POLICY_CONTINUOUS_TRIGGER | \ + PTIMER_POLICY_NO_IMMEDIATE_TRIGGER) + static void xlnx_dp_update_irq(XlnxDPState *s); static uint64_t xlnx_dp_audio_read(void *opaque, hwaddr offset, unsigned size) @@ -773,6 +779,13 @@ static void xlnx_dp_write(void *opaque, hwaddr offset, uint64_t value, break; case DP_TRANSMITTER_ENABLE: s->core_registers[offset] = value & 0x01; + ptimer_transaction_begin(s->vblank); + if (value & 0x1) { + ptimer_run(s->vblank, 0); + } else { + ptimer_stop(s->vblank); + } + ptimer_transaction_commit(s->vblank); break; case DP_FORCE_SCRAMBLER_RESET: /* @@ -1177,9 +1190,6 @@ static void xlnx_dp_update_display(void *opaque) return; } - s->core_registers[DP_INT_STATUS] |= (1 << 13); - xlnx_dp_update_irq(s); - xlnx_dpdma_trigger_vsync_irq(s->dpdma); /* @@ -1275,6 +1285,14 @@ static void xlnx_dp_finalize(Object *obj) fifo8_destroy(&s->rx_fifo); } +static void vblank_hit(void *opaque) +{ + XlnxDPState *s = XLNX_DP(opaque); + + s->core_registers[DP_INT_STATUS] |= DP_INT_VBLNK_START; + xlnx_dp_update_irq(s); +} + static void xlnx_dp_realize(DeviceState *dev, Error **errp) { XlnxDPState *s = XLNX_DP(dev); @@ -1309,6 +1327,10 @@ static void xlnx_dp_realize(DeviceState *dev, Error **errp) &as); AUD_set_volume_out(s->amixer_output_stream, 0, 255, 255); xlnx_dp_audio_activate(s); + s->vblank = ptimer_init(vblank_hit, s, DP_VBLANK_PTIMER_POLICY); + ptimer_transaction_begin(s->vblank); + ptimer_set_freq(s->vblank, 30); + ptimer_transaction_commit(s->vblank); } static void xlnx_dp_reset(DeviceState *dev) diff --git a/include/hw/display/xlnx_dp.h b/include/hw/display/xlnx_dp.h index 1ef5a89ee7..e86a87f235 100644 --- a/include/hw/display/xlnx_dp.h +++ b/include/hw/display/xlnx_dp.h @@ -35,6 +35,7 @@ #include "hw/dma/xlnx_dpdma.h" #include "audio/audio.h" #include "qom/object.h" +#include "hw/ptimer.h" #define AUD_CHBUF_MAX_DEPTH (32 * KiB) #define MAX_QEMU_BUFFER_SIZE (4 * KiB) @@ -107,6 +108,8 @@ struct XlnxDPState { */ DPCDState *dpcd; I2CDDCState *edid; + + ptimer_state *vblank; }; #define TYPE_XLNX_DP "xlnx.v-dp" From 39f40d02f6af8e4718100b6a3854e963c962cfd7 Mon Sep 17 00:00:00 2001 From: Sai Pavan Boddu Date: Wed, 8 Jun 2022 19:38:47 +0100 Subject: [PATCH 858/935] xlnx_dp: Fix the interrupt disable logic Fix interrupt disable logic. Mask value 1 indicates that interrupts are disabled. Signed-off-by: Sai Pavan Boddu Reviewed-by: Edgar E. Iglesias Signed-off-by: Frederic Konrad Acked-by: Alistair Francis Message-id: 20220601172353.3220232-4-fkonrad@xilinx.com Signed-off-by: Peter Maydell --- hw/display/xlnx_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index ed856b596d..a071c81883 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -889,7 +889,7 @@ static void xlnx_dp_write(void *opaque, hwaddr offset, uint64_t value, xlnx_dp_update_irq(s); break; case DP_INT_DS: - s->core_registers[DP_INT_MASK] |= ~value; + s->core_registers[DP_INT_MASK] |= value; xlnx_dp_update_irq(s); break; default: From b3f5cc3fda5775b34aa52e111d50c9d10911b352 Mon Sep 17 00:00:00 2001 From: Frederic Konrad Date: Wed, 8 Jun 2022 19:38:48 +0100 Subject: [PATCH 859/935] xlnx-zynqmp: fix the irq mapping for the display port and its dma When the display port has been initially implemented the device driver wasn't using interrupts. Now that the display port driver waits for vblank interrupt it has been noticed that the irq mapping is wrong. So use the value from the linux device tree and the ultrascale+ reference manual. Signed-off-by: Frederic Konrad Reviewed-by: Edgar E. Iglesias Acked-by: Alistair Francis Message-id: 20220601172353.3220232-5-fkonrad@xilinx.com [PMM: refold lines in commit message] Signed-off-by: Peter Maydell --- hw/arm/xlnx-zynqmp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 375309e68e..383e177a00 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -60,10 +60,10 @@ #define SERDES_SIZE 0x20000 #define DP_ADDR 0xfd4a0000 -#define DP_IRQ 113 +#define DP_IRQ 0x77 #define DPDMA_ADDR 0xfd4c0000 -#define DPDMA_IRQ 116 +#define DPDMA_IRQ 0x7a #define APU_ADDR 0xfd5c0000 #define APU_IRQ 153 From d8cca960a9a5dbd216d2331cef3cc72f2c7338e0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:48 +0100 Subject: [PATCH 860/935] target/arm: Move stage_1_mmu_idx decl to internals.h Move the decl from ptw.h to internals.h. Provide an inline version for user-only, just as we do for arm_stage1_mmu_idx. Move an endif down to make the definition in helper.c be system only. Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-2-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 5 ++--- target/arm/internals.h | 5 +++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 5727ead5e4..829b660db9 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10517,12 +10517,10 @@ static inline uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, } } -#endif /* !CONFIG_USER_ONLY */ - /* Convert a possible stage1+2 MMU index into the appropriate * stage 1 MMU index */ -static inline ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx) +ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx) { switch (mmu_idx) { case ARMMMUIdx_SE10_0: @@ -10541,6 +10539,7 @@ static inline ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx) return mmu_idx; } } +#endif /* !CONFIG_USER_ONLY */ /* Return true if the translation regime is using LPAE format page tables */ static inline bool regime_using_lpae_format(CPUARMState *env, diff --git a/target/arm/internals.h b/target/arm/internals.h index 1e4887b2dd..049edce946 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -979,11 +979,16 @@ ARMMMUIdx arm_mmu_idx(CPUARMState *env); * Return the ARMMMUIdx for the stage1 traversal for the current regime. */ #ifdef CONFIG_USER_ONLY +static inline ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx) +{ + return ARMMMUIdx_Stage1_E0; +} static inline ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env) { return ARMMMUIdx_Stage1_E0; } #else +ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx); ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env); #endif From 8ae0886002aaf917601701df933617b2449e94b5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:48 +0100 Subject: [PATCH 861/935] target/arm: Move get_phys_addr to ptw.c Begin moving all of the page table walking functions out of helper.c, starting with get_phys_addr(). Create a temporary header file, "ptw.h", in which to share declarations between the two C files while we are moving functions. Move a few declarations to "internals.h", which will remain used by multiple C files. Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-3-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 344 +++++------------------------------------ target/arm/internals.h | 18 ++- target/arm/meson.build | 1 + target/arm/ptw.c | 267 ++++++++++++++++++++++++++++++++ target/arm/ptw.h | 51 ++++++ 5 files changed, 372 insertions(+), 309 deletions(-) create mode 100644 target/arm/ptw.c create mode 100644 target/arm/ptw.h diff --git a/target/arm/helper.c b/target/arm/helper.c index 829b660db9..3ffd122178 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -37,22 +37,11 @@ #include "semihosting/common-semi.h" #endif #include "cpregs.h" +#include "ptw.h" #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */ -#ifndef CONFIG_USER_ONLY - -static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - bool s1_is_el0, - hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, - target_ulong *page_size_ptr, - ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) - __attribute__((nonnull)); -#endif - static void switch_mode(CPUARMState *env, int mode); -static int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx); static uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri) { @@ -10440,17 +10429,10 @@ uint64_t arm_sctlr(CPUARMState *env, int el) return env->cp15.sctlr_el[el]; } -/* Return the SCTLR value which controls this address translation regime */ -static inline uint64_t regime_sctlr(CPUARMState *env, ARMMMUIdx mmu_idx) -{ - return env->cp15.sctlr_el[regime_el(env, mmu_idx)]; -} - #ifndef CONFIG_USER_ONLY /* Return true if the specified stage of address translation is disabled */ -static inline bool regime_translation_disabled(CPUARMState *env, - ARMMMUIdx mmu_idx) +bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx) { uint64_t hcr_el2; @@ -10542,8 +10524,7 @@ ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx) #endif /* !CONFIG_USER_ONLY */ /* Return true if the translation regime is using LPAE format page tables */ -static inline bool regime_using_lpae_format(CPUARMState *env, - ARMMMUIdx mmu_idx) +bool regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx) { int el = regime_el(env, mmu_idx); if (el == 2 || arm_el_is_aa64(env, el)) { @@ -10567,7 +10548,7 @@ bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx) } #ifndef CONFIG_USER_ONLY -static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx) +bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx) { switch (mmu_idx) { case ARMMMUIdx_SE10_0: @@ -10959,11 +10940,11 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, return 0; } -static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, int *prot, - target_ulong *page_size, - ARMMMUFaultInfo *fi) +bool get_phys_addr_v5(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, int *prot, + target_ulong *page_size, + ARMMMUFaultInfo *fi) { CPUState *cs = env_cpu(env); int level = 1; @@ -11081,10 +11062,10 @@ do_fault: return true; } -static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size, ARMMMUFaultInfo *fi) +bool get_phys_addr_v6(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, + target_ulong *page_size, ARMMMUFaultInfo *fi) { CPUState *cs = env_cpu(env); ARMCPU *cpu = env_archcpu(env); @@ -11360,7 +11341,7 @@ unsigned int arm_pamax(ARMCPU *cpu) return pamax_map[parange]; } -static int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx) +int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx) { if (regime_has_2_ranges(mmu_idx)) { return extract64(tcr, 37, 2); @@ -11372,7 +11353,7 @@ static int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx) } } -static int aa64_va_parameter_tbid(uint64_t tcr, ARMMMUIdx mmu_idx) +int aa64_va_parameter_tbid(uint64_t tcr, ARMMMUIdx mmu_idx) { if (regime_has_2_ranges(mmu_idx)) { return extract64(tcr, 51, 2); @@ -11602,12 +11583,12 @@ static ARMVAParameters aa32_va_parameters(CPUARMState *env, uint32_t va, * @fi: set to fault info if the translation fails * @cacheattrs: (if non-NULL) set to the cacheability/shareability attributes */ -static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - bool s1_is_el0, - hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, - target_ulong *page_size_ptr, - ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) +bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + bool s1_is_el0, + hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, + target_ulong *page_size_ptr, + ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) { ARMCPU *cpu = env_archcpu(env); CPUState *cs = CPU(cpu); @@ -12055,11 +12036,11 @@ static inline bool m_is_system_region(CPUARMState *env, uint32_t address) return arm_feature(env, ARM_FEATURE_M) && extract32(address, 29, 3) == 0x7; } -static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, int *prot, - target_ulong *page_size, - ARMMMUFaultInfo *fi) +bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, int *prot, + target_ulong *page_size, + ARMMMUFaultInfo *fi) { ARMCPU *cpu = env_archcpu(env); int n; @@ -12501,11 +12482,11 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, } -static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *txattrs, - int *prot, target_ulong *page_size, - ARMMMUFaultInfo *fi) +bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, MemTxAttrs *txattrs, + int *prot, target_ulong *page_size, + ARMMMUFaultInfo *fi) { uint32_t secure = regime_is_secure(env, mmu_idx); V8M_SAttributes sattrs = {}; @@ -12575,10 +12556,10 @@ static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, return ret; } -static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, int *prot, - ARMMMUFaultInfo *fi) +bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, int *prot, + ARMMMUFaultInfo *fi) { int n; uint32_t mask; @@ -12795,8 +12776,8 @@ static uint8_t combined_attrs_fwb(CPUARMState *env, * @s1: Attributes from stage 1 walk * @s2: Attributes from stage 2 walk */ -static ARMCacheAttrs combine_cacheattrs(CPUARMState *env, - ARMCacheAttrs s1, ARMCacheAttrs s2) +ARMCacheAttrs combine_cacheattrs(CPUARMState *env, + ARMCacheAttrs s1, ARMCacheAttrs s2) { ARMCacheAttrs ret; bool tagged = false; @@ -12848,256 +12829,6 @@ static ARMCacheAttrs combine_cacheattrs(CPUARMState *env, return ret; } - -/* get_phys_addr - get the physical address for this virtual address - * - * Find the physical address corresponding to the given virtual address, - * by doing a translation table walk on MMU based systems or using the - * MPU state on MPU based systems. - * - * Returns false if the translation was successful. Otherwise, phys_ptr, attrs, - * prot and page_size may not be filled in, and the populated fsr value provides - * information on why the translation aborted, in the format of a - * DFSR/IFSR fault register, with the following caveats: - * * we honour the short vs long DFSR format differences. - * * the WnR bit is never set (the caller must do this). - * * for PSMAv5 based systems we don't bother to return a full FSR format - * value. - * - * @env: CPUARMState - * @address: virtual address to get physical address for - * @access_type: 0 for read, 1 for write, 2 for execute - * @mmu_idx: MMU index indicating required translation regime - * @phys_ptr: set to the physical address corresponding to the virtual address - * @attrs: set to the memory transaction attributes to use - * @prot: set to the permissions for the page containing phys_ptr - * @page_size: set to the size of the page containing phys_ptr - * @fi: set to fault info if the translation fails - * @cacheattrs: (if non-NULL) set to the cacheability/shareability attributes - */ -bool get_phys_addr(CPUARMState *env, target_ulong address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size, - ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) -{ - ARMMMUIdx s1_mmu_idx = stage_1_mmu_idx(mmu_idx); - - if (mmu_idx != s1_mmu_idx) { - /* Call ourselves recursively to do the stage 1 and then stage 2 - * translations if mmu_idx is a two-stage regime. - */ - if (arm_feature(env, ARM_FEATURE_EL2)) { - hwaddr ipa; - int s2_prot; - int ret; - bool ipa_secure; - ARMCacheAttrs cacheattrs2 = {}; - ARMMMUIdx s2_mmu_idx; - bool is_el0; - - ret = get_phys_addr(env, address, access_type, s1_mmu_idx, &ipa, - attrs, prot, page_size, fi, cacheattrs); - - /* If S1 fails or S2 is disabled, return early. */ - if (ret || regime_translation_disabled(env, ARMMMUIdx_Stage2)) { - *phys_ptr = ipa; - return ret; - } - - ipa_secure = attrs->secure; - if (arm_is_secure_below_el3(env)) { - if (ipa_secure) { - attrs->secure = !(env->cp15.vstcr_el2.raw_tcr & VSTCR_SW); - } else { - attrs->secure = !(env->cp15.vtcr_el2.raw_tcr & VTCR_NSW); - } - } else { - assert(!ipa_secure); - } - - s2_mmu_idx = attrs->secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2; - is_el0 = mmu_idx == ARMMMUIdx_E10_0 || mmu_idx == ARMMMUIdx_SE10_0; - - /* S1 is done. Now do S2 translation. */ - ret = get_phys_addr_lpae(env, ipa, access_type, s2_mmu_idx, is_el0, - phys_ptr, attrs, &s2_prot, - page_size, fi, &cacheattrs2); - fi->s2addr = ipa; - /* Combine the S1 and S2 perms. */ - *prot &= s2_prot; - - /* If S2 fails, return early. */ - if (ret) { - return ret; - } - - /* Combine the S1 and S2 cache attributes. */ - if (arm_hcr_el2_eff(env) & HCR_DC) { - /* - * HCR.DC forces the first stage attributes to - * Normal Non-Shareable, - * Inner Write-Back Read-Allocate Write-Allocate, - * Outer Write-Back Read-Allocate Write-Allocate. - * Do not overwrite Tagged within attrs. - */ - if (cacheattrs->attrs != 0xf0) { - cacheattrs->attrs = 0xff; - } - cacheattrs->shareability = 0; - } - *cacheattrs = combine_cacheattrs(env, *cacheattrs, cacheattrs2); - - /* Check if IPA translates to secure or non-secure PA space. */ - if (arm_is_secure_below_el3(env)) { - if (ipa_secure) { - attrs->secure = - !(env->cp15.vstcr_el2.raw_tcr & (VSTCR_SA | VSTCR_SW)); - } else { - attrs->secure = - !((env->cp15.vtcr_el2.raw_tcr & (VTCR_NSA | VTCR_NSW)) - || (env->cp15.vstcr_el2.raw_tcr & (VSTCR_SA | VSTCR_SW))); - } - } - return 0; - } else { - /* - * For non-EL2 CPUs a stage1+stage2 translation is just stage 1. - */ - mmu_idx = stage_1_mmu_idx(mmu_idx); - } - } - - /* The page table entries may downgrade secure to non-secure, but - * cannot upgrade an non-secure translation regime's attributes - * to secure. - */ - attrs->secure = regime_is_secure(env, mmu_idx); - attrs->user = regime_is_user(env, mmu_idx); - - /* Fast Context Switch Extension. This doesn't exist at all in v8. - * In v7 and earlier it affects all stage 1 translations. - */ - if (address < 0x02000000 && mmu_idx != ARMMMUIdx_Stage2 - && !arm_feature(env, ARM_FEATURE_V8)) { - if (regime_el(env, mmu_idx) == 3) { - address += env->cp15.fcseidr_s; - } else { - address += env->cp15.fcseidr_ns; - } - } - - if (arm_feature(env, ARM_FEATURE_PMSA)) { - bool ret; - *page_size = TARGET_PAGE_SIZE; - - if (arm_feature(env, ARM_FEATURE_V8)) { - /* PMSAv8 */ - ret = get_phys_addr_pmsav8(env, address, access_type, mmu_idx, - phys_ptr, attrs, prot, page_size, fi); - } else if (arm_feature(env, ARM_FEATURE_V7)) { - /* PMSAv7 */ - ret = get_phys_addr_pmsav7(env, address, access_type, mmu_idx, - phys_ptr, prot, page_size, fi); - } else { - /* Pre-v7 MPU */ - ret = get_phys_addr_pmsav5(env, address, access_type, mmu_idx, - phys_ptr, prot, fi); - } - qemu_log_mask(CPU_LOG_MMU, "PMSA MPU lookup for %s at 0x%08" PRIx32 - " mmu_idx %u -> %s (prot %c%c%c)\n", - access_type == MMU_DATA_LOAD ? "reading" : - (access_type == MMU_DATA_STORE ? "writing" : "execute"), - (uint32_t)address, mmu_idx, - ret ? "Miss" : "Hit", - *prot & PAGE_READ ? 'r' : '-', - *prot & PAGE_WRITE ? 'w' : '-', - *prot & PAGE_EXEC ? 'x' : '-'); - - return ret; - } - - /* Definitely a real MMU, not an MPU */ - - if (regime_translation_disabled(env, mmu_idx)) { - uint64_t hcr; - uint8_t memattr; - - /* - * MMU disabled. S1 addresses within aa64 translation regimes are - * still checked for bounds -- see AArch64.TranslateAddressS1Off. - */ - if (mmu_idx != ARMMMUIdx_Stage2 && mmu_idx != ARMMMUIdx_Stage2_S) { - int r_el = regime_el(env, mmu_idx); - if (arm_el_is_aa64(env, r_el)) { - int pamax = arm_pamax(env_archcpu(env)); - uint64_t tcr = env->cp15.tcr_el[r_el].raw_tcr; - int addrtop, tbi; - - tbi = aa64_va_parameter_tbi(tcr, mmu_idx); - if (access_type == MMU_INST_FETCH) { - tbi &= ~aa64_va_parameter_tbid(tcr, mmu_idx); - } - tbi = (tbi >> extract64(address, 55, 1)) & 1; - addrtop = (tbi ? 55 : 63); - - if (extract64(address, pamax, addrtop - pamax + 1) != 0) { - fi->type = ARMFault_AddressSize; - fi->level = 0; - fi->stage2 = false; - return 1; - } - - /* - * When TBI is disabled, we've just validated that all of the - * bits above PAMax are zero, so logically we only need to - * clear the top byte for TBI. But it's clearer to follow - * the pseudocode set of addrdesc.paddress. - */ - address = extract64(address, 0, 52); - } - } - *phys_ptr = address; - *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - *page_size = TARGET_PAGE_SIZE; - - /* Fill in cacheattr a-la AArch64.TranslateAddressS1Off. */ - hcr = arm_hcr_el2_eff(env); - cacheattrs->shareability = 0; - cacheattrs->is_s2_format = false; - if (hcr & HCR_DC) { - if (hcr & HCR_DCT) { - memattr = 0xf0; /* Tagged, Normal, WB, RWA */ - } else { - memattr = 0xff; /* Normal, WB, RWA */ - } - } else if (access_type == MMU_INST_FETCH) { - if (regime_sctlr(env, mmu_idx) & SCTLR_I) { - memattr = 0xee; /* Normal, WT, RA, NT */ - } else { - memattr = 0x44; /* Normal, NC, No */ - } - cacheattrs->shareability = 2; /* outer sharable */ - } else { - memattr = 0x00; /* Device, nGnRnE */ - } - cacheattrs->attrs = memattr; - return 0; - } - - if (regime_using_lpae_format(env, mmu_idx)) { - return get_phys_addr_lpae(env, address, access_type, mmu_idx, false, - phys_ptr, attrs, prot, page_size, - fi, cacheattrs); - } else if (regime_sctlr(env, mmu_idx) & SCTLR_XP) { - return get_phys_addr_v6(env, address, access_type, mmu_idx, - phys_ptr, attrs, prot, page_size, fi); - } else { - return get_phys_addr_v5(env, address, access_type, mmu_idx, - phys_ptr, prot, page_size, fi); - } -} - hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, MemTxAttrs *attrs) { @@ -13121,7 +12852,6 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, } return phys_addr; } - #endif /* Note that signed overflow is undefined in C. The following routines are diff --git a/target/arm/internals.h b/target/arm/internals.h index 049edce946..1d83146d56 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -613,8 +613,13 @@ ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env, /* Return the MMU index for a v7M CPU in the specified security state */ ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate); -/* Return true if the stage 1 translation regime is using LPAE format page - * tables */ +/* Return true if the translation regime is using LPAE format page tables */ +bool regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx); + +/* + * Return true if the stage 1 translation regime is using LPAE + * format page tables + */ bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx); /* Raise a data fault alignment exception for the specified virtual address */ @@ -777,6 +782,12 @@ static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx) } } +/* Return the SCTLR value which controls this address translation regime */ +static inline uint64_t regime_sctlr(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + return env->cp15.sctlr_el[regime_el(env, mmu_idx)]; +} + /* Return the TCR controlling this translation regime */ static inline TCR *regime_tcr(CPUARMState *env, ARMMMUIdx mmu_idx) { @@ -1095,6 +1106,9 @@ typedef struct ARMVAParameters { ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, ARMMMUIdx mmu_idx, bool data); +int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx); +int aa64_va_parameter_tbid(uint64_t tcr, ARMMMUIdx mmu_idx); + static inline int exception_target_el(CPUARMState *env) { int target_el = MAX(1, arm_current_el(env)); diff --git a/target/arm/meson.build b/target/arm/meson.build index 50f152214a..ac571fc45d 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -58,6 +58,7 @@ arm_softmmu_ss.add(files( 'machine.c', 'monitor.c', 'psci.c', + 'ptw.c', )) subdir('hvf') diff --git a/target/arm/ptw.c b/target/arm/ptw.c new file mode 100644 index 0000000000..318000f6d9 --- /dev/null +++ b/target/arm/ptw.c @@ -0,0 +1,267 @@ +/* + * ARM page table walking. + * + * This code is licensed under the GNU GPL v2 or later. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "internals.h" +#include "ptw.h" + + +/** + * get_phys_addr - get the physical address for this virtual address + * + * Find the physical address corresponding to the given virtual address, + * by doing a translation table walk on MMU based systems or using the + * MPU state on MPU based systems. + * + * Returns false if the translation was successful. Otherwise, phys_ptr, attrs, + * prot and page_size may not be filled in, and the populated fsr value provides + * information on why the translation aborted, in the format of a + * DFSR/IFSR fault register, with the following caveats: + * * we honour the short vs long DFSR format differences. + * * the WnR bit is never set (the caller must do this). + * * for PSMAv5 based systems we don't bother to return a full FSR format + * value. + * + * @env: CPUARMState + * @address: virtual address to get physical address for + * @access_type: 0 for read, 1 for write, 2 for execute + * @mmu_idx: MMU index indicating required translation regime + * @phys_ptr: set to the physical address corresponding to the virtual address + * @attrs: set to the memory transaction attributes to use + * @prot: set to the permissions for the page containing phys_ptr + * @page_size: set to the size of the page containing phys_ptr + * @fi: set to fault info if the translation fails + * @cacheattrs: (if non-NULL) set to the cacheability/shareability attributes + */ +bool get_phys_addr(CPUARMState *env, target_ulong address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, + target_ulong *page_size, + ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) +{ + ARMMMUIdx s1_mmu_idx = stage_1_mmu_idx(mmu_idx); + + if (mmu_idx != s1_mmu_idx) { + /* + * Call ourselves recursively to do the stage 1 and then stage 2 + * translations if mmu_idx is a two-stage regime. + */ + if (arm_feature(env, ARM_FEATURE_EL2)) { + hwaddr ipa; + int s2_prot; + int ret; + bool ipa_secure; + ARMCacheAttrs cacheattrs2 = {}; + ARMMMUIdx s2_mmu_idx; + bool is_el0; + + ret = get_phys_addr(env, address, access_type, s1_mmu_idx, &ipa, + attrs, prot, page_size, fi, cacheattrs); + + /* If S1 fails or S2 is disabled, return early. */ + if (ret || regime_translation_disabled(env, ARMMMUIdx_Stage2)) { + *phys_ptr = ipa; + return ret; + } + + ipa_secure = attrs->secure; + if (arm_is_secure_below_el3(env)) { + if (ipa_secure) { + attrs->secure = !(env->cp15.vstcr_el2.raw_tcr & VSTCR_SW); + } else { + attrs->secure = !(env->cp15.vtcr_el2.raw_tcr & VTCR_NSW); + } + } else { + assert(!ipa_secure); + } + + s2_mmu_idx = attrs->secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2; + is_el0 = mmu_idx == ARMMMUIdx_E10_0 || mmu_idx == ARMMMUIdx_SE10_0; + + /* S1 is done. Now do S2 translation. */ + ret = get_phys_addr_lpae(env, ipa, access_type, s2_mmu_idx, is_el0, + phys_ptr, attrs, &s2_prot, + page_size, fi, &cacheattrs2); + fi->s2addr = ipa; + /* Combine the S1 and S2 perms. */ + *prot &= s2_prot; + + /* If S2 fails, return early. */ + if (ret) { + return ret; + } + + /* Combine the S1 and S2 cache attributes. */ + if (arm_hcr_el2_eff(env) & HCR_DC) { + /* + * HCR.DC forces the first stage attributes to + * Normal Non-Shareable, + * Inner Write-Back Read-Allocate Write-Allocate, + * Outer Write-Back Read-Allocate Write-Allocate. + * Do not overwrite Tagged within attrs. + */ + if (cacheattrs->attrs != 0xf0) { + cacheattrs->attrs = 0xff; + } + cacheattrs->shareability = 0; + } + *cacheattrs = combine_cacheattrs(env, *cacheattrs, cacheattrs2); + + /* Check if IPA translates to secure or non-secure PA space. */ + if (arm_is_secure_below_el3(env)) { + if (ipa_secure) { + attrs->secure = + !(env->cp15.vstcr_el2.raw_tcr & (VSTCR_SA | VSTCR_SW)); + } else { + attrs->secure = + !((env->cp15.vtcr_el2.raw_tcr & (VTCR_NSA | VTCR_NSW)) + || (env->cp15.vstcr_el2.raw_tcr & (VSTCR_SA | VSTCR_SW))); + } + } + return 0; + } else { + /* + * For non-EL2 CPUs a stage1+stage2 translation is just stage 1. + */ + mmu_idx = stage_1_mmu_idx(mmu_idx); + } + } + + /* + * The page table entries may downgrade secure to non-secure, but + * cannot upgrade an non-secure translation regime's attributes + * to secure. + */ + attrs->secure = regime_is_secure(env, mmu_idx); + attrs->user = regime_is_user(env, mmu_idx); + + /* + * Fast Context Switch Extension. This doesn't exist at all in v8. + * In v7 and earlier it affects all stage 1 translations. + */ + if (address < 0x02000000 && mmu_idx != ARMMMUIdx_Stage2 + && !arm_feature(env, ARM_FEATURE_V8)) { + if (regime_el(env, mmu_idx) == 3) { + address += env->cp15.fcseidr_s; + } else { + address += env->cp15.fcseidr_ns; + } + } + + if (arm_feature(env, ARM_FEATURE_PMSA)) { + bool ret; + *page_size = TARGET_PAGE_SIZE; + + if (arm_feature(env, ARM_FEATURE_V8)) { + /* PMSAv8 */ + ret = get_phys_addr_pmsav8(env, address, access_type, mmu_idx, + phys_ptr, attrs, prot, page_size, fi); + } else if (arm_feature(env, ARM_FEATURE_V7)) { + /* PMSAv7 */ + ret = get_phys_addr_pmsav7(env, address, access_type, mmu_idx, + phys_ptr, prot, page_size, fi); + } else { + /* Pre-v7 MPU */ + ret = get_phys_addr_pmsav5(env, address, access_type, mmu_idx, + phys_ptr, prot, fi); + } + qemu_log_mask(CPU_LOG_MMU, "PMSA MPU lookup for %s at 0x%08" PRIx32 + " mmu_idx %u -> %s (prot %c%c%c)\n", + access_type == MMU_DATA_LOAD ? "reading" : + (access_type == MMU_DATA_STORE ? "writing" : "execute"), + (uint32_t)address, mmu_idx, + ret ? "Miss" : "Hit", + *prot & PAGE_READ ? 'r' : '-', + *prot & PAGE_WRITE ? 'w' : '-', + *prot & PAGE_EXEC ? 'x' : '-'); + + return ret; + } + + /* Definitely a real MMU, not an MPU */ + + if (regime_translation_disabled(env, mmu_idx)) { + uint64_t hcr; + uint8_t memattr; + + /* + * MMU disabled. S1 addresses within aa64 translation regimes are + * still checked for bounds -- see AArch64.TranslateAddressS1Off. + */ + if (mmu_idx != ARMMMUIdx_Stage2 && mmu_idx != ARMMMUIdx_Stage2_S) { + int r_el = regime_el(env, mmu_idx); + if (arm_el_is_aa64(env, r_el)) { + int pamax = arm_pamax(env_archcpu(env)); + uint64_t tcr = env->cp15.tcr_el[r_el].raw_tcr; + int addrtop, tbi; + + tbi = aa64_va_parameter_tbi(tcr, mmu_idx); + if (access_type == MMU_INST_FETCH) { + tbi &= ~aa64_va_parameter_tbid(tcr, mmu_idx); + } + tbi = (tbi >> extract64(address, 55, 1)) & 1; + addrtop = (tbi ? 55 : 63); + + if (extract64(address, pamax, addrtop - pamax + 1) != 0) { + fi->type = ARMFault_AddressSize; + fi->level = 0; + fi->stage2 = false; + return 1; + } + + /* + * When TBI is disabled, we've just validated that all of the + * bits above PAMax are zero, so logically we only need to + * clear the top byte for TBI. But it's clearer to follow + * the pseudocode set of addrdesc.paddress. + */ + address = extract64(address, 0, 52); + } + } + *phys_ptr = address; + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + *page_size = TARGET_PAGE_SIZE; + + /* Fill in cacheattr a-la AArch64.TranslateAddressS1Off. */ + hcr = arm_hcr_el2_eff(env); + cacheattrs->shareability = 0; + cacheattrs->is_s2_format = false; + if (hcr & HCR_DC) { + if (hcr & HCR_DCT) { + memattr = 0xf0; /* Tagged, Normal, WB, RWA */ + } else { + memattr = 0xff; /* Normal, WB, RWA */ + } + } else if (access_type == MMU_INST_FETCH) { + if (regime_sctlr(env, mmu_idx) & SCTLR_I) { + memattr = 0xee; /* Normal, WT, RA, NT */ + } else { + memattr = 0x44; /* Normal, NC, No */ + } + cacheattrs->shareability = 2; /* outer sharable */ + } else { + memattr = 0x00; /* Device, nGnRnE */ + } + cacheattrs->attrs = memattr; + return 0; + } + + if (regime_using_lpae_format(env, mmu_idx)) { + return get_phys_addr_lpae(env, address, access_type, mmu_idx, false, + phys_ptr, attrs, prot, page_size, + fi, cacheattrs); + } else if (regime_sctlr(env, mmu_idx) & SCTLR_XP) { + return get_phys_addr_v6(env, address, access_type, mmu_idx, + phys_ptr, attrs, prot, page_size, fi); + } else { + return get_phys_addr_v5(env, address, access_type, mmu_idx, + phys_ptr, prot, page_size, fi); + } +} diff --git a/target/arm/ptw.h b/target/arm/ptw.h new file mode 100644 index 0000000000..e2023ae750 --- /dev/null +++ b/target/arm/ptw.h @@ -0,0 +1,51 @@ +/* + * ARM page table walking. + * + * This code is licensed under the GNU GPL v2 or later. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef TARGET_ARM_PTW_H +#define TARGET_ARM_PTW_H + +#ifndef CONFIG_USER_ONLY + +bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx); +bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx); +ARMCacheAttrs combine_cacheattrs(CPUARMState *env, + ARMCacheAttrs s1, ARMCacheAttrs s2); + +bool get_phys_addr_v5(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, int *prot, + target_ulong *page_size, + ARMMMUFaultInfo *fi); +bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, int *prot, + ARMMMUFaultInfo *fi); +bool get_phys_addr_v6(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, + target_ulong *page_size, ARMMMUFaultInfo *fi); +bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, int *prot, + target_ulong *page_size, + ARMMMUFaultInfo *fi); +bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, MemTxAttrs *txattrs, + int *prot, target_ulong *page_size, + ARMMMUFaultInfo *fi); +bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + bool s1_is_el0, + hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, + target_ulong *page_size_ptr, + ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) + __attribute__((nonnull)); + +#endif /* !CONFIG_USER_ONLY */ +#endif /* TARGET_ARM_PTW_H */ From f2d2f5ceb87e828546f7b544f1289193f3b920ce Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:48 +0100 Subject: [PATCH 862/935] target/arm: Move get_phys_addr_v5 to ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-4-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 137 +++----------------------------------------- target/arm/ptw.c | 123 +++++++++++++++++++++++++++++++++++++++ target/arm/ptw.h | 15 +++-- 3 files changed, 140 insertions(+), 135 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 3ffd122178..321716914b 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10578,8 +10578,7 @@ bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx) * @ap: The 3-bit access permissions (AP[2:0]) * @domain_prot: The 2-bit domain access permissions */ -static inline int ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, - int ap, int domain_prot) +int ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap, int domain_prot) { bool is_user = regime_is_user(env, mmu_idx); @@ -10782,8 +10781,8 @@ static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, return prot_rw | PAGE_EXEC; } -static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, - uint32_t *table, uint32_t address) +bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, + uint32_t *table, uint32_t address) { /* Note that we can only get here for an AArch32 PL0/PL1 lookup */ TCR *tcr = regime_tcr(env, mmu_idx); @@ -10882,8 +10881,8 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, } /* All loads done in the course of a page table walk go through here. */ -static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, - ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi) +uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, + ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; @@ -10911,8 +10910,8 @@ static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, return 0; } -static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, - ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi) +uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, + ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; @@ -10940,128 +10939,6 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, return 0; } -bool get_phys_addr_v5(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, int *prot, - target_ulong *page_size, - ARMMMUFaultInfo *fi) -{ - CPUState *cs = env_cpu(env); - int level = 1; - uint32_t table; - uint32_t desc; - int type; - int ap; - int domain = 0; - int domain_prot; - hwaddr phys_addr; - uint32_t dacr; - - /* Pagetable walk. */ - /* Lookup l1 descriptor. */ - if (!get_level1_table_address(env, mmu_idx, &table, address)) { - /* Section translation fault if page walk is disabled by PD0 or PD1 */ - fi->type = ARMFault_Translation; - goto do_fault; - } - desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), - mmu_idx, fi); - if (fi->type != ARMFault_None) { - goto do_fault; - } - type = (desc & 3); - domain = (desc >> 5) & 0x0f; - if (regime_el(env, mmu_idx) == 1) { - dacr = env->cp15.dacr_ns; - } else { - dacr = env->cp15.dacr_s; - } - domain_prot = (dacr >> (domain * 2)) & 3; - if (type == 0) { - /* Section translation fault. */ - fi->type = ARMFault_Translation; - goto do_fault; - } - if (type != 2) { - level = 2; - } - if (domain_prot == 0 || domain_prot == 2) { - fi->type = ARMFault_Domain; - goto do_fault; - } - if (type == 2) { - /* 1Mb section. */ - phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); - ap = (desc >> 10) & 3; - *page_size = 1024 * 1024; - } else { - /* Lookup l2 entry. */ - if (type == 1) { - /* Coarse pagetable. */ - table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); - } else { - /* Fine pagetable. */ - table = (desc & 0xfffff000) | ((address >> 8) & 0xffc); - } - desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), - mmu_idx, fi); - if (fi->type != ARMFault_None) { - goto do_fault; - } - switch (desc & 3) { - case 0: /* Page translation fault. */ - fi->type = ARMFault_Translation; - goto do_fault; - case 1: /* 64k page. */ - phys_addr = (desc & 0xffff0000) | (address & 0xffff); - ap = (desc >> (4 + ((address >> 13) & 6))) & 3; - *page_size = 0x10000; - break; - case 2: /* 4k page. */ - phys_addr = (desc & 0xfffff000) | (address & 0xfff); - ap = (desc >> (4 + ((address >> 9) & 6))) & 3; - *page_size = 0x1000; - break; - case 3: /* 1k page, or ARMv6/XScale "extended small (4k) page" */ - if (type == 1) { - /* ARMv6/XScale extended small page format */ - if (arm_feature(env, ARM_FEATURE_XSCALE) - || arm_feature(env, ARM_FEATURE_V6)) { - phys_addr = (desc & 0xfffff000) | (address & 0xfff); - *page_size = 0x1000; - } else { - /* UNPREDICTABLE in ARMv5; we choose to take a - * page translation fault. - */ - fi->type = ARMFault_Translation; - goto do_fault; - } - } else { - phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); - *page_size = 0x400; - } - ap = (desc >> 4) & 3; - break; - default: - /* Never happens, but compiler isn't smart enough to tell. */ - g_assert_not_reached(); - } - } - *prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot); - *prot |= *prot ? PAGE_EXEC : 0; - if (!(*prot & (1 << access_type))) { - /* Access permission fault. */ - fi->type = ARMFault_Permission; - goto do_fault; - } - *phys_ptr = phys_addr; - return false; -do_fault: - fi->domain = domain; - fi->level = level; - return true; -} - bool get_phys_addr_v6(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 318000f6d9..09c4472628 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -13,6 +13,129 @@ #include "ptw.h" +static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, int *prot, + target_ulong *page_size, + ARMMMUFaultInfo *fi) +{ + CPUState *cs = env_cpu(env); + int level = 1; + uint32_t table; + uint32_t desc; + int type; + int ap; + int domain = 0; + int domain_prot; + hwaddr phys_addr; + uint32_t dacr; + + /* Pagetable walk. */ + /* Lookup l1 descriptor. */ + if (!get_level1_table_address(env, mmu_idx, &table, address)) { + /* Section translation fault if page walk is disabled by PD0 or PD1 */ + fi->type = ARMFault_Translation; + goto do_fault; + } + desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), + mmu_idx, fi); + if (fi->type != ARMFault_None) { + goto do_fault; + } + type = (desc & 3); + domain = (desc >> 5) & 0x0f; + if (regime_el(env, mmu_idx) == 1) { + dacr = env->cp15.dacr_ns; + } else { + dacr = env->cp15.dacr_s; + } + domain_prot = (dacr >> (domain * 2)) & 3; + if (type == 0) { + /* Section translation fault. */ + fi->type = ARMFault_Translation; + goto do_fault; + } + if (type != 2) { + level = 2; + } + if (domain_prot == 0 || domain_prot == 2) { + fi->type = ARMFault_Domain; + goto do_fault; + } + if (type == 2) { + /* 1Mb section. */ + phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); + ap = (desc >> 10) & 3; + *page_size = 1024 * 1024; + } else { + /* Lookup l2 entry. */ + if (type == 1) { + /* Coarse pagetable. */ + table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); + } else { + /* Fine pagetable. */ + table = (desc & 0xfffff000) | ((address >> 8) & 0xffc); + } + desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), + mmu_idx, fi); + if (fi->type != ARMFault_None) { + goto do_fault; + } + switch (desc & 3) { + case 0: /* Page translation fault. */ + fi->type = ARMFault_Translation; + goto do_fault; + case 1: /* 64k page. */ + phys_addr = (desc & 0xffff0000) | (address & 0xffff); + ap = (desc >> (4 + ((address >> 13) & 6))) & 3; + *page_size = 0x10000; + break; + case 2: /* 4k page. */ + phys_addr = (desc & 0xfffff000) | (address & 0xfff); + ap = (desc >> (4 + ((address >> 9) & 6))) & 3; + *page_size = 0x1000; + break; + case 3: /* 1k page, or ARMv6/XScale "extended small (4k) page" */ + if (type == 1) { + /* ARMv6/XScale extended small page format */ + if (arm_feature(env, ARM_FEATURE_XSCALE) + || arm_feature(env, ARM_FEATURE_V6)) { + phys_addr = (desc & 0xfffff000) | (address & 0xfff); + *page_size = 0x1000; + } else { + /* + * UNPREDICTABLE in ARMv5; we choose to take a + * page translation fault. + */ + fi->type = ARMFault_Translation; + goto do_fault; + } + } else { + phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); + *page_size = 0x400; + } + ap = (desc >> 4) & 3; + break; + default: + /* Never happens, but compiler isn't smart enough to tell. */ + g_assert_not_reached(); + } + } + *prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot); + *prot |= *prot ? PAGE_EXEC : 0; + if (!(*prot & (1 << access_type))) { + /* Access permission fault. */ + fi->type = ARMFault_Permission; + goto do_fault; + } + *phys_ptr = phys_addr; + return false; +do_fault: + fi->domain = domain; + fi->level = level; + return true; +} + /** * get_phys_addr - get the physical address for this virtual address * diff --git a/target/arm/ptw.h b/target/arm/ptw.h index e2023ae750..2dbd97b8cb 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -11,16 +11,21 @@ #ifndef CONFIG_USER_ONLY +uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, + ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi); +uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, + ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi); + bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx); bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx); ARMCacheAttrs combine_cacheattrs(CPUARMState *env, ARMCacheAttrs s1, ARMCacheAttrs s2); -bool get_phys_addr_v5(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, int *prot, - target_ulong *page_size, - ARMMMUFaultInfo *fi); +bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, + uint32_t *table, uint32_t address); +int ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, + int ap, int domain_prot); + bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, int *prot, From 53c038efb7a634dd5b6ede8eb034791c0dc83f43 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:48 +0100 Subject: [PATCH 863/935] target/arm: Move get_phys_addr_v6 to ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-5-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 161 +------------------------------------------- target/arm/ptw.c | 153 +++++++++++++++++++++++++++++++++++++++++ target/arm/ptw.h | 11 +-- 3 files changed, 161 insertions(+), 164 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 321716914b..4a58822025 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10631,7 +10631,7 @@ int ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap, int domain_prot) * @ap: The 2-bit simple AP (AP[2:1]) * @is_user: TRUE if accessing from PL0 */ -static inline int simple_ap_to_rw_prot_is_user(int ap, bool is_user) +int simple_ap_to_rw_prot_is_user(int ap, bool is_user) { switch (ap) { case 0: @@ -10647,12 +10647,6 @@ static inline int simple_ap_to_rw_prot_is_user(int ap, bool is_user) } } -static inline int -simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap) -{ - return simple_ap_to_rw_prot_is_user(ap, regime_is_user(env, mmu_idx)); -} - /* Translate S2 section/page access permissions to protection flags * * @env: CPUARMState @@ -10939,159 +10933,6 @@ uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, return 0; } -bool get_phys_addr_v6(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size, ARMMMUFaultInfo *fi) -{ - CPUState *cs = env_cpu(env); - ARMCPU *cpu = env_archcpu(env); - int level = 1; - uint32_t table; - uint32_t desc; - uint32_t xn; - uint32_t pxn = 0; - int type; - int ap; - int domain = 0; - int domain_prot; - hwaddr phys_addr; - uint32_t dacr; - bool ns; - - /* Pagetable walk. */ - /* Lookup l1 descriptor. */ - if (!get_level1_table_address(env, mmu_idx, &table, address)) { - /* Section translation fault if page walk is disabled by PD0 or PD1 */ - fi->type = ARMFault_Translation; - goto do_fault; - } - desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), - mmu_idx, fi); - if (fi->type != ARMFault_None) { - goto do_fault; - } - type = (desc & 3); - if (type == 0 || (type == 3 && !cpu_isar_feature(aa32_pxn, cpu))) { - /* Section translation fault, or attempt to use the encoding - * which is Reserved on implementations without PXN. - */ - fi->type = ARMFault_Translation; - goto do_fault; - } - if ((type == 1) || !(desc & (1 << 18))) { - /* Page or Section. */ - domain = (desc >> 5) & 0x0f; - } - if (regime_el(env, mmu_idx) == 1) { - dacr = env->cp15.dacr_ns; - } else { - dacr = env->cp15.dacr_s; - } - if (type == 1) { - level = 2; - } - domain_prot = (dacr >> (domain * 2)) & 3; - if (domain_prot == 0 || domain_prot == 2) { - /* Section or Page domain fault */ - fi->type = ARMFault_Domain; - goto do_fault; - } - if (type != 1) { - if (desc & (1 << 18)) { - /* Supersection. */ - phys_addr = (desc & 0xff000000) | (address & 0x00ffffff); - phys_addr |= (uint64_t)extract32(desc, 20, 4) << 32; - phys_addr |= (uint64_t)extract32(desc, 5, 4) << 36; - *page_size = 0x1000000; - } else { - /* Section. */ - phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); - *page_size = 0x100000; - } - ap = ((desc >> 10) & 3) | ((desc >> 13) & 4); - xn = desc & (1 << 4); - pxn = desc & 1; - ns = extract32(desc, 19, 1); - } else { - if (cpu_isar_feature(aa32_pxn, cpu)) { - pxn = (desc >> 2) & 1; - } - ns = extract32(desc, 3, 1); - /* Lookup l2 entry. */ - table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); - desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), - mmu_idx, fi); - if (fi->type != ARMFault_None) { - goto do_fault; - } - ap = ((desc >> 4) & 3) | ((desc >> 7) & 4); - switch (desc & 3) { - case 0: /* Page translation fault. */ - fi->type = ARMFault_Translation; - goto do_fault; - case 1: /* 64k page. */ - phys_addr = (desc & 0xffff0000) | (address & 0xffff); - xn = desc & (1 << 15); - *page_size = 0x10000; - break; - case 2: case 3: /* 4k page. */ - phys_addr = (desc & 0xfffff000) | (address & 0xfff); - xn = desc & 1; - *page_size = 0x1000; - break; - default: - /* Never happens, but compiler isn't smart enough to tell. */ - g_assert_not_reached(); - } - } - if (domain_prot == 3) { - *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - } else { - if (pxn && !regime_is_user(env, mmu_idx)) { - xn = 1; - } - if (xn && access_type == MMU_INST_FETCH) { - fi->type = ARMFault_Permission; - goto do_fault; - } - - if (arm_feature(env, ARM_FEATURE_V6K) && - (regime_sctlr(env, mmu_idx) & SCTLR_AFE)) { - /* The simplified model uses AP[0] as an access control bit. */ - if ((ap & 1) == 0) { - /* Access flag fault. */ - fi->type = ARMFault_AccessFlag; - goto do_fault; - } - *prot = simple_ap_to_rw_prot(env, mmu_idx, ap >> 1); - } else { - *prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot); - } - if (*prot && !xn) { - *prot |= PAGE_EXEC; - } - if (!(*prot & (1 << access_type))) { - /* Access permission fault. */ - fi->type = ARMFault_Permission; - goto do_fault; - } - } - if (ns) { - /* The NS bit will (as required by the architecture) have no effect if - * the CPU doesn't support TZ or this is a non-secure translation - * regime, because the attribute will already be non-secure. - */ - attrs->secure = false; - } - *phys_ptr = phys_addr; - return false; -do_fault: - fi->domain = domain; - fi->level = level; - return true; -} - /* * check_s2_mmu_setup * @cpu: ARMCPU diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 09c4472628..6a1f4b549d 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -136,6 +136,159 @@ do_fault: return true; } +static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, + target_ulong *page_size, ARMMMUFaultInfo *fi) +{ + CPUState *cs = env_cpu(env); + ARMCPU *cpu = env_archcpu(env); + int level = 1; + uint32_t table; + uint32_t desc; + uint32_t xn; + uint32_t pxn = 0; + int type; + int ap; + int domain = 0; + int domain_prot; + hwaddr phys_addr; + uint32_t dacr; + bool ns; + + /* Pagetable walk. */ + /* Lookup l1 descriptor. */ + if (!get_level1_table_address(env, mmu_idx, &table, address)) { + /* Section translation fault if page walk is disabled by PD0 or PD1 */ + fi->type = ARMFault_Translation; + goto do_fault; + } + desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), + mmu_idx, fi); + if (fi->type != ARMFault_None) { + goto do_fault; + } + type = (desc & 3); + if (type == 0 || (type == 3 && !cpu_isar_feature(aa32_pxn, cpu))) { + /* Section translation fault, or attempt to use the encoding + * which is Reserved on implementations without PXN. + */ + fi->type = ARMFault_Translation; + goto do_fault; + } + if ((type == 1) || !(desc & (1 << 18))) { + /* Page or Section. */ + domain = (desc >> 5) & 0x0f; + } + if (regime_el(env, mmu_idx) == 1) { + dacr = env->cp15.dacr_ns; + } else { + dacr = env->cp15.dacr_s; + } + if (type == 1) { + level = 2; + } + domain_prot = (dacr >> (domain * 2)) & 3; + if (domain_prot == 0 || domain_prot == 2) { + /* Section or Page domain fault */ + fi->type = ARMFault_Domain; + goto do_fault; + } + if (type != 1) { + if (desc & (1 << 18)) { + /* Supersection. */ + phys_addr = (desc & 0xff000000) | (address & 0x00ffffff); + phys_addr |= (uint64_t)extract32(desc, 20, 4) << 32; + phys_addr |= (uint64_t)extract32(desc, 5, 4) << 36; + *page_size = 0x1000000; + } else { + /* Section. */ + phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); + *page_size = 0x100000; + } + ap = ((desc >> 10) & 3) | ((desc >> 13) & 4); + xn = desc & (1 << 4); + pxn = desc & 1; + ns = extract32(desc, 19, 1); + } else { + if (cpu_isar_feature(aa32_pxn, cpu)) { + pxn = (desc >> 2) & 1; + } + ns = extract32(desc, 3, 1); + /* Lookup l2 entry. */ + table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); + desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), + mmu_idx, fi); + if (fi->type != ARMFault_None) { + goto do_fault; + } + ap = ((desc >> 4) & 3) | ((desc >> 7) & 4); + switch (desc & 3) { + case 0: /* Page translation fault. */ + fi->type = ARMFault_Translation; + goto do_fault; + case 1: /* 64k page. */ + phys_addr = (desc & 0xffff0000) | (address & 0xffff); + xn = desc & (1 << 15); + *page_size = 0x10000; + break; + case 2: case 3: /* 4k page. */ + phys_addr = (desc & 0xfffff000) | (address & 0xfff); + xn = desc & 1; + *page_size = 0x1000; + break; + default: + /* Never happens, but compiler isn't smart enough to tell. */ + g_assert_not_reached(); + } + } + if (domain_prot == 3) { + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + } else { + if (pxn && !regime_is_user(env, mmu_idx)) { + xn = 1; + } + if (xn && access_type == MMU_INST_FETCH) { + fi->type = ARMFault_Permission; + goto do_fault; + } + + if (arm_feature(env, ARM_FEATURE_V6K) && + (regime_sctlr(env, mmu_idx) & SCTLR_AFE)) { + /* The simplified model uses AP[0] as an access control bit. */ + if ((ap & 1) == 0) { + /* Access flag fault. */ + fi->type = ARMFault_AccessFlag; + goto do_fault; + } + *prot = simple_ap_to_rw_prot(env, mmu_idx, ap >> 1); + } else { + *prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot); + } + if (*prot && !xn) { + *prot |= PAGE_EXEC; + } + if (!(*prot & (1 << access_type))) { + /* Access permission fault. */ + fi->type = ARMFault_Permission; + goto do_fault; + } + } + if (ns) { + /* The NS bit will (as required by the architecture) have no effect if + * the CPU doesn't support TZ or this is a non-secure translation + * regime, because the attribute will already be non-secure. + */ + attrs->secure = false; + } + *phys_ptr = phys_addr; + return false; +do_fault: + fi->domain = domain; + fi->level = level; + return true; +} + /** * get_phys_addr - get the physical address for this virtual address * diff --git a/target/arm/ptw.h b/target/arm/ptw.h index 2dbd97b8cb..349b842d3c 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -25,15 +25,18 @@ bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, uint32_t *table, uint32_t address); int ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap, int domain_prot); +int simple_ap_to_rw_prot_is_user(int ap, bool is_user); + +static inline int +simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap) +{ + return simple_ap_to_rw_prot_is_user(ap, regime_is_user(env, mmu_idx)); +} bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, int *prot, ARMMMUFaultInfo *fi); -bool get_phys_addr_v6(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size, ARMMMUFaultInfo *fi); bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, int *prot, From 9a12fb366d442751603dc91ab5c5f9b7c828c783 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:49 +0100 Subject: [PATCH 864/935] target/arm: Move get_phys_addr_pmsav5 to ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-6-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 85 --------------------------------------------- target/arm/ptw.c | 85 +++++++++++++++++++++++++++++++++++++++++++++ target/arm/ptw.h | 4 --- 3 files changed, 85 insertions(+), 89 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 4a58822025..5d01019010 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -12274,91 +12274,6 @@ bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, return ret; } -bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, int *prot, - ARMMMUFaultInfo *fi) -{ - int n; - uint32_t mask; - uint32_t base; - bool is_user = regime_is_user(env, mmu_idx); - - if (regime_translation_disabled(env, mmu_idx)) { - /* MPU disabled. */ - *phys_ptr = address; - *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - return false; - } - - *phys_ptr = address; - for (n = 7; n >= 0; n--) { - base = env->cp15.c6_region[n]; - if ((base & 1) == 0) { - continue; - } - mask = 1 << ((base >> 1) & 0x1f); - /* Keep this shift separate from the above to avoid an - (undefined) << 32. */ - mask = (mask << 1) - 1; - if (((base ^ address) & ~mask) == 0) { - break; - } - } - if (n < 0) { - fi->type = ARMFault_Background; - return true; - } - - if (access_type == MMU_INST_FETCH) { - mask = env->cp15.pmsav5_insn_ap; - } else { - mask = env->cp15.pmsav5_data_ap; - } - mask = (mask >> (n * 4)) & 0xf; - switch (mask) { - case 0: - fi->type = ARMFault_Permission; - fi->level = 1; - return true; - case 1: - if (is_user) { - fi->type = ARMFault_Permission; - fi->level = 1; - return true; - } - *prot = PAGE_READ | PAGE_WRITE; - break; - case 2: - *prot = PAGE_READ; - if (!is_user) { - *prot |= PAGE_WRITE; - } - break; - case 3: - *prot = PAGE_READ | PAGE_WRITE; - break; - case 5: - if (is_user) { - fi->type = ARMFault_Permission; - fi->level = 1; - return true; - } - *prot = PAGE_READ; - break; - case 6: - *prot = PAGE_READ; - break; - default: - /* Bad permission. */ - fi->type = ARMFault_Permission; - fi->level = 1; - return true; - } - *prot |= PAGE_EXEC; - return false; -} - /* Combine either inner or outer cacheability attributes for normal * memory, according to table D4-42 and pseudocode procedure * CombineS1S2AttrHints() of ARM DDI 0487B.b (the ARMv8 ARM). diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 6a1f4b549d..5c32648a16 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -289,6 +289,91 @@ do_fault: return true; } +static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, int *prot, + ARMMMUFaultInfo *fi) +{ + int n; + uint32_t mask; + uint32_t base; + bool is_user = regime_is_user(env, mmu_idx); + + if (regime_translation_disabled(env, mmu_idx)) { + /* MPU disabled. */ + *phys_ptr = address; + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + return false; + } + + *phys_ptr = address; + for (n = 7; n >= 0; n--) { + base = env->cp15.c6_region[n]; + if ((base & 1) == 0) { + continue; + } + mask = 1 << ((base >> 1) & 0x1f); + /* Keep this shift separate from the above to avoid an + (undefined) << 32. */ + mask = (mask << 1) - 1; + if (((base ^ address) & ~mask) == 0) { + break; + } + } + if (n < 0) { + fi->type = ARMFault_Background; + return true; + } + + if (access_type == MMU_INST_FETCH) { + mask = env->cp15.pmsav5_insn_ap; + } else { + mask = env->cp15.pmsav5_data_ap; + } + mask = (mask >> (n * 4)) & 0xf; + switch (mask) { + case 0: + fi->type = ARMFault_Permission; + fi->level = 1; + return true; + case 1: + if (is_user) { + fi->type = ARMFault_Permission; + fi->level = 1; + return true; + } + *prot = PAGE_READ | PAGE_WRITE; + break; + case 2: + *prot = PAGE_READ; + if (!is_user) { + *prot |= PAGE_WRITE; + } + break; + case 3: + *prot = PAGE_READ | PAGE_WRITE; + break; + case 5: + if (is_user) { + fi->type = ARMFault_Permission; + fi->level = 1; + return true; + } + *prot = PAGE_READ; + break; + case 6: + *prot = PAGE_READ; + break; + default: + /* Bad permission. */ + fi->type = ARMFault_Permission; + fi->level = 1; + return true; + } + *prot |= PAGE_EXEC; + return false; +} + /** * get_phys_addr - get the physical address for this virtual address * diff --git a/target/arm/ptw.h b/target/arm/ptw.h index 349b842d3c..324a9dde14 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -33,10 +33,6 @@ simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap) return simple_ap_to_rw_prot_is_user(ap, regime_is_user(env, mmu_idx)); } -bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, int *prot, - ARMMMUFaultInfo *fi); bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, int *prot, From 7d2e08c96077bcf7ed31b6b7c7b7066801b4b89d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:49 +0100 Subject: [PATCH 865/935] target/arm: Move get_phys_addr_pmsav7_default to ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-7-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 41 ----------------------------------------- target/arm/ptw.c | 41 +++++++++++++++++++++++++++++++++++++++++ target/arm/ptw.h | 3 +++ 3 files changed, 44 insertions(+), 41 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 5d01019010..d4f7c05625 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -11678,47 +11678,6 @@ do_fault: return true; } -static inline void get_phys_addr_pmsav7_default(CPUARMState *env, - ARMMMUIdx mmu_idx, - int32_t address, int *prot) -{ - if (!arm_feature(env, ARM_FEATURE_M)) { - *prot = PAGE_READ | PAGE_WRITE; - switch (address) { - case 0xF0000000 ... 0xFFFFFFFF: - if (regime_sctlr(env, mmu_idx) & SCTLR_V) { - /* hivecs execing is ok */ - *prot |= PAGE_EXEC; - } - break; - case 0x00000000 ... 0x7FFFFFFF: - *prot |= PAGE_EXEC; - break; - } - } else { - /* Default system address map for M profile cores. - * The architecture specifies which regions are execute-never; - * at the MPU level no other checks are defined. - */ - switch (address) { - case 0x00000000 ... 0x1fffffff: /* ROM */ - case 0x20000000 ... 0x3fffffff: /* SRAM */ - case 0x60000000 ... 0x7fffffff: /* RAM */ - case 0x80000000 ... 0x9fffffff: /* RAM */ - *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - break; - case 0x40000000 ... 0x5fffffff: /* Peripheral */ - case 0xa0000000 ... 0xbfffffff: /* Device */ - case 0xc0000000 ... 0xdfffffff: /* Device */ - case 0xe0000000 ... 0xffffffff: /* System */ - *prot = PAGE_READ | PAGE_WRITE; - break; - default: - g_assert_not_reached(); - } - } -} - static bool pmsav7_use_background_region(ARMCPU *cpu, ARMMMUIdx mmu_idx, bool is_user) { diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 5c32648a16..74650c6c52 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -374,6 +374,47 @@ static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, return false; } +void get_phys_addr_pmsav7_default(CPUARMState *env, + ARMMMUIdx mmu_idx, + int32_t address, int *prot) +{ + if (!arm_feature(env, ARM_FEATURE_M)) { + *prot = PAGE_READ | PAGE_WRITE; + switch (address) { + case 0xF0000000 ... 0xFFFFFFFF: + if (regime_sctlr(env, mmu_idx) & SCTLR_V) { + /* hivecs execing is ok */ + *prot |= PAGE_EXEC; + } + break; + case 0x00000000 ... 0x7FFFFFFF: + *prot |= PAGE_EXEC; + break; + } + } else { + /* Default system address map for M profile cores. + * The architecture specifies which regions are execute-never; + * at the MPU level no other checks are defined. + */ + switch (address) { + case 0x00000000 ... 0x1fffffff: /* ROM */ + case 0x20000000 ... 0x3fffffff: /* SRAM */ + case 0x60000000 ... 0x7fffffff: /* RAM */ + case 0x80000000 ... 0x9fffffff: /* RAM */ + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + break; + case 0x40000000 ... 0x5fffffff: /* Peripheral */ + case 0xa0000000 ... 0xbfffffff: /* Device */ + case 0xc0000000 ... 0xdfffffff: /* Device */ + case 0xe0000000 ... 0xffffffff: /* System */ + *prot = PAGE_READ | PAGE_WRITE; + break; + default: + g_assert_not_reached(); + } + } +} + /** * get_phys_addr - get the physical address for this virtual address * diff --git a/target/arm/ptw.h b/target/arm/ptw.h index 324a9dde14..d6e3fee152 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -33,6 +33,9 @@ simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap) return simple_ap_to_rw_prot_is_user(ap, regime_is_user(env, mmu_idx)); } +void get_phys_addr_pmsav7_default(CPUARMState *env, + ARMMMUIdx mmu_idx, + int32_t address, int *prot); bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, int *prot, From 1f2e87e5aba133ecf4c85000a61d5d760176dd6c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:49 +0100 Subject: [PATCH 866/935] target/arm: Move get_phys_addr_pmsav7 to ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-8-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 194 +------------------------------------------- target/arm/ptw.c | 190 +++++++++++++++++++++++++++++++++++++++++++ target/arm/ptw.h | 10 +-- 3 files changed, 198 insertions(+), 196 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index d4f7c05625..2ebaf69407 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -11678,8 +11678,7 @@ do_fault: return true; } -static bool pmsav7_use_background_region(ARMCPU *cpu, - ARMMMUIdx mmu_idx, bool is_user) +bool pmsav7_use_background_region(ARMCPU *cpu, ARMMMUIdx mmu_idx, bool is_user) { /* Return true if we should use the default memory map as a * "background" region if there are no hits against any MPU regions. @@ -11698,14 +11697,14 @@ static bool pmsav7_use_background_region(ARMCPU *cpu, } } -static inline bool m_is_ppb_region(CPUARMState *env, uint32_t address) +bool m_is_ppb_region(CPUARMState *env, uint32_t address) { /* True if address is in the M profile PPB region 0xe0000000 - 0xe00fffff */ return arm_feature(env, ARM_FEATURE_M) && extract32(address, 20, 12) == 0xe00; } -static inline bool m_is_system_region(CPUARMState *env, uint32_t address) +bool m_is_system_region(CPUARMState *env, uint32_t address) { /* True if address is in the M profile system region * 0xe0000000 - 0xffffffff @@ -11713,193 +11712,6 @@ static inline bool m_is_system_region(CPUARMState *env, uint32_t address) return arm_feature(env, ARM_FEATURE_M) && extract32(address, 29, 3) == 0x7; } -bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, int *prot, - target_ulong *page_size, - ARMMMUFaultInfo *fi) -{ - ARMCPU *cpu = env_archcpu(env); - int n; - bool is_user = regime_is_user(env, mmu_idx); - - *phys_ptr = address; - *page_size = TARGET_PAGE_SIZE; - *prot = 0; - - if (regime_translation_disabled(env, mmu_idx) || - m_is_ppb_region(env, address)) { - /* MPU disabled or M profile PPB access: use default memory map. - * The other case which uses the default memory map in the - * v7M ARM ARM pseudocode is exception vector reads from the vector - * table. In QEMU those accesses are done in arm_v7m_load_vector(), - * which always does a direct read using address_space_ldl(), rather - * than going via this function, so we don't need to check that here. - */ - get_phys_addr_pmsav7_default(env, mmu_idx, address, prot); - } else { /* MPU enabled */ - for (n = (int)cpu->pmsav7_dregion - 1; n >= 0; n--) { - /* region search */ - uint32_t base = env->pmsav7.drbar[n]; - uint32_t rsize = extract32(env->pmsav7.drsr[n], 1, 5); - uint32_t rmask; - bool srdis = false; - - if (!(env->pmsav7.drsr[n] & 0x1)) { - continue; - } - - if (!rsize) { - qemu_log_mask(LOG_GUEST_ERROR, - "DRSR[%d]: Rsize field cannot be 0\n", n); - continue; - } - rsize++; - rmask = (1ull << rsize) - 1; - - if (base & rmask) { - qemu_log_mask(LOG_GUEST_ERROR, - "DRBAR[%d]: 0x%" PRIx32 " misaligned " - "to DRSR region size, mask = 0x%" PRIx32 "\n", - n, base, rmask); - continue; - } - - if (address < base || address > base + rmask) { - /* - * Address not in this region. We must check whether the - * region covers addresses in the same page as our address. - * In that case we must not report a size that covers the - * whole page for a subsequent hit against a different MPU - * region or the background region, because it would result in - * incorrect TLB hits for subsequent accesses to addresses that - * are in this MPU region. - */ - if (ranges_overlap(base, rmask, - address & TARGET_PAGE_MASK, - TARGET_PAGE_SIZE)) { - *page_size = 1; - } - continue; - } - - /* Region matched */ - - if (rsize >= 8) { /* no subregions for regions < 256 bytes */ - int i, snd; - uint32_t srdis_mask; - - rsize -= 3; /* sub region size (power of 2) */ - snd = ((address - base) >> rsize) & 0x7; - srdis = extract32(env->pmsav7.drsr[n], snd + 8, 1); - - srdis_mask = srdis ? 0x3 : 0x0; - for (i = 2; i <= 8 && rsize < TARGET_PAGE_BITS; i *= 2) { - /* This will check in groups of 2, 4 and then 8, whether - * the subregion bits are consistent. rsize is incremented - * back up to give the region size, considering consistent - * adjacent subregions as one region. Stop testing if rsize - * is already big enough for an entire QEMU page. - */ - int snd_rounded = snd & ~(i - 1); - uint32_t srdis_multi = extract32(env->pmsav7.drsr[n], - snd_rounded + 8, i); - if (srdis_mask ^ srdis_multi) { - break; - } - srdis_mask = (srdis_mask << i) | srdis_mask; - rsize++; - } - } - if (srdis) { - continue; - } - if (rsize < TARGET_PAGE_BITS) { - *page_size = 1 << rsize; - } - break; - } - - if (n == -1) { /* no hits */ - if (!pmsav7_use_background_region(cpu, mmu_idx, is_user)) { - /* background fault */ - fi->type = ARMFault_Background; - return true; - } - get_phys_addr_pmsav7_default(env, mmu_idx, address, prot); - } else { /* a MPU hit! */ - uint32_t ap = extract32(env->pmsav7.dracr[n], 8, 3); - uint32_t xn = extract32(env->pmsav7.dracr[n], 12, 1); - - if (m_is_system_region(env, address)) { - /* System space is always execute never */ - xn = 1; - } - - if (is_user) { /* User mode AP bit decoding */ - switch (ap) { - case 0: - case 1: - case 5: - break; /* no access */ - case 3: - *prot |= PAGE_WRITE; - /* fall through */ - case 2: - case 6: - *prot |= PAGE_READ | PAGE_EXEC; - break; - case 7: - /* for v7M, same as 6; for R profile a reserved value */ - if (arm_feature(env, ARM_FEATURE_M)) { - *prot |= PAGE_READ | PAGE_EXEC; - break; - } - /* fall through */ - default: - qemu_log_mask(LOG_GUEST_ERROR, - "DRACR[%d]: Bad value for AP bits: 0x%" - PRIx32 "\n", n, ap); - } - } else { /* Priv. mode AP bits decoding */ - switch (ap) { - case 0: - break; /* no access */ - case 1: - case 2: - case 3: - *prot |= PAGE_WRITE; - /* fall through */ - case 5: - case 6: - *prot |= PAGE_READ | PAGE_EXEC; - break; - case 7: - /* for v7M, same as 6; for R profile a reserved value */ - if (arm_feature(env, ARM_FEATURE_M)) { - *prot |= PAGE_READ | PAGE_EXEC; - break; - } - /* fall through */ - default: - qemu_log_mask(LOG_GUEST_ERROR, - "DRACR[%d]: Bad value for AP bits: 0x%" - PRIx32 "\n", n, ap); - } - } - - /* execute never */ - if (xn) { - *prot &= ~PAGE_EXEC; - } - } - } - - fi->type = ARMFault_Permission; - fi->level = 1; - return !(*prot & (1 << access_type)); -} - static bool v8m_is_sau_exempt(CPUARMState *env, uint32_t address, MMUAccessType access_type) { diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 74650c6c52..27715dbfa8 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -8,6 +8,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" +#include "qemu/range.h" #include "cpu.h" #include "internals.h" #include "ptw.h" @@ -415,6 +416,195 @@ void get_phys_addr_pmsav7_default(CPUARMState *env, } } +static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, int *prot, + target_ulong *page_size, + ARMMMUFaultInfo *fi) +{ + ARMCPU *cpu = env_archcpu(env); + int n; + bool is_user = regime_is_user(env, mmu_idx); + + *phys_ptr = address; + *page_size = TARGET_PAGE_SIZE; + *prot = 0; + + if (regime_translation_disabled(env, mmu_idx) || + m_is_ppb_region(env, address)) { + /* + * MPU disabled or M profile PPB access: use default memory map. + * The other case which uses the default memory map in the + * v7M ARM ARM pseudocode is exception vector reads from the vector + * table. In QEMU those accesses are done in arm_v7m_load_vector(), + * which always does a direct read using address_space_ldl(), rather + * than going via this function, so we don't need to check that here. + */ + get_phys_addr_pmsav7_default(env, mmu_idx, address, prot); + } else { /* MPU enabled */ + for (n = (int)cpu->pmsav7_dregion - 1; n >= 0; n--) { + /* region search */ + uint32_t base = env->pmsav7.drbar[n]; + uint32_t rsize = extract32(env->pmsav7.drsr[n], 1, 5); + uint32_t rmask; + bool srdis = false; + + if (!(env->pmsav7.drsr[n] & 0x1)) { + continue; + } + + if (!rsize) { + qemu_log_mask(LOG_GUEST_ERROR, + "DRSR[%d]: Rsize field cannot be 0\n", n); + continue; + } + rsize++; + rmask = (1ull << rsize) - 1; + + if (base & rmask) { + qemu_log_mask(LOG_GUEST_ERROR, + "DRBAR[%d]: 0x%" PRIx32 " misaligned " + "to DRSR region size, mask = 0x%" PRIx32 "\n", + n, base, rmask); + continue; + } + + if (address < base || address > base + rmask) { + /* + * Address not in this region. We must check whether the + * region covers addresses in the same page as our address. + * In that case we must not report a size that covers the + * whole page for a subsequent hit against a different MPU + * region or the background region, because it would result in + * incorrect TLB hits for subsequent accesses to addresses that + * are in this MPU region. + */ + if (ranges_overlap(base, rmask, + address & TARGET_PAGE_MASK, + TARGET_PAGE_SIZE)) { + *page_size = 1; + } + continue; + } + + /* Region matched */ + + if (rsize >= 8) { /* no subregions for regions < 256 bytes */ + int i, snd; + uint32_t srdis_mask; + + rsize -= 3; /* sub region size (power of 2) */ + snd = ((address - base) >> rsize) & 0x7; + srdis = extract32(env->pmsav7.drsr[n], snd + 8, 1); + + srdis_mask = srdis ? 0x3 : 0x0; + for (i = 2; i <= 8 && rsize < TARGET_PAGE_BITS; i *= 2) { + /* + * This will check in groups of 2, 4 and then 8, whether + * the subregion bits are consistent. rsize is incremented + * back up to give the region size, considering consistent + * adjacent subregions as one region. Stop testing if rsize + * is already big enough for an entire QEMU page. + */ + int snd_rounded = snd & ~(i - 1); + uint32_t srdis_multi = extract32(env->pmsav7.drsr[n], + snd_rounded + 8, i); + if (srdis_mask ^ srdis_multi) { + break; + } + srdis_mask = (srdis_mask << i) | srdis_mask; + rsize++; + } + } + if (srdis) { + continue; + } + if (rsize < TARGET_PAGE_BITS) { + *page_size = 1 << rsize; + } + break; + } + + if (n == -1) { /* no hits */ + if (!pmsav7_use_background_region(cpu, mmu_idx, is_user)) { + /* background fault */ + fi->type = ARMFault_Background; + return true; + } + get_phys_addr_pmsav7_default(env, mmu_idx, address, prot); + } else { /* a MPU hit! */ + uint32_t ap = extract32(env->pmsav7.dracr[n], 8, 3); + uint32_t xn = extract32(env->pmsav7.dracr[n], 12, 1); + + if (m_is_system_region(env, address)) { + /* System space is always execute never */ + xn = 1; + } + + if (is_user) { /* User mode AP bit decoding */ + switch (ap) { + case 0: + case 1: + case 5: + break; /* no access */ + case 3: + *prot |= PAGE_WRITE; + /* fall through */ + case 2: + case 6: + *prot |= PAGE_READ | PAGE_EXEC; + break; + case 7: + /* for v7M, same as 6; for R profile a reserved value */ + if (arm_feature(env, ARM_FEATURE_M)) { + *prot |= PAGE_READ | PAGE_EXEC; + break; + } + /* fall through */ + default: + qemu_log_mask(LOG_GUEST_ERROR, + "DRACR[%d]: Bad value for AP bits: 0x%" + PRIx32 "\n", n, ap); + } + } else { /* Priv. mode AP bits decoding */ + switch (ap) { + case 0: + break; /* no access */ + case 1: + case 2: + case 3: + *prot |= PAGE_WRITE; + /* fall through */ + case 5: + case 6: + *prot |= PAGE_READ | PAGE_EXEC; + break; + case 7: + /* for v7M, same as 6; for R profile a reserved value */ + if (arm_feature(env, ARM_FEATURE_M)) { + *prot |= PAGE_READ | PAGE_EXEC; + break; + } + /* fall through */ + default: + qemu_log_mask(LOG_GUEST_ERROR, + "DRACR[%d]: Bad value for AP bits: 0x%" + PRIx32 "\n", n, ap); + } + } + + /* execute never */ + if (xn) { + *prot &= ~PAGE_EXEC; + } + } + } + + fi->type = ARMFault_Permission; + fi->level = 1; + return !(*prot & (1 << access_type)); +} + /** * get_phys_addr - get the physical address for this virtual address * diff --git a/target/arm/ptw.h b/target/arm/ptw.h index d6e3fee152..d24b7c263a 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -33,14 +33,14 @@ simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap) return simple_ap_to_rw_prot_is_user(ap, regime_is_user(env, mmu_idx)); } +bool m_is_ppb_region(CPUARMState *env, uint32_t address); +bool m_is_system_region(CPUARMState *env, uint32_t address); + void get_phys_addr_pmsav7_default(CPUARMState *env, ARMMMUIdx mmu_idx, int32_t address, int *prot); -bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, int *prot, - target_ulong *page_size, - ARMMMUFaultInfo *fi); +bool pmsav7_use_background_region(ARMCPU *cpu, ARMMMUIdx mmu_idx, bool is_user); + bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *txattrs, From 730d5c31d8872e94d08877ad62f44cc49bc01c90 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:49 +0100 Subject: [PATCH 867/935] target/arm: Move get_phys_addr_pmsav8 to ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-9-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 75 ------------------------------------------- target/arm/ptw.c | 77 +++++++++++++++++++++++++++++++++++++++++++++ target/arm/ptw.h | 5 --- 3 files changed, 77 insertions(+), 80 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 2ebaf69407..44997fd179 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -11970,81 +11970,6 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, return !(*prot & (1 << access_type)); } - -bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *txattrs, - int *prot, target_ulong *page_size, - ARMMMUFaultInfo *fi) -{ - uint32_t secure = regime_is_secure(env, mmu_idx); - V8M_SAttributes sattrs = {}; - bool ret; - bool mpu_is_subpage; - - if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { - v8m_security_lookup(env, address, access_type, mmu_idx, &sattrs); - if (access_type == MMU_INST_FETCH) { - /* Instruction fetches always use the MMU bank and the - * transaction attribute determined by the fetch address, - * regardless of CPU state. This is painful for QEMU - * to handle, because it would mean we need to encode - * into the mmu_idx not just the (user, negpri) information - * for the current security state but also that for the - * other security state, which would balloon the number - * of mmu_idx values needed alarmingly. - * Fortunately we can avoid this because it's not actually - * possible to arbitrarily execute code from memory with - * the wrong security attribute: it will always generate - * an exception of some kind or another, apart from the - * special case of an NS CPU executing an SG instruction - * in S&NSC memory. So we always just fail the translation - * here and sort things out in the exception handler - * (including possibly emulating an SG instruction). - */ - if (sattrs.ns != !secure) { - if (sattrs.nsc) { - fi->type = ARMFault_QEMU_NSCExec; - } else { - fi->type = ARMFault_QEMU_SFault; - } - *page_size = sattrs.subpage ? 1 : TARGET_PAGE_SIZE; - *phys_ptr = address; - *prot = 0; - return true; - } - } else { - /* For data accesses we always use the MMU bank indicated - * by the current CPU state, but the security attributes - * might downgrade a secure access to nonsecure. - */ - if (sattrs.ns) { - txattrs->secure = false; - } else if (!secure) { - /* NS access to S memory must fault. - * Architecturally we should first check whether the - * MPU information for this address indicates that we - * are doing an unaligned access to Device memory, which - * should generate a UsageFault instead. QEMU does not - * currently check for that kind of unaligned access though. - * If we added it we would need to do so as a special case - * for M_FAKE_FSR_SFAULT in arm_v7m_cpu_do_interrupt(). - */ - fi->type = ARMFault_QEMU_SFault; - *page_size = sattrs.subpage ? 1 : TARGET_PAGE_SIZE; - *phys_ptr = address; - *prot = 0; - return true; - } - } - } - - ret = pmsav8_mpu_lookup(env, address, access_type, mmu_idx, phys_ptr, - txattrs, prot, &mpu_is_subpage, fi, NULL); - *page_size = sattrs.subpage || mpu_is_subpage ? 1 : TARGET_PAGE_SIZE; - return ret; -} - /* Combine either inner or outer cacheability attributes for normal * memory, according to table D4-42 and pseudocode procedure * CombineS1S2AttrHints() of ARM DDI 0487B.b (the ARMv8 ARM). diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 27715dbfa8..28caa7a7ae 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -605,6 +605,83 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, return !(*prot & (1 << access_type)); } +static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, MemTxAttrs *txattrs, + int *prot, target_ulong *page_size, + ARMMMUFaultInfo *fi) +{ + uint32_t secure = regime_is_secure(env, mmu_idx); + V8M_SAttributes sattrs = {}; + bool ret; + bool mpu_is_subpage; + + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { + v8m_security_lookup(env, address, access_type, mmu_idx, &sattrs); + if (access_type == MMU_INST_FETCH) { + /* + * Instruction fetches always use the MMU bank and the + * transaction attribute determined by the fetch address, + * regardless of CPU state. This is painful for QEMU + * to handle, because it would mean we need to encode + * into the mmu_idx not just the (user, negpri) information + * for the current security state but also that for the + * other security state, which would balloon the number + * of mmu_idx values needed alarmingly. + * Fortunately we can avoid this because it's not actually + * possible to arbitrarily execute code from memory with + * the wrong security attribute: it will always generate + * an exception of some kind or another, apart from the + * special case of an NS CPU executing an SG instruction + * in S&NSC memory. So we always just fail the translation + * here and sort things out in the exception handler + * (including possibly emulating an SG instruction). + */ + if (sattrs.ns != !secure) { + if (sattrs.nsc) { + fi->type = ARMFault_QEMU_NSCExec; + } else { + fi->type = ARMFault_QEMU_SFault; + } + *page_size = sattrs.subpage ? 1 : TARGET_PAGE_SIZE; + *phys_ptr = address; + *prot = 0; + return true; + } + } else { + /* + * For data accesses we always use the MMU bank indicated + * by the current CPU state, but the security attributes + * might downgrade a secure access to nonsecure. + */ + if (sattrs.ns) { + txattrs->secure = false; + } else if (!secure) { + /* + * NS access to S memory must fault. + * Architecturally we should first check whether the + * MPU information for this address indicates that we + * are doing an unaligned access to Device memory, which + * should generate a UsageFault instead. QEMU does not + * currently check for that kind of unaligned access though. + * If we added it we would need to do so as a special case + * for M_FAKE_FSR_SFAULT in arm_v7m_cpu_do_interrupt(). + */ + fi->type = ARMFault_QEMU_SFault; + *page_size = sattrs.subpage ? 1 : TARGET_PAGE_SIZE; + *phys_ptr = address; + *prot = 0; + return true; + } + } + } + + ret = pmsav8_mpu_lookup(env, address, access_type, mmu_idx, phys_ptr, + txattrs, prot, &mpu_is_subpage, fi, NULL); + *page_size = sattrs.subpage || mpu_is_subpage ? 1 : TARGET_PAGE_SIZE; + return ret; +} + /** * get_phys_addr - get the physical address for this virtual address * diff --git a/target/arm/ptw.h b/target/arm/ptw.h index d24b7c263a..d569507951 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -41,11 +41,6 @@ void get_phys_addr_pmsav7_default(CPUARMState *env, int32_t address, int *prot); bool pmsav7_use_background_region(ARMCPU *cpu, ARMMMUIdx mmu_idx, bool is_user); -bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *txattrs, - int *prot, target_ulong *page_size, - ARMMMUFaultInfo *fi); bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, bool s1_is_el0, From fedbaa0503d2c56d4ef58ca9a08121e2af7f5e54 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:50 +0100 Subject: [PATCH 868/935] target/arm: Move pmsav8_mpu_lookup to ptw.c This is the final user of get_phys_addr_pmsav7_default within helper.c, so make it static within ptw.c. Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-10-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 136 ----------------------------------------- target/arm/ptw.c | 146 +++++++++++++++++++++++++++++++++++++++++++- target/arm/ptw.h | 3 - 3 files changed, 143 insertions(+), 142 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 44997fd179..cb23413d8e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -11834,142 +11834,6 @@ void v8m_security_lookup(CPUARMState *env, uint32_t address, } } -bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *txattrs, - int *prot, bool *is_subpage, - ARMMMUFaultInfo *fi, uint32_t *mregion) -{ - /* Perform a PMSAv8 MPU lookup (without also doing the SAU check - * that a full phys-to-virt translation does). - * mregion is (if not NULL) set to the region number which matched, - * or -1 if no region number is returned (MPU off, address did not - * hit a region, address hit in multiple regions). - * We set is_subpage to true if the region hit doesn't cover the - * entire TARGET_PAGE the address is within. - */ - ARMCPU *cpu = env_archcpu(env); - bool is_user = regime_is_user(env, mmu_idx); - uint32_t secure = regime_is_secure(env, mmu_idx); - int n; - int matchregion = -1; - bool hit = false; - uint32_t addr_page_base = address & TARGET_PAGE_MASK; - uint32_t addr_page_limit = addr_page_base + (TARGET_PAGE_SIZE - 1); - - *is_subpage = false; - *phys_ptr = address; - *prot = 0; - if (mregion) { - *mregion = -1; - } - - /* Unlike the ARM ARM pseudocode, we don't need to check whether this - * was an exception vector read from the vector table (which is always - * done using the default system address map), because those accesses - * are done in arm_v7m_load_vector(), which always does a direct - * read using address_space_ldl(), rather than going via this function. - */ - if (regime_translation_disabled(env, mmu_idx)) { /* MPU disabled */ - hit = true; - } else if (m_is_ppb_region(env, address)) { - hit = true; - } else { - if (pmsav7_use_background_region(cpu, mmu_idx, is_user)) { - hit = true; - } - - for (n = (int)cpu->pmsav7_dregion - 1; n >= 0; n--) { - /* region search */ - /* Note that the base address is bits [31:5] from the register - * with bits [4:0] all zeroes, but the limit address is bits - * [31:5] from the register with bits [4:0] all ones. - */ - uint32_t base = env->pmsav8.rbar[secure][n] & ~0x1f; - uint32_t limit = env->pmsav8.rlar[secure][n] | 0x1f; - - if (!(env->pmsav8.rlar[secure][n] & 0x1)) { - /* Region disabled */ - continue; - } - - if (address < base || address > limit) { - /* - * Address not in this region. We must check whether the - * region covers addresses in the same page as our address. - * In that case we must not report a size that covers the - * whole page for a subsequent hit against a different MPU - * region or the background region, because it would result in - * incorrect TLB hits for subsequent accesses to addresses that - * are in this MPU region. - */ - if (limit >= base && - ranges_overlap(base, limit - base + 1, - addr_page_base, - TARGET_PAGE_SIZE)) { - *is_subpage = true; - } - continue; - } - - if (base > addr_page_base || limit < addr_page_limit) { - *is_subpage = true; - } - - if (matchregion != -1) { - /* Multiple regions match -- always a failure (unlike - * PMSAv7 where highest-numbered-region wins) - */ - fi->type = ARMFault_Permission; - fi->level = 1; - return true; - } - - matchregion = n; - hit = true; - } - } - - if (!hit) { - /* background fault */ - fi->type = ARMFault_Background; - return true; - } - - if (matchregion == -1) { - /* hit using the background region */ - get_phys_addr_pmsav7_default(env, mmu_idx, address, prot); - } else { - uint32_t ap = extract32(env->pmsav8.rbar[secure][matchregion], 1, 2); - uint32_t xn = extract32(env->pmsav8.rbar[secure][matchregion], 0, 1); - bool pxn = false; - - if (arm_feature(env, ARM_FEATURE_V8_1M)) { - pxn = extract32(env->pmsav8.rlar[secure][matchregion], 4, 1); - } - - if (m_is_system_region(env, address)) { - /* System space is always execute never */ - xn = 1; - } - - *prot = simple_ap_to_rw_prot(env, mmu_idx, ap); - if (*prot && !xn && !(pxn && !is_user)) { - *prot |= PAGE_EXEC; - } - /* We don't need to look the attribute up in the MAIR0/MAIR1 - * registers because that only tells us about cacheability. - */ - if (mregion) { - *mregion = matchregion; - } - } - - fi->type = ARMFault_Permission; - fi->level = 1; - return !(*prot & (1 << access_type)); -} - /* Combine either inner or outer cacheability attributes for normal * memory, according to table D4-42 and pseudocode procedure * CombineS1S2AttrHints() of ARM DDI 0487B.b (the ARMv8 ARM). diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 28caa7a7ae..989e783cce 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -375,9 +375,8 @@ static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, return false; } -void get_phys_addr_pmsav7_default(CPUARMState *env, - ARMMMUIdx mmu_idx, - int32_t address, int *prot) +static void get_phys_addr_pmsav7_default(CPUARMState *env, ARMMMUIdx mmu_idx, + int32_t address, int *prot) { if (!arm_feature(env, ARM_FEATURE_M)) { *prot = PAGE_READ | PAGE_WRITE; @@ -605,6 +604,147 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, return !(*prot & (1 << access_type)); } +bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, MemTxAttrs *txattrs, + int *prot, bool *is_subpage, + ARMMMUFaultInfo *fi, uint32_t *mregion) +{ + /* + * Perform a PMSAv8 MPU lookup (without also doing the SAU check + * that a full phys-to-virt translation does). + * mregion is (if not NULL) set to the region number which matched, + * or -1 if no region number is returned (MPU off, address did not + * hit a region, address hit in multiple regions). + * We set is_subpage to true if the region hit doesn't cover the + * entire TARGET_PAGE the address is within. + */ + ARMCPU *cpu = env_archcpu(env); + bool is_user = regime_is_user(env, mmu_idx); + uint32_t secure = regime_is_secure(env, mmu_idx); + int n; + int matchregion = -1; + bool hit = false; + uint32_t addr_page_base = address & TARGET_PAGE_MASK; + uint32_t addr_page_limit = addr_page_base + (TARGET_PAGE_SIZE - 1); + + *is_subpage = false; + *phys_ptr = address; + *prot = 0; + if (mregion) { + *mregion = -1; + } + + /* + * Unlike the ARM ARM pseudocode, we don't need to check whether this + * was an exception vector read from the vector table (which is always + * done using the default system address map), because those accesses + * are done in arm_v7m_load_vector(), which always does a direct + * read using address_space_ldl(), rather than going via this function. + */ + if (regime_translation_disabled(env, mmu_idx)) { /* MPU disabled */ + hit = true; + } else if (m_is_ppb_region(env, address)) { + hit = true; + } else { + if (pmsav7_use_background_region(cpu, mmu_idx, is_user)) { + hit = true; + } + + for (n = (int)cpu->pmsav7_dregion - 1; n >= 0; n--) { + /* region search */ + /* + * Note that the base address is bits [31:5] from the register + * with bits [4:0] all zeroes, but the limit address is bits + * [31:5] from the register with bits [4:0] all ones. + */ + uint32_t base = env->pmsav8.rbar[secure][n] & ~0x1f; + uint32_t limit = env->pmsav8.rlar[secure][n] | 0x1f; + + if (!(env->pmsav8.rlar[secure][n] & 0x1)) { + /* Region disabled */ + continue; + } + + if (address < base || address > limit) { + /* + * Address not in this region. We must check whether the + * region covers addresses in the same page as our address. + * In that case we must not report a size that covers the + * whole page for a subsequent hit against a different MPU + * region or the background region, because it would result in + * incorrect TLB hits for subsequent accesses to addresses that + * are in this MPU region. + */ + if (limit >= base && + ranges_overlap(base, limit - base + 1, + addr_page_base, + TARGET_PAGE_SIZE)) { + *is_subpage = true; + } + continue; + } + + if (base > addr_page_base || limit < addr_page_limit) { + *is_subpage = true; + } + + if (matchregion != -1) { + /* + * Multiple regions match -- always a failure (unlike + * PMSAv7 where highest-numbered-region wins) + */ + fi->type = ARMFault_Permission; + fi->level = 1; + return true; + } + + matchregion = n; + hit = true; + } + } + + if (!hit) { + /* background fault */ + fi->type = ARMFault_Background; + return true; + } + + if (matchregion == -1) { + /* hit using the background region */ + get_phys_addr_pmsav7_default(env, mmu_idx, address, prot); + } else { + uint32_t ap = extract32(env->pmsav8.rbar[secure][matchregion], 1, 2); + uint32_t xn = extract32(env->pmsav8.rbar[secure][matchregion], 0, 1); + bool pxn = false; + + if (arm_feature(env, ARM_FEATURE_V8_1M)) { + pxn = extract32(env->pmsav8.rlar[secure][matchregion], 4, 1); + } + + if (m_is_system_region(env, address)) { + /* System space is always execute never */ + xn = 1; + } + + *prot = simple_ap_to_rw_prot(env, mmu_idx, ap); + if (*prot && !xn && !(pxn && !is_user)) { + *prot |= PAGE_EXEC; + } + /* + * We don't need to look the attribute up in the MAIR0/MAIR1 + * registers because that only tells us about cacheability. + */ + if (mregion) { + *mregion = matchregion; + } + } + + fi->type = ARMFault_Permission; + fi->level = 1; + return !(*prot & (1 << access_type)); +} + static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *txattrs, diff --git a/target/arm/ptw.h b/target/arm/ptw.h index d569507951..8d2e239714 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -36,9 +36,6 @@ simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap) bool m_is_ppb_region(CPUARMState *env, uint32_t address); bool m_is_system_region(CPUARMState *env, uint32_t address); -void get_phys_addr_pmsav7_default(CPUARMState *env, - ARMMMUIdx mmu_idx, - int32_t address, int *prot); bool pmsav7_use_background_region(ARMCPU *cpu, ARMMMUIdx mmu_idx, bool is_user); bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, From c8e436c9f72bca95e37a155d6ead42d55f74eed2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:50 +0100 Subject: [PATCH 869/935] target/arm: Move pmsav7_use_background_region to ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-11-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 19 ------------------- target/arm/ptw.c | 21 +++++++++++++++++++++ target/arm/ptw.h | 2 -- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index cb23413d8e..62e48f0925 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -11678,25 +11678,6 @@ do_fault: return true; } -bool pmsav7_use_background_region(ARMCPU *cpu, ARMMMUIdx mmu_idx, bool is_user) -{ - /* Return true if we should use the default memory map as a - * "background" region if there are no hits against any MPU regions. - */ - CPUARMState *env = &cpu->env; - - if (is_user) { - return false; - } - - if (arm_feature(env, ARM_FEATURE_M)) { - return env->v7m.mpu_ctrl[regime_is_secure(env, mmu_idx)] - & R_V7M_MPU_CTRL_PRIVDEFENA_MASK; - } else { - return regime_sctlr(env, mmu_idx) & SCTLR_BR; - } -} - bool m_is_ppb_region(CPUARMState *env, uint32_t address) { /* True if address is in the M profile PPB region 0xe0000000 - 0xe00fffff */ diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 989e783cce..b82638b5a0 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -415,6 +415,27 @@ static void get_phys_addr_pmsav7_default(CPUARMState *env, ARMMMUIdx mmu_idx, } } +static bool pmsav7_use_background_region(ARMCPU *cpu, ARMMMUIdx mmu_idx, + bool is_user) +{ + /* + * Return true if we should use the default memory map as a + * "background" region if there are no hits against any MPU regions. + */ + CPUARMState *env = &cpu->env; + + if (is_user) { + return false; + } + + if (arm_feature(env, ARM_FEATURE_M)) { + return env->v7m.mpu_ctrl[regime_is_secure(env, mmu_idx)] + & R_V7M_MPU_CTRL_PRIVDEFENA_MASK; + } else { + return regime_sctlr(env, mmu_idx) & SCTLR_BR; + } +} + static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, int *prot, diff --git a/target/arm/ptw.h b/target/arm/ptw.h index 8d2e239714..d2d2711908 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -36,8 +36,6 @@ simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap) bool m_is_ppb_region(CPUARMState *env, uint32_t address); bool m_is_system_region(CPUARMState *env, uint32_t address); -bool pmsav7_use_background_region(ARMCPU *cpu, ARMMMUIdx mmu_idx, bool is_user); - bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, bool s1_is_el0, From 2c1f429df38822ce6955224d784f1567f8af219f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:50 +0100 Subject: [PATCH 870/935] target/arm: Move v8m_security_lookup to ptw.c This function has one private helper, v8m_is_sau_exempt, so move that at the same time. Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-12-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 123 ------------------------------------------ target/arm/ptw.c | 126 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 123 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 62e48f0925..d6a749ad0e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -9,7 +9,6 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qemu/log.h" -#include "target/arm/idau.h" #include "trace.h" #include "cpu.h" #include "internals.h" @@ -11693,128 +11692,6 @@ bool m_is_system_region(CPUARMState *env, uint32_t address) return arm_feature(env, ARM_FEATURE_M) && extract32(address, 29, 3) == 0x7; } -static bool v8m_is_sau_exempt(CPUARMState *env, - uint32_t address, MMUAccessType access_type) -{ - /* The architecture specifies that certain address ranges are - * exempt from v8M SAU/IDAU checks. - */ - return - (access_type == MMU_INST_FETCH && m_is_system_region(env, address)) || - (address >= 0xe0000000 && address <= 0xe0002fff) || - (address >= 0xe000e000 && address <= 0xe000efff) || - (address >= 0xe002e000 && address <= 0xe002efff) || - (address >= 0xe0040000 && address <= 0xe0041fff) || - (address >= 0xe00ff000 && address <= 0xe00fffff); -} - -void v8m_security_lookup(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - V8M_SAttributes *sattrs) -{ - /* Look up the security attributes for this address. Compare the - * pseudocode SecurityCheck() function. - * We assume the caller has zero-initialized *sattrs. - */ - ARMCPU *cpu = env_archcpu(env); - int r; - bool idau_exempt = false, idau_ns = true, idau_nsc = true; - int idau_region = IREGION_NOTVALID; - uint32_t addr_page_base = address & TARGET_PAGE_MASK; - uint32_t addr_page_limit = addr_page_base + (TARGET_PAGE_SIZE - 1); - - if (cpu->idau) { - IDAUInterfaceClass *iic = IDAU_INTERFACE_GET_CLASS(cpu->idau); - IDAUInterface *ii = IDAU_INTERFACE(cpu->idau); - - iic->check(ii, address, &idau_region, &idau_exempt, &idau_ns, - &idau_nsc); - } - - if (access_type == MMU_INST_FETCH && extract32(address, 28, 4) == 0xf) { - /* 0xf0000000..0xffffffff is always S for insn fetches */ - return; - } - - if (idau_exempt || v8m_is_sau_exempt(env, address, access_type)) { - sattrs->ns = !regime_is_secure(env, mmu_idx); - return; - } - - if (idau_region != IREGION_NOTVALID) { - sattrs->irvalid = true; - sattrs->iregion = idau_region; - } - - switch (env->sau.ctrl & 3) { - case 0: /* SAU.ENABLE == 0, SAU.ALLNS == 0 */ - break; - case 2: /* SAU.ENABLE == 0, SAU.ALLNS == 1 */ - sattrs->ns = true; - break; - default: /* SAU.ENABLE == 1 */ - for (r = 0; r < cpu->sau_sregion; r++) { - if (env->sau.rlar[r] & 1) { - uint32_t base = env->sau.rbar[r] & ~0x1f; - uint32_t limit = env->sau.rlar[r] | 0x1f; - - if (base <= address && limit >= address) { - if (base > addr_page_base || limit < addr_page_limit) { - sattrs->subpage = true; - } - if (sattrs->srvalid) { - /* If we hit in more than one region then we must report - * as Secure, not NS-Callable, with no valid region - * number info. - */ - sattrs->ns = false; - sattrs->nsc = false; - sattrs->sregion = 0; - sattrs->srvalid = false; - break; - } else { - if (env->sau.rlar[r] & 2) { - sattrs->nsc = true; - } else { - sattrs->ns = true; - } - sattrs->srvalid = true; - sattrs->sregion = r; - } - } else { - /* - * Address not in this region. We must check whether the - * region covers addresses in the same page as our address. - * In that case we must not report a size that covers the - * whole page for a subsequent hit against a different MPU - * region or the background region, because it would result - * in incorrect TLB hits for subsequent accesses to - * addresses that are in this MPU region. - */ - if (limit >= base && - ranges_overlap(base, limit - base + 1, - addr_page_base, - TARGET_PAGE_SIZE)) { - sattrs->subpage = true; - } - } - } - } - break; - } - - /* - * The IDAU will override the SAU lookup results if it specifies - * higher security than the SAU does. - */ - if (!idau_ns) { - if (sattrs->ns || (!idau_nsc && sattrs->nsc)) { - sattrs->ns = false; - sattrs->nsc = idau_nsc; - } - } -} - /* Combine either inner or outer cacheability attributes for normal * memory, according to table D4-42 and pseudocode procedure * CombineS1S2AttrHints() of ARM DDI 0487B.b (the ARMv8 ARM). diff --git a/target/arm/ptw.c b/target/arm/ptw.c index b82638b5a0..c15fba43c3 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -11,6 +11,7 @@ #include "qemu/range.h" #include "cpu.h" #include "internals.h" +#include "idau.h" #include "ptw.h" @@ -766,6 +767,131 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, return !(*prot & (1 << access_type)); } +static bool v8m_is_sau_exempt(CPUARMState *env, + uint32_t address, MMUAccessType access_type) +{ + /* + * The architecture specifies that certain address ranges are + * exempt from v8M SAU/IDAU checks. + */ + return + (access_type == MMU_INST_FETCH && m_is_system_region(env, address)) || + (address >= 0xe0000000 && address <= 0xe0002fff) || + (address >= 0xe000e000 && address <= 0xe000efff) || + (address >= 0xe002e000 && address <= 0xe002efff) || + (address >= 0xe0040000 && address <= 0xe0041fff) || + (address >= 0xe00ff000 && address <= 0xe00fffff); +} + +void v8m_security_lookup(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + V8M_SAttributes *sattrs) +{ + /* + * Look up the security attributes for this address. Compare the + * pseudocode SecurityCheck() function. + * We assume the caller has zero-initialized *sattrs. + */ + ARMCPU *cpu = env_archcpu(env); + int r; + bool idau_exempt = false, idau_ns = true, idau_nsc = true; + int idau_region = IREGION_NOTVALID; + uint32_t addr_page_base = address & TARGET_PAGE_MASK; + uint32_t addr_page_limit = addr_page_base + (TARGET_PAGE_SIZE - 1); + + if (cpu->idau) { + IDAUInterfaceClass *iic = IDAU_INTERFACE_GET_CLASS(cpu->idau); + IDAUInterface *ii = IDAU_INTERFACE(cpu->idau); + + iic->check(ii, address, &idau_region, &idau_exempt, &idau_ns, + &idau_nsc); + } + + if (access_type == MMU_INST_FETCH && extract32(address, 28, 4) == 0xf) { + /* 0xf0000000..0xffffffff is always S for insn fetches */ + return; + } + + if (idau_exempt || v8m_is_sau_exempt(env, address, access_type)) { + sattrs->ns = !regime_is_secure(env, mmu_idx); + return; + } + + if (idau_region != IREGION_NOTVALID) { + sattrs->irvalid = true; + sattrs->iregion = idau_region; + } + + switch (env->sau.ctrl & 3) { + case 0: /* SAU.ENABLE == 0, SAU.ALLNS == 0 */ + break; + case 2: /* SAU.ENABLE == 0, SAU.ALLNS == 1 */ + sattrs->ns = true; + break; + default: /* SAU.ENABLE == 1 */ + for (r = 0; r < cpu->sau_sregion; r++) { + if (env->sau.rlar[r] & 1) { + uint32_t base = env->sau.rbar[r] & ~0x1f; + uint32_t limit = env->sau.rlar[r] | 0x1f; + + if (base <= address && limit >= address) { + if (base > addr_page_base || limit < addr_page_limit) { + sattrs->subpage = true; + } + if (sattrs->srvalid) { + /* + * If we hit in more than one region then we must report + * as Secure, not NS-Callable, with no valid region + * number info. + */ + sattrs->ns = false; + sattrs->nsc = false; + sattrs->sregion = 0; + sattrs->srvalid = false; + break; + } else { + if (env->sau.rlar[r] & 2) { + sattrs->nsc = true; + } else { + sattrs->ns = true; + } + sattrs->srvalid = true; + sattrs->sregion = r; + } + } else { + /* + * Address not in this region. We must check whether the + * region covers addresses in the same page as our address. + * In that case we must not report a size that covers the + * whole page for a subsequent hit against a different MPU + * region or the background region, because it would result + * in incorrect TLB hits for subsequent accesses to + * addresses that are in this MPU region. + */ + if (limit >= base && + ranges_overlap(base, limit - base + 1, + addr_page_base, + TARGET_PAGE_SIZE)) { + sattrs->subpage = true; + } + } + } + } + break; + } + + /* + * The IDAU will override the SAU lookup results if it specifies + * higher security than the SAU does. + */ + if (!idau_ns) { + if (sattrs->ns || (!idau_nsc && sattrs->nsc)) { + sattrs->ns = false; + sattrs->nsc = idau_nsc; + } + } +} + static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *txattrs, From 47ff5ba9d08c2c769794a59b88f1c19ada004730 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:50 +0100 Subject: [PATCH 871/935] target/arm: Move m_is_{ppb,system}_region to ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-13-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 15 --------------- target/arm/ptw.c | 16 ++++++++++++++++ target/arm/ptw.h | 3 --- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index d6a749ad0e..d2ef12346b 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -11677,21 +11677,6 @@ do_fault: return true; } -bool m_is_ppb_region(CPUARMState *env, uint32_t address) -{ - /* True if address is in the M profile PPB region 0xe0000000 - 0xe00fffff */ - return arm_feature(env, ARM_FEATURE_M) && - extract32(address, 20, 12) == 0xe00; -} - -bool m_is_system_region(CPUARMState *env, uint32_t address) -{ - /* True if address is in the M profile system region - * 0xe0000000 - 0xffffffff - */ - return arm_feature(env, ARM_FEATURE_M) && extract32(address, 29, 3) == 0x7; -} - /* Combine either inner or outer cacheability attributes for normal * memory, according to table D4-42 and pseudocode procedure * CombineS1S2AttrHints() of ARM DDI 0487B.b (the ARMv8 ARM). diff --git a/target/arm/ptw.c b/target/arm/ptw.c index c15fba43c3..32ba2e5e8b 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -416,6 +416,22 @@ static void get_phys_addr_pmsav7_default(CPUARMState *env, ARMMMUIdx mmu_idx, } } +static bool m_is_ppb_region(CPUARMState *env, uint32_t address) +{ + /* True if address is in the M profile PPB region 0xe0000000 - 0xe00fffff */ + return arm_feature(env, ARM_FEATURE_M) && + extract32(address, 20, 12) == 0xe00; +} + +static bool m_is_system_region(CPUARMState *env, uint32_t address) +{ + /* + * True if address is in the M profile system region + * 0xe0000000 - 0xffffffff + */ + return arm_feature(env, ARM_FEATURE_M) && extract32(address, 29, 3) == 0x7; +} + static bool pmsav7_use_background_region(ARMCPU *cpu, ARMMMUIdx mmu_idx, bool is_user) { diff --git a/target/arm/ptw.h b/target/arm/ptw.h index d2d2711908..6c47a57599 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -33,9 +33,6 @@ simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap) return simple_ap_to_rw_prot_is_user(ap, regime_is_user(env, mmu_idx)); } -bool m_is_ppb_region(CPUARMState *env, uint32_t address); -bool m_is_system_region(CPUARMState *env, uint32_t address); - bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, bool s1_is_el0, From 4c74ab157b056710b043a02c8101c449c179ae11 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:51 +0100 Subject: [PATCH 872/935] target/arm: Move get_level1_table_address to ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-14-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 26 +------------------------- target/arm/ptw.c | 23 +++++++++++++++++++++++ target/arm/ptw.h | 4 ++-- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index d2ef12346b..a144cb2641 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10482,8 +10482,7 @@ static inline bool regime_translation_big_endian(CPUARMState *env, } /* Return the TTBR associated with this translation regime */ -static inline uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, - int ttbrn) +uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, int ttbrn) { if (mmu_idx == ARMMMUIdx_Stage2) { return env->cp15.vttbr_el2; @@ -10774,29 +10773,6 @@ static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, return prot_rw | PAGE_EXEC; } -bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, - uint32_t *table, uint32_t address) -{ - /* Note that we can only get here for an AArch32 PL0/PL1 lookup */ - TCR *tcr = regime_tcr(env, mmu_idx); - - if (address & tcr->mask) { - if (tcr->raw_tcr & TTBCR_PD1) { - /* Translation table walk disabled for TTBR1 */ - return false; - } - *table = regime_ttbr(env, mmu_idx, 1) & 0xffffc000; - } else { - if (tcr->raw_tcr & TTBCR_PD0) { - /* Translation table walk disabled for TTBR0 */ - return false; - } - *table = regime_ttbr(env, mmu_idx, 0) & tcr->base_mask; - } - *table |= (address >> 18) & 0x3ffc; - return true; -} - static bool ptw_attrs_are_device(CPUARMState *env, ARMCacheAttrs cacheattrs) { /* diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 32ba2e5e8b..5737a3976b 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -15,6 +15,29 @@ #include "ptw.h" +static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, + uint32_t *table, uint32_t address) +{ + /* Note that we can only get here for an AArch32 PL0/PL1 lookup */ + TCR *tcr = regime_tcr(env, mmu_idx); + + if (address & tcr->mask) { + if (tcr->raw_tcr & TTBCR_PD1) { + /* Translation table walk disabled for TTBR1 */ + return false; + } + *table = regime_ttbr(env, mmu_idx, 1) & 0xffffc000; + } else { + if (tcr->raw_tcr & TTBCR_PD0) { + /* Translation table walk disabled for TTBR0 */ + return false; + } + *table = regime_ttbr(env, mmu_idx, 0) & tcr->base_mask; + } + *table |= (address >> 18) & 0x3ffc; + return true; +} + static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, int *prot, diff --git a/target/arm/ptw.h b/target/arm/ptw.h index 6c47a57599..dd6fb93f33 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -18,11 +18,11 @@ uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx); bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx); +uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, int ttbrn); + ARMCacheAttrs combine_cacheattrs(CPUARMState *env, ARMCacheAttrs s1, ARMCacheAttrs s2); -bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, - uint32_t *table, uint32_t address); int ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap, int domain_prot); int simple_ap_to_rw_prot_is_user(int ap, bool is_user); From 966f4bb7d88554ed74e1006c516ddeef37e523d6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:51 +0100 Subject: [PATCH 873/935] target/arm: Move combine_cacheattrs and subroutines to ptw.c There are a handful of helpers for combine_cacheattrs that we can move at the same time as the main entry point. Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-15-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 218 ------------------------------------------- target/arm/ptw.c | 221 ++++++++++++++++++++++++++++++++++++++++++++ target/arm/ptw.h | 3 - 3 files changed, 221 insertions(+), 221 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index a144cb2641..dab485e64a 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10977,36 +10977,6 @@ static bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level, } return true; } - -/* Translate from the 4-bit stage 2 representation of - * memory attributes (without cache-allocation hints) to - * the 8-bit representation of the stage 1 MAIR registers - * (which includes allocation hints). - * - * ref: shared/translation/attrs/S2AttrDecode() - * .../S2ConvertAttrsHints() - */ -static uint8_t convert_stage2_attrs(CPUARMState *env, uint8_t s2attrs) -{ - uint8_t hiattr = extract32(s2attrs, 2, 2); - uint8_t loattr = extract32(s2attrs, 0, 2); - uint8_t hihint = 0, lohint = 0; - - if (hiattr != 0) { /* normal memory */ - if (arm_hcr_el2_eff(env) & HCR_CD) { /* cache disabled */ - hiattr = loattr = 1; /* non-cacheable */ - } else { - if (hiattr != 1) { /* Write-through or write-back */ - hihint = 3; /* RW allocate */ - } - if (loattr != 1) { /* Write-through or write-back */ - lohint = 3; /* RW allocate */ - } - } - } - - return (hiattr << 6) | (hihint << 4) | (loattr << 2) | lohint; -} #endif /* !CONFIG_USER_ONLY */ /* This mapping is common between ID_AA64MMFR0.PARANGE and TCR_ELx.{I}PS. */ @@ -11653,194 +11623,6 @@ do_fault: return true; } -/* Combine either inner or outer cacheability attributes for normal - * memory, according to table D4-42 and pseudocode procedure - * CombineS1S2AttrHints() of ARM DDI 0487B.b (the ARMv8 ARM). - * - * NB: only stage 1 includes allocation hints (RW bits), leading to - * some asymmetry. - */ -static uint8_t combine_cacheattr_nibble(uint8_t s1, uint8_t s2) -{ - if (s1 == 4 || s2 == 4) { - /* non-cacheable has precedence */ - return 4; - } else if (extract32(s1, 2, 2) == 0 || extract32(s1, 2, 2) == 2) { - /* stage 1 write-through takes precedence */ - return s1; - } else if (extract32(s2, 2, 2) == 2) { - /* stage 2 write-through takes precedence, but the allocation hint - * is still taken from stage 1 - */ - return (2 << 2) | extract32(s1, 0, 2); - } else { /* write-back */ - return s1; - } -} - -/* - * Combine the memory type and cacheability attributes of - * s1 and s2 for the HCR_EL2.FWB == 0 case, returning the - * combined attributes in MAIR_EL1 format. - */ -static uint8_t combined_attrs_nofwb(CPUARMState *env, - ARMCacheAttrs s1, ARMCacheAttrs s2) -{ - uint8_t s1lo, s2lo, s1hi, s2hi, s2_mair_attrs, ret_attrs; - - s2_mair_attrs = convert_stage2_attrs(env, s2.attrs); - - s1lo = extract32(s1.attrs, 0, 4); - s2lo = extract32(s2_mair_attrs, 0, 4); - s1hi = extract32(s1.attrs, 4, 4); - s2hi = extract32(s2_mair_attrs, 4, 4); - - /* Combine memory type and cacheability attributes */ - if (s1hi == 0 || s2hi == 0) { - /* Device has precedence over normal */ - if (s1lo == 0 || s2lo == 0) { - /* nGnRnE has precedence over anything */ - ret_attrs = 0; - } else if (s1lo == 4 || s2lo == 4) { - /* non-Reordering has precedence over Reordering */ - ret_attrs = 4; /* nGnRE */ - } else if (s1lo == 8 || s2lo == 8) { - /* non-Gathering has precedence over Gathering */ - ret_attrs = 8; /* nGRE */ - } else { - ret_attrs = 0xc; /* GRE */ - } - } else { /* Normal memory */ - /* Outer/inner cacheability combine independently */ - ret_attrs = combine_cacheattr_nibble(s1hi, s2hi) << 4 - | combine_cacheattr_nibble(s1lo, s2lo); - } - return ret_attrs; -} - -static uint8_t force_cacheattr_nibble_wb(uint8_t attr) -{ - /* - * Given the 4 bits specifying the outer or inner cacheability - * in MAIR format, return a value specifying Normal Write-Back, - * with the allocation and transient hints taken from the input - * if the input specified some kind of cacheable attribute. - */ - if (attr == 0 || attr == 4) { - /* - * 0 == an UNPREDICTABLE encoding - * 4 == Non-cacheable - * Either way, force Write-Back RW allocate non-transient - */ - return 0xf; - } - /* Change WriteThrough to WriteBack, keep allocation and transient hints */ - return attr | 4; -} - -/* - * Combine the memory type and cacheability attributes of - * s1 and s2 for the HCR_EL2.FWB == 1 case, returning the - * combined attributes in MAIR_EL1 format. - */ -static uint8_t combined_attrs_fwb(CPUARMState *env, - ARMCacheAttrs s1, ARMCacheAttrs s2) -{ - switch (s2.attrs) { - case 7: - /* Use stage 1 attributes */ - return s1.attrs; - case 6: - /* - * Force Normal Write-Back. Note that if S1 is Normal cacheable - * then we take the allocation hints from it; otherwise it is - * RW allocate, non-transient. - */ - if ((s1.attrs & 0xf0) == 0) { - /* S1 is Device */ - return 0xff; - } - /* Need to check the Inner and Outer nibbles separately */ - return force_cacheattr_nibble_wb(s1.attrs & 0xf) | - force_cacheattr_nibble_wb(s1.attrs >> 4) << 4; - case 5: - /* If S1 attrs are Device, use them; otherwise Normal Non-cacheable */ - if ((s1.attrs & 0xf0) == 0) { - return s1.attrs; - } - return 0x44; - case 0 ... 3: - /* Force Device, of subtype specified by S2 */ - return s2.attrs << 2; - default: - /* - * RESERVED values (including RES0 descriptor bit [5] being nonzero); - * arbitrarily force Device. - */ - return 0; - } -} - -/* Combine S1 and S2 cacheability/shareability attributes, per D4.5.4 - * and CombineS1S2Desc() - * - * @env: CPUARMState - * @s1: Attributes from stage 1 walk - * @s2: Attributes from stage 2 walk - */ -ARMCacheAttrs combine_cacheattrs(CPUARMState *env, - ARMCacheAttrs s1, ARMCacheAttrs s2) -{ - ARMCacheAttrs ret; - bool tagged = false; - - assert(s2.is_s2_format && !s1.is_s2_format); - ret.is_s2_format = false; - - if (s1.attrs == 0xf0) { - tagged = true; - s1.attrs = 0xff; - } - - /* Combine shareability attributes (table D4-43) */ - if (s1.shareability == 2 || s2.shareability == 2) { - /* if either are outer-shareable, the result is outer-shareable */ - ret.shareability = 2; - } else if (s1.shareability == 3 || s2.shareability == 3) { - /* if either are inner-shareable, the result is inner-shareable */ - ret.shareability = 3; - } else { - /* both non-shareable */ - ret.shareability = 0; - } - - /* Combine memory type and cacheability attributes */ - if (arm_hcr_el2_eff(env) & HCR_FWB) { - ret.attrs = combined_attrs_fwb(env, s1, s2); - } else { - ret.attrs = combined_attrs_nofwb(env, s1, s2); - } - - /* - * Any location for which the resultant memory type is any - * type of Device memory is always treated as Outer Shareable. - * Any location for which the resultant memory type is Normal - * Inner Non-cacheable, Outer Non-cacheable is always treated - * as Outer Shareable. - * TODO: FEAT_XS adds another value (0x40) also meaning iNCoNC - */ - if ((ret.attrs & 0xf0) == 0 || ret.attrs == 0x44) { - ret.shareability = 2; - } - - /* TODO: CombineS1S2Desc does not consider transient, only WB, RWA. */ - if (tagged && ret.attrs == 0xff) { - ret.attrs = 0xf0; - } - - return ret; -} - hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, MemTxAttrs *attrs) { diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 5737a3976b..f2ca2bb8fe 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -1008,6 +1008,227 @@ static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, return ret; } +/* + * Translate from the 4-bit stage 2 representation of + * memory attributes (without cache-allocation hints) to + * the 8-bit representation of the stage 1 MAIR registers + * (which includes allocation hints). + * + * ref: shared/translation/attrs/S2AttrDecode() + * .../S2ConvertAttrsHints() + */ +static uint8_t convert_stage2_attrs(CPUARMState *env, uint8_t s2attrs) +{ + uint8_t hiattr = extract32(s2attrs, 2, 2); + uint8_t loattr = extract32(s2attrs, 0, 2); + uint8_t hihint = 0, lohint = 0; + + if (hiattr != 0) { /* normal memory */ + if (arm_hcr_el2_eff(env) & HCR_CD) { /* cache disabled */ + hiattr = loattr = 1; /* non-cacheable */ + } else { + if (hiattr != 1) { /* Write-through or write-back */ + hihint = 3; /* RW allocate */ + } + if (loattr != 1) { /* Write-through or write-back */ + lohint = 3; /* RW allocate */ + } + } + } + + return (hiattr << 6) | (hihint << 4) | (loattr << 2) | lohint; +} + +/* + * Combine either inner or outer cacheability attributes for normal + * memory, according to table D4-42 and pseudocode procedure + * CombineS1S2AttrHints() of ARM DDI 0487B.b (the ARMv8 ARM). + * + * NB: only stage 1 includes allocation hints (RW bits), leading to + * some asymmetry. + */ +static uint8_t combine_cacheattr_nibble(uint8_t s1, uint8_t s2) +{ + if (s1 == 4 || s2 == 4) { + /* non-cacheable has precedence */ + return 4; + } else if (extract32(s1, 2, 2) == 0 || extract32(s1, 2, 2) == 2) { + /* stage 1 write-through takes precedence */ + return s1; + } else if (extract32(s2, 2, 2) == 2) { + /* stage 2 write-through takes precedence, but the allocation hint + * is still taken from stage 1 + */ + return (2 << 2) | extract32(s1, 0, 2); + } else { /* write-back */ + return s1; + } +} + +/* + * Combine the memory type and cacheability attributes of + * s1 and s2 for the HCR_EL2.FWB == 0 case, returning the + * combined attributes in MAIR_EL1 format. + */ +static uint8_t combined_attrs_nofwb(CPUARMState *env, + ARMCacheAttrs s1, ARMCacheAttrs s2) +{ + uint8_t s1lo, s2lo, s1hi, s2hi, s2_mair_attrs, ret_attrs; + + s2_mair_attrs = convert_stage2_attrs(env, s2.attrs); + + s1lo = extract32(s1.attrs, 0, 4); + s2lo = extract32(s2_mair_attrs, 0, 4); + s1hi = extract32(s1.attrs, 4, 4); + s2hi = extract32(s2_mair_attrs, 4, 4); + + /* Combine memory type and cacheability attributes */ + if (s1hi == 0 || s2hi == 0) { + /* Device has precedence over normal */ + if (s1lo == 0 || s2lo == 0) { + /* nGnRnE has precedence over anything */ + ret_attrs = 0; + } else if (s1lo == 4 || s2lo == 4) { + /* non-Reordering has precedence over Reordering */ + ret_attrs = 4; /* nGnRE */ + } else if (s1lo == 8 || s2lo == 8) { + /* non-Gathering has precedence over Gathering */ + ret_attrs = 8; /* nGRE */ + } else { + ret_attrs = 0xc; /* GRE */ + } + } else { /* Normal memory */ + /* Outer/inner cacheability combine independently */ + ret_attrs = combine_cacheattr_nibble(s1hi, s2hi) << 4 + | combine_cacheattr_nibble(s1lo, s2lo); + } + return ret_attrs; +} + +static uint8_t force_cacheattr_nibble_wb(uint8_t attr) +{ + /* + * Given the 4 bits specifying the outer or inner cacheability + * in MAIR format, return a value specifying Normal Write-Back, + * with the allocation and transient hints taken from the input + * if the input specified some kind of cacheable attribute. + */ + if (attr == 0 || attr == 4) { + /* + * 0 == an UNPREDICTABLE encoding + * 4 == Non-cacheable + * Either way, force Write-Back RW allocate non-transient + */ + return 0xf; + } + /* Change WriteThrough to WriteBack, keep allocation and transient hints */ + return attr | 4; +} + +/* + * Combine the memory type and cacheability attributes of + * s1 and s2 for the HCR_EL2.FWB == 1 case, returning the + * combined attributes in MAIR_EL1 format. + */ +static uint8_t combined_attrs_fwb(CPUARMState *env, + ARMCacheAttrs s1, ARMCacheAttrs s2) +{ + switch (s2.attrs) { + case 7: + /* Use stage 1 attributes */ + return s1.attrs; + case 6: + /* + * Force Normal Write-Back. Note that if S1 is Normal cacheable + * then we take the allocation hints from it; otherwise it is + * RW allocate, non-transient. + */ + if ((s1.attrs & 0xf0) == 0) { + /* S1 is Device */ + return 0xff; + } + /* Need to check the Inner and Outer nibbles separately */ + return force_cacheattr_nibble_wb(s1.attrs & 0xf) | + force_cacheattr_nibble_wb(s1.attrs >> 4) << 4; + case 5: + /* If S1 attrs are Device, use them; otherwise Normal Non-cacheable */ + if ((s1.attrs & 0xf0) == 0) { + return s1.attrs; + } + return 0x44; + case 0 ... 3: + /* Force Device, of subtype specified by S2 */ + return s2.attrs << 2; + default: + /* + * RESERVED values (including RES0 descriptor bit [5] being nonzero); + * arbitrarily force Device. + */ + return 0; + } +} + +/* + * Combine S1 and S2 cacheability/shareability attributes, per D4.5.4 + * and CombineS1S2Desc() + * + * @env: CPUARMState + * @s1: Attributes from stage 1 walk + * @s2: Attributes from stage 2 walk + */ +static ARMCacheAttrs combine_cacheattrs(CPUARMState *env, + ARMCacheAttrs s1, ARMCacheAttrs s2) +{ + ARMCacheAttrs ret; + bool tagged = false; + + assert(s2.is_s2_format && !s1.is_s2_format); + ret.is_s2_format = false; + + if (s1.attrs == 0xf0) { + tagged = true; + s1.attrs = 0xff; + } + + /* Combine shareability attributes (table D4-43) */ + if (s1.shareability == 2 || s2.shareability == 2) { + /* if either are outer-shareable, the result is outer-shareable */ + ret.shareability = 2; + } else if (s1.shareability == 3 || s2.shareability == 3) { + /* if either are inner-shareable, the result is inner-shareable */ + ret.shareability = 3; + } else { + /* both non-shareable */ + ret.shareability = 0; + } + + /* Combine memory type and cacheability attributes */ + if (arm_hcr_el2_eff(env) & HCR_FWB) { + ret.attrs = combined_attrs_fwb(env, s1, s2); + } else { + ret.attrs = combined_attrs_nofwb(env, s1, s2); + } + + /* + * Any location for which the resultant memory type is any + * type of Device memory is always treated as Outer Shareable. + * Any location for which the resultant memory type is Normal + * Inner Non-cacheable, Outer Non-cacheable is always treated + * as Outer Shareable. + * TODO: FEAT_XS adds another value (0x40) also meaning iNCoNC + */ + if ((ret.attrs & 0xf0) == 0 || ret.attrs == 0x44) { + ret.shareability = 2; + } + + /* TODO: CombineS1S2Desc does not consider transient, only WB, RWA. */ + if (tagged && ret.attrs == 0xff) { + ret.attrs = 0xf0; + } + + return ret; +} + /** * get_phys_addr - get the physical address for this virtual address * diff --git a/target/arm/ptw.h b/target/arm/ptw.h index dd6fb93f33..b2dfe489bb 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -20,9 +20,6 @@ bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx); bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx); uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, int ttbrn); -ARMCacheAttrs combine_cacheattrs(CPUARMState *env, - ARMCacheAttrs s1, ARMCacheAttrs s2); - int ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap, int domain_prot); int simple_ap_to_rw_prot_is_user(int ap, bool is_user); From 3283222acd7579cdbc338360fa6e611027f3c8dc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:51 +0100 Subject: [PATCH 874/935] target/arm: Move get_phys_addr_lpae to ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-16-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 416 +------------------------------------------- target/arm/ptw.c | 411 +++++++++++++++++++++++++++++++++++++++++++ target/arm/ptw.h | 10 ++ 3 files changed, 429 insertions(+), 408 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index dab485e64a..7de815fe98 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10652,7 +10652,7 @@ int simple_ap_to_rw_prot_is_user(int ap, bool is_user) * @xn: XN (execute-never) bits * @s1_is_el0: true if this is S2 of an S1+2 walk for EL0 */ -static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0) +int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0) { int prot = 0; @@ -10703,8 +10703,8 @@ static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0) * @xn: XN (execute-never) bit * @pxn: PXN (privileged execute-never) bit */ -static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, - int ap, int ns, int xn, int pxn) +int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, + int ap, int ns, int xn, int pxn) { bool is_user = regime_is_user(env, mmu_idx); int prot_rw, user_rw; @@ -10919,8 +10919,8 @@ uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, * Returns true if the suggested S2 translation parameters are OK and * false otherwise. */ -static bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level, - int inputsize, int stride, int outputsize) +bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level, + int inputsize, int stride, int outputsize) { const int grainsize = stride + 3; int startsizecheck; @@ -10980,7 +10980,7 @@ static bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level, #endif /* !CONFIG_USER_ONLY */ /* This mapping is common between ID_AA64MMFR0.PARANGE and TCR_ELx.{I}PS. */ -static const uint8_t pamax_map[] = { +const uint8_t pamax_map[] = { [0] = 32, [1] = 36, [2] = 40, @@ -11159,8 +11159,8 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, } #ifndef CONFIG_USER_ONLY -static ARMVAParameters aa32_va_parameters(CPUARMState *env, uint32_t va, - ARMMMUIdx mmu_idx) +ARMVAParameters aa32_va_parameters(CPUARMState *env, uint32_t va, + ARMMMUIdx mmu_idx) { uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr; uint32_t el = regime_el(env, mmu_idx); @@ -11223,406 +11223,6 @@ static ARMVAParameters aa32_va_parameters(CPUARMState *env, uint32_t va, }; } -/** - * get_phys_addr_lpae: perform one stage of page table walk, LPAE format - * - * Returns false if the translation was successful. Otherwise, phys_ptr, attrs, - * prot and page_size may not be filled in, and the populated fsr value provides - * information on why the translation aborted, in the format of a long-format - * DFSR/IFSR fault register, with the following caveats: - * * the WnR bit is never set (the caller must do this). - * - * @env: CPUARMState - * @address: virtual address to get physical address for - * @access_type: MMU_DATA_LOAD, MMU_DATA_STORE or MMU_INST_FETCH - * @mmu_idx: MMU index indicating required translation regime - * @s1_is_el0: if @mmu_idx is ARMMMUIdx_Stage2 (so this is a stage 2 page table - * walk), must be true if this is stage 2 of a stage 1+2 walk for an - * EL0 access). If @mmu_idx is anything else, @s1_is_el0 is ignored. - * @phys_ptr: set to the physical address corresponding to the virtual address - * @attrs: set to the memory transaction attributes to use - * @prot: set to the permissions for the page containing phys_ptr - * @page_size_ptr: set to the size of the page containing phys_ptr - * @fi: set to fault info if the translation fails - * @cacheattrs: (if non-NULL) set to the cacheability/shareability attributes - */ -bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - bool s1_is_el0, - hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, - target_ulong *page_size_ptr, - ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) -{ - ARMCPU *cpu = env_archcpu(env); - CPUState *cs = CPU(cpu); - /* Read an LPAE long-descriptor translation table. */ - ARMFaultType fault_type = ARMFault_Translation; - uint32_t level; - ARMVAParameters param; - uint64_t ttbr; - hwaddr descaddr, indexmask, indexmask_grainsize; - uint32_t tableattrs; - target_ulong page_size; - uint32_t attrs; - int32_t stride; - int addrsize, inputsize, outputsize; - TCR *tcr = regime_tcr(env, mmu_idx); - int ap, ns, xn, pxn; - uint32_t el = regime_el(env, mmu_idx); - uint64_t descaddrmask; - bool aarch64 = arm_el_is_aa64(env, el); - bool guarded = false; - - /* TODO: This code does not support shareability levels. */ - if (aarch64) { - int ps; - - param = aa64_va_parameters(env, address, mmu_idx, - access_type != MMU_INST_FETCH); - level = 0; - - /* - * If TxSZ is programmed to a value larger than the maximum, - * or smaller than the effective minimum, it is IMPLEMENTATION - * DEFINED whether we behave as if the field were programmed - * within bounds, or if a level 0 Translation fault is generated. - * - * With FEAT_LVA, fault on less than minimum becomes required, - * so our choice is to always raise the fault. - */ - if (param.tsz_oob) { - fault_type = ARMFault_Translation; - goto do_fault; - } - - addrsize = 64 - 8 * param.tbi; - inputsize = 64 - param.tsz; - - /* - * Bound PS by PARANGE to find the effective output address size. - * ID_AA64MMFR0 is a read-only register so values outside of the - * supported mappings can be considered an implementation error. - */ - ps = FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE); - ps = MIN(ps, param.ps); - assert(ps < ARRAY_SIZE(pamax_map)); - outputsize = pamax_map[ps]; - } else { - param = aa32_va_parameters(env, address, mmu_idx); - level = 1; - addrsize = (mmu_idx == ARMMMUIdx_Stage2 ? 40 : 32); - inputsize = addrsize - param.tsz; - outputsize = 40; - } - - /* - * We determined the region when collecting the parameters, but we - * have not yet validated that the address is valid for the region. - * Extract the top bits and verify that they all match select. - * - * For aa32, if inputsize == addrsize, then we have selected the - * region by exclusion in aa32_va_parameters and there is no more - * validation to do here. - */ - if (inputsize < addrsize) { - target_ulong top_bits = sextract64(address, inputsize, - addrsize - inputsize); - if (-top_bits != param.select) { - /* The gap between the two regions is a Translation fault */ - fault_type = ARMFault_Translation; - goto do_fault; - } - } - - if (param.using64k) { - stride = 13; - } else if (param.using16k) { - stride = 11; - } else { - stride = 9; - } - - /* Note that QEMU ignores shareability and cacheability attributes, - * so we don't need to do anything with the SH, ORGN, IRGN fields - * in the TTBCR. Similarly, TTBCR:A1 selects whether we get the - * ASID from TTBR0 or TTBR1, but QEMU's TLB doesn't currently - * implement any ASID-like capability so we can ignore it (instead - * we will always flush the TLB any time the ASID is changed). - */ - ttbr = regime_ttbr(env, mmu_idx, param.select); - - /* Here we should have set up all the parameters for the translation: - * inputsize, ttbr, epd, stride, tbi - */ - - if (param.epd) { - /* Translation table walk disabled => Translation fault on TLB miss - * Note: This is always 0 on 64-bit EL2 and EL3. - */ - goto do_fault; - } - - if (mmu_idx != ARMMMUIdx_Stage2 && mmu_idx != ARMMMUIdx_Stage2_S) { - /* The starting level depends on the virtual address size (which can - * be up to 48 bits) and the translation granule size. It indicates - * the number of strides (stride bits at a time) needed to - * consume the bits of the input address. In the pseudocode this is: - * level = 4 - RoundUp((inputsize - grainsize) / stride) - * where their 'inputsize' is our 'inputsize', 'grainsize' is - * our 'stride + 3' and 'stride' is our 'stride'. - * Applying the usual "rounded up m/n is (m+n-1)/n" and simplifying: - * = 4 - (inputsize - stride - 3 + stride - 1) / stride - * = 4 - (inputsize - 4) / stride; - */ - level = 4 - (inputsize - 4) / stride; - } else { - /* For stage 2 translations the starting level is specified by the - * VTCR_EL2.SL0 field (whose interpretation depends on the page size) - */ - uint32_t sl0 = extract32(tcr->raw_tcr, 6, 2); - uint32_t sl2 = extract64(tcr->raw_tcr, 33, 1); - uint32_t startlevel; - bool ok; - - /* SL2 is RES0 unless DS=1 & 4kb granule. */ - if (param.ds && stride == 9 && sl2) { - if (sl0 != 0) { - level = 0; - fault_type = ARMFault_Translation; - goto do_fault; - } - startlevel = -1; - } else if (!aarch64 || stride == 9) { - /* AArch32 or 4KB pages */ - startlevel = 2 - sl0; - - if (cpu_isar_feature(aa64_st, cpu)) { - startlevel &= 3; - } - } else { - /* 16KB or 64KB pages */ - startlevel = 3 - sl0; - } - - /* Check that the starting level is valid. */ - ok = check_s2_mmu_setup(cpu, aarch64, startlevel, - inputsize, stride, outputsize); - if (!ok) { - fault_type = ARMFault_Translation; - goto do_fault; - } - level = startlevel; - } - - indexmask_grainsize = MAKE_64BIT_MASK(0, stride + 3); - indexmask = MAKE_64BIT_MASK(0, inputsize - (stride * (4 - level))); - - /* Now we can extract the actual base address from the TTBR */ - descaddr = extract64(ttbr, 0, 48); - - /* - * For FEAT_LPA and PS=6, bits [51:48] of descaddr are in [5:2] of TTBR. - * - * Otherwise, if the base address is out of range, raise AddressSizeFault. - * In the pseudocode, this is !IsZero(baseregister<47:outputsize>), - * but we've just cleared the bits above 47, so simplify the test. - */ - if (outputsize > 48) { - descaddr |= extract64(ttbr, 2, 4) << 48; - } else if (descaddr >> outputsize) { - level = 0; - fault_type = ARMFault_AddressSize; - goto do_fault; - } - - /* - * We rely on this masking to clear the RES0 bits at the bottom of the TTBR - * and also to mask out CnP (bit 0) which could validly be non-zero. - */ - descaddr &= ~indexmask; - - /* - * For AArch32, the address field in the descriptor goes up to bit 39 - * for both v7 and v8. However, for v8 the SBZ bits [47:40] must be 0 - * or an AddressSize fault is raised. So for v8 we extract those SBZ - * bits as part of the address, which will be checked via outputsize. - * For AArch64, the address field goes up to bit 47, or 49 with FEAT_LPA2; - * the highest bits of a 52-bit output are placed elsewhere. - */ - if (param.ds) { - descaddrmask = MAKE_64BIT_MASK(0, 50); - } else if (arm_feature(env, ARM_FEATURE_V8)) { - descaddrmask = MAKE_64BIT_MASK(0, 48); - } else { - descaddrmask = MAKE_64BIT_MASK(0, 40); - } - descaddrmask &= ~indexmask_grainsize; - - /* Secure accesses start with the page table in secure memory and - * can be downgraded to non-secure at any step. Non-secure accesses - * remain non-secure. We implement this by just ORing in the NSTable/NS - * bits at each step. - */ - tableattrs = regime_is_secure(env, mmu_idx) ? 0 : (1 << 4); - for (;;) { - uint64_t descriptor; - bool nstable; - - descaddr |= (address >> (stride * (4 - level))) & indexmask; - descaddr &= ~7ULL; - nstable = extract32(tableattrs, 4, 1); - descriptor = arm_ldq_ptw(cs, descaddr, !nstable, mmu_idx, fi); - if (fi->type != ARMFault_None) { - goto do_fault; - } - - if (!(descriptor & 1) || - (!(descriptor & 2) && (level == 3))) { - /* Invalid, or the Reserved level 3 encoding */ - goto do_fault; - } - - descaddr = descriptor & descaddrmask; - - /* - * For FEAT_LPA and PS=6, bits [51:48] of descaddr are in [15:12] - * of descriptor. For FEAT_LPA2 and effective DS, bits [51:50] of - * descaddr are in [9:8]. Otherwise, if descaddr is out of range, - * raise AddressSizeFault. - */ - if (outputsize > 48) { - if (param.ds) { - descaddr |= extract64(descriptor, 8, 2) << 50; - } else { - descaddr |= extract64(descriptor, 12, 4) << 48; - } - } else if (descaddr >> outputsize) { - fault_type = ARMFault_AddressSize; - goto do_fault; - } - - if ((descriptor & 2) && (level < 3)) { - /* Table entry. The top five bits are attributes which may - * propagate down through lower levels of the table (and - * which are all arranged so that 0 means "no effect", so - * we can gather them up by ORing in the bits at each level). - */ - tableattrs |= extract64(descriptor, 59, 5); - level++; - indexmask = indexmask_grainsize; - continue; - } - /* - * Block entry at level 1 or 2, or page entry at level 3. - * These are basically the same thing, although the number - * of bits we pull in from the vaddr varies. Note that although - * descaddrmask masks enough of the low bits of the descriptor - * to give a correct page or table address, the address field - * in a block descriptor is smaller; so we need to explicitly - * clear the lower bits here before ORing in the low vaddr bits. - */ - page_size = (1ULL << ((stride * (4 - level)) + 3)); - descaddr &= ~(page_size - 1); - descaddr |= (address & (page_size - 1)); - /* Extract attributes from the descriptor */ - attrs = extract64(descriptor, 2, 10) - | (extract64(descriptor, 52, 12) << 10); - - if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) { - /* Stage 2 table descriptors do not include any attribute fields */ - break; - } - /* Merge in attributes from table descriptors */ - attrs |= nstable << 3; /* NS */ - guarded = extract64(descriptor, 50, 1); /* GP */ - if (param.hpd) { - /* HPD disables all the table attributes except NSTable. */ - break; - } - attrs |= extract32(tableattrs, 0, 2) << 11; /* XN, PXN */ - /* The sense of AP[1] vs APTable[0] is reversed, as APTable[0] == 1 - * means "force PL1 access only", which means forcing AP[1] to 0. - */ - attrs &= ~(extract32(tableattrs, 2, 1) << 4); /* !APT[0] => AP[1] */ - attrs |= extract32(tableattrs, 3, 1) << 5; /* APT[1] => AP[2] */ - break; - } - /* Here descaddr is the final physical address, and attributes - * are all in attrs. - */ - fault_type = ARMFault_AccessFlag; - if ((attrs & (1 << 8)) == 0) { - /* Access flag */ - goto do_fault; - } - - ap = extract32(attrs, 4, 2); - - if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) { - ns = mmu_idx == ARMMMUIdx_Stage2; - xn = extract32(attrs, 11, 2); - *prot = get_S2prot(env, ap, xn, s1_is_el0); - } else { - ns = extract32(attrs, 3, 1); - xn = extract32(attrs, 12, 1); - pxn = extract32(attrs, 11, 1); - *prot = get_S1prot(env, mmu_idx, aarch64, ap, ns, xn, pxn); - } - - fault_type = ARMFault_Permission; - if (!(*prot & (1 << access_type))) { - goto do_fault; - } - - if (ns) { - /* The NS bit will (as required by the architecture) have no effect if - * the CPU doesn't support TZ or this is a non-secure translation - * regime, because the attribute will already be non-secure. - */ - txattrs->secure = false; - } - /* When in aarch64 mode, and BTI is enabled, remember GP in the IOTLB. */ - if (aarch64 && guarded && cpu_isar_feature(aa64_bti, cpu)) { - arm_tlb_bti_gp(txattrs) = true; - } - - if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) { - cacheattrs->is_s2_format = true; - cacheattrs->attrs = extract32(attrs, 0, 4); - } else { - /* Index into MAIR registers for cache attributes */ - uint8_t attrindx = extract32(attrs, 0, 3); - uint64_t mair = env->cp15.mair_el[regime_el(env, mmu_idx)]; - assert(attrindx <= 7); - cacheattrs->is_s2_format = false; - cacheattrs->attrs = extract64(mair, attrindx * 8, 8); - } - - /* - * For FEAT_LPA2 and effective DS, the SH field in the attributes - * was re-purposed for output address bits. The SH attribute in - * that case comes from TCR_ELx, which we extracted earlier. - */ - if (param.ds) { - cacheattrs->shareability = param.sh; - } else { - cacheattrs->shareability = extract32(attrs, 6, 2); - } - - *phys_ptr = descaddr; - *page_size_ptr = page_size; - return false; - -do_fault: - fi->type = fault_type; - fi->level = level; - /* Tag the error as S2 for failed S1 PTW at S2 or ordinary S2. */ - fi->stage2 = fi->s1ptw || (mmu_idx == ARMMMUIdx_Stage2 || - mmu_idx == ARMMMUIdx_Stage2_S); - fi->s1ns = mmu_idx == ARMMMUIdx_Stage2; - return true; -} - hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, MemTxAttrs *attrs) { diff --git a/target/arm/ptw.c b/target/arm/ptw.c index f2ca2bb8fe..cbccf91b13 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -314,6 +314,417 @@ do_fault: return true; } +/** + * get_phys_addr_lpae: perform one stage of page table walk, LPAE format + * + * Returns false if the translation was successful. Otherwise, phys_ptr, + * attrs, prot and page_size may not be filled in, and the populated fsr + * value provides information on why the translation aborted, in the format + * of a long-format DFSR/IFSR fault register, with the following caveat: + * the WnR bit is never set (the caller must do this). + * + * @env: CPUARMState + * @address: virtual address to get physical address for + * @access_type: MMU_DATA_LOAD, MMU_DATA_STORE or MMU_INST_FETCH + * @mmu_idx: MMU index indicating required translation regime + * @s1_is_el0: if @mmu_idx is ARMMMUIdx_Stage2 (so this is a stage 2 page + * table walk), must be true if this is stage 2 of a stage 1+2 + * walk for an EL0 access. If @mmu_idx is anything else, + * @s1_is_el0 is ignored. + * @phys_ptr: set to the physical address corresponding to the virtual address + * @attrs: set to the memory transaction attributes to use + * @prot: set to the permissions for the page containing phys_ptr + * @page_size_ptr: set to the size of the page containing phys_ptr + * @fi: set to fault info if the translation fails + * @cacheattrs: (if non-NULL) set to the cacheability/shareability attributes + */ +bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + bool s1_is_el0, + hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, + target_ulong *page_size_ptr, + ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) +{ + ARMCPU *cpu = env_archcpu(env); + CPUState *cs = CPU(cpu); + /* Read an LPAE long-descriptor translation table. */ + ARMFaultType fault_type = ARMFault_Translation; + uint32_t level; + ARMVAParameters param; + uint64_t ttbr; + hwaddr descaddr, indexmask, indexmask_grainsize; + uint32_t tableattrs; + target_ulong page_size; + uint32_t attrs; + int32_t stride; + int addrsize, inputsize, outputsize; + TCR *tcr = regime_tcr(env, mmu_idx); + int ap, ns, xn, pxn; + uint32_t el = regime_el(env, mmu_idx); + uint64_t descaddrmask; + bool aarch64 = arm_el_is_aa64(env, el); + bool guarded = false; + + /* TODO: This code does not support shareability levels. */ + if (aarch64) { + int ps; + + param = aa64_va_parameters(env, address, mmu_idx, + access_type != MMU_INST_FETCH); + level = 0; + + /* + * If TxSZ is programmed to a value larger than the maximum, + * or smaller than the effective minimum, it is IMPLEMENTATION + * DEFINED whether we behave as if the field were programmed + * within bounds, or if a level 0 Translation fault is generated. + * + * With FEAT_LVA, fault on less than minimum becomes required, + * so our choice is to always raise the fault. + */ + if (param.tsz_oob) { + fault_type = ARMFault_Translation; + goto do_fault; + } + + addrsize = 64 - 8 * param.tbi; + inputsize = 64 - param.tsz; + + /* + * Bound PS by PARANGE to find the effective output address size. + * ID_AA64MMFR0 is a read-only register so values outside of the + * supported mappings can be considered an implementation error. + */ + ps = FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE); + ps = MIN(ps, param.ps); + assert(ps < ARRAY_SIZE(pamax_map)); + outputsize = pamax_map[ps]; + } else { + param = aa32_va_parameters(env, address, mmu_idx); + level = 1; + addrsize = (mmu_idx == ARMMMUIdx_Stage2 ? 40 : 32); + inputsize = addrsize - param.tsz; + outputsize = 40; + } + + /* + * We determined the region when collecting the parameters, but we + * have not yet validated that the address is valid for the region. + * Extract the top bits and verify that they all match select. + * + * For aa32, if inputsize == addrsize, then we have selected the + * region by exclusion in aa32_va_parameters and there is no more + * validation to do here. + */ + if (inputsize < addrsize) { + target_ulong top_bits = sextract64(address, inputsize, + addrsize - inputsize); + if (-top_bits != param.select) { + /* The gap between the two regions is a Translation fault */ + fault_type = ARMFault_Translation; + goto do_fault; + } + } + + if (param.using64k) { + stride = 13; + } else if (param.using16k) { + stride = 11; + } else { + stride = 9; + } + + /* + * Note that QEMU ignores shareability and cacheability attributes, + * so we don't need to do anything with the SH, ORGN, IRGN fields + * in the TTBCR. Similarly, TTBCR:A1 selects whether we get the + * ASID from TTBR0 or TTBR1, but QEMU's TLB doesn't currently + * implement any ASID-like capability so we can ignore it (instead + * we will always flush the TLB any time the ASID is changed). + */ + ttbr = regime_ttbr(env, mmu_idx, param.select); + + /* + * Here we should have set up all the parameters for the translation: + * inputsize, ttbr, epd, stride, tbi + */ + + if (param.epd) { + /* + * Translation table walk disabled => Translation fault on TLB miss + * Note: This is always 0 on 64-bit EL2 and EL3. + */ + goto do_fault; + } + + if (mmu_idx != ARMMMUIdx_Stage2 && mmu_idx != ARMMMUIdx_Stage2_S) { + /* + * The starting level depends on the virtual address size (which can + * be up to 48 bits) and the translation granule size. It indicates + * the number of strides (stride bits at a time) needed to + * consume the bits of the input address. In the pseudocode this is: + * level = 4 - RoundUp((inputsize - grainsize) / stride) + * where their 'inputsize' is our 'inputsize', 'grainsize' is + * our 'stride + 3' and 'stride' is our 'stride'. + * Applying the usual "rounded up m/n is (m+n-1)/n" and simplifying: + * = 4 - (inputsize - stride - 3 + stride - 1) / stride + * = 4 - (inputsize - 4) / stride; + */ + level = 4 - (inputsize - 4) / stride; + } else { + /* + * For stage 2 translations the starting level is specified by the + * VTCR_EL2.SL0 field (whose interpretation depends on the page size) + */ + uint32_t sl0 = extract32(tcr->raw_tcr, 6, 2); + uint32_t sl2 = extract64(tcr->raw_tcr, 33, 1); + uint32_t startlevel; + bool ok; + + /* SL2 is RES0 unless DS=1 & 4kb granule. */ + if (param.ds && stride == 9 && sl2) { + if (sl0 != 0) { + level = 0; + fault_type = ARMFault_Translation; + goto do_fault; + } + startlevel = -1; + } else if (!aarch64 || stride == 9) { + /* AArch32 or 4KB pages */ + startlevel = 2 - sl0; + + if (cpu_isar_feature(aa64_st, cpu)) { + startlevel &= 3; + } + } else { + /* 16KB or 64KB pages */ + startlevel = 3 - sl0; + } + + /* Check that the starting level is valid. */ + ok = check_s2_mmu_setup(cpu, aarch64, startlevel, + inputsize, stride, outputsize); + if (!ok) { + fault_type = ARMFault_Translation; + goto do_fault; + } + level = startlevel; + } + + indexmask_grainsize = MAKE_64BIT_MASK(0, stride + 3); + indexmask = MAKE_64BIT_MASK(0, inputsize - (stride * (4 - level))); + + /* Now we can extract the actual base address from the TTBR */ + descaddr = extract64(ttbr, 0, 48); + + /* + * For FEAT_LPA and PS=6, bits [51:48] of descaddr are in [5:2] of TTBR. + * + * Otherwise, if the base address is out of range, raise AddressSizeFault. + * In the pseudocode, this is !IsZero(baseregister<47:outputsize>), + * but we've just cleared the bits above 47, so simplify the test. + */ + if (outputsize > 48) { + descaddr |= extract64(ttbr, 2, 4) << 48; + } else if (descaddr >> outputsize) { + level = 0; + fault_type = ARMFault_AddressSize; + goto do_fault; + } + + /* + * We rely on this masking to clear the RES0 bits at the bottom of the TTBR + * and also to mask out CnP (bit 0) which could validly be non-zero. + */ + descaddr &= ~indexmask; + + /* + * For AArch32, the address field in the descriptor goes up to bit 39 + * for both v7 and v8. However, for v8 the SBZ bits [47:40] must be 0 + * or an AddressSize fault is raised. So for v8 we extract those SBZ + * bits as part of the address, which will be checked via outputsize. + * For AArch64, the address field goes up to bit 47, or 49 with FEAT_LPA2; + * the highest bits of a 52-bit output are placed elsewhere. + */ + if (param.ds) { + descaddrmask = MAKE_64BIT_MASK(0, 50); + } else if (arm_feature(env, ARM_FEATURE_V8)) { + descaddrmask = MAKE_64BIT_MASK(0, 48); + } else { + descaddrmask = MAKE_64BIT_MASK(0, 40); + } + descaddrmask &= ~indexmask_grainsize; + + /* + * Secure accesses start with the page table in secure memory and + * can be downgraded to non-secure at any step. Non-secure accesses + * remain non-secure. We implement this by just ORing in the NSTable/NS + * bits at each step. + */ + tableattrs = regime_is_secure(env, mmu_idx) ? 0 : (1 << 4); + for (;;) { + uint64_t descriptor; + bool nstable; + + descaddr |= (address >> (stride * (4 - level))) & indexmask; + descaddr &= ~7ULL; + nstable = extract32(tableattrs, 4, 1); + descriptor = arm_ldq_ptw(cs, descaddr, !nstable, mmu_idx, fi); + if (fi->type != ARMFault_None) { + goto do_fault; + } + + if (!(descriptor & 1) || + (!(descriptor & 2) && (level == 3))) { + /* Invalid, or the Reserved level 3 encoding */ + goto do_fault; + } + + descaddr = descriptor & descaddrmask; + + /* + * For FEAT_LPA and PS=6, bits [51:48] of descaddr are in [15:12] + * of descriptor. For FEAT_LPA2 and effective DS, bits [51:50] of + * descaddr are in [9:8]. Otherwise, if descaddr is out of range, + * raise AddressSizeFault. + */ + if (outputsize > 48) { + if (param.ds) { + descaddr |= extract64(descriptor, 8, 2) << 50; + } else { + descaddr |= extract64(descriptor, 12, 4) << 48; + } + } else if (descaddr >> outputsize) { + fault_type = ARMFault_AddressSize; + goto do_fault; + } + + if ((descriptor & 2) && (level < 3)) { + /* + * Table entry. The top five bits are attributes which may + * propagate down through lower levels of the table (and + * which are all arranged so that 0 means "no effect", so + * we can gather them up by ORing in the bits at each level). + */ + tableattrs |= extract64(descriptor, 59, 5); + level++; + indexmask = indexmask_grainsize; + continue; + } + /* + * Block entry at level 1 or 2, or page entry at level 3. + * These are basically the same thing, although the number + * of bits we pull in from the vaddr varies. Note that although + * descaddrmask masks enough of the low bits of the descriptor + * to give a correct page or table address, the address field + * in a block descriptor is smaller; so we need to explicitly + * clear the lower bits here before ORing in the low vaddr bits. + */ + page_size = (1ULL << ((stride * (4 - level)) + 3)); + descaddr &= ~(page_size - 1); + descaddr |= (address & (page_size - 1)); + /* Extract attributes from the descriptor */ + attrs = extract64(descriptor, 2, 10) + | (extract64(descriptor, 52, 12) << 10); + + if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) { + /* Stage 2 table descriptors do not include any attribute fields */ + break; + } + /* Merge in attributes from table descriptors */ + attrs |= nstable << 3; /* NS */ + guarded = extract64(descriptor, 50, 1); /* GP */ + if (param.hpd) { + /* HPD disables all the table attributes except NSTable. */ + break; + } + attrs |= extract32(tableattrs, 0, 2) << 11; /* XN, PXN */ + /* + * The sense of AP[1] vs APTable[0] is reversed, as APTable[0] == 1 + * means "force PL1 access only", which means forcing AP[1] to 0. + */ + attrs &= ~(extract32(tableattrs, 2, 1) << 4); /* !APT[0] => AP[1] */ + attrs |= extract32(tableattrs, 3, 1) << 5; /* APT[1] => AP[2] */ + break; + } + /* + * Here descaddr is the final physical address, and attributes + * are all in attrs. + */ + fault_type = ARMFault_AccessFlag; + if ((attrs & (1 << 8)) == 0) { + /* Access flag */ + goto do_fault; + } + + ap = extract32(attrs, 4, 2); + + if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) { + ns = mmu_idx == ARMMMUIdx_Stage2; + xn = extract32(attrs, 11, 2); + *prot = get_S2prot(env, ap, xn, s1_is_el0); + } else { + ns = extract32(attrs, 3, 1); + xn = extract32(attrs, 12, 1); + pxn = extract32(attrs, 11, 1); + *prot = get_S1prot(env, mmu_idx, aarch64, ap, ns, xn, pxn); + } + + fault_type = ARMFault_Permission; + if (!(*prot & (1 << access_type))) { + goto do_fault; + } + + if (ns) { + /* + * The NS bit will (as required by the architecture) have no effect if + * the CPU doesn't support TZ or this is a non-secure translation + * regime, because the attribute will already be non-secure. + */ + txattrs->secure = false; + } + /* When in aarch64 mode, and BTI is enabled, remember GP in the IOTLB. */ + if (aarch64 && guarded && cpu_isar_feature(aa64_bti, cpu)) { + arm_tlb_bti_gp(txattrs) = true; + } + + if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) { + cacheattrs->is_s2_format = true; + cacheattrs->attrs = extract32(attrs, 0, 4); + } else { + /* Index into MAIR registers for cache attributes */ + uint8_t attrindx = extract32(attrs, 0, 3); + uint64_t mair = env->cp15.mair_el[regime_el(env, mmu_idx)]; + assert(attrindx <= 7); + cacheattrs->is_s2_format = false; + cacheattrs->attrs = extract64(mair, attrindx * 8, 8); + } + + /* + * For FEAT_LPA2 and effective DS, the SH field in the attributes + * was re-purposed for output address bits. The SH attribute in + * that case comes from TCR_ELx, which we extracted earlier. + */ + if (param.ds) { + cacheattrs->shareability = param.sh; + } else { + cacheattrs->shareability = extract32(attrs, 6, 2); + } + + *phys_ptr = descaddr; + *page_size_ptr = page_size; + return false; + +do_fault: + fi->type = fault_type; + fi->level = level; + /* Tag the error as S2 for failed S1 PTW at S2 or ordinary S2. */ + fi->stage2 = fi->s1ptw || (mmu_idx == ARMMMUIdx_Stage2 || + mmu_idx == ARMMMUIdx_Stage2_S); + fi->s1ns = mmu_idx == ARMMMUIdx_Stage2; + return true; +} + static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, int *prot, diff --git a/target/arm/ptw.h b/target/arm/ptw.h index b2dfe489bb..31744df664 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -11,6 +11,8 @@ #ifndef CONFIG_USER_ONLY +extern const uint8_t pamax_map[7]; + uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi); uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, @@ -30,6 +32,14 @@ simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap) return simple_ap_to_rw_prot_is_user(ap, regime_is_user(env, mmu_idx)); } +ARMVAParameters aa32_va_parameters(CPUARMState *env, uint32_t va, + ARMMMUIdx mmu_idx); +bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level, + int inputsize, int stride, int outputsize); +int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0); +int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, + int ap, int ns, int xn, int pxn); + bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, bool s1_is_el0, From 11552bb0d95484c99233ec2f09c25261885d08ed Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:51 +0100 Subject: [PATCH 875/935] target/arm: Move arm_{ldl,ldq}_ptw to ptw.c Move the ptw load functions, plus 3 common subroutines: S1_ptw_translate, ptw_attrs_are_device, and regime_translation_big_endian. This also allows get_phys_addr_lpae to become static again. Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-17-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 141 -------------------------------------- target/arm/ptw.c | 160 ++++++++++++++++++++++++++++++++++++++++++-- target/arm/ptw.h | 13 ---- 3 files changed, 154 insertions(+), 160 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 7de815fe98..398bcd62ab 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10475,12 +10475,6 @@ bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx) return (regime_sctlr(env, mmu_idx) & SCTLR_M) == 0; } -static inline bool regime_translation_big_endian(CPUARMState *env, - ARMMMUIdx mmu_idx) -{ - return (regime_sctlr(env, mmu_idx) & SCTLR_EE) != 0; -} - /* Return the TTBR associated with this translation regime */ uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, int ttbrn) { @@ -10773,141 +10767,6 @@ int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, return prot_rw | PAGE_EXEC; } -static bool ptw_attrs_are_device(CPUARMState *env, ARMCacheAttrs cacheattrs) -{ - /* - * For an S1 page table walk, the stage 1 attributes are always - * some form of "this is Normal memory". The combined S1+S2 - * attributes are therefore only Device if stage 2 specifies Device. - * With HCR_EL2.FWB == 0 this is when descriptor bits [5:4] are 0b00, - * ie when cacheattrs.attrs bits [3:2] are 0b00. - * With HCR_EL2.FWB == 1 this is when descriptor bit [4] is 0, ie - * when cacheattrs.attrs bit [2] is 0. - */ - assert(cacheattrs.is_s2_format); - if (arm_hcr_el2_eff(env) & HCR_FWB) { - return (cacheattrs.attrs & 0x4) == 0; - } else { - return (cacheattrs.attrs & 0xc) == 0; - } -} - -/* Translate a S1 pagetable walk through S2 if needed. */ -static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, - hwaddr addr, bool *is_secure, - ARMMMUFaultInfo *fi) -{ - if (arm_mmu_idx_is_stage1_of_2(mmu_idx) && - !regime_translation_disabled(env, ARMMMUIdx_Stage2)) { - target_ulong s2size; - hwaddr s2pa; - int s2prot; - int ret; - ARMMMUIdx s2_mmu_idx = *is_secure ? ARMMMUIdx_Stage2_S - : ARMMMUIdx_Stage2; - ARMCacheAttrs cacheattrs = {}; - MemTxAttrs txattrs = {}; - - ret = get_phys_addr_lpae(env, addr, MMU_DATA_LOAD, s2_mmu_idx, false, - &s2pa, &txattrs, &s2prot, &s2size, fi, - &cacheattrs); - if (ret) { - assert(fi->type != ARMFault_None); - fi->s2addr = addr; - fi->stage2 = true; - fi->s1ptw = true; - fi->s1ns = !*is_secure; - return ~0; - } - if ((arm_hcr_el2_eff(env) & HCR_PTW) && - ptw_attrs_are_device(env, cacheattrs)) { - /* - * PTW set and S1 walk touched S2 Device memory: - * generate Permission fault. - */ - fi->type = ARMFault_Permission; - fi->s2addr = addr; - fi->stage2 = true; - fi->s1ptw = true; - fi->s1ns = !*is_secure; - return ~0; - } - - if (arm_is_secure_below_el3(env)) { - /* Check if page table walk is to secure or non-secure PA space. */ - if (*is_secure) { - *is_secure = !(env->cp15.vstcr_el2.raw_tcr & VSTCR_SW); - } else { - *is_secure = !(env->cp15.vtcr_el2.raw_tcr & VTCR_NSW); - } - } else { - assert(!*is_secure); - } - - addr = s2pa; - } - return addr; -} - -/* All loads done in the course of a page table walk go through here. */ -uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, - ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi) -{ - ARMCPU *cpu = ARM_CPU(cs); - CPUARMState *env = &cpu->env; - MemTxAttrs attrs = {}; - MemTxResult result = MEMTX_OK; - AddressSpace *as; - uint32_t data; - - addr = S1_ptw_translate(env, mmu_idx, addr, &is_secure, fi); - attrs.secure = is_secure; - as = arm_addressspace(cs, attrs); - if (fi->s1ptw) { - return 0; - } - if (regime_translation_big_endian(env, mmu_idx)) { - data = address_space_ldl_be(as, addr, attrs, &result); - } else { - data = address_space_ldl_le(as, addr, attrs, &result); - } - if (result == MEMTX_OK) { - return data; - } - fi->type = ARMFault_SyncExternalOnWalk; - fi->ea = arm_extabort_type(result); - return 0; -} - -uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, - ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi) -{ - ARMCPU *cpu = ARM_CPU(cs); - CPUARMState *env = &cpu->env; - MemTxAttrs attrs = {}; - MemTxResult result = MEMTX_OK; - AddressSpace *as; - uint64_t data; - - addr = S1_ptw_translate(env, mmu_idx, addr, &is_secure, fi); - attrs.secure = is_secure; - as = arm_addressspace(cs, attrs); - if (fi->s1ptw) { - return 0; - } - if (regime_translation_big_endian(env, mmu_idx)) { - data = address_space_ldq_be(as, addr, attrs, &result); - } else { - data = address_space_ldq_le(as, addr, attrs, &result); - } - if (result == MEMTX_OK) { - return data; - } - fi->type = ARMFault_SyncExternalOnWalk; - fi->ea = arm_extabort_type(result); - return 0; -} - /* * check_s2_mmu_setup * @cpu: ARMCPU diff --git a/target/arm/ptw.c b/target/arm/ptw.c index cbccf91b13..e4b860d2ae 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -15,6 +15,154 @@ #include "ptw.h" +static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + bool s1_is_el0, hwaddr *phys_ptr, + MemTxAttrs *txattrs, int *prot, + target_ulong *page_size_ptr, + ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) + __attribute__((nonnull)); + +static bool regime_translation_big_endian(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + return (regime_sctlr(env, mmu_idx) & SCTLR_EE) != 0; +} + +static bool ptw_attrs_are_device(CPUARMState *env, ARMCacheAttrs cacheattrs) +{ + /* + * For an S1 page table walk, the stage 1 attributes are always + * some form of "this is Normal memory". The combined S1+S2 + * attributes are therefore only Device if stage 2 specifies Device. + * With HCR_EL2.FWB == 0 this is when descriptor bits [5:4] are 0b00, + * ie when cacheattrs.attrs bits [3:2] are 0b00. + * With HCR_EL2.FWB == 1 this is when descriptor bit [4] is 0, ie + * when cacheattrs.attrs bit [2] is 0. + */ + assert(cacheattrs.is_s2_format); + if (arm_hcr_el2_eff(env) & HCR_FWB) { + return (cacheattrs.attrs & 0x4) == 0; + } else { + return (cacheattrs.attrs & 0xc) == 0; + } +} + +/* Translate a S1 pagetable walk through S2 if needed. */ +static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, + hwaddr addr, bool *is_secure, + ARMMMUFaultInfo *fi) +{ + if (arm_mmu_idx_is_stage1_of_2(mmu_idx) && + !regime_translation_disabled(env, ARMMMUIdx_Stage2)) { + target_ulong s2size; + hwaddr s2pa; + int s2prot; + int ret; + ARMMMUIdx s2_mmu_idx = *is_secure ? ARMMMUIdx_Stage2_S + : ARMMMUIdx_Stage2; + ARMCacheAttrs cacheattrs = {}; + MemTxAttrs txattrs = {}; + + ret = get_phys_addr_lpae(env, addr, MMU_DATA_LOAD, s2_mmu_idx, false, + &s2pa, &txattrs, &s2prot, &s2size, fi, + &cacheattrs); + if (ret) { + assert(fi->type != ARMFault_None); + fi->s2addr = addr; + fi->stage2 = true; + fi->s1ptw = true; + fi->s1ns = !*is_secure; + return ~0; + } + if ((arm_hcr_el2_eff(env) & HCR_PTW) && + ptw_attrs_are_device(env, cacheattrs)) { + /* + * PTW set and S1 walk touched S2 Device memory: + * generate Permission fault. + */ + fi->type = ARMFault_Permission; + fi->s2addr = addr; + fi->stage2 = true; + fi->s1ptw = true; + fi->s1ns = !*is_secure; + return ~0; + } + + if (arm_is_secure_below_el3(env)) { + /* Check if page table walk is to secure or non-secure PA space. */ + if (*is_secure) { + *is_secure = !(env->cp15.vstcr_el2.raw_tcr & VSTCR_SW); + } else { + *is_secure = !(env->cp15.vtcr_el2.raw_tcr & VTCR_NSW); + } + } else { + assert(!*is_secure); + } + + addr = s2pa; + } + return addr; +} + +/* All loads done in the course of a page table walk go through here. */ +static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, + ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + MemTxAttrs attrs = {}; + MemTxResult result = MEMTX_OK; + AddressSpace *as; + uint32_t data; + + addr = S1_ptw_translate(env, mmu_idx, addr, &is_secure, fi); + attrs.secure = is_secure; + as = arm_addressspace(cs, attrs); + if (fi->s1ptw) { + return 0; + } + if (regime_translation_big_endian(env, mmu_idx)) { + data = address_space_ldl_be(as, addr, attrs, &result); + } else { + data = address_space_ldl_le(as, addr, attrs, &result); + } + if (result == MEMTX_OK) { + return data; + } + fi->type = ARMFault_SyncExternalOnWalk; + fi->ea = arm_extabort_type(result); + return 0; +} + +static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, + ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + MemTxAttrs attrs = {}; + MemTxResult result = MEMTX_OK; + AddressSpace *as; + uint64_t data; + + addr = S1_ptw_translate(env, mmu_idx, addr, &is_secure, fi); + attrs.secure = is_secure; + as = arm_addressspace(cs, attrs); + if (fi->s1ptw) { + return 0; + } + if (regime_translation_big_endian(env, mmu_idx)) { + data = address_space_ldq_be(as, addr, attrs, &result); + } else { + data = address_space_ldq_le(as, addr, attrs, &result); + } + if (result == MEMTX_OK) { + return data; + } + fi->type = ARMFault_SyncExternalOnWalk; + fi->ea = arm_extabort_type(result); + return 0; +} + static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, uint32_t *table, uint32_t address) { @@ -338,12 +486,12 @@ do_fault: * @fi: set to fault info if the translation fails * @cacheattrs: (if non-NULL) set to the cacheability/shareability attributes */ -bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - bool s1_is_el0, - hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, - target_ulong *page_size_ptr, - ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) +static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + bool s1_is_el0, hwaddr *phys_ptr, + MemTxAttrs *txattrs, int *prot, + target_ulong *page_size_ptr, + ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) { ARMCPU *cpu = env_archcpu(env); CPUState *cs = CPU(cpu); diff --git a/target/arm/ptw.h b/target/arm/ptw.h index 31744df664..28b8cb9fb8 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -13,11 +13,6 @@ extern const uint8_t pamax_map[7]; -uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, - ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi); -uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, - ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi); - bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx); bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx); uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, int ttbrn); @@ -40,13 +35,5 @@ int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0); int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, int ap, int ns, int xn, int pxn); -bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - bool s1_is_el0, - hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, - target_ulong *page_size_ptr, - ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) - __attribute__((nonnull)); - #endif /* !CONFIG_USER_ONLY */ #endif /* TARGET_ARM_PTW_H */ From cd6bc4d51730e9cf47489029d078d18c3bcb3ae2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:52 +0100 Subject: [PATCH 876/935] target/arm: Move {arm_s1_, }regime_using_lpae_format to tlb_helper.c These functions are used for both page table walking and for deciding what format in which to deliver exception results. Since ptw.c is only present for system mode, put the functions into tlb_helper.c. Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-18-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 24 ------------------------ target/arm/tlb_helper.c | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 398bcd62ab..d2b196ff3e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10515,30 +10515,6 @@ ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx) } #endif /* !CONFIG_USER_ONLY */ -/* Return true if the translation regime is using LPAE format page tables */ -bool regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx) -{ - int el = regime_el(env, mmu_idx); - if (el == 2 || arm_el_is_aa64(env, el)) { - return true; - } - if (arm_feature(env, ARM_FEATURE_LPAE) - && (regime_tcr(env, mmu_idx)->raw_tcr & TTBCR_EAE)) { - return true; - } - return false; -} - -/* Returns true if the stage 1 translation regime is using LPAE format page - * tables. Used when raising alignment exceptions, whose FSR changes depending - * on whether the long or short descriptor format is in use. */ -bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx) -{ - mmu_idx = stage_1_mmu_idx(mmu_idx); - - return regime_using_lpae_format(env, mmu_idx); -} - #ifndef CONFIG_USER_ONLY bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx) { diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c index 6421e16202..7d8a86b3c4 100644 --- a/target/arm/tlb_helper.c +++ b/target/arm/tlb_helper.c @@ -11,6 +11,32 @@ #include "exec/exec-all.h" #include "exec/helper-proto.h" + +/* Return true if the translation regime is using LPAE format page tables */ +bool regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + int el = regime_el(env, mmu_idx); + if (el == 2 || arm_el_is_aa64(env, el)) { + return true; + } + if (arm_feature(env, ARM_FEATURE_LPAE) + && (regime_tcr(env, mmu_idx)->raw_tcr & TTBCR_EAE)) { + return true; + } + return false; +} + +/* + * Returns true if the stage 1 translation regime is using LPAE format page + * tables. Used when raising alignment exceptions, whose FSR changes depending + * on whether the long or short descriptor format is in use. + */ +bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + mmu_idx = stage_1_mmu_idx(mmu_idx); + return regime_using_lpae_format(env, mmu_idx); +} + static inline uint32_t merge_syn_data_abort(uint32_t template_syn, unsigned int target_el, bool same_el, bool ea, From 1c73d84807712aad4c7b2e4e753d6870ab81145d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:52 +0100 Subject: [PATCH 877/935] target/arm: Move arm_pamax, pamax_map into ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-19-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 25 ------------------------- target/arm/ptw.c | 25 +++++++++++++++++++++++++ target/arm/ptw.h | 2 -- 3 files changed, 25 insertions(+), 27 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index d2b196ff3e..563e34ecde 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10814,31 +10814,6 @@ bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level, } #endif /* !CONFIG_USER_ONLY */ -/* This mapping is common between ID_AA64MMFR0.PARANGE and TCR_ELx.{I}PS. */ -const uint8_t pamax_map[] = { - [0] = 32, - [1] = 36, - [2] = 40, - [3] = 42, - [4] = 44, - [5] = 48, - [6] = 52, -}; - -/* The cpu-specific constant value of PAMax; also used by hw/arm/virt. */ -unsigned int arm_pamax(ARMCPU *cpu) -{ - unsigned int parange = - FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE); - - /* - * id_aa64mmfr0 is a read-only register so values outside of the - * supported mappings can be considered an implementation error. - */ - assert(parange < ARRAY_SIZE(pamax_map)); - return pamax_map[parange]; -} - int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx) { if (regime_has_2_ranges(mmu_idx)) { diff --git a/target/arm/ptw.c b/target/arm/ptw.c index e4b860d2ae..d754273fa1 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -23,6 +23,31 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) __attribute__((nonnull)); +/* This mapping is common between ID_AA64MMFR0.PARANGE and TCR_ELx.{I}PS. */ +static const uint8_t pamax_map[] = { + [0] = 32, + [1] = 36, + [2] = 40, + [3] = 42, + [4] = 44, + [5] = 48, + [6] = 52, +}; + +/* The cpu-specific constant value of PAMax; also used by hw/arm/virt. */ +unsigned int arm_pamax(ARMCPU *cpu) +{ + unsigned int parange = + FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE); + + /* + * id_aa64mmfr0 is a read-only register so values outside of the + * supported mappings can be considered an implementation error. + */ + assert(parange < ARRAY_SIZE(pamax_map)); + return pamax_map[parange]; +} + static bool regime_translation_big_endian(CPUARMState *env, ARMMMUIdx mmu_idx) { return (regime_sctlr(env, mmu_idx) & SCTLR_EE) != 0; diff --git a/target/arm/ptw.h b/target/arm/ptw.h index 28b8cb9fb8..fba650d01c 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -11,8 +11,6 @@ #ifndef CONFIG_USER_ONLY -extern const uint8_t pamax_map[7]; - bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx); bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx); uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, int ttbrn); From f8526edc2f32b66a585618afc1dabd960a4c9b95 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:52 +0100 Subject: [PATCH 878/935] target/arm: Move get_S1prot, get_S2prot to ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-20-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 128 -------------------------------------------- target/arm/ptw.c | 128 ++++++++++++++++++++++++++++++++++++++++++++ target/arm/ptw.h | 3 -- 3 files changed, 128 insertions(+), 131 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 563e34ecde..148eb28ba8 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10615,134 +10615,6 @@ int simple_ap_to_rw_prot_is_user(int ap, bool is_user) } } -/* Translate S2 section/page access permissions to protection flags - * - * @env: CPUARMState - * @s2ap: The 2-bit stage2 access permissions (S2AP) - * @xn: XN (execute-never) bits - * @s1_is_el0: true if this is S2 of an S1+2 walk for EL0 - */ -int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0) -{ - int prot = 0; - - if (s2ap & 1) { - prot |= PAGE_READ; - } - if (s2ap & 2) { - prot |= PAGE_WRITE; - } - - if (cpu_isar_feature(any_tts2uxn, env_archcpu(env))) { - switch (xn) { - case 0: - prot |= PAGE_EXEC; - break; - case 1: - if (s1_is_el0) { - prot |= PAGE_EXEC; - } - break; - case 2: - break; - case 3: - if (!s1_is_el0) { - prot |= PAGE_EXEC; - } - break; - default: - g_assert_not_reached(); - } - } else { - if (!extract32(xn, 1, 1)) { - if (arm_el_is_aa64(env, 2) || prot & PAGE_READ) { - prot |= PAGE_EXEC; - } - } - } - return prot; -} - -/* Translate section/page access permissions to protection flags - * - * @env: CPUARMState - * @mmu_idx: MMU index indicating required translation regime - * @is_aa64: TRUE if AArch64 - * @ap: The 2-bit simple AP (AP[2:1]) - * @ns: NS (non-secure) bit - * @xn: XN (execute-never) bit - * @pxn: PXN (privileged execute-never) bit - */ -int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, - int ap, int ns, int xn, int pxn) -{ - bool is_user = regime_is_user(env, mmu_idx); - int prot_rw, user_rw; - bool have_wxn; - int wxn = 0; - - assert(mmu_idx != ARMMMUIdx_Stage2); - assert(mmu_idx != ARMMMUIdx_Stage2_S); - - user_rw = simple_ap_to_rw_prot_is_user(ap, true); - if (is_user) { - prot_rw = user_rw; - } else { - if (user_rw && regime_is_pan(env, mmu_idx)) { - /* PAN forbids data accesses but doesn't affect insn fetch */ - prot_rw = 0; - } else { - prot_rw = simple_ap_to_rw_prot_is_user(ap, false); - } - } - - if (ns && arm_is_secure(env) && (env->cp15.scr_el3 & SCR_SIF)) { - return prot_rw; - } - - /* TODO have_wxn should be replaced with - * ARM_FEATURE_V8 || (ARM_FEATURE_V7 && ARM_FEATURE_EL2) - * when ARM_FEATURE_EL2 starts getting set. For now we assume all LPAE - * compatible processors have EL2, which is required for [U]WXN. - */ - have_wxn = arm_feature(env, ARM_FEATURE_LPAE); - - if (have_wxn) { - wxn = regime_sctlr(env, mmu_idx) & SCTLR_WXN; - } - - if (is_aa64) { - if (regime_has_2_ranges(mmu_idx) && !is_user) { - xn = pxn || (user_rw & PAGE_WRITE); - } - } else if (arm_feature(env, ARM_FEATURE_V7)) { - switch (regime_el(env, mmu_idx)) { - case 1: - case 3: - if (is_user) { - xn = xn || !(user_rw & PAGE_READ); - } else { - int uwxn = 0; - if (have_wxn) { - uwxn = regime_sctlr(env, mmu_idx) & SCTLR_UWXN; - } - xn = xn || !(prot_rw & PAGE_READ) || pxn || - (uwxn && (user_rw & PAGE_WRITE)); - } - break; - case 2: - break; - } - } else { - xn = wxn = 0; - } - - if (xn || (wxn && (prot_rw & PAGE_WRITE))) { - return prot_rw; - } - return prot_rw | PAGE_EXEC; -} - /* * check_s2_mmu_setup * @cpu: ARMCPU diff --git a/target/arm/ptw.c b/target/arm/ptw.c index d754273fa1..af9ad42028 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -487,6 +487,134 @@ do_fault: return true; } +/* + * Translate S2 section/page access permissions to protection flags + * @env: CPUARMState + * @s2ap: The 2-bit stage2 access permissions (S2AP) + * @xn: XN (execute-never) bits + * @s1_is_el0: true if this is S2 of an S1+2 walk for EL0 + */ +static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0) +{ + int prot = 0; + + if (s2ap & 1) { + prot |= PAGE_READ; + } + if (s2ap & 2) { + prot |= PAGE_WRITE; + } + + if (cpu_isar_feature(any_tts2uxn, env_archcpu(env))) { + switch (xn) { + case 0: + prot |= PAGE_EXEC; + break; + case 1: + if (s1_is_el0) { + prot |= PAGE_EXEC; + } + break; + case 2: + break; + case 3: + if (!s1_is_el0) { + prot |= PAGE_EXEC; + } + break; + default: + g_assert_not_reached(); + } + } else { + if (!extract32(xn, 1, 1)) { + if (arm_el_is_aa64(env, 2) || prot & PAGE_READ) { + prot |= PAGE_EXEC; + } + } + } + return prot; +} + +/* + * Translate section/page access permissions to protection flags + * @env: CPUARMState + * @mmu_idx: MMU index indicating required translation regime + * @is_aa64: TRUE if AArch64 + * @ap: The 2-bit simple AP (AP[2:1]) + * @ns: NS (non-secure) bit + * @xn: XN (execute-never) bit + * @pxn: PXN (privileged execute-never) bit + */ +static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, + int ap, int ns, int xn, int pxn) +{ + bool is_user = regime_is_user(env, mmu_idx); + int prot_rw, user_rw; + bool have_wxn; + int wxn = 0; + + assert(mmu_idx != ARMMMUIdx_Stage2); + assert(mmu_idx != ARMMMUIdx_Stage2_S); + + user_rw = simple_ap_to_rw_prot_is_user(ap, true); + if (is_user) { + prot_rw = user_rw; + } else { + if (user_rw && regime_is_pan(env, mmu_idx)) { + /* PAN forbids data accesses but doesn't affect insn fetch */ + prot_rw = 0; + } else { + prot_rw = simple_ap_to_rw_prot_is_user(ap, false); + } + } + + if (ns && arm_is_secure(env) && (env->cp15.scr_el3 & SCR_SIF)) { + return prot_rw; + } + + /* TODO have_wxn should be replaced with + * ARM_FEATURE_V8 || (ARM_FEATURE_V7 && ARM_FEATURE_EL2) + * when ARM_FEATURE_EL2 starts getting set. For now we assume all LPAE + * compatible processors have EL2, which is required for [U]WXN. + */ + have_wxn = arm_feature(env, ARM_FEATURE_LPAE); + + if (have_wxn) { + wxn = regime_sctlr(env, mmu_idx) & SCTLR_WXN; + } + + if (is_aa64) { + if (regime_has_2_ranges(mmu_idx) && !is_user) { + xn = pxn || (user_rw & PAGE_WRITE); + } + } else if (arm_feature(env, ARM_FEATURE_V7)) { + switch (regime_el(env, mmu_idx)) { + case 1: + case 3: + if (is_user) { + xn = xn || !(user_rw & PAGE_READ); + } else { + int uwxn = 0; + if (have_wxn) { + uwxn = regime_sctlr(env, mmu_idx) & SCTLR_UWXN; + } + xn = xn || !(prot_rw & PAGE_READ) || pxn || + (uwxn && (user_rw & PAGE_WRITE)); + } + break; + case 2: + break; + } + } else { + xn = wxn = 0; + } + + if (xn || (wxn && (prot_rw & PAGE_WRITE))) { + return prot_rw; + } + return prot_rw | PAGE_EXEC; +} + /** * get_phys_addr_lpae: perform one stage of page table walk, LPAE format * diff --git a/target/arm/ptw.h b/target/arm/ptw.h index fba650d01c..93147e0b06 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -29,9 +29,6 @@ ARMVAParameters aa32_va_parameters(CPUARMState *env, uint32_t va, ARMMMUIdx mmu_idx); bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level, int inputsize, int stride, int outputsize); -int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0); -int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, - int ap, int ns, int xn, int pxn); #endif /* !CONFIG_USER_ONLY */ #endif /* TARGET_ARM_PTW_H */ From c5168785d208527c45f455619abe2539182a9fff Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:52 +0100 Subject: [PATCH 879/935] target/arm: Move check_s2_mmu_setup to ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-21-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 70 --------------------------------------------- target/arm/ptw.c | 70 +++++++++++++++++++++++++++++++++++++++++++++ target/arm/ptw.h | 2 -- 3 files changed, 70 insertions(+), 72 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 148eb28ba8..2526f4c6c4 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10614,76 +10614,6 @@ int simple_ap_to_rw_prot_is_user(int ap, bool is_user) g_assert_not_reached(); } } - -/* - * check_s2_mmu_setup - * @cpu: ARMCPU - * @is_aa64: True if the translation regime is in AArch64 state - * @startlevel: Suggested starting level - * @inputsize: Bitsize of IPAs - * @stride: Page-table stride (See the ARM ARM) - * - * Returns true if the suggested S2 translation parameters are OK and - * false otherwise. - */ -bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level, - int inputsize, int stride, int outputsize) -{ - const int grainsize = stride + 3; - int startsizecheck; - - /* - * Negative levels are usually not allowed... - * Except for FEAT_LPA2, 4k page table, 52-bit address space, which - * begins with level -1. Note that previous feature tests will have - * eliminated this combination if it is not enabled. - */ - if (level < (inputsize == 52 && stride == 9 ? -1 : 0)) { - return false; - } - - startsizecheck = inputsize - ((3 - level) * stride + grainsize); - if (startsizecheck < 1 || startsizecheck > stride + 4) { - return false; - } - - if (is_aa64) { - switch (stride) { - case 13: /* 64KB Pages. */ - if (level == 0 || (level == 1 && outputsize <= 42)) { - return false; - } - break; - case 11: /* 16KB Pages. */ - if (level == 0 || (level == 1 && outputsize <= 40)) { - return false; - } - break; - case 9: /* 4KB Pages. */ - if (level == 0 && outputsize <= 42) { - return false; - } - break; - default: - g_assert_not_reached(); - } - - /* Inputsize checks. */ - if (inputsize > outputsize && - (arm_el_is_aa64(&cpu->env, 1) || inputsize > 40)) { - /* This is CONSTRAINED UNPREDICTABLE and we choose to fault. */ - return false; - } - } else { - /* AArch32 only supports 4KB pages. Assert on that. */ - assert(stride == 9); - - if (level == 0) { - return false; - } - } - return true; -} #endif /* !CONFIG_USER_ONLY */ int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx) diff --git a/target/arm/ptw.c b/target/arm/ptw.c index af9ad42028..525272e99a 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -615,6 +615,76 @@ static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, return prot_rw | PAGE_EXEC; } +/* + * check_s2_mmu_setup + * @cpu: ARMCPU + * @is_aa64: True if the translation regime is in AArch64 state + * @startlevel: Suggested starting level + * @inputsize: Bitsize of IPAs + * @stride: Page-table stride (See the ARM ARM) + * + * Returns true if the suggested S2 translation parameters are OK and + * false otherwise. + */ +static bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level, + int inputsize, int stride, int outputsize) +{ + const int grainsize = stride + 3; + int startsizecheck; + + /* + * Negative levels are usually not allowed... + * Except for FEAT_LPA2, 4k page table, 52-bit address space, which + * begins with level -1. Note that previous feature tests will have + * eliminated this combination if it is not enabled. + */ + if (level < (inputsize == 52 && stride == 9 ? -1 : 0)) { + return false; + } + + startsizecheck = inputsize - ((3 - level) * stride + grainsize); + if (startsizecheck < 1 || startsizecheck > stride + 4) { + return false; + } + + if (is_aa64) { + switch (stride) { + case 13: /* 64KB Pages. */ + if (level == 0 || (level == 1 && outputsize <= 42)) { + return false; + } + break; + case 11: /* 16KB Pages. */ + if (level == 0 || (level == 1 && outputsize <= 40)) { + return false; + } + break; + case 9: /* 4KB Pages. */ + if (level == 0 && outputsize <= 42) { + return false; + } + break; + default: + g_assert_not_reached(); + } + + /* Inputsize checks. */ + if (inputsize > outputsize && + (arm_el_is_aa64(&cpu->env, 1) || inputsize > 40)) { + /* This is CONSTRAINED UNPREDICTABLE and we choose to fault. */ + return false; + } + } else { + /* AArch32 only supports 4KB pages. Assert on that. */ + assert(stride == 9); + + if (level == 0) { + return false; + } + } + return true; +} + /** * get_phys_addr_lpae: perform one stage of page table walk, LPAE format * diff --git a/target/arm/ptw.h b/target/arm/ptw.h index 93147e0b06..a71161b01b 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -27,8 +27,6 @@ simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap) ARMVAParameters aa32_va_parameters(CPUARMState *env, uint32_t va, ARMMMUIdx mmu_idx); -bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level, - int inputsize, int stride, int outputsize); #endif /* !CONFIG_USER_ONLY */ #endif /* TARGET_ARM_PTW_H */ From 2f0ec92e9488e1ac6c7293fe37a5f1c0e1737b36 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:53 +0100 Subject: [PATCH 880/935] target/arm: Move aa32_va_parameters to ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-22-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 64 --------------------------------------------- target/arm/ptw.c | 64 +++++++++++++++++++++++++++++++++++++++++++++ target/arm/ptw.h | 3 --- 3 files changed, 64 insertions(+), 67 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 2526f4c6c4..f61f1da61e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10771,70 +10771,6 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, } #ifndef CONFIG_USER_ONLY -ARMVAParameters aa32_va_parameters(CPUARMState *env, uint32_t va, - ARMMMUIdx mmu_idx) -{ - uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr; - uint32_t el = regime_el(env, mmu_idx); - int select, tsz; - bool epd, hpd; - - assert(mmu_idx != ARMMMUIdx_Stage2_S); - - if (mmu_idx == ARMMMUIdx_Stage2) { - /* VTCR */ - bool sext = extract32(tcr, 4, 1); - bool sign = extract32(tcr, 3, 1); - - /* - * If the sign-extend bit is not the same as t0sz[3], the result - * is unpredictable. Flag this as a guest error. - */ - if (sign != sext) { - qemu_log_mask(LOG_GUEST_ERROR, - "AArch32: VTCR.S / VTCR.T0SZ[3] mismatch\n"); - } - tsz = sextract32(tcr, 0, 4) + 8; - select = 0; - hpd = false; - epd = false; - } else if (el == 2) { - /* HTCR */ - tsz = extract32(tcr, 0, 3); - select = 0; - hpd = extract64(tcr, 24, 1); - epd = false; - } else { - int t0sz = extract32(tcr, 0, 3); - int t1sz = extract32(tcr, 16, 3); - - if (t1sz == 0) { - select = va > (0xffffffffu >> t0sz); - } else { - /* Note that we will detect errors later. */ - select = va >= ~(0xffffffffu >> t1sz); - } - if (!select) { - tsz = t0sz; - epd = extract32(tcr, 7, 1); - hpd = extract64(tcr, 41, 1); - } else { - tsz = t1sz; - epd = extract32(tcr, 23, 1); - hpd = extract64(tcr, 42, 1); - } - /* For aarch32, hpd0 is not enabled without t2e as well. */ - hpd &= extract32(tcr, 6, 1); - } - - return (ARMVAParameters) { - .tsz = tsz, - .select = select, - .epd = epd, - .hpd = hpd, - }; -} - hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, MemTxAttrs *attrs) { diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 525272e99a..427813ea56 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -615,6 +615,70 @@ static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, return prot_rw | PAGE_EXEC; } +static ARMVAParameters aa32_va_parameters(CPUARMState *env, uint32_t va, + ARMMMUIdx mmu_idx) +{ + uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr; + uint32_t el = regime_el(env, mmu_idx); + int select, tsz; + bool epd, hpd; + + assert(mmu_idx != ARMMMUIdx_Stage2_S); + + if (mmu_idx == ARMMMUIdx_Stage2) { + /* VTCR */ + bool sext = extract32(tcr, 4, 1); + bool sign = extract32(tcr, 3, 1); + + /* + * If the sign-extend bit is not the same as t0sz[3], the result + * is unpredictable. Flag this as a guest error. + */ + if (sign != sext) { + qemu_log_mask(LOG_GUEST_ERROR, + "AArch32: VTCR.S / VTCR.T0SZ[3] mismatch\n"); + } + tsz = sextract32(tcr, 0, 4) + 8; + select = 0; + hpd = false; + epd = false; + } else if (el == 2) { + /* HTCR */ + tsz = extract32(tcr, 0, 3); + select = 0; + hpd = extract64(tcr, 24, 1); + epd = false; + } else { + int t0sz = extract32(tcr, 0, 3); + int t1sz = extract32(tcr, 16, 3); + + if (t1sz == 0) { + select = va > (0xffffffffu >> t0sz); + } else { + /* Note that we will detect errors later. */ + select = va >= ~(0xffffffffu >> t1sz); + } + if (!select) { + tsz = t0sz; + epd = extract32(tcr, 7, 1); + hpd = extract64(tcr, 41, 1); + } else { + tsz = t1sz; + epd = extract32(tcr, 23, 1); + hpd = extract64(tcr, 42, 1); + } + /* For aarch32, hpd0 is not enabled without t2e as well. */ + hpd &= extract32(tcr, 6, 1); + } + + return (ARMVAParameters) { + .tsz = tsz, + .select = select, + .epd = epd, + .hpd = hpd, + }; +} + /* * check_s2_mmu_setup * @cpu: ARMCPU diff --git a/target/arm/ptw.h b/target/arm/ptw.h index a71161b01b..9314fb4d23 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -25,8 +25,5 @@ simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap) return simple_ap_to_rw_prot_is_user(ap, regime_is_user(env, mmu_idx)); } -ARMVAParameters aa32_va_parameters(CPUARMState *env, uint32_t va, - ARMMMUIdx mmu_idx); - #endif /* !CONFIG_USER_ONLY */ #endif /* TARGET_ARM_PTW_H */ From 4845d3be1239a956a4cedd5c2ca7863837487927 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:53 +0100 Subject: [PATCH 881/935] target/arm: Move ap_to_tw_prot etc to ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-23-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 77 ------------------------------------------ target/arm/ptw.c | 81 +++++++++++++++++++++++++++++++++++++++++++++ target/arm/ptw.h | 10 ------ 3 files changed, 81 insertions(+), 87 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index f61f1da61e..e894afcb49 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10537,83 +10537,6 @@ bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx) g_assert_not_reached(); } } - -/* Translate section/page access permissions to page - * R/W protection flags - * - * @env: CPUARMState - * @mmu_idx: MMU index indicating required translation regime - * @ap: The 3-bit access permissions (AP[2:0]) - * @domain_prot: The 2-bit domain access permissions - */ -int ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap, int domain_prot) -{ - bool is_user = regime_is_user(env, mmu_idx); - - if (domain_prot == 3) { - return PAGE_READ | PAGE_WRITE; - } - - switch (ap) { - case 0: - if (arm_feature(env, ARM_FEATURE_V7)) { - return 0; - } - switch (regime_sctlr(env, mmu_idx) & (SCTLR_S | SCTLR_R)) { - case SCTLR_S: - return is_user ? 0 : PAGE_READ; - case SCTLR_R: - return PAGE_READ; - default: - return 0; - } - case 1: - return is_user ? 0 : PAGE_READ | PAGE_WRITE; - case 2: - if (is_user) { - return PAGE_READ; - } else { - return PAGE_READ | PAGE_WRITE; - } - case 3: - return PAGE_READ | PAGE_WRITE; - case 4: /* Reserved. */ - return 0; - case 5: - return is_user ? 0 : PAGE_READ; - case 6: - return PAGE_READ; - case 7: - if (!arm_feature(env, ARM_FEATURE_V6K)) { - return 0; - } - return PAGE_READ; - default: - g_assert_not_reached(); - } -} - -/* Translate section/page access permissions to page - * R/W protection flags. - * - * @ap: The 2-bit simple AP (AP[2:1]) - * @is_user: TRUE if accessing from PL0 - */ -int simple_ap_to_rw_prot_is_user(int ap, bool is_user) -{ - switch (ap) { - case 0: - return is_user ? 0 : PAGE_READ | PAGE_WRITE; - case 1: - return PAGE_READ | PAGE_WRITE; - case 2: - return is_user ? 0 : PAGE_READ; - case 3: - return PAGE_READ; - default: - g_assert_not_reached(); - } -} #endif /* !CONFIG_USER_ONLY */ int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx) diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 427813ea56..9ab77c3998 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -211,6 +211,87 @@ static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, return true; } +/* + * Translate section/page access permissions to page R/W protection flags + * @env: CPUARMState + * @mmu_idx: MMU index indicating required translation regime + * @ap: The 3-bit access permissions (AP[2:0]) + * @domain_prot: The 2-bit domain access permissions + */ +static int ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, + int ap, int domain_prot) +{ + bool is_user = regime_is_user(env, mmu_idx); + + if (domain_prot == 3) { + return PAGE_READ | PAGE_WRITE; + } + + switch (ap) { + case 0: + if (arm_feature(env, ARM_FEATURE_V7)) { + return 0; + } + switch (regime_sctlr(env, mmu_idx) & (SCTLR_S | SCTLR_R)) { + case SCTLR_S: + return is_user ? 0 : PAGE_READ; + case SCTLR_R: + return PAGE_READ; + default: + return 0; + } + case 1: + return is_user ? 0 : PAGE_READ | PAGE_WRITE; + case 2: + if (is_user) { + return PAGE_READ; + } else { + return PAGE_READ | PAGE_WRITE; + } + case 3: + return PAGE_READ | PAGE_WRITE; + case 4: /* Reserved. */ + return 0; + case 5: + return is_user ? 0 : PAGE_READ; + case 6: + return PAGE_READ; + case 7: + if (!arm_feature(env, ARM_FEATURE_V6K)) { + return 0; + } + return PAGE_READ; + default: + g_assert_not_reached(); + } +} + +/* + * Translate section/page access permissions to page R/W protection flags. + * @ap: The 2-bit simple AP (AP[2:1]) + * @is_user: TRUE if accessing from PL0 + */ +static int simple_ap_to_rw_prot_is_user(int ap, bool is_user) +{ + switch (ap) { + case 0: + return is_user ? 0 : PAGE_READ | PAGE_WRITE; + case 1: + return PAGE_READ | PAGE_WRITE; + case 2: + return is_user ? 0 : PAGE_READ; + case 3: + return PAGE_READ; + default: + g_assert_not_reached(); + } +} + +static int simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap) +{ + return simple_ap_to_rw_prot_is_user(ap, regime_is_user(env, mmu_idx)); +} + static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, int *prot, diff --git a/target/arm/ptw.h b/target/arm/ptw.h index 9314fb4d23..85ad576794 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -15,15 +15,5 @@ bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx); bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx); uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, int ttbrn); -int ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, - int ap, int domain_prot); -int simple_ap_to_rw_prot_is_user(int ap, bool is_user); - -static inline int -simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap) -{ - return simple_ap_to_rw_prot_is_user(ap, regime_is_user(env, mmu_idx)); -} - #endif /* !CONFIG_USER_ONLY */ #endif /* TARGET_ARM_PTW_H */ From 0c23d56fc149ada0823648481c09b5d2047570f4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:53 +0100 Subject: [PATCH 882/935] target/arm: Move regime_is_user to ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-24-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 24 ------------------------ target/arm/ptw.c | 22 ++++++++++++++++++++++ target/arm/ptw.h | 1 - 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index e894afcb49..8deb0fa94c 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10515,30 +10515,6 @@ ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx) } #endif /* !CONFIG_USER_ONLY */ -#ifndef CONFIG_USER_ONLY -bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx) -{ - switch (mmu_idx) { - case ARMMMUIdx_SE10_0: - case ARMMMUIdx_E20_0: - case ARMMMUIdx_SE20_0: - case ARMMMUIdx_Stage1_E0: - case ARMMMUIdx_Stage1_SE0: - case ARMMMUIdx_MUser: - case ARMMMUIdx_MSUser: - case ARMMMUIdx_MUserNegPri: - case ARMMMUIdx_MSUserNegPri: - return true; - default: - return false; - case ARMMMUIdx_E10_0: - case ARMMMUIdx_E10_1: - case ARMMMUIdx_E10_1_PAN: - g_assert_not_reached(); - } -} -#endif /* !CONFIG_USER_ONLY */ - int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx) { if (regime_has_2_ranges(mmu_idx)) { diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 9ab77c3998..8db4b5edf1 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -53,6 +53,28 @@ static bool regime_translation_big_endian(CPUARMState *env, ARMMMUIdx mmu_idx) return (regime_sctlr(env, mmu_idx) & SCTLR_EE) != 0; } +static bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + switch (mmu_idx) { + case ARMMMUIdx_SE10_0: + case ARMMMUIdx_E20_0: + case ARMMMUIdx_SE20_0: + case ARMMMUIdx_Stage1_E0: + case ARMMMUIdx_Stage1_SE0: + case ARMMMUIdx_MUser: + case ARMMMUIdx_MSUser: + case ARMMMUIdx_MUserNegPri: + case ARMMMUIdx_MSUserNegPri: + return true; + default: + return false; + case ARMMMUIdx_E10_0: + case ARMMMUIdx_E10_1: + case ARMMMUIdx_E10_1_PAN: + g_assert_not_reached(); + } +} + static bool ptw_attrs_are_device(CPUARMState *env, ARMCacheAttrs cacheattrs) { /* diff --git a/target/arm/ptw.h b/target/arm/ptw.h index 85ad576794..3d3061a435 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -11,7 +11,6 @@ #ifndef CONFIG_USER_ONLY -bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx); bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx); uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, int ttbrn); From 3b318aaeef120a71544771cd84884ccad5fdff0a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:53 +0100 Subject: [PATCH 883/935] target/arm: Move regime_ttbr to ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-25-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 16 ---------------- target/arm/ptw.c | 16 ++++++++++++++++ target/arm/ptw.h | 1 - 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 8deb0fa94c..fdda87e87e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10475,22 +10475,6 @@ bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx) return (regime_sctlr(env, mmu_idx) & SCTLR_M) == 0; } -/* Return the TTBR associated with this translation regime */ -uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, int ttbrn) -{ - if (mmu_idx == ARMMMUIdx_Stage2) { - return env->cp15.vttbr_el2; - } - if (mmu_idx == ARMMMUIdx_Stage2_S) { - return env->cp15.vsttbr_el2; - } - if (ttbrn == 0) { - return env->cp15.ttbr0_el[regime_el(env, mmu_idx)]; - } else { - return env->cp15.ttbr1_el[regime_el(env, mmu_idx)]; - } -} - /* Convert a possible stage1+2 MMU index into the appropriate * stage 1 MMU index */ diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 8db4b5edf1..dc559e6bdf 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -75,6 +75,22 @@ static bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx) } } +/* Return the TTBR associated with this translation regime */ +static uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, int ttbrn) +{ + if (mmu_idx == ARMMMUIdx_Stage2) { + return env->cp15.vttbr_el2; + } + if (mmu_idx == ARMMMUIdx_Stage2_S) { + return env->cp15.vsttbr_el2; + } + if (ttbrn == 0) { + return env->cp15.ttbr0_el[regime_el(env, mmu_idx)]; + } else { + return env->cp15.ttbr1_el[regime_el(env, mmu_idx)]; + } +} + static bool ptw_attrs_are_device(CPUARMState *env, ARMCacheAttrs cacheattrs) { /* diff --git a/target/arm/ptw.h b/target/arm/ptw.h index 3d3061a435..ed152ddaf4 100644 --- a/target/arm/ptw.h +++ b/target/arm/ptw.h @@ -12,7 +12,6 @@ #ifndef CONFIG_USER_ONLY bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx); -uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, int ttbrn); #endif /* !CONFIG_USER_ONLY */ #endif /* TARGET_ARM_PTW_H */ From 8db1a3a0bba1dbe71a3d363b23416a3c30653ddd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:53 +0100 Subject: [PATCH 884/935] target/arm: Move regime_translation_disabled to ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-26-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 47 --------------------------------------------- target/arm/ptw.c | 47 ++++++++++++++++++++++++++++++++++++++++++++- target/arm/ptw.h | 17 ---------------- 3 files changed, 46 insertions(+), 65 deletions(-) delete mode 100644 target/arm/ptw.h diff --git a/target/arm/helper.c b/target/arm/helper.c index fdda87e87e..69b1c060c1 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -36,7 +36,6 @@ #include "semihosting/common-semi.h" #endif #include "cpregs.h" -#include "ptw.h" #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */ @@ -10429,52 +10428,6 @@ uint64_t arm_sctlr(CPUARMState *env, int el) } #ifndef CONFIG_USER_ONLY - -/* Return true if the specified stage of address translation is disabled */ -bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx) -{ - uint64_t hcr_el2; - - if (arm_feature(env, ARM_FEATURE_M)) { - switch (env->v7m.mpu_ctrl[regime_is_secure(env, mmu_idx)] & - (R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK)) { - case R_V7M_MPU_CTRL_ENABLE_MASK: - /* Enabled, but not for HardFault and NMI */ - return mmu_idx & ARM_MMU_IDX_M_NEGPRI; - case R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK: - /* Enabled for all cases */ - return false; - case 0: - default: - /* HFNMIENA set and ENABLE clear is UNPREDICTABLE, but - * we warned about that in armv7m_nvic.c when the guest set it. - */ - return true; - } - } - - hcr_el2 = arm_hcr_el2_eff(env); - - if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) { - /* HCR.DC means HCR.VM behaves as 1 */ - return (hcr_el2 & (HCR_DC | HCR_VM)) == 0; - } - - if (hcr_el2 & HCR_TGE) { - /* TGE means that NS EL0/1 act as if SCTLR_EL1.M is zero */ - if (!regime_is_secure(env, mmu_idx) && regime_el(env, mmu_idx) == 1) { - return true; - } - } - - if ((hcr_el2 & HCR_DC) && arm_mmu_idx_is_stage1_of_2(mmu_idx)) { - /* HCR.DC means SCTLR_EL1.M behaves as 0 */ - return true; - } - - return (regime_sctlr(env, mmu_idx) & SCTLR_M) == 0; -} - /* Convert a possible stage1+2 MMU index into the appropriate * stage 1 MMU index */ diff --git a/target/arm/ptw.c b/target/arm/ptw.c index dc559e6bdf..ec60afd9bf 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -12,7 +12,6 @@ #include "cpu.h" #include "internals.h" #include "idau.h" -#include "ptw.h" static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, @@ -91,6 +90,52 @@ static uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, int ttbrn) } } +/* Return true if the specified stage of address translation is disabled */ +static bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + uint64_t hcr_el2; + + if (arm_feature(env, ARM_FEATURE_M)) { + switch (env->v7m.mpu_ctrl[regime_is_secure(env, mmu_idx)] & + (R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK)) { + case R_V7M_MPU_CTRL_ENABLE_MASK: + /* Enabled, but not for HardFault and NMI */ + return mmu_idx & ARM_MMU_IDX_M_NEGPRI; + case R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK: + /* Enabled for all cases */ + return false; + case 0: + default: + /* + * HFNMIENA set and ENABLE clear is UNPREDICTABLE, but + * we warned about that in armv7m_nvic.c when the guest set it. + */ + return true; + } + } + + hcr_el2 = arm_hcr_el2_eff(env); + + if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) { + /* HCR.DC means HCR.VM behaves as 1 */ + return (hcr_el2 & (HCR_DC | HCR_VM)) == 0; + } + + if (hcr_el2 & HCR_TGE) { + /* TGE means that NS EL0/1 act as if SCTLR_EL1.M is zero */ + if (!regime_is_secure(env, mmu_idx) && regime_el(env, mmu_idx) == 1) { + return true; + } + } + + if ((hcr_el2 & HCR_DC) && arm_mmu_idx_is_stage1_of_2(mmu_idx)) { + /* HCR.DC means SCTLR_EL1.M behaves as 0 */ + return true; + } + + return (regime_sctlr(env, mmu_idx) & SCTLR_M) == 0; +} + static bool ptw_attrs_are_device(CPUARMState *env, ARMCacheAttrs cacheattrs) { /* diff --git a/target/arm/ptw.h b/target/arm/ptw.h deleted file mode 100644 index ed152ddaf4..0000000000 --- a/target/arm/ptw.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * ARM page table walking. - * - * This code is licensed under the GNU GPL v2 or later. - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#ifndef TARGET_ARM_PTW_H -#define TARGET_ARM_PTW_H - -#ifndef CONFIG_USER_ONLY - -bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx); - -#endif /* !CONFIG_USER_ONLY */ -#endif /* TARGET_ARM_PTW_H */ From 23971205cf38e63964b7e110df7d5a293277a48e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:54 +0100 Subject: [PATCH 885/935] target/arm: Move arm_cpu_get_phys_page_attrs_debug to ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-27-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 26 -------------------------- target/arm/ptw.c | 24 ++++++++++++++++++++++++ 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 69b1c060c1..fe1e426f88 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10606,32 +10606,6 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, }; } -#ifndef CONFIG_USER_ONLY -hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, - MemTxAttrs *attrs) -{ - ARMCPU *cpu = ARM_CPU(cs); - CPUARMState *env = &cpu->env; - hwaddr phys_addr; - target_ulong page_size; - int prot; - bool ret; - ARMMMUFaultInfo fi = {}; - ARMMMUIdx mmu_idx = arm_mmu_idx(env); - ARMCacheAttrs cacheattrs = {}; - - *attrs = (MemTxAttrs) {}; - - ret = get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &phys_addr, - attrs, &prot, &page_size, &fi, &cacheattrs); - - if (ret) { - return -1; - } - return phys_addr; -} -#endif - /* Note that signed overflow is undefined in C. The following routines are careful to use unsigned types where modulo arithmetic is required. Failure to do so _will_ break on newer gcc. */ diff --git a/target/arm/ptw.c b/target/arm/ptw.c index ec60afd9bf..e9f6870d0a 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -2491,3 +2491,27 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, phys_ptr, prot, page_size, fi); } } + +hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, + MemTxAttrs *attrs) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + hwaddr phys_addr; + target_ulong page_size; + int prot; + bool ret; + ARMMMUFaultInfo fi = {}; + ARMMMUIdx mmu_idx = arm_mmu_idx(env); + ARMCacheAttrs cacheattrs = {}; + + *attrs = (MemTxAttrs) {}; + + ret = get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &phys_addr, + attrs, &prot, &page_size, &fi, &cacheattrs); + + if (ret) { + return -1; + } + return phys_addr; +} From 1d2612553640a79e049708b9d87a9cd3ddb29af6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:54 +0100 Subject: [PATCH 886/935] target/arm: Move stage_1_mmu_idx, arm_stage1_mmu_idx to ptw.c Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-28-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 32 -------------------------------- target/arm/ptw.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index fe1e426f88..37cf9fa6ab 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10427,31 +10427,6 @@ uint64_t arm_sctlr(CPUARMState *env, int el) return env->cp15.sctlr_el[el]; } -#ifndef CONFIG_USER_ONLY -/* Convert a possible stage1+2 MMU index into the appropriate - * stage 1 MMU index - */ -ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx) -{ - switch (mmu_idx) { - case ARMMMUIdx_SE10_0: - return ARMMMUIdx_Stage1_SE0; - case ARMMMUIdx_SE10_1: - return ARMMMUIdx_Stage1_SE1; - case ARMMMUIdx_SE10_1_PAN: - return ARMMMUIdx_Stage1_SE1_PAN; - case ARMMMUIdx_E10_0: - return ARMMMUIdx_Stage1_E0; - case ARMMMUIdx_E10_1: - return ARMMMUIdx_Stage1_E1; - case ARMMMUIdx_E10_1_PAN: - return ARMMMUIdx_Stage1_E1_PAN; - default: - return mmu_idx; - } -} -#endif /* !CONFIG_USER_ONLY */ - int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx) { if (regime_has_2_ranges(mmu_idx)) { @@ -11081,13 +11056,6 @@ ARMMMUIdx arm_mmu_idx(CPUARMState *env) return arm_mmu_idx_el(env, arm_current_el(env)); } -#ifndef CONFIG_USER_ONLY -ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env) -{ - return stage_1_mmu_idx(arm_mmu_idx(env)); -} -#endif - static CPUARMTBFlags rebuild_hflags_common(CPUARMState *env, int fp_el, ARMMMUIdx mmu_idx, CPUARMTBFlags flags) diff --git a/target/arm/ptw.c b/target/arm/ptw.c index e9f6870d0a..49e9a1d108 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -47,6 +47,34 @@ unsigned int arm_pamax(ARMCPU *cpu) return pamax_map[parange]; } +/* + * Convert a possible stage1+2 MMU index into the appropriate stage 1 MMU index + */ +ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx) +{ + switch (mmu_idx) { + case ARMMMUIdx_SE10_0: + return ARMMMUIdx_Stage1_SE0; + case ARMMMUIdx_SE10_1: + return ARMMMUIdx_Stage1_SE1; + case ARMMMUIdx_SE10_1_PAN: + return ARMMMUIdx_Stage1_SE1_PAN; + case ARMMMUIdx_E10_0: + return ARMMMUIdx_Stage1_E0; + case ARMMMUIdx_E10_1: + return ARMMMUIdx_Stage1_E1; + case ARMMMUIdx_E10_1_PAN: + return ARMMMUIdx_Stage1_E1_PAN; + default: + return mmu_idx; + } +} + +ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env) +{ + return stage_1_mmu_idx(arm_mmu_idx(env)); +} + static bool regime_translation_big_endian(CPUARMState *env, ARMMMUIdx mmu_idx) { return (regime_sctlr(env, mmu_idx) & SCTLR_EE) != 0; From 5e79887ba67e22bfd890b72f94c482176a200fbc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:54 +0100 Subject: [PATCH 887/935] target/arm: Pass CPUARMState to arm_ld[lq]_ptw The use of ARM_CPU to recover env from cs calls object_class_dynamic_cast, which shows up on the profile. This is pointless, because all callers already have env, and the reverse operation, env_cpu, is only pointer arithmetic. Signed-off-by: Richard Henderson Message-id: 20220604040607.269301-29-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/ptw.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 49e9a1d108..4d97a24808 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -241,11 +241,10 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, } /* All loads done in the course of a page table walk go through here. */ -static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, +static uint32_t arm_ldl_ptw(CPUARMState *env, hwaddr addr, bool is_secure, ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi) { - ARMCPU *cpu = ARM_CPU(cs); - CPUARMState *env = &cpu->env; + CPUState *cs = env_cpu(env); MemTxAttrs attrs = {}; MemTxResult result = MEMTX_OK; AddressSpace *as; @@ -270,11 +269,10 @@ static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, return 0; } -static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, +static uint64_t arm_ldq_ptw(CPUARMState *env, hwaddr addr, bool is_secure, ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi) { - ARMCPU *cpu = ARM_CPU(cs); - CPUARMState *env = &cpu->env; + CPUState *cs = env_cpu(env); MemTxAttrs attrs = {}; MemTxResult result = MEMTX_OK; AddressSpace *as; @@ -409,7 +407,6 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, target_ulong *page_size, ARMMMUFaultInfo *fi) { - CPUState *cs = env_cpu(env); int level = 1; uint32_t table; uint32_t desc; @@ -427,7 +424,7 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, fi->type = ARMFault_Translation; goto do_fault; } - desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), + desc = arm_ldl_ptw(env, table, regime_is_secure(env, mmu_idx), mmu_idx, fi); if (fi->type != ARMFault_None) { goto do_fault; @@ -466,7 +463,7 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, /* Fine pagetable. */ table = (desc & 0xfffff000) | ((address >> 8) & 0xffc); } - desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), + desc = arm_ldl_ptw(env, table, regime_is_secure(env, mmu_idx), mmu_idx, fi); if (fi->type != ARMFault_None) { goto do_fault; @@ -531,7 +528,6 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, target_ulong *page_size, ARMMMUFaultInfo *fi) { - CPUState *cs = env_cpu(env); ARMCPU *cpu = env_archcpu(env); int level = 1; uint32_t table; @@ -553,7 +549,7 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, fi->type = ARMFault_Translation; goto do_fault; } - desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), + desc = arm_ldl_ptw(env, table, regime_is_secure(env, mmu_idx), mmu_idx, fi); if (fi->type != ARMFault_None) { goto do_fault; @@ -607,7 +603,7 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, ns = extract32(desc, 3, 1); /* Lookup l2 entry. */ table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); - desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), + desc = arm_ldl_ptw(env, table, regime_is_secure(env, mmu_idx), mmu_idx, fi); if (fi->type != ARMFault_None) { goto do_fault; @@ -973,7 +969,6 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) { ARMCPU *cpu = env_archcpu(env); - CPUState *cs = CPU(cpu); /* Read an LPAE long-descriptor translation table. */ ARMFaultType fault_type = ARMFault_Translation; uint32_t level; @@ -1196,7 +1191,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, descaddr |= (address >> (stride * (4 - level))) & indexmask; descaddr &= ~7ULL; nstable = extract32(tableattrs, 4, 1); - descriptor = arm_ldq_ptw(cs, descaddr, !nstable, mmu_idx, fi); + descriptor = arm_ldq_ptw(env, descaddr, !nstable, mmu_idx, fi); if (fi->type != ARMFault_None) { goto do_fault; } From f45ce4c35f5e0873bbbc3119eff8539610233b7e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:54 +0100 Subject: [PATCH 888/935] target/arm: Rename TBFLAG_A64 ZCR_LEN to VL With SME, the vector length does not only come from ZCR_ELx. Comment that this is either NVL or SVL, like the pseudocode. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 3 ++- target/arm/helper.c | 2 +- target/arm/translate-a64.c | 2 +- target/arm/translate-a64.h | 2 +- target/arm/translate-sve.c | 2 +- target/arm/translate.h | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 0ee1705a4f..e791ffdd6b 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3241,7 +3241,8 @@ FIELD(TBFLAG_M32, MVE_NO_PRED, 5, 1) /* Not cached. */ */ FIELD(TBFLAG_A64, TBII, 0, 2) FIELD(TBFLAG_A64, SVEEXC_EL, 2, 2) -FIELD(TBFLAG_A64, ZCR_LEN, 4, 4) +/* The current vector length, either NVL or SVL. */ +FIELD(TBFLAG_A64, VL, 4, 4) FIELD(TBFLAG_A64, PAUTH_ACTIVE, 8, 1) FIELD(TBFLAG_A64, BT, 9, 1) FIELD(TBFLAG_A64, BTYPE, 10, 2) /* Not cached. */ diff --git a/target/arm/helper.c b/target/arm/helper.c index 37cf9fa6ab..c228deca75 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -11181,7 +11181,7 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, zcr_len = sve_zcr_len_for_el(env, el); } DP_TBFLAG_A64(flags, SVEEXC_EL, sve_el); - DP_TBFLAG_A64(flags, ZCR_LEN, zcr_len); + DP_TBFLAG_A64(flags, VL, zcr_len); } sctlr = regime_sctlr(env, stage1); diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 935e1929bb..d438fb89e7 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -14608,7 +14608,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM); dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL); dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL); - dc->sve_len = (EX_TBFLAG_A64(tb_flags, ZCR_LEN) + 1) * 16; + dc->vl = (EX_TBFLAG_A64(tb_flags, VL) + 1) * 16; dc->pauth_active = EX_TBFLAG_A64(tb_flags, PAUTH_ACTIVE); dc->bt = EX_TBFLAG_A64(tb_flags, BT); dc->btype = EX_TBFLAG_A64(tb_flags, BTYPE); diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h index f2e8ee0ee1..dbc917ee65 100644 --- a/target/arm/translate-a64.h +++ b/target/arm/translate-a64.h @@ -104,7 +104,7 @@ static inline TCGv_ptr vec_full_reg_ptr(DisasContext *s, int regno) /* Return the byte size of the "whole" vector register, VL / 8. */ static inline int vec_full_reg_size(DisasContext *s) { - return s->sve_len; + return s->vl; } bool disas_sve(DisasContext *, uint32_t); diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 836511d719..67761bf2cc 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -111,7 +111,7 @@ static inline int pred_full_reg_offset(DisasContext *s, int regno) /* Return the byte size of the whole predicate register, VL / 64. */ static inline int pred_full_reg_size(DisasContext *s) { - return s->sve_len >> 3; + return s->vl >> 3; } /* Round up the size of a register to a size allowed by diff --git a/target/arm/translate.h b/target/arm/translate.h index 9f0bb270c5..f473a21ed4 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -42,7 +42,7 @@ typedef struct DisasContext { bool ns; /* Use non-secure CPREG bank on access */ int fp_excp_el; /* FP exception EL or 0 if enabled */ int sve_excp_el; /* SVE exception EL or 0 if enabled */ - int sve_len; /* SVE vector length in bytes */ + int vl; /* current vector length in bytes */ /* Flag indicating that exceptions from secure mode are routed to EL3. */ bool secure_routed_to_el3; bool vfp_enabled; /* FP enabled via FPSCR.EN */ From 8b599e5c0274cd5e4a33be6a10d6cd04631a74d1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:55 +0100 Subject: [PATCH 889/935] linux-user/aarch64: Introduce sve_vq Add an interface function to extract the digested vector length rather than the raw zcr_el[1] value. This fixes an incorrect return from do_prctl_set_vl where we didn't take into account the set of vector lengths supported by the cpu. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- linux-user/aarch64/signal.c | 4 ++-- linux-user/aarch64/target_prctl.h | 20 +++++++++++++------- target/arm/cpu.h | 11 +++++++++++ 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c index 7de4c96eb9..7da0e36c6d 100644 --- a/linux-user/aarch64/signal.c +++ b/linux-user/aarch64/signal.c @@ -315,7 +315,7 @@ static int target_restore_sigframe(CPUARMState *env, case TARGET_SVE_MAGIC: if (cpu_isar_feature(aa64_sve, env_archcpu(env))) { - vq = (env->vfp.zcr_el[1] & 0xf) + 1; + vq = sve_vq(env); sve_size = QEMU_ALIGN_UP(TARGET_SVE_SIG_CONTEXT_SIZE(vq), 16); if (!sve && size == sve_size) { sve = (struct target_sve_context *)ctx; @@ -434,7 +434,7 @@ static void target_setup_frame(int usig, struct target_sigaction *ka, /* SVE state needs saving only if it exists. */ if (cpu_isar_feature(aa64_sve, env_archcpu(env))) { - vq = (env->vfp.zcr_el[1] & 0xf) + 1; + vq = sve_vq(env); sve_size = QEMU_ALIGN_UP(TARGET_SVE_SIG_CONTEXT_SIZE(vq), 16); sve_ofs = alloc_sigframe_space(sve_size, &layout); } diff --git a/linux-user/aarch64/target_prctl.h b/linux-user/aarch64/target_prctl.h index 3f5a5d3933..1d440ffbea 100644 --- a/linux-user/aarch64/target_prctl.h +++ b/linux-user/aarch64/target_prctl.h @@ -10,7 +10,7 @@ static abi_long do_prctl_get_vl(CPUArchState *env) { ARMCPU *cpu = env_archcpu(env); if (cpu_isar_feature(aa64_sve, cpu)) { - return ((cpu->env.vfp.zcr_el[1] & 0xf) + 1) * 16; + return sve_vq(env) * 16; } return -TARGET_EINVAL; } @@ -25,18 +25,24 @@ static abi_long do_prctl_set_vl(CPUArchState *env, abi_long arg2) */ if (cpu_isar_feature(aa64_sve, env_archcpu(env)) && arg2 >= 0 && arg2 <= 512 * 16 && !(arg2 & 15)) { - ARMCPU *cpu = env_archcpu(env); uint32_t vq, old_vq; - old_vq = (env->vfp.zcr_el[1] & 0xf) + 1; - vq = MAX(arg2 / 16, 1); - vq = MIN(vq, cpu->sve_max_vq); + old_vq = sve_vq(env); + /* + * Bound the value of arg2, so that we know that it fits into + * the 4-bit field in ZCR_EL1. Rely on the hflags rebuild to + * sort out the length supported by the cpu. + */ + vq = MAX(arg2 / 16, 1); + vq = MIN(vq, ARM_MAX_VQ); + env->vfp.zcr_el[1] = vq - 1; + arm_rebuild_hflags(env); + + vq = sve_vq(env); if (vq < old_vq) { aarch64_sve_narrow_vq(env, vq); } - env->vfp.zcr_el[1] = vq - 1; - arm_rebuild_hflags(env); return vq * 16; } return -TARGET_EINVAL; diff --git a/target/arm/cpu.h b/target/arm/cpu.h index e791ffdd6b..f5af88b686 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3286,6 +3286,17 @@ static inline int cpu_mmu_index(CPUARMState *env, bool ifetch) return EX_TBFLAG_ANY(env->hflags, MMUIDX); } +/** + * sve_vq + * @env: the cpu context + * + * Return the VL cached within env->hflags, in units of quadwords. + */ +static inline int sve_vq(CPUARMState *env) +{ + return EX_TBFLAG_A64(env->hflags, VL) + 1; +} + static inline bool bswap_code(bool sctlr_b) { #ifdef CONFIG_USER_ONLY From 61a8c23a3b56607ee6e745b4cf7975170df88801 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:55 +0100 Subject: [PATCH 890/935] target/arm: Remove route_to_el2 check from sve_exception_el We handle this routing in raise_exception. Promoting the value early means that we can't directly compare FPEXC_EL and SVEEXC_EL. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-4-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index c228deca75..1bd77af7e5 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6149,8 +6149,7 @@ int sve_exception_el(CPUARMState *env, int el) /* fall through */ case 0: case 2: - /* route_to_el2 */ - return hcr_el2 & HCR_TGE ? 2 : 1; + return 1; } /* Check CPACR.FPEN. */ From 397d922c6248509c6d490f82088f00cbc716287c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:55 +0100 Subject: [PATCH 891/935] target/arm: Remove fp checks from sve_exception_el Instead of checking these bits in fp_exception_el and also in sve_exception_el, document that we must compare the results. The only place where we have not already checked that FP EL is zero is in rebuild_hflags_a64. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 58 +++++++++++++++------------------------------ 1 file changed, 19 insertions(+), 39 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 1bd77af7e5..4f4044c688 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6129,11 +6129,15 @@ static const ARMCPRegInfo minimal_ras_reginfo[] = { .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.vsesr_el2) }, }; -/* Return the exception level to which exceptions should be taken - * via SVEAccessTrap. If an exception should be routed through - * AArch64.AdvSIMDFPAccessTrap, return 0; fp_exception_el should - * take care of raising that exception. - * C.f. the ARM pseudocode function CheckSVEEnabled. +/* + * Return the exception level to which exceptions should be taken + * via SVEAccessTrap. This excludes the check for whether the exception + * should be routed through AArch64.AdvSIMDFPAccessTrap. That can easily + * be found by testing 0 < fp_exception_el < sve_exception_el. + * + * C.f. the ARM pseudocode function CheckSVEEnabled. Note that the + * pseudocode does *not* separate out the FP trap checks, but has them + * all in one function. */ int sve_exception_el(CPUARMState *env, int el) { @@ -6151,18 +6155,6 @@ int sve_exception_el(CPUARMState *env, int el) case 2: return 1; } - - /* Check CPACR.FPEN. */ - switch (FIELD_EX64(env->cp15.cpacr_el1, CPACR_EL1, FPEN)) { - case 1: - if (el != 0) { - break; - } - /* fall through */ - case 0: - case 2: - return 0; - } } /* @@ -6180,24 +6172,10 @@ int sve_exception_el(CPUARMState *env, int el) case 2: return 2; } - - switch (FIELD_EX32(env->cp15.cptr_el[2], CPTR_EL2, FPEN)) { - case 1: - if (el == 2 || !(hcr_el2 & HCR_TGE)) { - break; - } - /* fall through */ - case 0: - case 2: - return 0; - } } else if (arm_is_el2_enabled(env)) { if (FIELD_EX64(env->cp15.cptr_el[2], CPTR_EL2, TZ)) { return 2; } - if (FIELD_EX64(env->cp15.cptr_el[2], CPTR_EL2, TFP)) { - return 0; - } } } @@ -11168,19 +11146,21 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, if (cpu_isar_feature(aa64_sve, env_archcpu(env))) { int sve_el = sve_exception_el(env, el); - uint32_t zcr_len; /* - * If SVE is disabled, but FP is enabled, - * then the effective len is 0. + * If either FP or SVE are disabled, translator does not need len. + * If SVE EL > FP EL, FP exception has precedence, and translator + * does not need SVE EL. Save potential re-translations by forcing + * the unneeded data to zero. */ - if (sve_el != 0 && fp_el == 0) { - zcr_len = 0; - } else { - zcr_len = sve_zcr_len_for_el(env, el); + if (fp_el != 0) { + if (sve_el > fp_el) { + sve_el = 0; + } + } else if (sve_el == 0) { + DP_TBFLAG_A64(flags, VL, sve_zcr_len_for_el(env, el)); } DP_TBFLAG_A64(flags, SVEEXC_EL, sve_el); - DP_TBFLAG_A64(flags, VL, zcr_len); } sctlr = regime_sctlr(env, stage1); From 19668718ad188e1b6a162bb52357a67fd407c96c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:55 +0100 Subject: [PATCH 892/935] target/arm: Add el_is_in_host This (newish) ARM pseudocode function is easier to work with than open-coded tests for HCR_E2H etc. Use of the function will be staged into the code base in parts. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-6-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 28 ++++++++++++++++++++++++++++ target/arm/internals.h | 2 ++ 2 files changed, 30 insertions(+) diff --git a/target/arm/helper.c b/target/arm/helper.c index 4f4044c688..322508170e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5282,6 +5282,34 @@ uint64_t arm_hcr_el2_eff(CPUARMState *env) return ret; } +/* + * Corresponds to ARM pseudocode function ELIsInHost(). + */ +bool el_is_in_host(CPUARMState *env, int el) +{ + uint64_t mask; + + /* + * Since we only care about E2H and TGE, we can skip arm_hcr_el2_eff(). + * Perform the simplest bit tests first, and validate EL2 afterward. + */ + if (el & 1) { + return false; /* EL1 or EL3 */ + } + + /* + * Note that hcr_write() checks isar_feature_aa64_vh(), + * aka HaveVirtHostExt(), in allowing HCR_E2H to be set. + */ + mask = el ? HCR_E2H : HCR_E2H | HCR_TGE; + if ((env->cp15.hcr_el2 & mask) != mask) { + return false; + } + + /* TGE and/or E2H set: double check those bits are currently legal. */ + return arm_is_el2_enabled(env) && arm_el_is_aa64(env, 2); +} + static void hcrx_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { diff --git a/target/arm/internals.h b/target/arm/internals.h index 1d83146d56..ceaddcbfd6 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1347,6 +1347,8 @@ static inline void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu) { } void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu); #endif +bool el_is_in_host(CPUARMState *env, int el); + void aa32_max_features(ARMCPU *cpu); #endif From c6225bebc2498e9dd85bdd4de1840925650c7a9f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:56 +0100 Subject: [PATCH 893/935] target/arm: Use el_is_in_host for sve_zcr_len_for_el The ARM pseudocode function NVL uses this predicate now, and I think it's a bit clearer. Simplify the pseudocode condition by noting that IsInHost is always false for EL1. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-7-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 322508170e..6b17c0f507 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6238,8 +6238,7 @@ uint32_t sve_zcr_len_for_el(CPUARMState *env, int el) ARMCPU *cpu = env_archcpu(env); uint32_t zcr_len = cpu->sve_max_vq - 1; - if (el <= 1 && - (arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) { + if (el <= 1 && !el_is_in_host(env, el)) { zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[1]); } if (el <= 2 && arm_feature(env, ARM_FEATURE_EL2)) { From aa4451b60e6a2b1bc4e9a8f6bbf90b266e2a4390 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:56 +0100 Subject: [PATCH 894/935] target/arm: Use el_is_in_host for sve_exception_el The ARM pseudocode function CheckNormalSVEEnabled uses this predicate now, and I think it's a bit clearer. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-8-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 6b17c0f507..40b60b1eea 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6170,9 +6170,7 @@ static const ARMCPRegInfo minimal_ras_reginfo[] = { int sve_exception_el(CPUARMState *env, int el) { #ifndef CONFIG_USER_ONLY - uint64_t hcr_el2 = arm_hcr_el2_eff(env); - - if (el <= 1 && (hcr_el2 & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) { + if (el <= 1 && !el_is_in_host(env, el)) { switch (FIELD_EX64(env->cp15.cpacr_el1, CPACR_EL1, ZEN)) { case 1: if (el != 0) { @@ -6189,6 +6187,7 @@ int sve_exception_el(CPUARMState *env, int el) * CPTR_EL2 changes format with HCR_EL2.E2H (regardless of TGE). */ if (el <= 2) { + uint64_t hcr_el2 = arm_hcr_el2_eff(env); if (hcr_el2 & HCR_E2H) { switch (FIELD_EX64(env->cp15.cptr_el[2], CPTR_EL2, ZEN)) { case 1: From 7d38cb92aad848b9c935588815d0b3a5e157aabb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:56 +0100 Subject: [PATCH 895/935] target/arm: Hoist arm_is_el2_enabled check in sve_exception_el This check is buried within arm_hcr_el2_eff(), but since we have to have the explicit check for CPTR_EL2.TZ, we might as well just check it once at the beginning of the block. Once this is done, we can test HCR_EL2.{E2H,TGE} directly, rather than going through arm_hcr_el2_eff(). Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-9-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 40b60b1eea..61e8026d0e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6183,15 +6183,12 @@ int sve_exception_el(CPUARMState *env, int el) } } - /* - * CPTR_EL2 changes format with HCR_EL2.E2H (regardless of TGE). - */ - if (el <= 2) { - uint64_t hcr_el2 = arm_hcr_el2_eff(env); - if (hcr_el2 & HCR_E2H) { + if (el <= 2 && arm_is_el2_enabled(env)) { + /* CPTR_EL2 changes format with HCR_EL2.E2H (regardless of TGE). */ + if (env->cp15.hcr_el2 & HCR_E2H) { switch (FIELD_EX64(env->cp15.cptr_el[2], CPTR_EL2, ZEN)) { case 1: - if (el != 0 || !(hcr_el2 & HCR_TGE)) { + if (el != 0 || !(env->cp15.hcr_el2 & HCR_TGE)) { break; } /* fall through */ @@ -6199,7 +6196,7 @@ int sve_exception_el(CPUARMState *env, int el) case 2: return 2; } - } else if (arm_is_el2_enabled(env)) { + } else { if (FIELD_EX64(env->cp15.cptr_el[2], CPTR_EL2, TZ)) { return 2; } From 87252bdecdafd49f8f4da6244a40415c27053bc3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:56 +0100 Subject: [PATCH 896/935] target/arm: Do not use aarch64_sve_zcr_get_valid_len in reset We don't need to constrain the value set in zcr_el[1], because it will be done by sve_zcr_len_for_el. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-10-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index d2bd74c2ed..0621944167 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -208,8 +208,7 @@ static void arm_cpu_reset(DeviceState *dev) CPACR_EL1, ZEN, 3); /* with reasonable vector length */ if (cpu_isar_feature(aa64_sve, cpu)) { - env->vfp.zcr_el[1] = - aarch64_sve_zcr_get_valid_len(cpu, cpu->sve_default_vq - 1); + env->vfp.zcr_el[1] = cpu->sve_default_vq - 1; } /* * Enable 48-bit address space (TODO: take reserved_va into account). From 9b5f422559a528f4117aa9c3098fddf3d7c535ba Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:57 +0100 Subject: [PATCH 897/935] target/arm: Merge aarch64_sve_zcr_get_valid_len into caller This function is used only once, and will need modification for Streaming SVE mode. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-11-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 30 +++++++++++------------------- target/arm/internals.h | 11 ----------- 2 files changed, 11 insertions(+), 30 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 61e8026d0e..de159c644c 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6212,39 +6212,31 @@ int sve_exception_el(CPUARMState *env, int el) return 0; } -uint32_t aarch64_sve_zcr_get_valid_len(ARMCPU *cpu, uint32_t start_len) -{ - uint32_t end_len; - - start_len = MIN(start_len, ARM_MAX_VQ - 1); - end_len = start_len; - - if (!test_bit(start_len, cpu->sve_vq_map)) { - end_len = find_last_bit(cpu->sve_vq_map, start_len); - assert(end_len < start_len); - } - return end_len; -} - /* * Given that SVE is enabled, return the vector length for EL. */ uint32_t sve_zcr_len_for_el(CPUARMState *env, int el) { ARMCPU *cpu = env_archcpu(env); - uint32_t zcr_len = cpu->sve_max_vq - 1; + uint32_t len = cpu->sve_max_vq - 1; + uint32_t end_len; if (el <= 1 && !el_is_in_host(env, el)) { - zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[1]); + len = MIN(len, 0xf & (uint32_t)env->vfp.zcr_el[1]); } if (el <= 2 && arm_feature(env, ARM_FEATURE_EL2)) { - zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[2]); + len = MIN(len, 0xf & (uint32_t)env->vfp.zcr_el[2]); } if (arm_feature(env, ARM_FEATURE_EL3)) { - zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[3]); + len = MIN(len, 0xf & (uint32_t)env->vfp.zcr_el[3]); } - return aarch64_sve_zcr_get_valid_len(cpu, zcr_len); + end_len = len; + if (!test_bit(len, cpu->sve_vq_map)) { + end_len = find_last_bit(cpu->sve_vq_map, len); + assert(end_len < len); + } + return end_len; } static void zcr_write(CPUARMState *env, const ARMCPRegInfo *ri, diff --git a/target/arm/internals.h b/target/arm/internals.h index ceaddcbfd6..79eb463753 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -189,17 +189,6 @@ void arm_translate_init(void); void arm_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb); #endif /* CONFIG_TCG */ -/** - * aarch64_sve_zcr_get_valid_len: - * @cpu: cpu context - * @start_len: maximum len to consider - * - * Return the maximum supported sve vector length <= @start_len. - * Note that both @start_len and the return value are in units - * of ZCR_ELx.LEN, so the vector bit length is (x + 1) * 128. - */ -uint32_t aarch64_sve_zcr_get_valid_len(ARMCPU *cpu, uint32_t start_len); - enum arm_fprounding { FPROUNDING_TIEEVEN, FPROUNDING_POSINF, From 886902ece71b5e795fea3e052a32f047d2f8fe33 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:57 +0100 Subject: [PATCH 898/935] target/arm: Use uint32_t instead of bitmap for sve vq's The bitmap need only hold 15 bits; bitmap is over-complicated. We can simplify operations quite a bit with plain logical ops. The introduction of SVE_VQ_POW2_MAP eliminates the need for looping in order to search for powers of two. Simply perform the logical ops and use count leading or trailing zeros as required to find the result. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-12-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 6 +-- target/arm/cpu64.c | 117 ++++++++++++++++++++--------------------- target/arm/helper.c | 9 +--- target/arm/internals.h | 5 ++ target/arm/kvm64.c | 36 +++---------- target/arm/kvm_arm.h | 7 ++- 6 files changed, 75 insertions(+), 105 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index f5af88b686..73f24a5760 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1041,9 +1041,9 @@ struct ArchCPU { * Bits set in sve_vq_supported represent valid vector lengths for * the CPU type. */ - DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ); - DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ); - DECLARE_BITMAP(sve_vq_supported, ARM_MAX_VQ); + uint32_t sve_vq_map; + uint32_t sve_vq_init; + uint32_t sve_vq_supported; /* Generic timer counter frequency, in Hz */ uint64_t gt_cntfrq_hz; diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index cce68dd82a..15665c962b 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -355,8 +355,11 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) * any of the above. Finally, if SVE is not disabled, then at least one * vector length must be enabled. */ - DECLARE_BITMAP(tmp, ARM_MAX_VQ); - uint32_t vq, max_vq = 0; + uint32_t vq_map = cpu->sve_vq_map; + uint32_t vq_init = cpu->sve_vq_init; + uint32_t vq_supported; + uint32_t vq_mask = 0; + uint32_t tmp, vq, max_vq = 0; /* * CPU models specify a set of supported vector lengths which are @@ -364,10 +367,16 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) * in the supported bitmap results in an error. When KVM is enabled we * fetch the supported bitmap from the host. */ - if (kvm_enabled() && kvm_arm_sve_supported()) { - kvm_arm_sve_get_vls(CPU(cpu), cpu->sve_vq_supported); - } else if (kvm_enabled()) { - assert(!cpu_isar_feature(aa64_sve, cpu)); + if (kvm_enabled()) { + if (kvm_arm_sve_supported()) { + cpu->sve_vq_supported = kvm_arm_sve_get_vls(CPU(cpu)); + vq_supported = cpu->sve_vq_supported; + } else { + assert(!cpu_isar_feature(aa64_sve, cpu)); + vq_supported = 0; + } + } else { + vq_supported = cpu->sve_vq_supported; } /* @@ -375,8 +384,9 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) * From the properties, sve_vq_map implies sve_vq_init. * Check first for any sve enabled. */ - if (!bitmap_empty(cpu->sve_vq_map, ARM_MAX_VQ)) { - max_vq = find_last_bit(cpu->sve_vq_map, ARM_MAX_VQ) + 1; + if (vq_map != 0) { + max_vq = 32 - clz32(vq_map); + vq_mask = MAKE_64BIT_MASK(0, max_vq); if (cpu->sve_max_vq && max_vq > cpu->sve_max_vq) { error_setg(errp, "cannot enable sve%d", max_vq * 128); @@ -392,15 +402,10 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) * For KVM we have to automatically enable all supported unitialized * lengths, even when the smaller lengths are not all powers-of-two. */ - bitmap_andnot(tmp, cpu->sve_vq_supported, cpu->sve_vq_init, max_vq); - bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq); + vq_map |= vq_supported & ~vq_init & vq_mask; } else { /* Propagate enabled bits down through required powers-of-two. */ - for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) { - if (!test_bit(vq - 1, cpu->sve_vq_init)) { - set_bit(vq - 1, cpu->sve_vq_map); - } - } + vq_map |= SVE_VQ_POW2_MAP & ~vq_init & vq_mask; } } else if (cpu->sve_max_vq == 0) { /* @@ -413,25 +418,18 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) if (kvm_enabled()) { /* Disabling a supported length disables all larger lengths. */ - for (vq = 1; vq <= ARM_MAX_VQ; ++vq) { - if (test_bit(vq - 1, cpu->sve_vq_init) && - test_bit(vq - 1, cpu->sve_vq_supported)) { - break; - } - } + tmp = vq_init & vq_supported; } else { /* Disabling a power-of-two disables all larger lengths. */ - for (vq = 1; vq <= ARM_MAX_VQ; vq <<= 1) { - if (test_bit(vq - 1, cpu->sve_vq_init)) { - break; - } - } + tmp = vq_init & SVE_VQ_POW2_MAP; } + vq = ctz32(tmp) + 1; max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ; - bitmap_andnot(cpu->sve_vq_map, cpu->sve_vq_supported, - cpu->sve_vq_init, max_vq); - if (max_vq == 0 || bitmap_empty(cpu->sve_vq_map, max_vq)) { + vq_mask = MAKE_64BIT_MASK(0, max_vq); + vq_map = vq_supported & ~vq_init & vq_mask; + + if (max_vq == 0 || vq_map == 0) { error_setg(errp, "cannot disable sve%d", vq * 128); error_append_hint(errp, "Disabling sve%d results in all " "vector lengths being disabled.\n", @@ -441,7 +439,8 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) return; } - max_vq = find_last_bit(cpu->sve_vq_map, max_vq) + 1; + max_vq = 32 - clz32(vq_map); + vq_mask = MAKE_64BIT_MASK(0, max_vq); } /* @@ -451,9 +450,9 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) */ if (cpu->sve_max_vq != 0) { max_vq = cpu->sve_max_vq; + vq_mask = MAKE_64BIT_MASK(0, max_vq); - if (!test_bit(max_vq - 1, cpu->sve_vq_map) && - test_bit(max_vq - 1, cpu->sve_vq_init)) { + if (vq_init & ~vq_map & (1 << (max_vq - 1))) { error_setg(errp, "cannot disable sve%d", max_vq * 128); error_append_hint(errp, "The maximum vector length must be " "enabled, sve-max-vq=%d (%d bits)\n", @@ -462,8 +461,7 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) } /* Set all bits not explicitly set within sve-max-vq. */ - bitmap_complement(tmp, cpu->sve_vq_init, max_vq); - bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq); + vq_map |= ~vq_init & vq_mask; } /* @@ -472,13 +470,14 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) * are clear, just in case anybody looks. */ assert(max_vq != 0); - bitmap_clear(cpu->sve_vq_map, max_vq, ARM_MAX_VQ - max_vq); + assert(vq_mask != 0); + vq_map &= vq_mask; /* Ensure the set of lengths matches what is supported. */ - bitmap_xor(tmp, cpu->sve_vq_map, cpu->sve_vq_supported, max_vq); - if (!bitmap_empty(tmp, max_vq)) { - vq = find_last_bit(tmp, max_vq) + 1; - if (test_bit(vq - 1, cpu->sve_vq_map)) { + tmp = vq_map ^ (vq_supported & vq_mask); + if (tmp) { + vq = 32 - clz32(tmp); + if (vq_map & (1 << (vq - 1))) { if (cpu->sve_max_vq) { error_setg(errp, "cannot set sve-max-vq=%d", cpu->sve_max_vq); error_append_hint(errp, "This CPU does not support " @@ -502,15 +501,15 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) return; } else { /* Ensure all required powers-of-two are enabled. */ - for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) { - if (!test_bit(vq - 1, cpu->sve_vq_map)) { - error_setg(errp, "cannot disable sve%d", vq * 128); - error_append_hint(errp, "sve%d is required as it " - "is a power-of-two length smaller " - "than the maximum, sve%d\n", - vq * 128, max_vq * 128); - return; - } + tmp = SVE_VQ_POW2_MAP & vq_mask & ~vq_map; + if (tmp) { + vq = 32 - clz32(tmp); + error_setg(errp, "cannot disable sve%d", vq * 128); + error_append_hint(errp, "sve%d is required as it " + "is a power-of-two length smaller " + "than the maximum, sve%d\n", + vq * 128, max_vq * 128); + return; } } } @@ -530,6 +529,7 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) /* From now on sve_max_vq is the actual maximum supported length. */ cpu->sve_max_vq = max_vq; + cpu->sve_vq_map = vq_map; } static void cpu_max_get_sve_max_vq(Object *obj, Visitor *v, const char *name, @@ -590,7 +590,7 @@ static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name, if (!cpu_isar_feature(aa64_sve, cpu)) { value = false; } else { - value = test_bit(vq - 1, cpu->sve_vq_map); + value = extract32(cpu->sve_vq_map, vq - 1, 1); } visit_type_bool(v, name, &value, errp); } @@ -612,12 +612,8 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name, return; } - if (value) { - set_bit(vq - 1, cpu->sve_vq_map); - } else { - clear_bit(vq - 1, cpu->sve_vq_map); - } - set_bit(vq - 1, cpu->sve_vq_init); + cpu->sve_vq_map = deposit32(cpu->sve_vq_map, vq - 1, 1, value); + cpu->sve_vq_init |= 1 << (vq - 1); } static bool cpu_arm_get_sve(Object *obj, Error **errp) @@ -979,7 +975,7 @@ static void aarch64_max_initfn(Object *obj) cpu->dcz_blocksize = 7; /* 512 bytes */ #endif - bitmap_fill(cpu->sve_vq_supported, ARM_MAX_VQ); + cpu->sve_vq_supported = MAKE_64BIT_MASK(0, ARM_MAX_VQ); aarch64_add_pauth_properties(obj); aarch64_add_sve_properties(obj); @@ -1026,12 +1022,11 @@ static void aarch64_a64fx_initfn(Object *obj) cpu->gic_vprebits = 5; cpu->gic_pribits = 5; - /* Suppport of A64FX's vector length are 128,256 and 512bit only */ + /* The A64FX supports only 128, 256 and 512 bit vector lengths */ aarch64_add_sve_properties(obj); - bitmap_zero(cpu->sve_vq_supported, ARM_MAX_VQ); - set_bit(0, cpu->sve_vq_supported); /* 128bit */ - set_bit(1, cpu->sve_vq_supported); /* 256bit */ - set_bit(3, cpu->sve_vq_supported); /* 512bit */ + cpu->sve_vq_supported = (1 << 0) /* 128bit */ + | (1 << 1) /* 256bit */ + | (1 << 3); /* 512bit */ cpu->isar.reset_pmcr_el0 = 0x46014040; diff --git a/target/arm/helper.c b/target/arm/helper.c index de159c644c..90aac6bc12 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6219,7 +6219,6 @@ uint32_t sve_zcr_len_for_el(CPUARMState *env, int el) { ARMCPU *cpu = env_archcpu(env); uint32_t len = cpu->sve_max_vq - 1; - uint32_t end_len; if (el <= 1 && !el_is_in_host(env, el)) { len = MIN(len, 0xf & (uint32_t)env->vfp.zcr_el[1]); @@ -6231,12 +6230,8 @@ uint32_t sve_zcr_len_for_el(CPUARMState *env, int el) len = MIN(len, 0xf & (uint32_t)env->vfp.zcr_el[3]); } - end_len = len; - if (!test_bit(len, cpu->sve_vq_map)) { - end_len = find_last_bit(cpu->sve_vq_map, len); - assert(end_len < len); - } - return end_len; + len = 31 - clz32(cpu->sve_vq_map & MAKE_64BIT_MASK(0, len + 1)); + return len; } static void zcr_write(CPUARMState *env, const ARMCPRegInfo *ri, diff --git a/target/arm/internals.h b/target/arm/internals.h index 79eb463753..a1bae4588a 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1340,4 +1340,9 @@ bool el_is_in_host(CPUARMState *env, int el); void aa32_max_features(ARMCPU *cpu); +/* Powers of 2 for sve_vq_map et al. */ +#define SVE_VQ_POW2_MAP \ + ((1 << (1 - 1)) | (1 << (2 - 1)) | \ + (1 << (4 - 1)) | (1 << (8 - 1)) | (1 << (16 - 1))) + #endif diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index 363032da90..b3f635fc95 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -760,15 +760,13 @@ bool kvm_arm_steal_time_supported(void) QEMU_BUILD_BUG_ON(KVM_ARM64_SVE_VQ_MIN != 1); -void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map) +uint32_t kvm_arm_sve_get_vls(CPUState *cs) { /* Only call this function if kvm_arm_sve_supported() returns true. */ static uint64_t vls[KVM_ARM64_SVE_VLS_WORDS]; static bool probed; uint32_t vq = 0; - int i, j; - - bitmap_zero(map, ARM_MAX_VQ); + int i; /* * KVM ensures all host CPUs support the same set of vector lengths. @@ -809,46 +807,24 @@ void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map) if (vq > ARM_MAX_VQ) { warn_report("KVM supports vector lengths larger than " "QEMU can enable"); + vls[0] &= MAKE_64BIT_MASK(0, ARM_MAX_VQ); } } - for (i = 0; i < KVM_ARM64_SVE_VLS_WORDS; ++i) { - if (!vls[i]) { - continue; - } - for (j = 1; j <= 64; ++j) { - vq = j + i * 64; - if (vq > ARM_MAX_VQ) { - return; - } - if (vls[i] & (1UL << (j - 1))) { - set_bit(vq - 1, map); - } - } - } + return vls[0]; } static int kvm_arm_sve_set_vls(CPUState *cs) { - uint64_t vls[KVM_ARM64_SVE_VLS_WORDS] = {0}; + ARMCPU *cpu = ARM_CPU(cs); + uint64_t vls[KVM_ARM64_SVE_VLS_WORDS] = { cpu->sve_vq_map }; struct kvm_one_reg reg = { .id = KVM_REG_ARM64_SVE_VLS, .addr = (uint64_t)&vls[0], }; - ARMCPU *cpu = ARM_CPU(cs); - uint32_t vq; - int i, j; assert(cpu->sve_max_vq <= KVM_ARM64_SVE_VQ_MAX); - for (vq = 1; vq <= cpu->sve_max_vq; ++vq) { - if (test_bit(vq - 1, cpu->sve_vq_map)) { - i = (vq - 1) / 64; - j = (vq - 1) % 64; - vls[i] |= 1UL << j; - } - } - return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); } diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h index b7f78b5215..99017b635c 100644 --- a/target/arm/kvm_arm.h +++ b/target/arm/kvm_arm.h @@ -239,13 +239,12 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf); /** * kvm_arm_sve_get_vls: * @cs: CPUState - * @map: bitmap to fill in * * Get all the SVE vector lengths supported by the KVM host, setting * the bits corresponding to their length in quadwords minus one - * (vq - 1) in @map up to ARM_MAX_VQ. + * (vq - 1) up to ARM_MAX_VQ. Return the resulting map. */ -void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map); +uint32_t kvm_arm_sve_get_vls(CPUState *cs); /** * kvm_arm_set_cpu_features_from_host: @@ -439,7 +438,7 @@ static inline void kvm_arm_steal_time_finalize(ARMCPU *cpu, Error **errp) g_assert_not_reached(); } -static inline void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map) +static inline uint32_t kvm_arm_sve_get_vls(CPUState *cs) { g_assert_not_reached(); } From 5ef3cc563699d9b96e6b1acb15c7c02cf75d8266 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:57 +0100 Subject: [PATCH 899/935] target/arm: Rename sve_zcr_len_for_el to sve_vqm1_for_el This will be used for both Normal and Streaming SVE, and the value does not necessarily come from ZCR_ELx. While we're at it, emphasize the units in which the value is returned. Patch produced by git grep -l sve_zcr_len_for_el | \ xargs -n1 sed -i 's/sve_zcr_len_for_el/sve_vqm1_for_el/g' and then adding a function comment. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-13-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/arch_dump.c | 2 +- target/arm/cpu.c | 2 +- target/arm/cpu.h | 11 ++++++++++- target/arm/gdbstub64.c | 2 +- target/arm/helper.c | 12 ++++++------ 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/target/arm/arch_dump.c b/target/arm/arch_dump.c index 0184845310..b1f040e69f 100644 --- a/target/arm/arch_dump.c +++ b/target/arm/arch_dump.c @@ -166,7 +166,7 @@ static off_t sve_fpcr_offset(uint32_t vq) static uint32_t sve_current_vq(CPUARMState *env) { - return sve_zcr_len_for_el(env, arm_current_el(env)) + 1; + return sve_vqm1_for_el(env, arm_current_el(env)) + 1; } static size_t sve_size_vq(uint32_t vq) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 0621944167..1b5d535788 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -925,7 +925,7 @@ static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags) vfp_get_fpcr(env), vfp_get_fpsr(env)); if (cpu_isar_feature(aa64_sve, cpu) && sve_exception_el(env, el) == 0) { - int j, zcr_len = sve_zcr_len_for_el(env, el); + int j, zcr_len = sve_vqm1_for_el(env, el); for (i = 0; i <= FFR_PRED_NUM; i++) { bool eol; diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 73f24a5760..e45b5cb7fe 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1132,7 +1132,16 @@ void aarch64_sync_64_to_32(CPUARMState *env); int fp_exception_el(CPUARMState *env, int cur_el); int sve_exception_el(CPUARMState *env, int cur_el); -uint32_t sve_zcr_len_for_el(CPUARMState *env, int el); + +/** + * sve_vqm1_for_el: + * @env: CPUARMState + * @el: exception level + * + * Compute the current SVE vector length for @el, in units of + * Quadwords Minus 1 -- the same scale used for ZCR_ELx.LEN. + */ +uint32_t sve_vqm1_for_el(CPUARMState *env, int el); static inline bool is_a64(CPUARMState *env) { diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c index 596878666d..07a6746944 100644 --- a/target/arm/gdbstub64.c +++ b/target/arm/gdbstub64.c @@ -152,7 +152,7 @@ int arm_gdb_get_svereg(CPUARMState *env, GByteArray *buf, int reg) * We report in Vector Granules (VG) which is 64bit in a Z reg * while the ZCR works in Vector Quads (VQ) which is 128bit chunks. */ - int vq = sve_zcr_len_for_el(env, arm_current_el(env)) + 1; + int vq = sve_vqm1_for_el(env, arm_current_el(env)) + 1; return gdb_get_reg64(buf, vq * 2); } default: diff --git a/target/arm/helper.c b/target/arm/helper.c index 90aac6bc12..400f7cd1db 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6215,7 +6215,7 @@ int sve_exception_el(CPUARMState *env, int el) /* * Given that SVE is enabled, return the vector length for EL. */ -uint32_t sve_zcr_len_for_el(CPUARMState *env, int el) +uint32_t sve_vqm1_for_el(CPUARMState *env, int el) { ARMCPU *cpu = env_archcpu(env); uint32_t len = cpu->sve_max_vq - 1; @@ -6238,7 +6238,7 @@ static void zcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { int cur_el = arm_current_el(env); - int old_len = sve_zcr_len_for_el(env, cur_el); + int old_len = sve_vqm1_for_el(env, cur_el); int new_len; /* Bits other than [3:0] are RAZ/WI. */ @@ -6249,7 +6249,7 @@ static void zcr_write(CPUARMState *env, const ARMCPRegInfo *ri, * Because we arrived here, we know both FP and SVE are enabled; * otherwise we would have trapped access to the ZCR_ELn register. */ - new_len = sve_zcr_len_for_el(env, cur_el); + new_len = sve_vqm1_for_el(env, cur_el); if (new_len < old_len) { aarch64_sve_narrow_vq(env, new_len + 1); } @@ -11168,7 +11168,7 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, sve_el = 0; } } else if (sve_el == 0) { - DP_TBFLAG_A64(flags, VL, sve_zcr_len_for_el(env, el)); + DP_TBFLAG_A64(flags, VL, sve_vqm1_for_el(env, el)); } DP_TBFLAG_A64(flags, SVEEXC_EL, sve_el); } @@ -11534,10 +11534,10 @@ void aarch64_sve_change_el(CPUARMState *env, int old_el, */ old_a64 = old_el ? arm_el_is_aa64(env, old_el) : el0_a64; old_len = (old_a64 && !sve_exception_el(env, old_el) - ? sve_zcr_len_for_el(env, old_el) : 0); + ? sve_vqm1_for_el(env, old_el) : 0); new_a64 = new_el ? arm_el_is_aa64(env, new_el) : el0_a64; new_len = (new_a64 && !sve_exception_el(env, new_el) - ? sve_zcr_len_for_el(env, new_el) : 0); + ? sve_vqm1_for_el(env, new_el) : 0); /* When changing vector length, clear inaccessible state. */ if (new_len < old_len) { From d1ce862602ac23de7b3e8541507fc78a8c4a5766 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:57 +0100 Subject: [PATCH 900/935] target/arm: Split out load/store primitives to sve_ldst_internal.h Begin creation of sve_ldst_internal.h by moving the primitives that access host and tlb memory. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-14-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/sve_helper.c | 107 +-------------------------- target/arm/sve_ldst_internal.h | 127 +++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 106 deletions(-) create mode 100644 target/arm/sve_ldst_internal.h diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index 3bdcd4ce9d..0c6dde00aa 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -21,12 +21,12 @@ #include "cpu.h" #include "internals.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" #include "exec/helper-proto.h" #include "tcg/tcg-gvec-desc.h" #include "fpu/softfloat.h" #include "tcg/tcg.h" #include "vec_internal.h" +#include "sve_ldst_internal.h" /* Return a value for NZCV as per the ARM PredTest pseudofunction. @@ -5301,111 +5301,6 @@ void HELPER(sve_fcmla_zpzzz_d)(void *vd, void *vn, void *vm, void *va, * Load contiguous data, protected by a governing predicate. */ -/* - * Load one element into @vd + @reg_off from @host. - * The controlling predicate is known to be true. - */ -typedef void sve_ldst1_host_fn(void *vd, intptr_t reg_off, void *host); - -/* - * Load one element into @vd + @reg_off from (@env, @vaddr, @ra). - * The controlling predicate is known to be true. - */ -typedef void sve_ldst1_tlb_fn(CPUARMState *env, void *vd, intptr_t reg_off, - target_ulong vaddr, uintptr_t retaddr); - -/* - * Generate the above primitives. - */ - -#define DO_LD_HOST(NAME, H, TYPEE, TYPEM, HOST) \ -static void sve_##NAME##_host(void *vd, intptr_t reg_off, void *host) \ -{ \ - TYPEM val = HOST(host); \ - *(TYPEE *)(vd + H(reg_off)) = val; \ -} - -#define DO_ST_HOST(NAME, H, TYPEE, TYPEM, HOST) \ -static void sve_##NAME##_host(void *vd, intptr_t reg_off, void *host) \ -{ HOST(host, (TYPEM)*(TYPEE *)(vd + H(reg_off))); } - -#define DO_LD_TLB(NAME, H, TYPEE, TYPEM, TLB) \ -static void sve_##NAME##_tlb(CPUARMState *env, void *vd, intptr_t reg_off, \ - target_ulong addr, uintptr_t ra) \ -{ \ - *(TYPEE *)(vd + H(reg_off)) = \ - (TYPEM)TLB(env, useronly_clean_ptr(addr), ra); \ -} - -#define DO_ST_TLB(NAME, H, TYPEE, TYPEM, TLB) \ -static void sve_##NAME##_tlb(CPUARMState *env, void *vd, intptr_t reg_off, \ - target_ulong addr, uintptr_t ra) \ -{ \ - TLB(env, useronly_clean_ptr(addr), \ - (TYPEM)*(TYPEE *)(vd + H(reg_off)), ra); \ -} - -#define DO_LD_PRIM_1(NAME, H, TE, TM) \ - DO_LD_HOST(NAME, H, TE, TM, ldub_p) \ - DO_LD_TLB(NAME, H, TE, TM, cpu_ldub_data_ra) - -DO_LD_PRIM_1(ld1bb, H1, uint8_t, uint8_t) -DO_LD_PRIM_1(ld1bhu, H1_2, uint16_t, uint8_t) -DO_LD_PRIM_1(ld1bhs, H1_2, uint16_t, int8_t) -DO_LD_PRIM_1(ld1bsu, H1_4, uint32_t, uint8_t) -DO_LD_PRIM_1(ld1bss, H1_4, uint32_t, int8_t) -DO_LD_PRIM_1(ld1bdu, H1_8, uint64_t, uint8_t) -DO_LD_PRIM_1(ld1bds, H1_8, uint64_t, int8_t) - -#define DO_ST_PRIM_1(NAME, H, TE, TM) \ - DO_ST_HOST(st1##NAME, H, TE, TM, stb_p) \ - DO_ST_TLB(st1##NAME, H, TE, TM, cpu_stb_data_ra) - -DO_ST_PRIM_1(bb, H1, uint8_t, uint8_t) -DO_ST_PRIM_1(bh, H1_2, uint16_t, uint8_t) -DO_ST_PRIM_1(bs, H1_4, uint32_t, uint8_t) -DO_ST_PRIM_1(bd, H1_8, uint64_t, uint8_t) - -#define DO_LD_PRIM_2(NAME, H, TE, TM, LD) \ - DO_LD_HOST(ld1##NAME##_be, H, TE, TM, LD##_be_p) \ - DO_LD_HOST(ld1##NAME##_le, H, TE, TM, LD##_le_p) \ - DO_LD_TLB(ld1##NAME##_be, H, TE, TM, cpu_##LD##_be_data_ra) \ - DO_LD_TLB(ld1##NAME##_le, H, TE, TM, cpu_##LD##_le_data_ra) - -#define DO_ST_PRIM_2(NAME, H, TE, TM, ST) \ - DO_ST_HOST(st1##NAME##_be, H, TE, TM, ST##_be_p) \ - DO_ST_HOST(st1##NAME##_le, H, TE, TM, ST##_le_p) \ - DO_ST_TLB(st1##NAME##_be, H, TE, TM, cpu_##ST##_be_data_ra) \ - DO_ST_TLB(st1##NAME##_le, H, TE, TM, cpu_##ST##_le_data_ra) - -DO_LD_PRIM_2(hh, H1_2, uint16_t, uint16_t, lduw) -DO_LD_PRIM_2(hsu, H1_4, uint32_t, uint16_t, lduw) -DO_LD_PRIM_2(hss, H1_4, uint32_t, int16_t, lduw) -DO_LD_PRIM_2(hdu, H1_8, uint64_t, uint16_t, lduw) -DO_LD_PRIM_2(hds, H1_8, uint64_t, int16_t, lduw) - -DO_ST_PRIM_2(hh, H1_2, uint16_t, uint16_t, stw) -DO_ST_PRIM_2(hs, H1_4, uint32_t, uint16_t, stw) -DO_ST_PRIM_2(hd, H1_8, uint64_t, uint16_t, stw) - -DO_LD_PRIM_2(ss, H1_4, uint32_t, uint32_t, ldl) -DO_LD_PRIM_2(sdu, H1_8, uint64_t, uint32_t, ldl) -DO_LD_PRIM_2(sds, H1_8, uint64_t, int32_t, ldl) - -DO_ST_PRIM_2(ss, H1_4, uint32_t, uint32_t, stl) -DO_ST_PRIM_2(sd, H1_8, uint64_t, uint32_t, stl) - -DO_LD_PRIM_2(dd, H1_8, uint64_t, uint64_t, ldq) -DO_ST_PRIM_2(dd, H1_8, uint64_t, uint64_t, stq) - -#undef DO_LD_TLB -#undef DO_ST_TLB -#undef DO_LD_HOST -#undef DO_LD_PRIM_1 -#undef DO_ST_PRIM_1 -#undef DO_LD_PRIM_2 -#undef DO_ST_PRIM_2 - /* * Skip through a sequence of inactive elements in the guarding predicate @vg, * beginning at @reg_off bounded by @reg_max. Return the offset of the active diff --git a/target/arm/sve_ldst_internal.h b/target/arm/sve_ldst_internal.h new file mode 100644 index 0000000000..ef9117e84c --- /dev/null +++ b/target/arm/sve_ldst_internal.h @@ -0,0 +1,127 @@ +/* + * ARM SVE Load/Store Helpers + * + * Copyright (c) 2018-2022 Linaro + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#ifndef TARGET_ARM_SVE_LDST_INTERNAL_H +#define TARGET_ARM_SVE_LDST_INTERNAL_H + +#include "exec/cpu_ldst.h" + +/* + * Load one element into @vd + @reg_off from @host. + * The controlling predicate is known to be true. + */ +typedef void sve_ldst1_host_fn(void *vd, intptr_t reg_off, void *host); + +/* + * Load one element into @vd + @reg_off from (@env, @vaddr, @ra). + * The controlling predicate is known to be true. + */ +typedef void sve_ldst1_tlb_fn(CPUARMState *env, void *vd, intptr_t reg_off, + target_ulong vaddr, uintptr_t retaddr); + +/* + * Generate the above primitives. + */ + +#define DO_LD_HOST(NAME, H, TYPEE, TYPEM, HOST) \ +static inline void sve_##NAME##_host(void *vd, intptr_t reg_off, void *host) \ +{ TYPEM val = HOST(host); *(TYPEE *)(vd + H(reg_off)) = val; } + +#define DO_ST_HOST(NAME, H, TYPEE, TYPEM, HOST) \ +static inline void sve_##NAME##_host(void *vd, intptr_t reg_off, void *host) \ +{ TYPEM val = *(TYPEE *)(vd + H(reg_off)); HOST(host, val); } + +#define DO_LD_TLB(NAME, H, TYPEE, TYPEM, TLB) \ +static inline void sve_##NAME##_tlb(CPUARMState *env, void *vd, \ + intptr_t reg_off, target_ulong addr, uintptr_t ra) \ +{ \ + TYPEM val = TLB(env, useronly_clean_ptr(addr), ra); \ + *(TYPEE *)(vd + H(reg_off)) = val; \ +} + +#define DO_ST_TLB(NAME, H, TYPEE, TYPEM, TLB) \ +static inline void sve_##NAME##_tlb(CPUARMState *env, void *vd, \ + intptr_t reg_off, target_ulong addr, uintptr_t ra) \ +{ \ + TYPEM val = *(TYPEE *)(vd + H(reg_off)); \ + TLB(env, useronly_clean_ptr(addr), val, ra); \ +} + +#define DO_LD_PRIM_1(NAME, H, TE, TM) \ + DO_LD_HOST(NAME, H, TE, TM, ldub_p) \ + DO_LD_TLB(NAME, H, TE, TM, cpu_ldub_data_ra) + +DO_LD_PRIM_1(ld1bb, H1, uint8_t, uint8_t) +DO_LD_PRIM_1(ld1bhu, H1_2, uint16_t, uint8_t) +DO_LD_PRIM_1(ld1bhs, H1_2, uint16_t, int8_t) +DO_LD_PRIM_1(ld1bsu, H1_4, uint32_t, uint8_t) +DO_LD_PRIM_1(ld1bss, H1_4, uint32_t, int8_t) +DO_LD_PRIM_1(ld1bdu, H1_8, uint64_t, uint8_t) +DO_LD_PRIM_1(ld1bds, H1_8, uint64_t, int8_t) + +#define DO_ST_PRIM_1(NAME, H, TE, TM) \ + DO_ST_HOST(st1##NAME, H, TE, TM, stb_p) \ + DO_ST_TLB(st1##NAME, H, TE, TM, cpu_stb_data_ra) + +DO_ST_PRIM_1(bb, H1, uint8_t, uint8_t) +DO_ST_PRIM_1(bh, H1_2, uint16_t, uint8_t) +DO_ST_PRIM_1(bs, H1_4, uint32_t, uint8_t) +DO_ST_PRIM_1(bd, H1_8, uint64_t, uint8_t) + +#define DO_LD_PRIM_2(NAME, H, TE, TM, LD) \ + DO_LD_HOST(ld1##NAME##_be, H, TE, TM, LD##_be_p) \ + DO_LD_HOST(ld1##NAME##_le, H, TE, TM, LD##_le_p) \ + DO_LD_TLB(ld1##NAME##_be, H, TE, TM, cpu_##LD##_be_data_ra) \ + DO_LD_TLB(ld1##NAME##_le, H, TE, TM, cpu_##LD##_le_data_ra) + +#define DO_ST_PRIM_2(NAME, H, TE, TM, ST) \ + DO_ST_HOST(st1##NAME##_be, H, TE, TM, ST##_be_p) \ + DO_ST_HOST(st1##NAME##_le, H, TE, TM, ST##_le_p) \ + DO_ST_TLB(st1##NAME##_be, H, TE, TM, cpu_##ST##_be_data_ra) \ + DO_ST_TLB(st1##NAME##_le, H, TE, TM, cpu_##ST##_le_data_ra) + +DO_LD_PRIM_2(hh, H1_2, uint16_t, uint16_t, lduw) +DO_LD_PRIM_2(hsu, H1_4, uint32_t, uint16_t, lduw) +DO_LD_PRIM_2(hss, H1_4, uint32_t, int16_t, lduw) +DO_LD_PRIM_2(hdu, H1_8, uint64_t, uint16_t, lduw) +DO_LD_PRIM_2(hds, H1_8, uint64_t, int16_t, lduw) + +DO_ST_PRIM_2(hh, H1_2, uint16_t, uint16_t, stw) +DO_ST_PRIM_2(hs, H1_4, uint32_t, uint16_t, stw) +DO_ST_PRIM_2(hd, H1_8, uint64_t, uint16_t, stw) + +DO_LD_PRIM_2(ss, H1_4, uint32_t, uint32_t, ldl) +DO_LD_PRIM_2(sdu, H1_8, uint64_t, uint32_t, ldl) +DO_LD_PRIM_2(sds, H1_8, uint64_t, int32_t, ldl) + +DO_ST_PRIM_2(ss, H1_4, uint32_t, uint32_t, stl) +DO_ST_PRIM_2(sd, H1_8, uint64_t, uint32_t, stl) + +DO_LD_PRIM_2(dd, H1_8, uint64_t, uint64_t, ldq) +DO_ST_PRIM_2(dd, H1_8, uint64_t, uint64_t, stq) + +#undef DO_LD_TLB +#undef DO_ST_TLB +#undef DO_LD_HOST +#undef DO_LD_PRIM_1 +#undef DO_ST_PRIM_1 +#undef DO_LD_PRIM_2 +#undef DO_ST_PRIM_2 + +#endif /* TARGET_ARM_SVE_LDST_INTERNAL_H */ From 0b68112b399d77c765a0a5d9bb4f4b4e57541ee7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:58 +0100 Subject: [PATCH 901/935] target/arm: Export sve contiguous ldst support functions Export all of the support functions for performing bulk fault analysis on a set of elements at contiguous addresses controlled by a predicate. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-15-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/sve_helper.c | 87 ++++++------------------------- target/arm/sve_ldst_internal.h | 94 ++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 70 deletions(-) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index 0c6dde00aa..8cd371e3e3 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -5341,16 +5341,9 @@ static intptr_t find_next_active(uint64_t *vg, intptr_t reg_off, * exit via page fault exception. */ -typedef struct { - void *host; - int flags; - MemTxAttrs attrs; -} SVEHostPage; - -static bool sve_probe_page(SVEHostPage *info, bool nofault, - CPUARMState *env, target_ulong addr, - int mem_off, MMUAccessType access_type, - int mmu_idx, uintptr_t retaddr) +bool sve_probe_page(SVEHostPage *info, bool nofault, CPUARMState *env, + target_ulong addr, int mem_off, MMUAccessType access_type, + int mmu_idx, uintptr_t retaddr) { int flags; @@ -5406,59 +5399,13 @@ static bool sve_probe_page(SVEHostPage *info, bool nofault, return true; } - -/* - * Analyse contiguous data, protected by a governing predicate. - */ - -typedef enum { - FAULT_NO, - FAULT_FIRST, - FAULT_ALL, -} SVEContFault; - -typedef struct { - /* - * First and last element wholly contained within the two pages. - * mem_off_first[0] and reg_off_first[0] are always set >= 0. - * reg_off_last[0] may be < 0 if the first element crosses pages. - * All of mem_off_first[1], reg_off_first[1] and reg_off_last[1] - * are set >= 0 only if there are complete elements on a second page. - * - * The reg_off_* offsets are relative to the internal vector register. - * The mem_off_first offset is relative to the memory address; the - * two offsets are different when a load operation extends, a store - * operation truncates, or for multi-register operations. - */ - int16_t mem_off_first[2]; - int16_t reg_off_first[2]; - int16_t reg_off_last[2]; - - /* - * One element that is misaligned and spans both pages, - * or -1 if there is no such active element. - */ - int16_t mem_off_split; - int16_t reg_off_split; - - /* - * The byte offset at which the entire operation crosses a page boundary. - * Set >= 0 if and only if the entire operation spans two pages. - */ - int16_t page_split; - - /* TLB data for the two pages. */ - SVEHostPage page[2]; -} SVEContLdSt; - /* * Find first active element on each page, and a loose bound for the * final element on each page. Identify any single element that spans * the page boundary. Return true if there are any active elements. */ -static bool sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr, - uint64_t *vg, intptr_t reg_max, - int esz, int msize) +bool sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr, uint64_t *vg, + intptr_t reg_max, int esz, int msize) { const int esize = 1 << esz; const uint64_t pg_mask = pred_esz_masks[esz]; @@ -5548,9 +5495,9 @@ static bool sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr, * Control the generation of page faults with @fault. Return false if * there is no work to do, which can only happen with @fault == FAULT_NO. */ -static bool sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault, - CPUARMState *env, target_ulong addr, - MMUAccessType access_type, uintptr_t retaddr) +bool sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault, + CPUARMState *env, target_ulong addr, + MMUAccessType access_type, uintptr_t retaddr) { int mmu_idx = cpu_mmu_index(env, false); int mem_off = info->mem_off_first[0]; @@ -5606,12 +5553,12 @@ static bool sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault, return have_work; } -static void sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env, - uint64_t *vg, target_ulong addr, - int esize, int msize, int wp_access, - uintptr_t retaddr) -{ #ifndef CONFIG_USER_ONLY +void sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env, + uint64_t *vg, target_ulong addr, + int esize, int msize, int wp_access, + uintptr_t retaddr) +{ intptr_t mem_off, reg_off, reg_last; int flags0 = info->page[0].flags; int flags1 = info->page[1].flags; @@ -5667,12 +5614,12 @@ static void sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env, } while (reg_off & 63); } while (reg_off <= reg_last); } -#endif } +#endif -static void sve_cont_ldst_mte_check(SVEContLdSt *info, CPUARMState *env, - uint64_t *vg, target_ulong addr, int esize, - int msize, uint32_t mtedesc, uintptr_t ra) +void sve_cont_ldst_mte_check(SVEContLdSt *info, CPUARMState *env, + uint64_t *vg, target_ulong addr, int esize, + int msize, uint32_t mtedesc, uintptr_t ra) { intptr_t mem_off, reg_off, reg_last; diff --git a/target/arm/sve_ldst_internal.h b/target/arm/sve_ldst_internal.h index ef9117e84c..b5c473fc48 100644 --- a/target/arm/sve_ldst_internal.h +++ b/target/arm/sve_ldst_internal.h @@ -124,4 +124,98 @@ DO_ST_PRIM_2(dd, H1_8, uint64_t, uint64_t, stq) #undef DO_LD_PRIM_2 #undef DO_ST_PRIM_2 +/* + * Resolve the guest virtual address to info->host and info->flags. + * If @nofault, return false if the page is invalid, otherwise + * exit via page fault exception. + */ + +typedef struct { + void *host; + int flags; + MemTxAttrs attrs; +} SVEHostPage; + +bool sve_probe_page(SVEHostPage *info, bool nofault, CPUARMState *env, + target_ulong addr, int mem_off, MMUAccessType access_type, + int mmu_idx, uintptr_t retaddr); + +/* + * Analyse contiguous data, protected by a governing predicate. + */ + +typedef enum { + FAULT_NO, + FAULT_FIRST, + FAULT_ALL, +} SVEContFault; + +typedef struct { + /* + * First and last element wholly contained within the two pages. + * mem_off_first[0] and reg_off_first[0] are always set >= 0. + * reg_off_last[0] may be < 0 if the first element crosses pages. + * All of mem_off_first[1], reg_off_first[1] and reg_off_last[1] + * are set >= 0 only if there are complete elements on a second page. + * + * The reg_off_* offsets are relative to the internal vector register. + * The mem_off_first offset is relative to the memory address; the + * two offsets are different when a load operation extends, a store + * operation truncates, or for multi-register operations. + */ + int16_t mem_off_first[2]; + int16_t reg_off_first[2]; + int16_t reg_off_last[2]; + + /* + * One element that is misaligned and spans both pages, + * or -1 if there is no such active element. + */ + int16_t mem_off_split; + int16_t reg_off_split; + + /* + * The byte offset at which the entire operation crosses a page boundary. + * Set >= 0 if and only if the entire operation spans two pages. + */ + int16_t page_split; + + /* TLB data for the two pages. */ + SVEHostPage page[2]; +} SVEContLdSt; + +/* + * Find first active element on each page, and a loose bound for the + * final element on each page. Identify any single element that spans + * the page boundary. Return true if there are any active elements. + */ +bool sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr, uint64_t *vg, + intptr_t reg_max, int esz, int msize); + +/* + * Resolve the guest virtual addresses to info->page[]. + * Control the generation of page faults with @fault. Return false if + * there is no work to do, which can only happen with @fault == FAULT_NO. + */ +bool sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault, + CPUARMState *env, target_ulong addr, + MMUAccessType access_type, uintptr_t retaddr); + +#ifdef CONFIG_USER_ONLY +static inline void +sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env, uint64_t *vg, + target_ulong addr, int esize, int msize, + int wp_access, uintptr_t retaddr) +{ } +#else +void sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env, + uint64_t *vg, target_ulong addr, + int esize, int msize, int wp_access, + uintptr_t retaddr); +#endif + +void sve_cont_ldst_mte_check(SVEContLdSt *info, CPUARMState *env, uint64_t *vg, + target_ulong addr, int esize, int msize, + uint32_t mtedesc, uintptr_t ra); + #endif /* TARGET_ARM_SVE_LDST_INTERNAL_H */ From 820e0bb9ce1941af82d14ec4a981792cb3697956 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:58 +0100 Subject: [PATCH 902/935] target/arm: Move expand_pred_b to vec_internal.h Put the inline function near the array declaration. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-16-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/sve_helper.c | 9 --------- target/arm/vec_internal.h | 8 +++++++- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index 8cd371e3e3..e865c12527 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -103,15 +103,6 @@ uint32_t HELPER(sve_predtest)(void *vd, void *vg, uint32_t words) return flags; } -/* - * Expand active predicate bits to bytes, for byte elements. - * (The data table itself is in vec_helper.c as MVE also needs it.) - */ -static inline uint64_t expand_pred_b(uint8_t byte) -{ - return expand_pred_b_data[byte]; -} - /* Similarly for half-word elements. * for (i = 0; i < 256; ++i) { * unsigned long m = 0; diff --git a/target/arm/vec_internal.h b/target/arm/vec_internal.h index 1d63402042..d1a1ea4a66 100644 --- a/target/arm/vec_internal.h +++ b/target/arm/vec_internal.h @@ -50,8 +50,14 @@ #define H8(x) (x) #define H1_8(x) (x) -/* Data for expanding active predicate bits to bytes, for byte elements. */ +/* + * Expand active predicate bits to bytes, for byte elements. + */ extern const uint64_t expand_pred_b_data[256]; +static inline uint64_t expand_pred_b(uint8_t byte) +{ + return expand_pred_b_data[byte]; +} static inline void clear_tail(void *vd, uintptr_t opr_sz, uintptr_t max_sz) { From 05dd14bdfa89ffeb1a82b08776687d44b538185b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:58 +0100 Subject: [PATCH 903/935] target/arm: Use expand_pred_b in mve_helper.c Use the function instead of the array directly. Because the function performs its own masking, via the uint8_t parameter, we need to do nothing extra within the users: the bits above the first 2 (_uh) or 4 (_uw) will be discarded by assignment to the local bmask variables, and of course _uq uses the entire uint64_t result. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-17-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/mve_helper.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target/arm/mve_helper.c b/target/arm/mve_helper.c index 846962bf4c..403b345ea3 100644 --- a/target/arm/mve_helper.c +++ b/target/arm/mve_helper.c @@ -726,7 +726,7 @@ static void mergemask_sb(int8_t *d, int8_t r, uint16_t mask) static void mergemask_uh(uint16_t *d, uint16_t r, uint16_t mask) { - uint16_t bmask = expand_pred_b_data[mask & 3]; + uint16_t bmask = expand_pred_b(mask); *d = (*d & ~bmask) | (r & bmask); } @@ -737,7 +737,7 @@ static void mergemask_sh(int16_t *d, int16_t r, uint16_t mask) static void mergemask_uw(uint32_t *d, uint32_t r, uint16_t mask) { - uint32_t bmask = expand_pred_b_data[mask & 0xf]; + uint32_t bmask = expand_pred_b(mask); *d = (*d & ~bmask) | (r & bmask); } @@ -748,7 +748,7 @@ static void mergemask_sw(int32_t *d, int32_t r, uint16_t mask) static void mergemask_uq(uint64_t *d, uint64_t r, uint16_t mask) { - uint64_t bmask = expand_pred_b_data[mask & 0xff]; + uint64_t bmask = expand_pred_b(mask); *d = (*d & ~bmask) | (r & bmask); } From a613cf2d4ae61fbcdf084103ea10de193bfbe169 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:58 +0100 Subject: [PATCH 904/935] target/arm: Move expand_pred_h to vec_internal.h Move the data to vec_helper.c and the inline to vec_internal.h. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-18-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/sve_helper.c | 29 ----------------------------- target/arm/vec_helper.c | 26 ++++++++++++++++++++++++++ target/arm/vec_internal.h | 7 +++++++ 3 files changed, 33 insertions(+), 29 deletions(-) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index e865c12527..1654c0bbf9 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -103,35 +103,6 @@ uint32_t HELPER(sve_predtest)(void *vd, void *vg, uint32_t words) return flags; } -/* Similarly for half-word elements. - * for (i = 0; i < 256; ++i) { - * unsigned long m = 0; - * if (i & 0xaa) { - * continue; - * } - * for (j = 0; j < 8; j += 2) { - * if ((i >> j) & 1) { - * m |= 0xfffful << (j << 3); - * } - * } - * printf("[0x%x] = 0x%016lx,\n", i, m); - * } - */ -static inline uint64_t expand_pred_h(uint8_t byte) -{ - static const uint64_t word[] = { - [0x01] = 0x000000000000ffff, [0x04] = 0x00000000ffff0000, - [0x05] = 0x00000000ffffffff, [0x10] = 0x0000ffff00000000, - [0x11] = 0x0000ffff0000ffff, [0x14] = 0x0000ffffffff0000, - [0x15] = 0x0000ffffffffffff, [0x40] = 0xffff000000000000, - [0x41] = 0xffff00000000ffff, [0x44] = 0xffff0000ffff0000, - [0x45] = 0xffff0000ffffffff, [0x50] = 0xffffffff00000000, - [0x51] = 0xffffffff0000ffff, [0x54] = 0xffffffffffff0000, - [0x55] = 0xffffffffffffffff, - }; - return word[byte & 0x55]; -} - /* Similarly for single word elements. */ static inline uint64_t expand_pred_s(uint8_t byte) { diff --git a/target/arm/vec_helper.c b/target/arm/vec_helper.c index 17fb158362..26c373e522 100644 --- a/target/arm/vec_helper.c +++ b/target/arm/vec_helper.c @@ -127,6 +127,32 @@ const uint64_t expand_pred_b_data[256] = { 0xffffffffffffffff, }; +/* + * Similarly for half-word elements. + * for (i = 0; i < 256; ++i) { + * unsigned long m = 0; + * if (i & 0xaa) { + * continue; + * } + * for (j = 0; j < 8; j += 2) { + * if ((i >> j) & 1) { + * m |= 0xfffful << (j << 3); + * } + * } + * printf("[0x%x] = 0x%016lx,\n", i, m); + * } + */ +const uint64_t expand_pred_h_data[0x55 + 1] = { + [0x01] = 0x000000000000ffff, [0x04] = 0x00000000ffff0000, + [0x05] = 0x00000000ffffffff, [0x10] = 0x0000ffff00000000, + [0x11] = 0x0000ffff0000ffff, [0x14] = 0x0000ffffffff0000, + [0x15] = 0x0000ffffffffffff, [0x40] = 0xffff000000000000, + [0x41] = 0xffff00000000ffff, [0x44] = 0xffff0000ffff0000, + [0x45] = 0xffff0000ffffffff, [0x50] = 0xffffffff00000000, + [0x51] = 0xffffffff0000ffff, [0x54] = 0xffffffffffff0000, + [0x55] = 0xffffffffffffffff, +}; + /* Signed saturating rounding doubling multiply-accumulate high half, 8-bit */ int8_t do_sqrdmlah_b(int8_t src1, int8_t src2, int8_t src3, bool neg, bool round) diff --git a/target/arm/vec_internal.h b/target/arm/vec_internal.h index d1a1ea4a66..1d527fadac 100644 --- a/target/arm/vec_internal.h +++ b/target/arm/vec_internal.h @@ -59,6 +59,13 @@ static inline uint64_t expand_pred_b(uint8_t byte) return expand_pred_b_data[byte]; } +/* Similarly for half-word elements. */ +extern const uint64_t expand_pred_h_data[0x55 + 1]; +static inline uint64_t expand_pred_h(uint8_t byte) +{ + return expand_pred_h_data[byte & 0x55]; +} + static inline void clear_tail(void *vd, uintptr_t opr_sz, uintptr_t max_sz) { uint64_t *d = vd + opr_sz; From 72db2aa353a98bd3486c9e5ef7e31ae7cf934849 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:58 +0100 Subject: [PATCH 905/935] target/arm: Export bfdotadd from vec_helper.c We will need this over in sme_helper.c. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-19-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/vec_helper.c | 2 +- target/arm/vec_internal.h | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/target/arm/vec_helper.c b/target/arm/vec_helper.c index 26c373e522..9a9c034e36 100644 --- a/target/arm/vec_helper.c +++ b/target/arm/vec_helper.c @@ -2557,7 +2557,7 @@ DO_MMLA_B(gvec_usmmla_b, do_usmmla_b) * BFloat16 Dot Product */ -static float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2) +float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2) { /* FPCR is ignored for BFDOT and BFMMLA. */ float_status bf_status = { diff --git a/target/arm/vec_internal.h b/target/arm/vec_internal.h index 1d527fadac..1f4ed80ff7 100644 --- a/target/arm/vec_internal.h +++ b/target/arm/vec_internal.h @@ -230,4 +230,17 @@ uint64_t pmull_h(uint64_t op1, uint64_t op2); */ uint64_t pmull_w(uint64_t op1, uint64_t op2); +/** + * bfdotadd: + * @sum: addend + * @e1, @e2: multiplicand vectors + * + * BFloat16 2-way dot product of @e1 & @e2, accumulating with @sum. + * The @e1 and @e2 operands correspond to the 32-bit source vector + * slots and contain two Bfloat16 values each. + * + * Corresponds to the ARM pseudocode function BFDotAdd. + */ +float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2); + #endif /* TARGET_ARM_VEC_INTERNAL_H */ From f305bf9436896b4cd9ef622034e166b024780874 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:59 +0100 Subject: [PATCH 906/935] target/arm: Add isar_feature_aa64_sme This will be used for implementing FEAT_SME. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-20-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index e45b5cb7fe..2e6153c540 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -4048,6 +4048,11 @@ static inline bool isar_feature_aa64_mte(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, MTE) >= 2; } +static inline bool isar_feature_aa64_sme(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SME) != 0; +} + static inline bool isar_feature_aa64_pmu_8_1(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 && From 414c54d515dba16bfaef643a8acec200c05f229a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jun 2022 19:38:59 +0100 Subject: [PATCH 907/935] target/arm: Add ID_AA64SMFR0_EL1 This register is allocated from the existing block of id registers, so it is already RES0 for cpus that do not implement SME. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20220607203306.657998-21-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 25 +++++++++++++++++++++++++ target/arm/helper.c | 4 ++-- target/arm/kvm64.c | 11 +++++++---- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 2e6153c540..78dbcb5592 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -966,6 +966,7 @@ struct ArchCPU { uint64_t id_aa64dfr0; uint64_t id_aa64dfr1; uint64_t id_aa64zfr0; + uint64_t id_aa64smfr0; uint64_t reset_pmcr_el0; } isar; uint64_t midr; @@ -2190,6 +2191,15 @@ FIELD(ID_AA64ZFR0, I8MM, 44, 4) FIELD(ID_AA64ZFR0, F32MM, 52, 4) FIELD(ID_AA64ZFR0, F64MM, 56, 4) +FIELD(ID_AA64SMFR0, F32F32, 32, 1) +FIELD(ID_AA64SMFR0, B16F32, 34, 1) +FIELD(ID_AA64SMFR0, F16F32, 35, 1) +FIELD(ID_AA64SMFR0, I8I32, 36, 4) +FIELD(ID_AA64SMFR0, F64F64, 48, 1) +FIELD(ID_AA64SMFR0, I16I64, 52, 4) +FIELD(ID_AA64SMFR0, SMEVER, 56, 4) +FIELD(ID_AA64SMFR0, FA64, 63, 1) + FIELD(ID_DFR0, COPDBG, 0, 4) FIELD(ID_DFR0, COPSDBG, 4, 4) FIELD(ID_DFR0, MMAPDBG, 8, 4) @@ -4195,6 +4205,21 @@ static inline bool isar_feature_aa64_sve_f64mm(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, F64MM) != 0; } +static inline bool isar_feature_aa64_sme_f64f64(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64smfr0, ID_AA64SMFR0, F64F64); +} + +static inline bool isar_feature_aa64_sme_i16i64(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64smfr0, ID_AA64SMFR0, I16I64) == 0xf; +} + +static inline bool isar_feature_aa64_sme_fa64(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64smfr0, ID_AA64SMFR0, FA64); +} + /* * Feature tests for "does this exist in either 32-bit or 64-bit?" */ diff --git a/target/arm/helper.c b/target/arm/helper.c index 400f7cd1db..ac9942d750 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -7722,11 +7722,11 @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_aa64_tid3, .resetvalue = cpu->isar.id_aa64zfr0 }, - { .name = "ID_AA64PFR5_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + { .name = "ID_AA64SMFR0_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 5, .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_aa64_tid3, - .resetvalue = 0 }, + .resetvalue = cpu->isar.id_aa64smfr0 }, { .name = "ID_AA64PFR6_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST, diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index b3f635fc95..ff8f65da22 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -574,6 +574,8 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) } else { err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr1, ARM64_SYS_REG(3, 0, 0, 4, 1)); + err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64smfr0, + ARM64_SYS_REG(3, 0, 0, 4, 5)); err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr0, ARM64_SYS_REG(3, 0, 0, 5, 0)); err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr1, @@ -682,10 +684,11 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) ahcf->isar.id_aa64pfr0 = t; /* - * Before v5.1, KVM did not support SVE and did not expose - * ID_AA64ZFR0_EL1 even as RAZ. After v5.1, KVM still does - * not expose the register to "user" requests like this - * unless the host supports SVE. + * There is a range of kernels between kernel commit 73433762fcae + * and f81cb2c3ad41 which have a bug where the kernel doesn't expose + * SYS_ID_AA64ZFR0_EL1 via the ONE_REG API unless the VM has enabled + * SVE support, so we only read it here, rather than together with all + * the other ID registers earlier. */ err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64zfr0, ARM64_SYS_REG(3, 0, 0, 4, 4)); From 7851b21a8192750adecbcf6e8780a20de5891ad6 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Fri, 13 May 2022 20:09:55 +0200 Subject: [PATCH 908/935] hw/ide/piix: Remove redundant "piix3-ide-xen" device class Commit 0f8445820f11a69154309863960328dda3dc1ad4 'xen: piix reuse pci generic class init function' already resolved redundant code which in turn rendered piix3-ide-xen redundant. Signed-off-by: Bernhard Beschow Reviewed-by: Anthony PERARD Message-Id: <20220513180957.90514-2-shentey@gmail.com> Signed-off-by: Anthony PERARD --- hw/i386/pc_piix.c | 3 +-- hw/ide/piix.c | 7 ------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 578e537b35..0e45521e74 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -246,8 +246,7 @@ static void pc_init1(MachineState *machine, if (pcmc->pci_enabled) { PCIDevice *dev; - dev = pci_create_simple(pci_bus, piix3_devfn + 1, - xen_enabled() ? "piix3-ide-xen" : "piix3-ide"); + dev = pci_create_simple(pci_bus, piix3_devfn + 1, "piix3-ide"); pci_ide_create_devs(dev); idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0"); idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1"); diff --git a/hw/ide/piix.c b/hw/ide/piix.c index ce89fd0aa3..2345fe9e1d 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -241,12 +241,6 @@ static const TypeInfo piix3_ide_info = { .class_init = piix3_ide_class_init, }; -static const TypeInfo piix3_ide_xen_info = { - .name = "piix3-ide-xen", - .parent = TYPE_PCI_IDE, - .class_init = piix3_ide_class_init, -}; - /* NOTE: for the PIIX4, the IRQs and IOports are hardcoded */ static void piix4_ide_class_init(ObjectClass *klass, void *data) { @@ -272,7 +266,6 @@ static const TypeInfo piix4_ide_info = { static void piix_ide_register_types(void) { type_register_static(&piix3_ide_info); - type_register_static(&piix3_ide_xen_info); type_register_static(&piix4_ide_info); } From 36902417460e3f9f1c63a79d802622fd774f1c30 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Fri, 13 May 2022 20:09:56 +0200 Subject: [PATCH 909/935] hw/ide/piix: Add some documentation to pci_piix3_xen_ide_unplug() The comment is based on commit message ae4d2eb273b167dad748ea4249720319240b1ac2 'xen-platform: add missing disk unplug option'. Since it seems to describe design decisions and limitations that still apply it seems worth having. Signed-off-by: Bernhard Beschow Reviewed-by: Anthony PERARD Message-Id: <20220513180957.90514-3-shentey@gmail.com> Signed-off-by: Anthony PERARD --- hw/ide/piix.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hw/ide/piix.c b/hw/ide/piix.c index 2345fe9e1d..bc1b37512a 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -173,6 +173,17 @@ static void pci_piix_ide_realize(PCIDevice *dev, Error **errp) } } +/* + * The Xen HVM unplug protocol [1] specifies a mechanism to allow guests to + * request unplug of 'aux' disks (which is stated to mean all IDE disks, + * except the primary master). + * + * NOTE: The semantics of what happens if unplug of all disks and 'aux' disks + * is simultaneously requested is not clear. The implementation assumes + * that an 'all' request overrides an 'aux' request. + * + * [1] https://xenbits.xen.org/gitweb/?p=xen.git;a=blob;f=docs/misc/hvm-emulated-unplug.pandoc + */ int pci_piix3_xen_ide_unplug(DeviceState *dev, bool aux) { PCIIDEState *pci_ide; From 6a8a8b62bdc8e3d7c5fc0f82ef4583707183b12f Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Fri, 13 May 2022 20:09:57 +0200 Subject: [PATCH 910/935] include/hw/ide: Unexport pci_piix3_xen_ide_unplug() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function was declared in a generic and public header, implemented in a device-specific source file but only used in xen_platform. Given its 'aux' parameter, this function is more xen-specific than piix-specific. Also, the hardcoded magic constants seem to be generic and related to PCIIDEState and IDEBus rather than piix. Therefore, move this function to xen_platform, unexport it, and drop the "piix3" in the function name as well. Signed-off-by: Bernhard Beschow Reviewed-by: Paul Durrant Acked-by: Anthony PERARD Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20220513180957.90514-4-shentey@gmail.com> Signed-off-by: Anthony PERARD --- hw/i386/xen/xen_platform.c | 48 +++++++++++++++++++++++++++++++++++++- hw/ide/piix.c | 46 ------------------------------------ include/hw/ide.h | 3 --- 3 files changed, 47 insertions(+), 50 deletions(-) diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c index 72028449ba..a64265cca0 100644 --- a/hw/i386/xen/xen_platform.c +++ b/hw/i386/xen/xen_platform.c @@ -26,6 +26,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/ide.h" +#include "hw/ide/pci.h" #include "hw/pci/pci.h" #include "hw/xen/xen_common.h" #include "migration/vmstate.h" @@ -134,6 +135,51 @@ static void pci_unplug_nics(PCIBus *bus) pci_for_each_device(bus, 0, unplug_nic, NULL); } +/* + * The Xen HVM unplug protocol [1] specifies a mechanism to allow guests to + * request unplug of 'aux' disks (which is stated to mean all IDE disks, + * except the primary master). + * + * NOTE: The semantics of what happens if unplug of all disks and 'aux' disks + * is simultaneously requested is not clear. The implementation assumes + * that an 'all' request overrides an 'aux' request. + * + * [1] https://xenbits.xen.org/gitweb/?p=xen.git;a=blob;f=docs/misc/hvm-emulated-unplug.pandoc + */ +static void pci_xen_ide_unplug(DeviceState *dev, bool aux) +{ + PCIIDEState *pci_ide; + int i; + IDEDevice *idedev; + IDEBus *idebus; + BlockBackend *blk; + + pci_ide = PCI_IDE(dev); + + for (i = aux ? 1 : 0; i < 4; i++) { + idebus = &pci_ide->bus[i / 2]; + blk = idebus->ifs[i % 2].blk; + + if (blk && idebus->ifs[i % 2].drive_kind != IDE_CD) { + if (!(i % 2)) { + idedev = idebus->master; + } else { + idedev = idebus->slave; + } + + blk_drain(blk); + blk_flush(blk); + + blk_detach_dev(blk, DEVICE(idedev)); + idebus->ifs[i % 2].blk = NULL; + idedev->conf.blk = NULL; + monitor_remove_blk(blk); + blk_unref(blk); + } + } + qdev_reset_all(dev); +} + static void unplug_disks(PCIBus *b, PCIDevice *d, void *opaque) { uint32_t flags = *(uint32_t *)opaque; @@ -147,7 +193,7 @@ static void unplug_disks(PCIBus *b, PCIDevice *d, void *opaque) switch (pci_get_word(d->config + PCI_CLASS_DEVICE)) { case PCI_CLASS_STORAGE_IDE: - pci_piix3_xen_ide_unplug(DEVICE(d), aux); + pci_xen_ide_unplug(DEVICE(d), aux); break; case PCI_CLASS_STORAGE_SCSI: diff --git a/hw/ide/piix.c b/hw/ide/piix.c index bc1b37512a..9a9b28078e 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -173,52 +173,6 @@ static void pci_piix_ide_realize(PCIDevice *dev, Error **errp) } } -/* - * The Xen HVM unplug protocol [1] specifies a mechanism to allow guests to - * request unplug of 'aux' disks (which is stated to mean all IDE disks, - * except the primary master). - * - * NOTE: The semantics of what happens if unplug of all disks and 'aux' disks - * is simultaneously requested is not clear. The implementation assumes - * that an 'all' request overrides an 'aux' request. - * - * [1] https://xenbits.xen.org/gitweb/?p=xen.git;a=blob;f=docs/misc/hvm-emulated-unplug.pandoc - */ -int pci_piix3_xen_ide_unplug(DeviceState *dev, bool aux) -{ - PCIIDEState *pci_ide; - int i; - IDEDevice *idedev; - IDEBus *idebus; - BlockBackend *blk; - - pci_ide = PCI_IDE(dev); - - for (i = aux ? 1 : 0; i < 4; i++) { - idebus = &pci_ide->bus[i / 2]; - blk = idebus->ifs[i % 2].blk; - - if (blk && idebus->ifs[i % 2].drive_kind != IDE_CD) { - if (!(i % 2)) { - idedev = idebus->master; - } else { - idedev = idebus->slave; - } - - blk_drain(blk); - blk_flush(blk); - - blk_detach_dev(blk, DEVICE(idedev)); - idebus->ifs[i % 2].blk = NULL; - idedev->conf.blk = NULL; - monitor_remove_blk(blk); - blk_unref(blk); - } - } - qdev_reset_all(dev); - return 0; -} - static void pci_piix_ide_exitfn(PCIDevice *dev) { PCIIDEState *d = PCI_IDE(dev); diff --git a/include/hw/ide.h b/include/hw/ide.h index c5ce5da4f4..60f1f4f714 100644 --- a/include/hw/ide.h +++ b/include/hw/ide.h @@ -8,9 +8,6 @@ ISADevice *isa_ide_init(ISABus *bus, int iobase, int iobase2, int isairq, DriveInfo *hd0, DriveInfo *hd1); -/* ide-pci.c */ -int pci_piix3_xen_ide_unplug(DeviceState *dev, bool aux); - /* ide-mmio.c */ void mmio_ide_init_drives(DeviceState *dev, DriveInfo *hd0, DriveInfo *hd1); From efe1592c43fe9b4053bf2987581a05736062a3cd Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Mon, 9 May 2022 11:13:39 +0200 Subject: [PATCH 911/935] MAINTAINERS: Cover hw/core/uboot_image.h within Generic Loader section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20220509091339.26016-1-alistair.francis@wdc.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 5580a36b68..b3af081c51 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2198,6 +2198,7 @@ Generic Loader M: Alistair Francis S: Maintained F: hw/core/generic-loader.c +F: hw/core/uboot_image.h F: include/hw/core/generic-loader.h F: docs/system/generic-loader.rst From de799beba7f927b2a1ed38128309316511311605 Mon Sep 17 00:00:00 2001 From: Weiwei Li Date: Tue, 31 May 2022 11:07:32 +0800 Subject: [PATCH 912/935] target/riscv: add support for zmmul extension v0.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the zmmul extension v0.1. This extension includes all multiplication operations from the M extension but not the divide ops. Signed-off-by: Weiwei Li Signed-off-by: Junqiang Wang Reviewed-by: Víctor Colombo Reviewed-by: Alistair Francis Message-Id: <20220531030732.3850-1-liweiwei@iscas.ac.cn> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 7 +++++++ target/riscv/cpu.h | 1 + target/riscv/insn_trans/trans_rvm.c.inc | 18 ++++++++++++------ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index a91253d4bd..bcbba3fbd5 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -600,6 +600,11 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) cpu->cfg.ext_ifencei = true; } + if (cpu->cfg.ext_m && cpu->cfg.ext_zmmul) { + warn_report("Zmmul will override M"); + cpu->cfg.ext_m = false; + } + if (cpu->cfg.ext_i && cpu->cfg.ext_e) { error_setg(errp, "I and E extensions are incompatible"); @@ -905,6 +910,7 @@ static Property riscv_cpu_properties[] = { /* These are experimental so mark with 'x-' */ DEFINE_PROP_BOOL("x-j", RISCVCPU, cfg.ext_j, false), + DEFINE_PROP_BOOL("x-zmmul", RISCVCPU, cfg.ext_zmmul, false), /* ePMP 0.9.3 */ DEFINE_PROP_BOOL("x-epmp", RISCVCPU, cfg.epmp, false), DEFINE_PROP_BOOL("x-aia", RISCVCPU, cfg.aia, false), @@ -1031,6 +1037,7 @@ static void riscv_isa_string_ext(RISCVCPU *cpu, char **isa_str, int max_str_len) struct isa_ext_data isa_edata_arr[] = { ISA_EDATA_ENTRY(zicsr, ext_icsr), ISA_EDATA_ENTRY(zifencei, ext_ifencei), + ISA_EDATA_ENTRY(zmmul, ext_zmmul), ISA_EDATA_ENTRY(zfh, ext_zfh), ISA_EDATA_ENTRY(zfhmin, ext_zfhmin), ISA_EDATA_ENTRY(zfinx, ext_zfinx), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index f08c3e8813..890d33cebb 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -411,6 +411,7 @@ struct RISCVCPUConfig { bool ext_zhinxmin; bool ext_zve32f; bool ext_zve64f; + bool ext_zmmul; uint32_t mvendorid; uint64_t marchid; diff --git a/target/riscv/insn_trans/trans_rvm.c.inc b/target/riscv/insn_trans/trans_rvm.c.inc index 16b029edf0..ec7f705aab 100644 --- a/target/riscv/insn_trans/trans_rvm.c.inc +++ b/target/riscv/insn_trans/trans_rvm.c.inc @@ -18,6 +18,12 @@ * this program. If not, see . */ +#define REQUIRE_M_OR_ZMMUL(ctx) do { \ + if (!ctx->cfg_ptr->ext_zmmul && !has_ext(ctx, RVM)) { \ + return false; \ + } \ +} while (0) + static void gen_mulhu_i128(TCGv r2, TCGv r3, TCGv al, TCGv ah, TCGv bl, TCGv bh) { TCGv tmpl = tcg_temp_new(); @@ -65,7 +71,7 @@ static void gen_mul_i128(TCGv rl, TCGv rh, static bool trans_mul(DisasContext *ctx, arg_mul *a) { - REQUIRE_EXT(ctx, RVM); + REQUIRE_M_OR_ZMMUL(ctx); return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl, gen_mul_i128); } @@ -109,7 +115,7 @@ static void gen_mulh_w(TCGv ret, TCGv s1, TCGv s2) static bool trans_mulh(DisasContext *ctx, arg_mulh *a) { - REQUIRE_EXT(ctx, RVM); + REQUIRE_M_OR_ZMMUL(ctx); return gen_arith_per_ol(ctx, a, EXT_SIGN, gen_mulh, gen_mulh_w, gen_mulh_i128); } @@ -161,7 +167,7 @@ static void gen_mulhsu_w(TCGv ret, TCGv arg1, TCGv arg2) static bool trans_mulhsu(DisasContext *ctx, arg_mulhsu *a) { - REQUIRE_EXT(ctx, RVM); + REQUIRE_M_OR_ZMMUL(ctx); return gen_arith_per_ol(ctx, a, EXT_NONE, gen_mulhsu, gen_mulhsu_w, gen_mulhsu_i128); } @@ -176,7 +182,7 @@ static void gen_mulhu(TCGv ret, TCGv s1, TCGv s2) static bool trans_mulhu(DisasContext *ctx, arg_mulhu *a) { - REQUIRE_EXT(ctx, RVM); + REQUIRE_M_OR_ZMMUL(ctx); /* gen_mulh_w works for either sign as input. */ return gen_arith_per_ol(ctx, a, EXT_ZERO, gen_mulhu, gen_mulh_w, gen_mulhu_i128); @@ -349,7 +355,7 @@ static bool trans_remu(DisasContext *ctx, arg_remu *a) static bool trans_mulw(DisasContext *ctx, arg_mulw *a) { REQUIRE_64_OR_128BIT(ctx); - REQUIRE_EXT(ctx, RVM); + REQUIRE_M_OR_ZMMUL(ctx); ctx->ol = MXL_RV32; return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl, NULL); } @@ -389,7 +395,7 @@ static bool trans_remuw(DisasContext *ctx, arg_remuw *a) static bool trans_muld(DisasContext *ctx, arg_muld *a) { REQUIRE_128BIT(ctx); - REQUIRE_EXT(ctx, RVM); + REQUIRE_M_OR_ZMMUL(ctx); ctx->ol = MXL_RV64; return gen_arith(ctx, a, EXT_SIGN, tcg_gen_mul_tl, NULL); } From f9a461b2d3b8ef4f36b7891eb4040693ee071719 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Thu, 26 May 2022 13:35:00 -0700 Subject: [PATCH 913/935] hw/riscv: virt: Generate fw_cfg DT node correctly fw_cfg DT node is generated after the create_fdt without any check if the DT is being loaded from the commandline. This results in FDT_ERR_EXISTS error if dtb is loaded from the commandline. Generate fw_cfg node only if the DT is not loaded from the commandline. Signed-off-by: Atish Patra Reviewed-by: Alistair Francis Message-Id: <20220526203500.847165-1-atishp@rivosinc.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 293e9c95b7..bc424dd2f5 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -975,6 +975,23 @@ static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap) g_free(name); } +static void create_fdt_fw_cfg(RISCVVirtState *s, const MemMapEntry *memmap) +{ + char *nodename; + MachineState *mc = MACHINE(s); + hwaddr base = memmap[VIRT_FW_CFG].base; + hwaddr size = memmap[VIRT_FW_CFG].size; + + nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base); + qemu_fdt_add_subnode(mc->fdt, nodename); + qemu_fdt_setprop_string(mc->fdt, nodename, + "compatible", "qemu,fw-cfg-mmio"); + qemu_fdt_setprop_sized_cells(mc->fdt, nodename, "reg", + 2, base, 2, size); + qemu_fdt_setprop(mc->fdt, nodename, "dma-coherent", NULL, 0); + g_free(nodename); +} + static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap, uint64_t mem_size, const char *cmdline, bool is_32_bit) { @@ -1023,6 +1040,7 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap, create_fdt_rtc(s, memmap, irq_mmio_phandle); create_fdt_flash(s, memmap); + create_fdt_fw_cfg(s, memmap); update_bootargs: if (cmdline && *cmdline) { @@ -1082,22 +1100,12 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, static FWCfgState *create_fw_cfg(const MachineState *mc) { hwaddr base = virt_memmap[VIRT_FW_CFG].base; - hwaddr size = virt_memmap[VIRT_FW_CFG].size; FWCfgState *fw_cfg; - char *nodename; fw_cfg = fw_cfg_init_mem_wide(base + 8, base, 8, base + 16, &address_space_memory); fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)mc->smp.cpus); - nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base); - qemu_fdt_add_subnode(mc->fdt, nodename); - qemu_fdt_setprop_string(mc->fdt, nodename, - "compatible", "qemu,fw-cfg-mmio"); - qemu_fdt_setprop_sized_cells(mc->fdt, nodename, "reg", - 2, base, 2, size); - qemu_fdt_setprop(mc->fdt, nodename, "dma-coherent", NULL, 0); - g_free(nodename); return fw_cfg; } From 40244040a7ac00d40db4dea02234d13502c30112 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 1 Jun 2022 11:36:31 +1000 Subject: [PATCH 914/935] hw/intc: sifive_plic: Avoid overflowing the addr_config buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit ad40be27 "target/riscv: Support start kernel directly by KVM" we have been overflowing the addr_config on "M,MS..." configurations, as reported https://gitlab.com/qemu-project/qemu/-/issues/1050. This commit changes the loop in sifive_plic_create() from iterating over the number of harts to just iterating over the addr_config. The addr_config is based on the hart_config, and will contain interrup details for all harts. This way we can't iterate past the end of addr_config. Fixes: ad40be27084536 ("target/riscv: Support start kernel directly by KVM") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1050 Signed-off-by: Alistair Francis Reviewed-by: Mingwang Li Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20220601013631.196854-1-alistair.francis@opensource.wdc.com> --- hw/intc/sifive_plic.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/hw/intc/sifive_plic.c b/hw/intc/sifive_plic.c index eebbcf33d4..56d60e9ac9 100644 --- a/hw/intc/sifive_plic.c +++ b/hw/intc/sifive_plic.c @@ -431,7 +431,7 @@ DeviceState *sifive_plic_create(hwaddr addr, char *hart_config, uint32_t context_stride, uint32_t aperture_size) { DeviceState *dev = qdev_new(TYPE_SIFIVE_PLIC); - int i, j = 0; + int i; SiFivePLICState *plic; assert(enable_stride == (enable_stride & -enable_stride)); @@ -451,18 +451,17 @@ DeviceState *sifive_plic_create(hwaddr addr, char *hart_config, sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); plic = SIFIVE_PLIC(dev); - for (i = 0; i < num_harts; i++) { - CPUState *cpu = qemu_get_cpu(hartid_base + i); - if (plic->addr_config[j].mode == PLICMode_M) { - j++; - qdev_connect_gpio_out(dev, num_harts + i, + for (i = 0; i < plic->num_addrs; i++) { + int cpu_num = plic->addr_config[i].hartid; + CPUState *cpu = qemu_get_cpu(hartid_base + cpu_num); + + if (plic->addr_config[i].mode == PLICMode_M) { + qdev_connect_gpio_out(dev, num_harts + cpu_num, qdev_get_gpio_in(DEVICE(cpu), IRQ_M_EXT)); } - - if (plic->addr_config[j].mode == PLICMode_S) { - j++; - qdev_connect_gpio_out(dev, i, + if (plic->addr_config[i].mode == PLICMode_S) { + qdev_connect_gpio_out(dev, cpu_num, qdev_get_gpio_in(DEVICE(cpu), IRQ_S_EXT)); } } From af9751316e53cdf7e98131afe6928a5f4445fe16 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Thu, 11 Nov 2021 14:11:40 +0000 Subject: [PATCH 915/935] hw/core/loader: return image sizes as ssize_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Various loader functions return an int which limits images to 2GB which is fine for things like a BIOS/kernel image, but if we want to be able to load memory images or large ramdisks then any file over 2GB would silently fail to load. Cc: Luc Michel Signed-off-by: Jamie Iles Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Luc Michel Reviewed-by: Alistair Francis Message-Id: <20211111141141.3295094-2-jamie@nuviainc.com> Signed-off-by: Alistair Francis --- hw/arm/armv7m.c | 2 +- hw/arm/boot.c | 8 ++-- hw/core/generic-loader.c | 2 +- hw/core/loader.c | 81 +++++++++++++++++++++------------------- hw/i386/x86.c | 2 +- hw/riscv/boot.c | 5 ++- include/hw/loader.h | 55 +++++++++++++-------------- 7 files changed, 80 insertions(+), 75 deletions(-) diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 32349ec94b..990861ee5e 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -570,7 +570,7 @@ static void armv7m_reset(void *opaque) void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, int mem_size) { - int image_size; + ssize_t image_size; uint64_t entry; int big_endian; AddressSpace *as; diff --git a/hw/arm/boot.c b/hw/arm/boot.c index a8de33fd64..ada2717f76 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -881,7 +881,7 @@ static int do_arm_linux_init(Object *obj, void *opaque) return 0; } -static int64_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry, +static ssize_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr, int elf_machine, AddressSpace *as) { @@ -892,7 +892,7 @@ static int64_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry, } elf_header; int data_swab = 0; bool big_endian; - int64_t ret = -1; + ssize_t ret = -1; Error *err = NULL; @@ -1014,7 +1014,7 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu, /* Set up for a direct boot of a kernel image file. */ CPUState *cs; AddressSpace *as = arm_boot_address_space(cpu, info); - int kernel_size; + ssize_t kernel_size; int initrd_size; int is_linux = 0; uint64_t elf_entry; @@ -1093,7 +1093,7 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu, if (kernel_size > info->ram_size) { error_report("kernel '%s' is too large to fit in RAM " - "(kernel size %d, RAM size %" PRId64 ")", + "(kernel size %zd, RAM size %" PRId64 ")", info->kernel_filename, kernel_size, info->ram_size); exit(1); } diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c index c666545aa0..4f4d77908d 100644 --- a/hw/core/generic-loader.c +++ b/hw/core/generic-loader.c @@ -67,7 +67,7 @@ static void generic_loader_realize(DeviceState *dev, Error **errp) GenericLoaderState *s = GENERIC_LOADER(dev); hwaddr entry; int big_endian; - int size = 0; + ssize_t size = 0; s->set_pc = false; diff --git a/hw/core/loader.c b/hw/core/loader.c index edde657ac3..0548830733 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -114,17 +114,17 @@ ssize_t read_targphys(const char *name, return did; } -int load_image_targphys(const char *filename, - hwaddr addr, uint64_t max_sz) +ssize_t load_image_targphys(const char *filename, + hwaddr addr, uint64_t max_sz) { return load_image_targphys_as(filename, addr, max_sz, NULL); } /* return the size or -1 if error */ -int load_image_targphys_as(const char *filename, - hwaddr addr, uint64_t max_sz, AddressSpace *as) +ssize_t load_image_targphys_as(const char *filename, + hwaddr addr, uint64_t max_sz, AddressSpace *as) { - int size; + ssize_t size; size = get_image_size(filename); if (size < 0 || size > max_sz) { @@ -138,9 +138,9 @@ int load_image_targphys_as(const char *filename, return size; } -int load_image_mr(const char *filename, MemoryRegion *mr) +ssize_t load_image_mr(const char *filename, MemoryRegion *mr) { - int size; + ssize_t size; if (!memory_access_is_direct(mr, false)) { /* Can only load an image into RAM or ROM */ @@ -222,8 +222,8 @@ static void bswap_ahdr(struct exec *e) : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x, target_page_size), target_page_size))) -int load_aout(const char *filename, hwaddr addr, int max_sz, - int bswap_needed, hwaddr target_page_size) +ssize_t load_aout(const char *filename, hwaddr addr, int max_sz, + int bswap_needed, hwaddr target_page_size) { int fd; ssize_t size, ret; @@ -617,13 +617,14 @@ toosmall: } /* Load a U-Boot image. */ -static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr, - int *is_linux, uint8_t image_type, - uint64_t (*translate_fn)(void *, uint64_t), - void *translate_opaque, AddressSpace *as) +static ssize_t load_uboot_image(const char *filename, hwaddr *ep, + hwaddr *loadaddr, int *is_linux, + uint8_t image_type, + uint64_t (*translate_fn)(void *, uint64_t), + void *translate_opaque, AddressSpace *as) { int fd; - int size; + ssize_t size; hwaddr address; uboot_image_header_t h; uboot_image_header_t *hdr = &h; @@ -760,40 +761,40 @@ out: return ret; } -int load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr, - int *is_linux, - uint64_t (*translate_fn)(void *, uint64_t), - void *translate_opaque) +ssize_t load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr, + int *is_linux, + uint64_t (*translate_fn)(void *, uint64_t), + void *translate_opaque) { return load_uboot_image(filename, ep, loadaddr, is_linux, IH_TYPE_KERNEL, translate_fn, translate_opaque, NULL); } -int load_uimage_as(const char *filename, hwaddr *ep, hwaddr *loadaddr, - int *is_linux, - uint64_t (*translate_fn)(void *, uint64_t), - void *translate_opaque, AddressSpace *as) +ssize_t load_uimage_as(const char *filename, hwaddr *ep, hwaddr *loadaddr, + int *is_linux, + uint64_t (*translate_fn)(void *, uint64_t), + void *translate_opaque, AddressSpace *as) { return load_uboot_image(filename, ep, loadaddr, is_linux, IH_TYPE_KERNEL, translate_fn, translate_opaque, as); } /* Load a ramdisk. */ -int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz) +ssize_t load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz) { return load_ramdisk_as(filename, addr, max_sz, NULL); } -int load_ramdisk_as(const char *filename, hwaddr addr, uint64_t max_sz, - AddressSpace *as) +ssize_t load_ramdisk_as(const char *filename, hwaddr addr, uint64_t max_sz, + AddressSpace *as) { return load_uboot_image(filename, NULL, &addr, NULL, IH_TYPE_RAMDISK, NULL, NULL, as); } /* Load a gzip-compressed kernel to a dynamically allocated buffer. */ -int load_image_gzipped_buffer(const char *filename, uint64_t max_sz, - uint8_t **buffer) +ssize_t load_image_gzipped_buffer(const char *filename, uint64_t max_sz, + uint8_t **buffer) { uint8_t *compressed_data = NULL; uint8_t *data = NULL; @@ -838,9 +839,9 @@ int load_image_gzipped_buffer(const char *filename, uint64_t max_sz, } /* Load a gzip-compressed kernel. */ -int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz) +ssize_t load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz) { - int bytes; + ssize_t bytes; uint8_t *data; bytes = load_image_gzipped_buffer(filename, max_sz, &data); @@ -970,14 +971,15 @@ static void *rom_set_mr(Rom *rom, Object *owner, const char *name, bool ro) return data; } -int rom_add_file(const char *file, const char *fw_dir, - hwaddr addr, int32_t bootindex, - bool option_rom, MemoryRegion *mr, - AddressSpace *as) +ssize_t rom_add_file(const char *file, const char *fw_dir, + hwaddr addr, int32_t bootindex, + bool option_rom, MemoryRegion *mr, + AddressSpace *as) { MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); Rom *rom; - int rc, fd = -1; + ssize_t rc; + int fd = -1; char devpath[100]; if (as && mr) { @@ -1019,7 +1021,7 @@ int rom_add_file(const char *file, const char *fw_dir, lseek(fd, 0, SEEK_SET); rc = read(fd, rom->data, rom->datasize); if (rc != rom->datasize) { - fprintf(stderr, "rom: file %-20s: read error: rc=%d (expected %zd)\n", + fprintf(stderr, "rom: file %-20s: read error: rc=%zd (expected %zd)\n", rom->name, rc, rom->datasize); goto err; } @@ -1138,12 +1140,12 @@ int rom_add_elf_program(const char *name, GMappedFile *mapped_file, void *data, return 0; } -int rom_add_vga(const char *file) +ssize_t rom_add_vga(const char *file) { return rom_add_file(file, "vgaroms", 0, -1, true, NULL, NULL); } -int rom_add_option(const char *file, int32_t bootindex) +ssize_t rom_add_option(const char *file, int32_t bootindex) { return rom_add_file(file, "genroms", 0, bootindex, true, NULL, NULL); } @@ -1846,11 +1848,12 @@ out: } /* return size or -1 if error */ -int load_targphys_hex_as(const char *filename, hwaddr *entry, AddressSpace *as) +ssize_t load_targphys_hex_as(const char *filename, hwaddr *entry, + AddressSpace *as) { gsize hex_blob_size; gchar *hex_blob; - int total_size = 0; + ssize_t total_size = 0; if (!g_file_get_contents(filename, &hex_blob, &hex_blob_size, NULL)) { return -1; diff --git a/hw/i386/x86.c b/hw/i386/x86.c index 78b05ab7a2..6003b4b2df 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -1115,7 +1115,7 @@ void x86_bios_rom_init(MachineState *ms, const char *default_firmware, char *filename; MemoryRegion *bios, *isa_bios; int bios_size, isa_bios_size; - int ret; + ssize_t ret; /* BIOS load */ bios_name = ms->firmware ?: default_firmware; diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 57a41df8e9..2d80f40b31 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -129,7 +129,8 @@ target_ulong riscv_load_firmware(const char *firmware_filename, hwaddr firmware_load_addr, symbol_fn_t sym_cb) { - uint64_t firmware_entry, firmware_size, firmware_end; + uint64_t firmware_entry, firmware_end; + ssize_t firmware_size; if (load_elf_ram_sym(firmware_filename, NULL, NULL, NULL, &firmware_entry, NULL, &firmware_end, NULL, @@ -185,7 +186,7 @@ target_ulong riscv_load_kernel(const char *kernel_filename, hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size, uint64_t kernel_entry, hwaddr *start) { - int size; + ssize_t size; /* * We want to put the initrd far enough into RAM that when the diff --git a/include/hw/loader.h b/include/hw/loader.h index 5572108ba5..70248e0da7 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -40,8 +40,8 @@ ssize_t load_image_size(const char *filename, void *addr, size_t size); * * Returns the size of the loaded image on success, -1 otherwise. */ -int load_image_targphys_as(const char *filename, - hwaddr addr, uint64_t max_sz, AddressSpace *as); +ssize_t load_image_targphys_as(const char *filename, + hwaddr addr, uint64_t max_sz, AddressSpace *as); /**load_targphys_hex_as: * @filename: Path to the .hex file @@ -53,14 +53,15 @@ int load_image_targphys_as(const char *filename, * * Returns the size of the loaded .hex file on success, -1 otherwise. */ -int load_targphys_hex_as(const char *filename, hwaddr *entry, AddressSpace *as); +ssize_t load_targphys_hex_as(const char *filename, hwaddr *entry, + AddressSpace *as); /** load_image_targphys: * Same as load_image_targphys_as(), but doesn't allow the caller to specify * an AddressSpace. */ -int load_image_targphys(const char *filename, hwaddr, - uint64_t max_sz); +ssize_t load_image_targphys(const char *filename, hwaddr, + uint64_t max_sz); /** * load_image_mr: load an image into a memory region @@ -73,7 +74,7 @@ int load_image_targphys(const char *filename, hwaddr, * If the file is larger than the memory region's size the call will fail. * Returns -1 on failure, or the size of the file. */ -int load_image_mr(const char *filename, MemoryRegion *mr); +ssize_t load_image_mr(const char *filename, MemoryRegion *mr); /* This is the limit on the maximum uncompressed image size that * load_image_gzipped_buffer() and load_image_gzipped() will read. It prevents @@ -81,9 +82,9 @@ int load_image_mr(const char *filename, MemoryRegion *mr); */ #define LOAD_IMAGE_MAX_GUNZIP_BYTES (256 << 20) -int load_image_gzipped_buffer(const char *filename, uint64_t max_sz, - uint8_t **buffer); -int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz); +ssize_t load_image_gzipped_buffer(const char *filename, uint64_t max_sz, + uint8_t **buffer); +ssize_t load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz); #define ELF_LOAD_FAILED -1 #define ELF_LOAD_NOT_ELF -2 @@ -183,8 +184,8 @@ ssize_t load_elf(const char *filename, */ void load_elf_hdr(const char *filename, void *hdr, bool *is64, Error **errp); -int load_aout(const char *filename, hwaddr addr, int max_sz, - int bswap_needed, hwaddr target_page_size); +ssize_t load_aout(const char *filename, hwaddr addr, int max_sz, + int bswap_needed, hwaddr target_page_size); #define LOAD_UIMAGE_LOADADDR_INVALID (-1) @@ -205,19 +206,19 @@ int load_aout(const char *filename, hwaddr addr, int max_sz, * * Returns the size of the loaded image on success, -1 otherwise. */ -int load_uimage_as(const char *filename, hwaddr *ep, - hwaddr *loadaddr, int *is_linux, - uint64_t (*translate_fn)(void *, uint64_t), - void *translate_opaque, AddressSpace *as); +ssize_t load_uimage_as(const char *filename, hwaddr *ep, + hwaddr *loadaddr, int *is_linux, + uint64_t (*translate_fn)(void *, uint64_t), + void *translate_opaque, AddressSpace *as); /** load_uimage: * Same as load_uimage_as(), but doesn't allow the caller to specify an * AddressSpace. */ -int load_uimage(const char *filename, hwaddr *ep, - hwaddr *loadaddr, int *is_linux, - uint64_t (*translate_fn)(void *, uint64_t), - void *translate_opaque); +ssize_t load_uimage(const char *filename, hwaddr *ep, + hwaddr *loadaddr, int *is_linux, + uint64_t (*translate_fn)(void *, uint64_t), + void *translate_opaque); /** * load_ramdisk_as: @@ -232,15 +233,15 @@ int load_uimage(const char *filename, hwaddr *ep, * * Returns the size of the loaded image on success, -1 otherwise. */ -int load_ramdisk_as(const char *filename, hwaddr addr, uint64_t max_sz, - AddressSpace *as); +ssize_t load_ramdisk_as(const char *filename, hwaddr addr, uint64_t max_sz, + AddressSpace *as); /** * load_ramdisk: * Same as load_ramdisk_as(), but doesn't allow the caller to specify * an AddressSpace. */ -int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz); +ssize_t load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz); ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src, size_t srclen); @@ -253,9 +254,9 @@ void pstrcpy_targphys(const char *name, extern bool option_rom_has_mr; extern bool rom_file_has_mr; -int rom_add_file(const char *file, const char *fw_dir, - hwaddr addr, int32_t bootindex, - bool option_rom, MemoryRegion *mr, AddressSpace *as); +ssize_t rom_add_file(const char *file, const char *fw_dir, + hwaddr addr, int32_t bootindex, + bool option_rom, MemoryRegion *mr, AddressSpace *as); MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len, size_t max_len, hwaddr addr, const char *fw_file_name, @@ -336,8 +337,8 @@ void hmp_info_roms(Monitor *mon, const QDict *qdict); #define rom_add_blob_fixed_as(_f, _b, _l, _a, _as) \ rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, NULL, _as, true) -int rom_add_vga(const char *file); -int rom_add_option(const char *file, int32_t bootindex); +ssize_t rom_add_vga(const char *file); +ssize_t rom_add_option(const char *file, int32_t bootindex); /* This is the usual maximum in uboot, so if a uImage overflows this, it would * overflow on real hardware too. */ From 8f42415fc1d1bb462f2001bf5e2ad3b78f14b2e3 Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Tue, 31 May 2022 17:05:44 -0400 Subject: [PATCH 916/935] target/riscv: Wake on VS-level external interrupts Whether or not VSEIP is pending isn't reflected in env->mip and must instead be determined from hstatus.vgein and hgeip. As a result a CPU in WFI won't wake on a VSEIP, which violates the WFI behavior as specified in the privileged ISA. Just use riscv_cpu_all_pending() instead, which already accounts for VSEIP. Signed-off-by: Andrew Bresticker Reviewed-by: Alistair Francis Message-Id: <20220531210544.181322-1-abrestic@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 +- target/riscv/cpu.h | 1 + target/riscv/cpu_helper.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index bcbba3fbd5..0497af45cc 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -391,7 +391,7 @@ static bool riscv_cpu_has_work(CPUState *cs) * Definition of the WFI instruction requires it to ignore the privilege * mode and delegation registers, but respect individual enables */ - return (env->mip & env->mie) != 0; + return riscv_cpu_all_pending(env) != 0; #else return true; #endif diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 890d33cebb..194a58d760 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -489,6 +489,7 @@ int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero); uint8_t riscv_cpu_default_priority(int irq); +uint64_t riscv_cpu_all_pending(CPURISCVState *env); int riscv_cpu_mirq_pending(CPURISCVState *env); int riscv_cpu_sirq_pending(CPURISCVState *env); int riscv_cpu_vsirq_pending(CPURISCVState *env); diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index d99fac9d2d..16c6045459 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -340,7 +340,7 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env, return best_irq; } -static uint64_t riscv_cpu_all_pending(CPURISCVState *env) +uint64_t riscv_cpu_all_pending(CPURISCVState *env) { uint32_t gein = get_field(env->hstatus, HSTATUS_VGEIN); uint64_t vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0; From d1d8541217ce8a23e9e751cd868c7d618817134a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9trot?= Date: Thu, 2 Jun 2022 17:52:46 +0200 Subject: [PATCH 917/935] target/riscv/debug.c: keep experimental rv128 support working MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an MXL_RV128 case in two switches so that no error is triggered when using the -cpu x-rv128 option. Signed-off-by: Frédéric Pétrot Acked-by: Alistair Francis Reviewed-by: Bin Meng Message-Id: <20220602155246.38837-1-frederic.petrot@univ-grenoble-alpes.fr> Signed-off-by: Alistair Francis --- target/riscv/debug.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/riscv/debug.c b/target/riscv/debug.c index 2f2a51c732..fc6e13222f 100644 --- a/target/riscv/debug.c +++ b/target/riscv/debug.c @@ -77,6 +77,7 @@ static inline target_ulong trigger_type(CPURISCVState *env, tdata1 = RV32_TYPE(type); break; case MXL_RV64: + case MXL_RV128: tdata1 = RV64_TYPE(type); break; default: @@ -123,6 +124,7 @@ static target_ulong tdata1_validate(CPURISCVState *env, target_ulong val, tdata1 = RV32_TYPE(t); break; case MXL_RV64: + case MXL_RV128: type = extract64(val, 60, 4); dmode = extract64(val, 59, 1); tdata1 = RV64_TYPE(t); From 8a085fb2ad812bf06145779bbb6a18a3e7439771 Mon Sep 17 00:00:00 2001 From: eopXD Date: Mon, 6 Jun 2022 06:16:16 +0000 Subject: [PATCH 918/935] target/riscv: rvv: Prune redundant ESZ, DSZ parameter passed No functional change intended in this commit. Signed-off-by: eop Chen Reviewed-by: Frank Chang Reviewed-by: Weiwei Li Reviewed-by: Alistair Francis Message-Id: <165449614532.19704.7000832880482980398-1@git.sr.ht> Signed-off-by: Alistair Francis --- target/riscv/vector_helper.c | 1132 +++++++++++++++++----------------- 1 file changed, 565 insertions(+), 567 deletions(-) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 576b14e5a3..85dd611cd9 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -710,7 +710,6 @@ RVVCALL(OPIVV2, vsub_vv_d, OP_SSS_D, H8, H8, H8, DO_SUB) static void do_vext_vv(void *vd, void *v0, void *vs1, void *vs2, CPURISCVState *env, uint32_t desc, - uint32_t esz, uint32_t dsz, opivv2_fn *fn) { uint32_t vm = vext_vm(desc); @@ -727,23 +726,23 @@ static void do_vext_vv(void *vd, void *v0, void *vs1, void *vs2, } /* generate the helpers for OPIVV */ -#define GEN_VEXT_VV(NAME, ESZ, DSZ) \ +#define GEN_VEXT_VV(NAME) \ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ void *vs2, CPURISCVState *env, \ uint32_t desc) \ { \ - do_vext_vv(vd, v0, vs1, vs2, env, desc, ESZ, DSZ, \ + do_vext_vv(vd, v0, vs1, vs2, env, desc, \ do_##NAME); \ } -GEN_VEXT_VV(vadd_vv_b, 1, 1) -GEN_VEXT_VV(vadd_vv_h, 2, 2) -GEN_VEXT_VV(vadd_vv_w, 4, 4) -GEN_VEXT_VV(vadd_vv_d, 8, 8) -GEN_VEXT_VV(vsub_vv_b, 1, 1) -GEN_VEXT_VV(vsub_vv_h, 2, 2) -GEN_VEXT_VV(vsub_vv_w, 4, 4) -GEN_VEXT_VV(vsub_vv_d, 8, 8) +GEN_VEXT_VV(vadd_vv_b) +GEN_VEXT_VV(vadd_vv_h) +GEN_VEXT_VV(vadd_vv_w) +GEN_VEXT_VV(vadd_vv_d) +GEN_VEXT_VV(vsub_vv_b) +GEN_VEXT_VV(vsub_vv_h) +GEN_VEXT_VV(vsub_vv_w) +GEN_VEXT_VV(vsub_vv_d) typedef void opivx2_fn(void *vd, target_long s1, void *vs2, int i); @@ -773,7 +772,6 @@ RVVCALL(OPIVX2, vrsub_vx_d, OP_SSS_D, H8, H8, DO_RSUB) static void do_vext_vx(void *vd, void *v0, target_long s1, void *vs2, CPURISCVState *env, uint32_t desc, - uint32_t esz, uint32_t dsz, opivx2_fn fn) { uint32_t vm = vext_vm(desc); @@ -790,27 +788,27 @@ static void do_vext_vx(void *vd, void *v0, target_long s1, void *vs2, } /* generate the helpers for OPIVX */ -#define GEN_VEXT_VX(NAME, ESZ, DSZ) \ +#define GEN_VEXT_VX(NAME) \ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ void *vs2, CPURISCVState *env, \ uint32_t desc) \ { \ - do_vext_vx(vd, v0, s1, vs2, env, desc, ESZ, DSZ, \ + do_vext_vx(vd, v0, s1, vs2, env, desc, \ do_##NAME); \ } -GEN_VEXT_VX(vadd_vx_b, 1, 1) -GEN_VEXT_VX(vadd_vx_h, 2, 2) -GEN_VEXT_VX(vadd_vx_w, 4, 4) -GEN_VEXT_VX(vadd_vx_d, 8, 8) -GEN_VEXT_VX(vsub_vx_b, 1, 1) -GEN_VEXT_VX(vsub_vx_h, 2, 2) -GEN_VEXT_VX(vsub_vx_w, 4, 4) -GEN_VEXT_VX(vsub_vx_d, 8, 8) -GEN_VEXT_VX(vrsub_vx_b, 1, 1) -GEN_VEXT_VX(vrsub_vx_h, 2, 2) -GEN_VEXT_VX(vrsub_vx_w, 4, 4) -GEN_VEXT_VX(vrsub_vx_d, 8, 8) +GEN_VEXT_VX(vadd_vx_b) +GEN_VEXT_VX(vadd_vx_h) +GEN_VEXT_VX(vadd_vx_w) +GEN_VEXT_VX(vadd_vx_d) +GEN_VEXT_VX(vsub_vx_b) +GEN_VEXT_VX(vsub_vx_h) +GEN_VEXT_VX(vsub_vx_w) +GEN_VEXT_VX(vsub_vx_d) +GEN_VEXT_VX(vrsub_vx_b) +GEN_VEXT_VX(vrsub_vx_h) +GEN_VEXT_VX(vrsub_vx_w) +GEN_VEXT_VX(vrsub_vx_d) void HELPER(vec_rsubs8)(void *d, void *a, uint64_t b, uint32_t desc) { @@ -889,30 +887,30 @@ RVVCALL(OPIVV2, vwadd_wv_w, WOP_WSSS_W, H8, H4, H4, DO_ADD) RVVCALL(OPIVV2, vwsub_wv_b, WOP_WSSS_B, H2, H1, H1, DO_SUB) RVVCALL(OPIVV2, vwsub_wv_h, WOP_WSSS_H, H4, H2, H2, DO_SUB) RVVCALL(OPIVV2, vwsub_wv_w, WOP_WSSS_W, H8, H4, H4, DO_SUB) -GEN_VEXT_VV(vwaddu_vv_b, 1, 2) -GEN_VEXT_VV(vwaddu_vv_h, 2, 4) -GEN_VEXT_VV(vwaddu_vv_w, 4, 8) -GEN_VEXT_VV(vwsubu_vv_b, 1, 2) -GEN_VEXT_VV(vwsubu_vv_h, 2, 4) -GEN_VEXT_VV(vwsubu_vv_w, 4, 8) -GEN_VEXT_VV(vwadd_vv_b, 1, 2) -GEN_VEXT_VV(vwadd_vv_h, 2, 4) -GEN_VEXT_VV(vwadd_vv_w, 4, 8) -GEN_VEXT_VV(vwsub_vv_b, 1, 2) -GEN_VEXT_VV(vwsub_vv_h, 2, 4) -GEN_VEXT_VV(vwsub_vv_w, 4, 8) -GEN_VEXT_VV(vwaddu_wv_b, 1, 2) -GEN_VEXT_VV(vwaddu_wv_h, 2, 4) -GEN_VEXT_VV(vwaddu_wv_w, 4, 8) -GEN_VEXT_VV(vwsubu_wv_b, 1, 2) -GEN_VEXT_VV(vwsubu_wv_h, 2, 4) -GEN_VEXT_VV(vwsubu_wv_w, 4, 8) -GEN_VEXT_VV(vwadd_wv_b, 1, 2) -GEN_VEXT_VV(vwadd_wv_h, 2, 4) -GEN_VEXT_VV(vwadd_wv_w, 4, 8) -GEN_VEXT_VV(vwsub_wv_b, 1, 2) -GEN_VEXT_VV(vwsub_wv_h, 2, 4) -GEN_VEXT_VV(vwsub_wv_w, 4, 8) +GEN_VEXT_VV(vwaddu_vv_b) +GEN_VEXT_VV(vwaddu_vv_h) +GEN_VEXT_VV(vwaddu_vv_w) +GEN_VEXT_VV(vwsubu_vv_b) +GEN_VEXT_VV(vwsubu_vv_h) +GEN_VEXT_VV(vwsubu_vv_w) +GEN_VEXT_VV(vwadd_vv_b) +GEN_VEXT_VV(vwadd_vv_h) +GEN_VEXT_VV(vwadd_vv_w) +GEN_VEXT_VV(vwsub_vv_b) +GEN_VEXT_VV(vwsub_vv_h) +GEN_VEXT_VV(vwsub_vv_w) +GEN_VEXT_VV(vwaddu_wv_b) +GEN_VEXT_VV(vwaddu_wv_h) +GEN_VEXT_VV(vwaddu_wv_w) +GEN_VEXT_VV(vwsubu_wv_b) +GEN_VEXT_VV(vwsubu_wv_h) +GEN_VEXT_VV(vwsubu_wv_w) +GEN_VEXT_VV(vwadd_wv_b) +GEN_VEXT_VV(vwadd_wv_h) +GEN_VEXT_VV(vwadd_wv_w) +GEN_VEXT_VV(vwsub_wv_b) +GEN_VEXT_VV(vwsub_wv_h) +GEN_VEXT_VV(vwsub_wv_w) RVVCALL(OPIVX2, vwaddu_vx_b, WOP_UUU_B, H2, H1, DO_ADD) RVVCALL(OPIVX2, vwaddu_vx_h, WOP_UUU_H, H4, H2, DO_ADD) @@ -938,30 +936,30 @@ RVVCALL(OPIVX2, vwadd_wx_w, WOP_WSSS_W, H8, H4, DO_ADD) RVVCALL(OPIVX2, vwsub_wx_b, WOP_WSSS_B, H2, H1, DO_SUB) RVVCALL(OPIVX2, vwsub_wx_h, WOP_WSSS_H, H4, H2, DO_SUB) RVVCALL(OPIVX2, vwsub_wx_w, WOP_WSSS_W, H8, H4, DO_SUB) -GEN_VEXT_VX(vwaddu_vx_b, 1, 2) -GEN_VEXT_VX(vwaddu_vx_h, 2, 4) -GEN_VEXT_VX(vwaddu_vx_w, 4, 8) -GEN_VEXT_VX(vwsubu_vx_b, 1, 2) -GEN_VEXT_VX(vwsubu_vx_h, 2, 4) -GEN_VEXT_VX(vwsubu_vx_w, 4, 8) -GEN_VEXT_VX(vwadd_vx_b, 1, 2) -GEN_VEXT_VX(vwadd_vx_h, 2, 4) -GEN_VEXT_VX(vwadd_vx_w, 4, 8) -GEN_VEXT_VX(vwsub_vx_b, 1, 2) -GEN_VEXT_VX(vwsub_vx_h, 2, 4) -GEN_VEXT_VX(vwsub_vx_w, 4, 8) -GEN_VEXT_VX(vwaddu_wx_b, 1, 2) -GEN_VEXT_VX(vwaddu_wx_h, 2, 4) -GEN_VEXT_VX(vwaddu_wx_w, 4, 8) -GEN_VEXT_VX(vwsubu_wx_b, 1, 2) -GEN_VEXT_VX(vwsubu_wx_h, 2, 4) -GEN_VEXT_VX(vwsubu_wx_w, 4, 8) -GEN_VEXT_VX(vwadd_wx_b, 1, 2) -GEN_VEXT_VX(vwadd_wx_h, 2, 4) -GEN_VEXT_VX(vwadd_wx_w, 4, 8) -GEN_VEXT_VX(vwsub_wx_b, 1, 2) -GEN_VEXT_VX(vwsub_wx_h, 2, 4) -GEN_VEXT_VX(vwsub_wx_w, 4, 8) +GEN_VEXT_VX(vwaddu_vx_b) +GEN_VEXT_VX(vwaddu_vx_h) +GEN_VEXT_VX(vwaddu_vx_w) +GEN_VEXT_VX(vwsubu_vx_b) +GEN_VEXT_VX(vwsubu_vx_h) +GEN_VEXT_VX(vwsubu_vx_w) +GEN_VEXT_VX(vwadd_vx_b) +GEN_VEXT_VX(vwadd_vx_h) +GEN_VEXT_VX(vwadd_vx_w) +GEN_VEXT_VX(vwsub_vx_b) +GEN_VEXT_VX(vwsub_vx_h) +GEN_VEXT_VX(vwsub_vx_w) +GEN_VEXT_VX(vwaddu_wx_b) +GEN_VEXT_VX(vwaddu_wx_h) +GEN_VEXT_VX(vwaddu_wx_w) +GEN_VEXT_VX(vwsubu_wx_b) +GEN_VEXT_VX(vwsubu_wx_h) +GEN_VEXT_VX(vwsubu_wx_w) +GEN_VEXT_VX(vwadd_wx_b) +GEN_VEXT_VX(vwadd_wx_h) +GEN_VEXT_VX(vwadd_wx_w) +GEN_VEXT_VX(vwsub_wx_b) +GEN_VEXT_VX(vwsub_wx_h) +GEN_VEXT_VX(vwsub_wx_w) /* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */ #define DO_VADC(N, M, C) (N + M + C) @@ -1091,18 +1089,18 @@ RVVCALL(OPIVV2, vxor_vv_b, OP_SSS_B, H1, H1, H1, DO_XOR) RVVCALL(OPIVV2, vxor_vv_h, OP_SSS_H, H2, H2, H2, DO_XOR) RVVCALL(OPIVV2, vxor_vv_w, OP_SSS_W, H4, H4, H4, DO_XOR) RVVCALL(OPIVV2, vxor_vv_d, OP_SSS_D, H8, H8, H8, DO_XOR) -GEN_VEXT_VV(vand_vv_b, 1, 1) -GEN_VEXT_VV(vand_vv_h, 2, 2) -GEN_VEXT_VV(vand_vv_w, 4, 4) -GEN_VEXT_VV(vand_vv_d, 8, 8) -GEN_VEXT_VV(vor_vv_b, 1, 1) -GEN_VEXT_VV(vor_vv_h, 2, 2) -GEN_VEXT_VV(vor_vv_w, 4, 4) -GEN_VEXT_VV(vor_vv_d, 8, 8) -GEN_VEXT_VV(vxor_vv_b, 1, 1) -GEN_VEXT_VV(vxor_vv_h, 2, 2) -GEN_VEXT_VV(vxor_vv_w, 4, 4) -GEN_VEXT_VV(vxor_vv_d, 8, 8) +GEN_VEXT_VV(vand_vv_b) +GEN_VEXT_VV(vand_vv_h) +GEN_VEXT_VV(vand_vv_w) +GEN_VEXT_VV(vand_vv_d) +GEN_VEXT_VV(vor_vv_b) +GEN_VEXT_VV(vor_vv_h) +GEN_VEXT_VV(vor_vv_w) +GEN_VEXT_VV(vor_vv_d) +GEN_VEXT_VV(vxor_vv_b) +GEN_VEXT_VV(vxor_vv_h) +GEN_VEXT_VV(vxor_vv_w) +GEN_VEXT_VV(vxor_vv_d) RVVCALL(OPIVX2, vand_vx_b, OP_SSS_B, H1, H1, DO_AND) RVVCALL(OPIVX2, vand_vx_h, OP_SSS_H, H2, H2, DO_AND) @@ -1116,18 +1114,18 @@ RVVCALL(OPIVX2, vxor_vx_b, OP_SSS_B, H1, H1, DO_XOR) RVVCALL(OPIVX2, vxor_vx_h, OP_SSS_H, H2, H2, DO_XOR) RVVCALL(OPIVX2, vxor_vx_w, OP_SSS_W, H4, H4, DO_XOR) RVVCALL(OPIVX2, vxor_vx_d, OP_SSS_D, H8, H8, DO_XOR) -GEN_VEXT_VX(vand_vx_b, 1, 1) -GEN_VEXT_VX(vand_vx_h, 2, 2) -GEN_VEXT_VX(vand_vx_w, 4, 4) -GEN_VEXT_VX(vand_vx_d, 8, 8) -GEN_VEXT_VX(vor_vx_b, 1, 1) -GEN_VEXT_VX(vor_vx_h, 2, 2) -GEN_VEXT_VX(vor_vx_w, 4, 4) -GEN_VEXT_VX(vor_vx_d, 8, 8) -GEN_VEXT_VX(vxor_vx_b, 1, 1) -GEN_VEXT_VX(vxor_vx_h, 2, 2) -GEN_VEXT_VX(vxor_vx_w, 4, 4) -GEN_VEXT_VX(vxor_vx_d, 8, 8) +GEN_VEXT_VX(vand_vx_b) +GEN_VEXT_VX(vand_vx_h) +GEN_VEXT_VX(vand_vx_w) +GEN_VEXT_VX(vand_vx_d) +GEN_VEXT_VX(vor_vx_b) +GEN_VEXT_VX(vor_vx_h) +GEN_VEXT_VX(vor_vx_w) +GEN_VEXT_VX(vor_vx_d) +GEN_VEXT_VX(vxor_vx_b) +GEN_VEXT_VX(vxor_vx_h) +GEN_VEXT_VX(vxor_vx_w) +GEN_VEXT_VX(vxor_vx_d) /* Vector Single-Width Bit Shift Instructions */ #define DO_SLL(N, M) (N << (M)) @@ -1348,22 +1346,22 @@ RVVCALL(OPIVV2, vmax_vv_b, OP_SSS_B, H1, H1, H1, DO_MAX) RVVCALL(OPIVV2, vmax_vv_h, OP_SSS_H, H2, H2, H2, DO_MAX) RVVCALL(OPIVV2, vmax_vv_w, OP_SSS_W, H4, H4, H4, DO_MAX) RVVCALL(OPIVV2, vmax_vv_d, OP_SSS_D, H8, H8, H8, DO_MAX) -GEN_VEXT_VV(vminu_vv_b, 1, 1) -GEN_VEXT_VV(vminu_vv_h, 2, 2) -GEN_VEXT_VV(vminu_vv_w, 4, 4) -GEN_VEXT_VV(vminu_vv_d, 8, 8) -GEN_VEXT_VV(vmin_vv_b, 1, 1) -GEN_VEXT_VV(vmin_vv_h, 2, 2) -GEN_VEXT_VV(vmin_vv_w, 4, 4) -GEN_VEXT_VV(vmin_vv_d, 8, 8) -GEN_VEXT_VV(vmaxu_vv_b, 1, 1) -GEN_VEXT_VV(vmaxu_vv_h, 2, 2) -GEN_VEXT_VV(vmaxu_vv_w, 4, 4) -GEN_VEXT_VV(vmaxu_vv_d, 8, 8) -GEN_VEXT_VV(vmax_vv_b, 1, 1) -GEN_VEXT_VV(vmax_vv_h, 2, 2) -GEN_VEXT_VV(vmax_vv_w, 4, 4) -GEN_VEXT_VV(vmax_vv_d, 8, 8) +GEN_VEXT_VV(vminu_vv_b) +GEN_VEXT_VV(vminu_vv_h) +GEN_VEXT_VV(vminu_vv_w) +GEN_VEXT_VV(vminu_vv_d) +GEN_VEXT_VV(vmin_vv_b) +GEN_VEXT_VV(vmin_vv_h) +GEN_VEXT_VV(vmin_vv_w) +GEN_VEXT_VV(vmin_vv_d) +GEN_VEXT_VV(vmaxu_vv_b) +GEN_VEXT_VV(vmaxu_vv_h) +GEN_VEXT_VV(vmaxu_vv_w) +GEN_VEXT_VV(vmaxu_vv_d) +GEN_VEXT_VV(vmax_vv_b) +GEN_VEXT_VV(vmax_vv_h) +GEN_VEXT_VV(vmax_vv_w) +GEN_VEXT_VV(vmax_vv_d) RVVCALL(OPIVX2, vminu_vx_b, OP_UUU_B, H1, H1, DO_MIN) RVVCALL(OPIVX2, vminu_vx_h, OP_UUU_H, H2, H2, DO_MIN) @@ -1381,22 +1379,22 @@ RVVCALL(OPIVX2, vmax_vx_b, OP_SSS_B, H1, H1, DO_MAX) RVVCALL(OPIVX2, vmax_vx_h, OP_SSS_H, H2, H2, DO_MAX) RVVCALL(OPIVX2, vmax_vx_w, OP_SSS_W, H4, H4, DO_MAX) RVVCALL(OPIVX2, vmax_vx_d, OP_SSS_D, H8, H8, DO_MAX) -GEN_VEXT_VX(vminu_vx_b, 1, 1) -GEN_VEXT_VX(vminu_vx_h, 2, 2) -GEN_VEXT_VX(vminu_vx_w, 4, 4) -GEN_VEXT_VX(vminu_vx_d, 8, 8) -GEN_VEXT_VX(vmin_vx_b, 1, 1) -GEN_VEXT_VX(vmin_vx_h, 2, 2) -GEN_VEXT_VX(vmin_vx_w, 4, 4) -GEN_VEXT_VX(vmin_vx_d, 8, 8) -GEN_VEXT_VX(vmaxu_vx_b, 1, 1) -GEN_VEXT_VX(vmaxu_vx_h, 2, 2) -GEN_VEXT_VX(vmaxu_vx_w, 4, 4) -GEN_VEXT_VX(vmaxu_vx_d, 8, 8) -GEN_VEXT_VX(vmax_vx_b, 1, 1) -GEN_VEXT_VX(vmax_vx_h, 2, 2) -GEN_VEXT_VX(vmax_vx_w, 4, 4) -GEN_VEXT_VX(vmax_vx_d, 8, 8) +GEN_VEXT_VX(vminu_vx_b) +GEN_VEXT_VX(vminu_vx_h) +GEN_VEXT_VX(vminu_vx_w) +GEN_VEXT_VX(vminu_vx_d) +GEN_VEXT_VX(vmin_vx_b) +GEN_VEXT_VX(vmin_vx_h) +GEN_VEXT_VX(vmin_vx_w) +GEN_VEXT_VX(vmin_vx_d) +GEN_VEXT_VX(vmaxu_vx_b) +GEN_VEXT_VX(vmaxu_vx_h) +GEN_VEXT_VX(vmaxu_vx_w) +GEN_VEXT_VX(vmaxu_vx_d) +GEN_VEXT_VX(vmax_vx_b) +GEN_VEXT_VX(vmax_vx_h) +GEN_VEXT_VX(vmax_vx_w) +GEN_VEXT_VX(vmax_vx_d) /* Vector Single-Width Integer Multiply Instructions */ #define DO_MUL(N, M) (N * M) @@ -1404,10 +1402,10 @@ RVVCALL(OPIVV2, vmul_vv_b, OP_SSS_B, H1, H1, H1, DO_MUL) RVVCALL(OPIVV2, vmul_vv_h, OP_SSS_H, H2, H2, H2, DO_MUL) RVVCALL(OPIVV2, vmul_vv_w, OP_SSS_W, H4, H4, H4, DO_MUL) RVVCALL(OPIVV2, vmul_vv_d, OP_SSS_D, H8, H8, H8, DO_MUL) -GEN_VEXT_VV(vmul_vv_b, 1, 1) -GEN_VEXT_VV(vmul_vv_h, 2, 2) -GEN_VEXT_VV(vmul_vv_w, 4, 4) -GEN_VEXT_VV(vmul_vv_d, 8, 8) +GEN_VEXT_VV(vmul_vv_b) +GEN_VEXT_VV(vmul_vv_h) +GEN_VEXT_VV(vmul_vv_w) +GEN_VEXT_VV(vmul_vv_d) static int8_t do_mulh_b(int8_t s2, int8_t s1) { @@ -1511,18 +1509,18 @@ RVVCALL(OPIVV2, vmulhsu_vv_b, OP_SUS_B, H1, H1, H1, do_mulhsu_b) RVVCALL(OPIVV2, vmulhsu_vv_h, OP_SUS_H, H2, H2, H2, do_mulhsu_h) RVVCALL(OPIVV2, vmulhsu_vv_w, OP_SUS_W, H4, H4, H4, do_mulhsu_w) RVVCALL(OPIVV2, vmulhsu_vv_d, OP_SUS_D, H8, H8, H8, do_mulhsu_d) -GEN_VEXT_VV(vmulh_vv_b, 1, 1) -GEN_VEXT_VV(vmulh_vv_h, 2, 2) -GEN_VEXT_VV(vmulh_vv_w, 4, 4) -GEN_VEXT_VV(vmulh_vv_d, 8, 8) -GEN_VEXT_VV(vmulhu_vv_b, 1, 1) -GEN_VEXT_VV(vmulhu_vv_h, 2, 2) -GEN_VEXT_VV(vmulhu_vv_w, 4, 4) -GEN_VEXT_VV(vmulhu_vv_d, 8, 8) -GEN_VEXT_VV(vmulhsu_vv_b, 1, 1) -GEN_VEXT_VV(vmulhsu_vv_h, 2, 2) -GEN_VEXT_VV(vmulhsu_vv_w, 4, 4) -GEN_VEXT_VV(vmulhsu_vv_d, 8, 8) +GEN_VEXT_VV(vmulh_vv_b) +GEN_VEXT_VV(vmulh_vv_h) +GEN_VEXT_VV(vmulh_vv_w) +GEN_VEXT_VV(vmulh_vv_d) +GEN_VEXT_VV(vmulhu_vv_b) +GEN_VEXT_VV(vmulhu_vv_h) +GEN_VEXT_VV(vmulhu_vv_w) +GEN_VEXT_VV(vmulhu_vv_d) +GEN_VEXT_VV(vmulhsu_vv_b) +GEN_VEXT_VV(vmulhsu_vv_h) +GEN_VEXT_VV(vmulhsu_vv_w) +GEN_VEXT_VV(vmulhsu_vv_d) RVVCALL(OPIVX2, vmul_vx_b, OP_SSS_B, H1, H1, DO_MUL) RVVCALL(OPIVX2, vmul_vx_h, OP_SSS_H, H2, H2, DO_MUL) @@ -1540,22 +1538,22 @@ RVVCALL(OPIVX2, vmulhsu_vx_b, OP_SUS_B, H1, H1, do_mulhsu_b) RVVCALL(OPIVX2, vmulhsu_vx_h, OP_SUS_H, H2, H2, do_mulhsu_h) RVVCALL(OPIVX2, vmulhsu_vx_w, OP_SUS_W, H4, H4, do_mulhsu_w) RVVCALL(OPIVX2, vmulhsu_vx_d, OP_SUS_D, H8, H8, do_mulhsu_d) -GEN_VEXT_VX(vmul_vx_b, 1, 1) -GEN_VEXT_VX(vmul_vx_h, 2, 2) -GEN_VEXT_VX(vmul_vx_w, 4, 4) -GEN_VEXT_VX(vmul_vx_d, 8, 8) -GEN_VEXT_VX(vmulh_vx_b, 1, 1) -GEN_VEXT_VX(vmulh_vx_h, 2, 2) -GEN_VEXT_VX(vmulh_vx_w, 4, 4) -GEN_VEXT_VX(vmulh_vx_d, 8, 8) -GEN_VEXT_VX(vmulhu_vx_b, 1, 1) -GEN_VEXT_VX(vmulhu_vx_h, 2, 2) -GEN_VEXT_VX(vmulhu_vx_w, 4, 4) -GEN_VEXT_VX(vmulhu_vx_d, 8, 8) -GEN_VEXT_VX(vmulhsu_vx_b, 1, 1) -GEN_VEXT_VX(vmulhsu_vx_h, 2, 2) -GEN_VEXT_VX(vmulhsu_vx_w, 4, 4) -GEN_VEXT_VX(vmulhsu_vx_d, 8, 8) +GEN_VEXT_VX(vmul_vx_b) +GEN_VEXT_VX(vmul_vx_h) +GEN_VEXT_VX(vmul_vx_w) +GEN_VEXT_VX(vmul_vx_d) +GEN_VEXT_VX(vmulh_vx_b) +GEN_VEXT_VX(vmulh_vx_h) +GEN_VEXT_VX(vmulh_vx_w) +GEN_VEXT_VX(vmulh_vx_d) +GEN_VEXT_VX(vmulhu_vx_b) +GEN_VEXT_VX(vmulhu_vx_h) +GEN_VEXT_VX(vmulhu_vx_w) +GEN_VEXT_VX(vmulhu_vx_d) +GEN_VEXT_VX(vmulhsu_vx_b) +GEN_VEXT_VX(vmulhsu_vx_h) +GEN_VEXT_VX(vmulhsu_vx_w) +GEN_VEXT_VX(vmulhsu_vx_d) /* Vector Integer Divide Instructions */ #define DO_DIVU(N, M) (unlikely(M == 0) ? (__typeof(N))(-1) : N / M) @@ -1581,22 +1579,22 @@ RVVCALL(OPIVV2, vrem_vv_b, OP_SSS_B, H1, H1, H1, DO_REM) RVVCALL(OPIVV2, vrem_vv_h, OP_SSS_H, H2, H2, H2, DO_REM) RVVCALL(OPIVV2, vrem_vv_w, OP_SSS_W, H4, H4, H4, DO_REM) RVVCALL(OPIVV2, vrem_vv_d, OP_SSS_D, H8, H8, H8, DO_REM) -GEN_VEXT_VV(vdivu_vv_b, 1, 1) -GEN_VEXT_VV(vdivu_vv_h, 2, 2) -GEN_VEXT_VV(vdivu_vv_w, 4, 4) -GEN_VEXT_VV(vdivu_vv_d, 8, 8) -GEN_VEXT_VV(vdiv_vv_b, 1, 1) -GEN_VEXT_VV(vdiv_vv_h, 2, 2) -GEN_VEXT_VV(vdiv_vv_w, 4, 4) -GEN_VEXT_VV(vdiv_vv_d, 8, 8) -GEN_VEXT_VV(vremu_vv_b, 1, 1) -GEN_VEXT_VV(vremu_vv_h, 2, 2) -GEN_VEXT_VV(vremu_vv_w, 4, 4) -GEN_VEXT_VV(vremu_vv_d, 8, 8) -GEN_VEXT_VV(vrem_vv_b, 1, 1) -GEN_VEXT_VV(vrem_vv_h, 2, 2) -GEN_VEXT_VV(vrem_vv_w, 4, 4) -GEN_VEXT_VV(vrem_vv_d, 8, 8) +GEN_VEXT_VV(vdivu_vv_b) +GEN_VEXT_VV(vdivu_vv_h) +GEN_VEXT_VV(vdivu_vv_w) +GEN_VEXT_VV(vdivu_vv_d) +GEN_VEXT_VV(vdiv_vv_b) +GEN_VEXT_VV(vdiv_vv_h) +GEN_VEXT_VV(vdiv_vv_w) +GEN_VEXT_VV(vdiv_vv_d) +GEN_VEXT_VV(vremu_vv_b) +GEN_VEXT_VV(vremu_vv_h) +GEN_VEXT_VV(vremu_vv_w) +GEN_VEXT_VV(vremu_vv_d) +GEN_VEXT_VV(vrem_vv_b) +GEN_VEXT_VV(vrem_vv_h) +GEN_VEXT_VV(vrem_vv_w) +GEN_VEXT_VV(vrem_vv_d) RVVCALL(OPIVX2, vdivu_vx_b, OP_UUU_B, H1, H1, DO_DIVU) RVVCALL(OPIVX2, vdivu_vx_h, OP_UUU_H, H2, H2, DO_DIVU) @@ -1614,22 +1612,22 @@ RVVCALL(OPIVX2, vrem_vx_b, OP_SSS_B, H1, H1, DO_REM) RVVCALL(OPIVX2, vrem_vx_h, OP_SSS_H, H2, H2, DO_REM) RVVCALL(OPIVX2, vrem_vx_w, OP_SSS_W, H4, H4, DO_REM) RVVCALL(OPIVX2, vrem_vx_d, OP_SSS_D, H8, H8, DO_REM) -GEN_VEXT_VX(vdivu_vx_b, 1, 1) -GEN_VEXT_VX(vdivu_vx_h, 2, 2) -GEN_VEXT_VX(vdivu_vx_w, 4, 4) -GEN_VEXT_VX(vdivu_vx_d, 8, 8) -GEN_VEXT_VX(vdiv_vx_b, 1, 1) -GEN_VEXT_VX(vdiv_vx_h, 2, 2) -GEN_VEXT_VX(vdiv_vx_w, 4, 4) -GEN_VEXT_VX(vdiv_vx_d, 8, 8) -GEN_VEXT_VX(vremu_vx_b, 1, 1) -GEN_VEXT_VX(vremu_vx_h, 2, 2) -GEN_VEXT_VX(vremu_vx_w, 4, 4) -GEN_VEXT_VX(vremu_vx_d, 8, 8) -GEN_VEXT_VX(vrem_vx_b, 1, 1) -GEN_VEXT_VX(vrem_vx_h, 2, 2) -GEN_VEXT_VX(vrem_vx_w, 4, 4) -GEN_VEXT_VX(vrem_vx_d, 8, 8) +GEN_VEXT_VX(vdivu_vx_b) +GEN_VEXT_VX(vdivu_vx_h) +GEN_VEXT_VX(vdivu_vx_w) +GEN_VEXT_VX(vdivu_vx_d) +GEN_VEXT_VX(vdiv_vx_b) +GEN_VEXT_VX(vdiv_vx_h) +GEN_VEXT_VX(vdiv_vx_w) +GEN_VEXT_VX(vdiv_vx_d) +GEN_VEXT_VX(vremu_vx_b) +GEN_VEXT_VX(vremu_vx_h) +GEN_VEXT_VX(vremu_vx_w) +GEN_VEXT_VX(vremu_vx_d) +GEN_VEXT_VX(vrem_vx_b) +GEN_VEXT_VX(vrem_vx_h) +GEN_VEXT_VX(vrem_vx_w) +GEN_VEXT_VX(vrem_vx_d) /* Vector Widening Integer Multiply Instructions */ RVVCALL(OPIVV2, vwmul_vv_b, WOP_SSS_B, H2, H1, H1, DO_MUL) @@ -1641,15 +1639,15 @@ RVVCALL(OPIVV2, vwmulu_vv_w, WOP_UUU_W, H8, H4, H4, DO_MUL) RVVCALL(OPIVV2, vwmulsu_vv_b, WOP_SUS_B, H2, H1, H1, DO_MUL) RVVCALL(OPIVV2, vwmulsu_vv_h, WOP_SUS_H, H4, H2, H2, DO_MUL) RVVCALL(OPIVV2, vwmulsu_vv_w, WOP_SUS_W, H8, H4, H4, DO_MUL) -GEN_VEXT_VV(vwmul_vv_b, 1, 2) -GEN_VEXT_VV(vwmul_vv_h, 2, 4) -GEN_VEXT_VV(vwmul_vv_w, 4, 8) -GEN_VEXT_VV(vwmulu_vv_b, 1, 2) -GEN_VEXT_VV(vwmulu_vv_h, 2, 4) -GEN_VEXT_VV(vwmulu_vv_w, 4, 8) -GEN_VEXT_VV(vwmulsu_vv_b, 1, 2) -GEN_VEXT_VV(vwmulsu_vv_h, 2, 4) -GEN_VEXT_VV(vwmulsu_vv_w, 4, 8) +GEN_VEXT_VV(vwmul_vv_b) +GEN_VEXT_VV(vwmul_vv_h) +GEN_VEXT_VV(vwmul_vv_w) +GEN_VEXT_VV(vwmulu_vv_b) +GEN_VEXT_VV(vwmulu_vv_h) +GEN_VEXT_VV(vwmulu_vv_w) +GEN_VEXT_VV(vwmulsu_vv_b) +GEN_VEXT_VV(vwmulsu_vv_h) +GEN_VEXT_VV(vwmulsu_vv_w) RVVCALL(OPIVX2, vwmul_vx_b, WOP_SSS_B, H2, H1, DO_MUL) RVVCALL(OPIVX2, vwmul_vx_h, WOP_SSS_H, H4, H2, DO_MUL) @@ -1660,15 +1658,15 @@ RVVCALL(OPIVX2, vwmulu_vx_w, WOP_UUU_W, H8, H4, DO_MUL) RVVCALL(OPIVX2, vwmulsu_vx_b, WOP_SUS_B, H2, H1, DO_MUL) RVVCALL(OPIVX2, vwmulsu_vx_h, WOP_SUS_H, H4, H2, DO_MUL) RVVCALL(OPIVX2, vwmulsu_vx_w, WOP_SUS_W, H8, H4, DO_MUL) -GEN_VEXT_VX(vwmul_vx_b, 1, 2) -GEN_VEXT_VX(vwmul_vx_h, 2, 4) -GEN_VEXT_VX(vwmul_vx_w, 4, 8) -GEN_VEXT_VX(vwmulu_vx_b, 1, 2) -GEN_VEXT_VX(vwmulu_vx_h, 2, 4) -GEN_VEXT_VX(vwmulu_vx_w, 4, 8) -GEN_VEXT_VX(vwmulsu_vx_b, 1, 2) -GEN_VEXT_VX(vwmulsu_vx_h, 2, 4) -GEN_VEXT_VX(vwmulsu_vx_w, 4, 8) +GEN_VEXT_VX(vwmul_vx_b) +GEN_VEXT_VX(vwmul_vx_h) +GEN_VEXT_VX(vwmul_vx_w) +GEN_VEXT_VX(vwmulu_vx_b) +GEN_VEXT_VX(vwmulu_vx_h) +GEN_VEXT_VX(vwmulu_vx_w) +GEN_VEXT_VX(vwmulsu_vx_b) +GEN_VEXT_VX(vwmulsu_vx_h) +GEN_VEXT_VX(vwmulsu_vx_w) /* Vector Single-Width Integer Multiply-Add Instructions */ #define OPIVV3(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \ @@ -1700,22 +1698,22 @@ RVVCALL(OPIVV3, vnmsub_vv_b, OP_SSS_B, H1, H1, H1, DO_NMSUB) RVVCALL(OPIVV3, vnmsub_vv_h, OP_SSS_H, H2, H2, H2, DO_NMSUB) RVVCALL(OPIVV3, vnmsub_vv_w, OP_SSS_W, H4, H4, H4, DO_NMSUB) RVVCALL(OPIVV3, vnmsub_vv_d, OP_SSS_D, H8, H8, H8, DO_NMSUB) -GEN_VEXT_VV(vmacc_vv_b, 1, 1) -GEN_VEXT_VV(vmacc_vv_h, 2, 2) -GEN_VEXT_VV(vmacc_vv_w, 4, 4) -GEN_VEXT_VV(vmacc_vv_d, 8, 8) -GEN_VEXT_VV(vnmsac_vv_b, 1, 1) -GEN_VEXT_VV(vnmsac_vv_h, 2, 2) -GEN_VEXT_VV(vnmsac_vv_w, 4, 4) -GEN_VEXT_VV(vnmsac_vv_d, 8, 8) -GEN_VEXT_VV(vmadd_vv_b, 1, 1) -GEN_VEXT_VV(vmadd_vv_h, 2, 2) -GEN_VEXT_VV(vmadd_vv_w, 4, 4) -GEN_VEXT_VV(vmadd_vv_d, 8, 8) -GEN_VEXT_VV(vnmsub_vv_b, 1, 1) -GEN_VEXT_VV(vnmsub_vv_h, 2, 2) -GEN_VEXT_VV(vnmsub_vv_w, 4, 4) -GEN_VEXT_VV(vnmsub_vv_d, 8, 8) +GEN_VEXT_VV(vmacc_vv_b) +GEN_VEXT_VV(vmacc_vv_h) +GEN_VEXT_VV(vmacc_vv_w) +GEN_VEXT_VV(vmacc_vv_d) +GEN_VEXT_VV(vnmsac_vv_b) +GEN_VEXT_VV(vnmsac_vv_h) +GEN_VEXT_VV(vnmsac_vv_w) +GEN_VEXT_VV(vnmsac_vv_d) +GEN_VEXT_VV(vmadd_vv_b) +GEN_VEXT_VV(vmadd_vv_h) +GEN_VEXT_VV(vmadd_vv_w) +GEN_VEXT_VV(vmadd_vv_d) +GEN_VEXT_VV(vnmsub_vv_b) +GEN_VEXT_VV(vnmsub_vv_h) +GEN_VEXT_VV(vnmsub_vv_w) +GEN_VEXT_VV(vnmsub_vv_d) #define OPIVX3(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \ static void do_##NAME(void *vd, target_long s1, void *vs2, int i) \ @@ -1741,22 +1739,22 @@ RVVCALL(OPIVX3, vnmsub_vx_b, OP_SSS_B, H1, H1, DO_NMSUB) RVVCALL(OPIVX3, vnmsub_vx_h, OP_SSS_H, H2, H2, DO_NMSUB) RVVCALL(OPIVX3, vnmsub_vx_w, OP_SSS_W, H4, H4, DO_NMSUB) RVVCALL(OPIVX3, vnmsub_vx_d, OP_SSS_D, H8, H8, DO_NMSUB) -GEN_VEXT_VX(vmacc_vx_b, 1, 1) -GEN_VEXT_VX(vmacc_vx_h, 2, 2) -GEN_VEXT_VX(vmacc_vx_w, 4, 4) -GEN_VEXT_VX(vmacc_vx_d, 8, 8) -GEN_VEXT_VX(vnmsac_vx_b, 1, 1) -GEN_VEXT_VX(vnmsac_vx_h, 2, 2) -GEN_VEXT_VX(vnmsac_vx_w, 4, 4) -GEN_VEXT_VX(vnmsac_vx_d, 8, 8) -GEN_VEXT_VX(vmadd_vx_b, 1, 1) -GEN_VEXT_VX(vmadd_vx_h, 2, 2) -GEN_VEXT_VX(vmadd_vx_w, 4, 4) -GEN_VEXT_VX(vmadd_vx_d, 8, 8) -GEN_VEXT_VX(vnmsub_vx_b, 1, 1) -GEN_VEXT_VX(vnmsub_vx_h, 2, 2) -GEN_VEXT_VX(vnmsub_vx_w, 4, 4) -GEN_VEXT_VX(vnmsub_vx_d, 8, 8) +GEN_VEXT_VX(vmacc_vx_b) +GEN_VEXT_VX(vmacc_vx_h) +GEN_VEXT_VX(vmacc_vx_w) +GEN_VEXT_VX(vmacc_vx_d) +GEN_VEXT_VX(vnmsac_vx_b) +GEN_VEXT_VX(vnmsac_vx_h) +GEN_VEXT_VX(vnmsac_vx_w) +GEN_VEXT_VX(vnmsac_vx_d) +GEN_VEXT_VX(vmadd_vx_b) +GEN_VEXT_VX(vmadd_vx_h) +GEN_VEXT_VX(vmadd_vx_w) +GEN_VEXT_VX(vmadd_vx_d) +GEN_VEXT_VX(vnmsub_vx_b) +GEN_VEXT_VX(vnmsub_vx_h) +GEN_VEXT_VX(vnmsub_vx_w) +GEN_VEXT_VX(vnmsub_vx_d) /* Vector Widening Integer Multiply-Add Instructions */ RVVCALL(OPIVV3, vwmaccu_vv_b, WOP_UUU_B, H2, H1, H1, DO_MACC) @@ -1768,15 +1766,15 @@ RVVCALL(OPIVV3, vwmacc_vv_w, WOP_SSS_W, H8, H4, H4, DO_MACC) RVVCALL(OPIVV3, vwmaccsu_vv_b, WOP_SSU_B, H2, H1, H1, DO_MACC) RVVCALL(OPIVV3, vwmaccsu_vv_h, WOP_SSU_H, H4, H2, H2, DO_MACC) RVVCALL(OPIVV3, vwmaccsu_vv_w, WOP_SSU_W, H8, H4, H4, DO_MACC) -GEN_VEXT_VV(vwmaccu_vv_b, 1, 2) -GEN_VEXT_VV(vwmaccu_vv_h, 2, 4) -GEN_VEXT_VV(vwmaccu_vv_w, 4, 8) -GEN_VEXT_VV(vwmacc_vv_b, 1, 2) -GEN_VEXT_VV(vwmacc_vv_h, 2, 4) -GEN_VEXT_VV(vwmacc_vv_w, 4, 8) -GEN_VEXT_VV(vwmaccsu_vv_b, 1, 2) -GEN_VEXT_VV(vwmaccsu_vv_h, 2, 4) -GEN_VEXT_VV(vwmaccsu_vv_w, 4, 8) +GEN_VEXT_VV(vwmaccu_vv_b) +GEN_VEXT_VV(vwmaccu_vv_h) +GEN_VEXT_VV(vwmaccu_vv_w) +GEN_VEXT_VV(vwmacc_vv_b) +GEN_VEXT_VV(vwmacc_vv_h) +GEN_VEXT_VV(vwmacc_vv_w) +GEN_VEXT_VV(vwmaccsu_vv_b) +GEN_VEXT_VV(vwmaccsu_vv_h) +GEN_VEXT_VV(vwmaccsu_vv_w) RVVCALL(OPIVX3, vwmaccu_vx_b, WOP_UUU_B, H2, H1, DO_MACC) RVVCALL(OPIVX3, vwmaccu_vx_h, WOP_UUU_H, H4, H2, DO_MACC) @@ -1790,18 +1788,18 @@ RVVCALL(OPIVX3, vwmaccsu_vx_w, WOP_SSU_W, H8, H4, DO_MACC) RVVCALL(OPIVX3, vwmaccus_vx_b, WOP_SUS_B, H2, H1, DO_MACC) RVVCALL(OPIVX3, vwmaccus_vx_h, WOP_SUS_H, H4, H2, DO_MACC) RVVCALL(OPIVX3, vwmaccus_vx_w, WOP_SUS_W, H8, H4, DO_MACC) -GEN_VEXT_VX(vwmaccu_vx_b, 1, 2) -GEN_VEXT_VX(vwmaccu_vx_h, 2, 4) -GEN_VEXT_VX(vwmaccu_vx_w, 4, 8) -GEN_VEXT_VX(vwmacc_vx_b, 1, 2) -GEN_VEXT_VX(vwmacc_vx_h, 2, 4) -GEN_VEXT_VX(vwmacc_vx_w, 4, 8) -GEN_VEXT_VX(vwmaccsu_vx_b, 1, 2) -GEN_VEXT_VX(vwmaccsu_vx_h, 2, 4) -GEN_VEXT_VX(vwmaccsu_vx_w, 4, 8) -GEN_VEXT_VX(vwmaccus_vx_b, 1, 2) -GEN_VEXT_VX(vwmaccus_vx_h, 2, 4) -GEN_VEXT_VX(vwmaccus_vx_w, 4, 8) +GEN_VEXT_VX(vwmaccu_vx_b) +GEN_VEXT_VX(vwmaccu_vx_h) +GEN_VEXT_VX(vwmaccu_vx_w) +GEN_VEXT_VX(vwmacc_vx_b) +GEN_VEXT_VX(vwmacc_vx_h) +GEN_VEXT_VX(vwmacc_vx_w) +GEN_VEXT_VX(vwmaccsu_vx_b) +GEN_VEXT_VX(vwmaccsu_vx_h) +GEN_VEXT_VX(vwmaccsu_vx_w) +GEN_VEXT_VX(vwmaccus_vx_b) +GEN_VEXT_VX(vwmaccus_vx_h) +GEN_VEXT_VX(vwmaccus_vx_w) /* Vector Integer Merge and Move Instructions */ #define GEN_VEXT_VMV_VV(NAME, ETYPE, H) \ @@ -1922,7 +1920,7 @@ vext_vv_rm_1(void *vd, void *v0, void *vs1, void *vs2, static inline void vext_vv_rm_2(void *vd, void *v0, void *vs1, void *vs2, CPURISCVState *env, - uint32_t desc, uint32_t esz, uint32_t dsz, + uint32_t desc, opivv2_rm_fn *fn) { uint32_t vm = vext_vm(desc); @@ -1949,11 +1947,11 @@ vext_vv_rm_2(void *vd, void *v0, void *vs1, void *vs2, } /* generate helpers for fixed point instructions with OPIVV format */ -#define GEN_VEXT_VV_RM(NAME, ESZ, DSZ) \ +#define GEN_VEXT_VV_RM(NAME) \ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ - vext_vv_rm_2(vd, v0, vs1, vs2, env, desc, ESZ, DSZ, \ + vext_vv_rm_2(vd, v0, vs1, vs2, env, desc, \ do_##NAME); \ } @@ -2004,10 +2002,10 @@ RVVCALL(OPIVV2_RM, vsaddu_vv_b, OP_UUU_B, H1, H1, H1, saddu8) RVVCALL(OPIVV2_RM, vsaddu_vv_h, OP_UUU_H, H2, H2, H2, saddu16) RVVCALL(OPIVV2_RM, vsaddu_vv_w, OP_UUU_W, H4, H4, H4, saddu32) RVVCALL(OPIVV2_RM, vsaddu_vv_d, OP_UUU_D, H8, H8, H8, saddu64) -GEN_VEXT_VV_RM(vsaddu_vv_b, 1, 1) -GEN_VEXT_VV_RM(vsaddu_vv_h, 2, 2) -GEN_VEXT_VV_RM(vsaddu_vv_w, 4, 4) -GEN_VEXT_VV_RM(vsaddu_vv_d, 8, 8) +GEN_VEXT_VV_RM(vsaddu_vv_b) +GEN_VEXT_VV_RM(vsaddu_vv_h) +GEN_VEXT_VV_RM(vsaddu_vv_w) +GEN_VEXT_VV_RM(vsaddu_vv_d) typedef void opivx2_rm_fn(void *vd, target_long s1, void *vs2, int i, CPURISCVState *env, int vxrm); @@ -2039,7 +2037,7 @@ vext_vx_rm_1(void *vd, void *v0, target_long s1, void *vs2, static inline void vext_vx_rm_2(void *vd, void *v0, target_long s1, void *vs2, CPURISCVState *env, - uint32_t desc, uint32_t esz, uint32_t dsz, + uint32_t desc, opivx2_rm_fn *fn) { uint32_t vm = vext_vm(desc); @@ -2066,11 +2064,11 @@ vext_vx_rm_2(void *vd, void *v0, target_long s1, void *vs2, } /* generate helpers for fixed point instructions with OPIVX format */ -#define GEN_VEXT_VX_RM(NAME, ESZ, DSZ) \ +#define GEN_VEXT_VX_RM(NAME) \ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ void *vs2, CPURISCVState *env, uint32_t desc) \ { \ - vext_vx_rm_2(vd, v0, s1, vs2, env, desc, ESZ, DSZ, \ + vext_vx_rm_2(vd, v0, s1, vs2, env, desc, \ do_##NAME); \ } @@ -2078,10 +2076,10 @@ RVVCALL(OPIVX2_RM, vsaddu_vx_b, OP_UUU_B, H1, H1, saddu8) RVVCALL(OPIVX2_RM, vsaddu_vx_h, OP_UUU_H, H2, H2, saddu16) RVVCALL(OPIVX2_RM, vsaddu_vx_w, OP_UUU_W, H4, H4, saddu32) RVVCALL(OPIVX2_RM, vsaddu_vx_d, OP_UUU_D, H8, H8, saddu64) -GEN_VEXT_VX_RM(vsaddu_vx_b, 1, 1) -GEN_VEXT_VX_RM(vsaddu_vx_h, 2, 2) -GEN_VEXT_VX_RM(vsaddu_vx_w, 4, 4) -GEN_VEXT_VX_RM(vsaddu_vx_d, 8, 8) +GEN_VEXT_VX_RM(vsaddu_vx_b) +GEN_VEXT_VX_RM(vsaddu_vx_h) +GEN_VEXT_VX_RM(vsaddu_vx_w) +GEN_VEXT_VX_RM(vsaddu_vx_d) static inline int8_t sadd8(CPURISCVState *env, int vxrm, int8_t a, int8_t b) { @@ -2127,19 +2125,19 @@ RVVCALL(OPIVV2_RM, vsadd_vv_b, OP_SSS_B, H1, H1, H1, sadd8) RVVCALL(OPIVV2_RM, vsadd_vv_h, OP_SSS_H, H2, H2, H2, sadd16) RVVCALL(OPIVV2_RM, vsadd_vv_w, OP_SSS_W, H4, H4, H4, sadd32) RVVCALL(OPIVV2_RM, vsadd_vv_d, OP_SSS_D, H8, H8, H8, sadd64) -GEN_VEXT_VV_RM(vsadd_vv_b, 1, 1) -GEN_VEXT_VV_RM(vsadd_vv_h, 2, 2) -GEN_VEXT_VV_RM(vsadd_vv_w, 4, 4) -GEN_VEXT_VV_RM(vsadd_vv_d, 8, 8) +GEN_VEXT_VV_RM(vsadd_vv_b) +GEN_VEXT_VV_RM(vsadd_vv_h) +GEN_VEXT_VV_RM(vsadd_vv_w) +GEN_VEXT_VV_RM(vsadd_vv_d) RVVCALL(OPIVX2_RM, vsadd_vx_b, OP_SSS_B, H1, H1, sadd8) RVVCALL(OPIVX2_RM, vsadd_vx_h, OP_SSS_H, H2, H2, sadd16) RVVCALL(OPIVX2_RM, vsadd_vx_w, OP_SSS_W, H4, H4, sadd32) RVVCALL(OPIVX2_RM, vsadd_vx_d, OP_SSS_D, H8, H8, sadd64) -GEN_VEXT_VX_RM(vsadd_vx_b, 1, 1) -GEN_VEXT_VX_RM(vsadd_vx_h, 2, 2) -GEN_VEXT_VX_RM(vsadd_vx_w, 4, 4) -GEN_VEXT_VX_RM(vsadd_vx_d, 8, 8) +GEN_VEXT_VX_RM(vsadd_vx_b) +GEN_VEXT_VX_RM(vsadd_vx_h) +GEN_VEXT_VX_RM(vsadd_vx_w) +GEN_VEXT_VX_RM(vsadd_vx_d) static inline uint8_t ssubu8(CPURISCVState *env, int vxrm, uint8_t a, uint8_t b) { @@ -2188,19 +2186,19 @@ RVVCALL(OPIVV2_RM, vssubu_vv_b, OP_UUU_B, H1, H1, H1, ssubu8) RVVCALL(OPIVV2_RM, vssubu_vv_h, OP_UUU_H, H2, H2, H2, ssubu16) RVVCALL(OPIVV2_RM, vssubu_vv_w, OP_UUU_W, H4, H4, H4, ssubu32) RVVCALL(OPIVV2_RM, vssubu_vv_d, OP_UUU_D, H8, H8, H8, ssubu64) -GEN_VEXT_VV_RM(vssubu_vv_b, 1, 1) -GEN_VEXT_VV_RM(vssubu_vv_h, 2, 2) -GEN_VEXT_VV_RM(vssubu_vv_w, 4, 4) -GEN_VEXT_VV_RM(vssubu_vv_d, 8, 8) +GEN_VEXT_VV_RM(vssubu_vv_b) +GEN_VEXT_VV_RM(vssubu_vv_h) +GEN_VEXT_VV_RM(vssubu_vv_w) +GEN_VEXT_VV_RM(vssubu_vv_d) RVVCALL(OPIVX2_RM, vssubu_vx_b, OP_UUU_B, H1, H1, ssubu8) RVVCALL(OPIVX2_RM, vssubu_vx_h, OP_UUU_H, H2, H2, ssubu16) RVVCALL(OPIVX2_RM, vssubu_vx_w, OP_UUU_W, H4, H4, ssubu32) RVVCALL(OPIVX2_RM, vssubu_vx_d, OP_UUU_D, H8, H8, ssubu64) -GEN_VEXT_VX_RM(vssubu_vx_b, 1, 1) -GEN_VEXT_VX_RM(vssubu_vx_h, 2, 2) -GEN_VEXT_VX_RM(vssubu_vx_w, 4, 4) -GEN_VEXT_VX_RM(vssubu_vx_d, 8, 8) +GEN_VEXT_VX_RM(vssubu_vx_b) +GEN_VEXT_VX_RM(vssubu_vx_h) +GEN_VEXT_VX_RM(vssubu_vx_w) +GEN_VEXT_VX_RM(vssubu_vx_d) static inline int8_t ssub8(CPURISCVState *env, int vxrm, int8_t a, int8_t b) { @@ -2246,19 +2244,19 @@ RVVCALL(OPIVV2_RM, vssub_vv_b, OP_SSS_B, H1, H1, H1, ssub8) RVVCALL(OPIVV2_RM, vssub_vv_h, OP_SSS_H, H2, H2, H2, ssub16) RVVCALL(OPIVV2_RM, vssub_vv_w, OP_SSS_W, H4, H4, H4, ssub32) RVVCALL(OPIVV2_RM, vssub_vv_d, OP_SSS_D, H8, H8, H8, ssub64) -GEN_VEXT_VV_RM(vssub_vv_b, 1, 1) -GEN_VEXT_VV_RM(vssub_vv_h, 2, 2) -GEN_VEXT_VV_RM(vssub_vv_w, 4, 4) -GEN_VEXT_VV_RM(vssub_vv_d, 8, 8) +GEN_VEXT_VV_RM(vssub_vv_b) +GEN_VEXT_VV_RM(vssub_vv_h) +GEN_VEXT_VV_RM(vssub_vv_w) +GEN_VEXT_VV_RM(vssub_vv_d) RVVCALL(OPIVX2_RM, vssub_vx_b, OP_SSS_B, H1, H1, ssub8) RVVCALL(OPIVX2_RM, vssub_vx_h, OP_SSS_H, H2, H2, ssub16) RVVCALL(OPIVX2_RM, vssub_vx_w, OP_SSS_W, H4, H4, ssub32) RVVCALL(OPIVX2_RM, vssub_vx_d, OP_SSS_D, H8, H8, ssub64) -GEN_VEXT_VX_RM(vssub_vx_b, 1, 1) -GEN_VEXT_VX_RM(vssub_vx_h, 2, 2) -GEN_VEXT_VX_RM(vssub_vx_w, 4, 4) -GEN_VEXT_VX_RM(vssub_vx_d, 8, 8) +GEN_VEXT_VX_RM(vssub_vx_b) +GEN_VEXT_VX_RM(vssub_vx_h) +GEN_VEXT_VX_RM(vssub_vx_w) +GEN_VEXT_VX_RM(vssub_vx_d) /* Vector Single-Width Averaging Add and Subtract */ static inline uint8_t get_round(int vxrm, uint64_t v, uint8_t shift) @@ -2310,19 +2308,19 @@ RVVCALL(OPIVV2_RM, vaadd_vv_b, OP_SSS_B, H1, H1, H1, aadd32) RVVCALL(OPIVV2_RM, vaadd_vv_h, OP_SSS_H, H2, H2, H2, aadd32) RVVCALL(OPIVV2_RM, vaadd_vv_w, OP_SSS_W, H4, H4, H4, aadd32) RVVCALL(OPIVV2_RM, vaadd_vv_d, OP_SSS_D, H8, H8, H8, aadd64) -GEN_VEXT_VV_RM(vaadd_vv_b, 1, 1) -GEN_VEXT_VV_RM(vaadd_vv_h, 2, 2) -GEN_VEXT_VV_RM(vaadd_vv_w, 4, 4) -GEN_VEXT_VV_RM(vaadd_vv_d, 8, 8) +GEN_VEXT_VV_RM(vaadd_vv_b) +GEN_VEXT_VV_RM(vaadd_vv_h) +GEN_VEXT_VV_RM(vaadd_vv_w) +GEN_VEXT_VV_RM(vaadd_vv_d) RVVCALL(OPIVX2_RM, vaadd_vx_b, OP_SSS_B, H1, H1, aadd32) RVVCALL(OPIVX2_RM, vaadd_vx_h, OP_SSS_H, H2, H2, aadd32) RVVCALL(OPIVX2_RM, vaadd_vx_w, OP_SSS_W, H4, H4, aadd32) RVVCALL(OPIVX2_RM, vaadd_vx_d, OP_SSS_D, H8, H8, aadd64) -GEN_VEXT_VX_RM(vaadd_vx_b, 1, 1) -GEN_VEXT_VX_RM(vaadd_vx_h, 2, 2) -GEN_VEXT_VX_RM(vaadd_vx_w, 4, 4) -GEN_VEXT_VX_RM(vaadd_vx_d, 8, 8) +GEN_VEXT_VX_RM(vaadd_vx_b) +GEN_VEXT_VX_RM(vaadd_vx_h) +GEN_VEXT_VX_RM(vaadd_vx_w) +GEN_VEXT_VX_RM(vaadd_vx_d) static inline uint32_t aaddu32(CPURISCVState *env, int vxrm, uint32_t a, uint32_t b) @@ -2347,19 +2345,19 @@ RVVCALL(OPIVV2_RM, vaaddu_vv_b, OP_UUU_B, H1, H1, H1, aaddu32) RVVCALL(OPIVV2_RM, vaaddu_vv_h, OP_UUU_H, H2, H2, H2, aaddu32) RVVCALL(OPIVV2_RM, vaaddu_vv_w, OP_UUU_W, H4, H4, H4, aaddu32) RVVCALL(OPIVV2_RM, vaaddu_vv_d, OP_UUU_D, H8, H8, H8, aaddu64) -GEN_VEXT_VV_RM(vaaddu_vv_b, 1, 1) -GEN_VEXT_VV_RM(vaaddu_vv_h, 2, 2) -GEN_VEXT_VV_RM(vaaddu_vv_w, 4, 4) -GEN_VEXT_VV_RM(vaaddu_vv_d, 8, 8) +GEN_VEXT_VV_RM(vaaddu_vv_b) +GEN_VEXT_VV_RM(vaaddu_vv_h) +GEN_VEXT_VV_RM(vaaddu_vv_w) +GEN_VEXT_VV_RM(vaaddu_vv_d) RVVCALL(OPIVX2_RM, vaaddu_vx_b, OP_UUU_B, H1, H1, aaddu32) RVVCALL(OPIVX2_RM, vaaddu_vx_h, OP_UUU_H, H2, H2, aaddu32) RVVCALL(OPIVX2_RM, vaaddu_vx_w, OP_UUU_W, H4, H4, aaddu32) RVVCALL(OPIVX2_RM, vaaddu_vx_d, OP_UUU_D, H8, H8, aaddu64) -GEN_VEXT_VX_RM(vaaddu_vx_b, 1, 1) -GEN_VEXT_VX_RM(vaaddu_vx_h, 2, 2) -GEN_VEXT_VX_RM(vaaddu_vx_w, 4, 4) -GEN_VEXT_VX_RM(vaaddu_vx_d, 8, 8) +GEN_VEXT_VX_RM(vaaddu_vx_b) +GEN_VEXT_VX_RM(vaaddu_vx_h) +GEN_VEXT_VX_RM(vaaddu_vx_w) +GEN_VEXT_VX_RM(vaaddu_vx_d) static inline int32_t asub32(CPURISCVState *env, int vxrm, int32_t a, int32_t b) { @@ -2383,19 +2381,19 @@ RVVCALL(OPIVV2_RM, vasub_vv_b, OP_SSS_B, H1, H1, H1, asub32) RVVCALL(OPIVV2_RM, vasub_vv_h, OP_SSS_H, H2, H2, H2, asub32) RVVCALL(OPIVV2_RM, vasub_vv_w, OP_SSS_W, H4, H4, H4, asub32) RVVCALL(OPIVV2_RM, vasub_vv_d, OP_SSS_D, H8, H8, H8, asub64) -GEN_VEXT_VV_RM(vasub_vv_b, 1, 1) -GEN_VEXT_VV_RM(vasub_vv_h, 2, 2) -GEN_VEXT_VV_RM(vasub_vv_w, 4, 4) -GEN_VEXT_VV_RM(vasub_vv_d, 8, 8) +GEN_VEXT_VV_RM(vasub_vv_b) +GEN_VEXT_VV_RM(vasub_vv_h) +GEN_VEXT_VV_RM(vasub_vv_w) +GEN_VEXT_VV_RM(vasub_vv_d) RVVCALL(OPIVX2_RM, vasub_vx_b, OP_SSS_B, H1, H1, asub32) RVVCALL(OPIVX2_RM, vasub_vx_h, OP_SSS_H, H2, H2, asub32) RVVCALL(OPIVX2_RM, vasub_vx_w, OP_SSS_W, H4, H4, asub32) RVVCALL(OPIVX2_RM, vasub_vx_d, OP_SSS_D, H8, H8, asub64) -GEN_VEXT_VX_RM(vasub_vx_b, 1, 1) -GEN_VEXT_VX_RM(vasub_vx_h, 2, 2) -GEN_VEXT_VX_RM(vasub_vx_w, 4, 4) -GEN_VEXT_VX_RM(vasub_vx_d, 8, 8) +GEN_VEXT_VX_RM(vasub_vx_b) +GEN_VEXT_VX_RM(vasub_vx_h) +GEN_VEXT_VX_RM(vasub_vx_w) +GEN_VEXT_VX_RM(vasub_vx_d) static inline uint32_t asubu32(CPURISCVState *env, int vxrm, uint32_t a, uint32_t b) @@ -2420,19 +2418,19 @@ RVVCALL(OPIVV2_RM, vasubu_vv_b, OP_UUU_B, H1, H1, H1, asubu32) RVVCALL(OPIVV2_RM, vasubu_vv_h, OP_UUU_H, H2, H2, H2, asubu32) RVVCALL(OPIVV2_RM, vasubu_vv_w, OP_UUU_W, H4, H4, H4, asubu32) RVVCALL(OPIVV2_RM, vasubu_vv_d, OP_UUU_D, H8, H8, H8, asubu64) -GEN_VEXT_VV_RM(vasubu_vv_b, 1, 1) -GEN_VEXT_VV_RM(vasubu_vv_h, 2, 2) -GEN_VEXT_VV_RM(vasubu_vv_w, 4, 4) -GEN_VEXT_VV_RM(vasubu_vv_d, 8, 8) +GEN_VEXT_VV_RM(vasubu_vv_b) +GEN_VEXT_VV_RM(vasubu_vv_h) +GEN_VEXT_VV_RM(vasubu_vv_w) +GEN_VEXT_VV_RM(vasubu_vv_d) RVVCALL(OPIVX2_RM, vasubu_vx_b, OP_UUU_B, H1, H1, asubu32) RVVCALL(OPIVX2_RM, vasubu_vx_h, OP_UUU_H, H2, H2, asubu32) RVVCALL(OPIVX2_RM, vasubu_vx_w, OP_UUU_W, H4, H4, asubu32) RVVCALL(OPIVX2_RM, vasubu_vx_d, OP_UUU_D, H8, H8, asubu64) -GEN_VEXT_VX_RM(vasubu_vx_b, 1, 1) -GEN_VEXT_VX_RM(vasubu_vx_h, 2, 2) -GEN_VEXT_VX_RM(vasubu_vx_w, 4, 4) -GEN_VEXT_VX_RM(vasubu_vx_d, 8, 8) +GEN_VEXT_VX_RM(vasubu_vx_b) +GEN_VEXT_VX_RM(vasubu_vx_h) +GEN_VEXT_VX_RM(vasubu_vx_w) +GEN_VEXT_VX_RM(vasubu_vx_d) /* Vector Single-Width Fractional Multiply with Rounding and Saturation */ static inline int8_t vsmul8(CPURISCVState *env, int vxrm, int8_t a, int8_t b) @@ -2527,19 +2525,19 @@ RVVCALL(OPIVV2_RM, vsmul_vv_b, OP_SSS_B, H1, H1, H1, vsmul8) RVVCALL(OPIVV2_RM, vsmul_vv_h, OP_SSS_H, H2, H2, H2, vsmul16) RVVCALL(OPIVV2_RM, vsmul_vv_w, OP_SSS_W, H4, H4, H4, vsmul32) RVVCALL(OPIVV2_RM, vsmul_vv_d, OP_SSS_D, H8, H8, H8, vsmul64) -GEN_VEXT_VV_RM(vsmul_vv_b, 1, 1) -GEN_VEXT_VV_RM(vsmul_vv_h, 2, 2) -GEN_VEXT_VV_RM(vsmul_vv_w, 4, 4) -GEN_VEXT_VV_RM(vsmul_vv_d, 8, 8) +GEN_VEXT_VV_RM(vsmul_vv_b) +GEN_VEXT_VV_RM(vsmul_vv_h) +GEN_VEXT_VV_RM(vsmul_vv_w) +GEN_VEXT_VV_RM(vsmul_vv_d) RVVCALL(OPIVX2_RM, vsmul_vx_b, OP_SSS_B, H1, H1, vsmul8) RVVCALL(OPIVX2_RM, vsmul_vx_h, OP_SSS_H, H2, H2, vsmul16) RVVCALL(OPIVX2_RM, vsmul_vx_w, OP_SSS_W, H4, H4, vsmul32) RVVCALL(OPIVX2_RM, vsmul_vx_d, OP_SSS_D, H8, H8, vsmul64) -GEN_VEXT_VX_RM(vsmul_vx_b, 1, 1) -GEN_VEXT_VX_RM(vsmul_vx_h, 2, 2) -GEN_VEXT_VX_RM(vsmul_vx_w, 4, 4) -GEN_VEXT_VX_RM(vsmul_vx_d, 8, 8) +GEN_VEXT_VX_RM(vsmul_vx_b) +GEN_VEXT_VX_RM(vsmul_vx_h) +GEN_VEXT_VX_RM(vsmul_vx_w) +GEN_VEXT_VX_RM(vsmul_vx_d) /* Vector Single-Width Scaling Shift Instructions */ static inline uint8_t @@ -2586,19 +2584,19 @@ RVVCALL(OPIVV2_RM, vssrl_vv_b, OP_UUU_B, H1, H1, H1, vssrl8) RVVCALL(OPIVV2_RM, vssrl_vv_h, OP_UUU_H, H2, H2, H2, vssrl16) RVVCALL(OPIVV2_RM, vssrl_vv_w, OP_UUU_W, H4, H4, H4, vssrl32) RVVCALL(OPIVV2_RM, vssrl_vv_d, OP_UUU_D, H8, H8, H8, vssrl64) -GEN_VEXT_VV_RM(vssrl_vv_b, 1, 1) -GEN_VEXT_VV_RM(vssrl_vv_h, 2, 2) -GEN_VEXT_VV_RM(vssrl_vv_w, 4, 4) -GEN_VEXT_VV_RM(vssrl_vv_d, 8, 8) +GEN_VEXT_VV_RM(vssrl_vv_b) +GEN_VEXT_VV_RM(vssrl_vv_h) +GEN_VEXT_VV_RM(vssrl_vv_w) +GEN_VEXT_VV_RM(vssrl_vv_d) RVVCALL(OPIVX2_RM, vssrl_vx_b, OP_UUU_B, H1, H1, vssrl8) RVVCALL(OPIVX2_RM, vssrl_vx_h, OP_UUU_H, H2, H2, vssrl16) RVVCALL(OPIVX2_RM, vssrl_vx_w, OP_UUU_W, H4, H4, vssrl32) RVVCALL(OPIVX2_RM, vssrl_vx_d, OP_UUU_D, H8, H8, vssrl64) -GEN_VEXT_VX_RM(vssrl_vx_b, 1, 1) -GEN_VEXT_VX_RM(vssrl_vx_h, 2, 2) -GEN_VEXT_VX_RM(vssrl_vx_w, 4, 4) -GEN_VEXT_VX_RM(vssrl_vx_d, 8, 8) +GEN_VEXT_VX_RM(vssrl_vx_b) +GEN_VEXT_VX_RM(vssrl_vx_h) +GEN_VEXT_VX_RM(vssrl_vx_w) +GEN_VEXT_VX_RM(vssrl_vx_d) static inline int8_t vssra8(CPURISCVState *env, int vxrm, int8_t a, int8_t b) @@ -2645,19 +2643,19 @@ RVVCALL(OPIVV2_RM, vssra_vv_b, OP_SSS_B, H1, H1, H1, vssra8) RVVCALL(OPIVV2_RM, vssra_vv_h, OP_SSS_H, H2, H2, H2, vssra16) RVVCALL(OPIVV2_RM, vssra_vv_w, OP_SSS_W, H4, H4, H4, vssra32) RVVCALL(OPIVV2_RM, vssra_vv_d, OP_SSS_D, H8, H8, H8, vssra64) -GEN_VEXT_VV_RM(vssra_vv_b, 1, 1) -GEN_VEXT_VV_RM(vssra_vv_h, 2, 2) -GEN_VEXT_VV_RM(vssra_vv_w, 4, 4) -GEN_VEXT_VV_RM(vssra_vv_d, 8, 8) +GEN_VEXT_VV_RM(vssra_vv_b) +GEN_VEXT_VV_RM(vssra_vv_h) +GEN_VEXT_VV_RM(vssra_vv_w) +GEN_VEXT_VV_RM(vssra_vv_d) RVVCALL(OPIVX2_RM, vssra_vx_b, OP_SSS_B, H1, H1, vssra8) RVVCALL(OPIVX2_RM, vssra_vx_h, OP_SSS_H, H2, H2, vssra16) RVVCALL(OPIVX2_RM, vssra_vx_w, OP_SSS_W, H4, H4, vssra32) RVVCALL(OPIVX2_RM, vssra_vx_d, OP_SSS_D, H8, H8, vssra64) -GEN_VEXT_VX_RM(vssra_vx_b, 1, 1) -GEN_VEXT_VX_RM(vssra_vx_h, 2, 2) -GEN_VEXT_VX_RM(vssra_vx_w, 4, 4) -GEN_VEXT_VX_RM(vssra_vx_d, 8, 8) +GEN_VEXT_VX_RM(vssra_vx_b) +GEN_VEXT_VX_RM(vssra_vx_h) +GEN_VEXT_VX_RM(vssra_vx_w) +GEN_VEXT_VX_RM(vssra_vx_d) /* Vector Narrowing Fixed-Point Clip Instructions */ static inline int8_t @@ -2720,16 +2718,16 @@ vnclip32(CPURISCVState *env, int vxrm, int64_t a, int32_t b) RVVCALL(OPIVV2_RM, vnclip_wv_b, NOP_SSS_B, H1, H2, H1, vnclip8) RVVCALL(OPIVV2_RM, vnclip_wv_h, NOP_SSS_H, H2, H4, H2, vnclip16) RVVCALL(OPIVV2_RM, vnclip_wv_w, NOP_SSS_W, H4, H8, H4, vnclip32) -GEN_VEXT_VV_RM(vnclip_wv_b, 1, 1) -GEN_VEXT_VV_RM(vnclip_wv_h, 2, 2) -GEN_VEXT_VV_RM(vnclip_wv_w, 4, 4) +GEN_VEXT_VV_RM(vnclip_wv_b) +GEN_VEXT_VV_RM(vnclip_wv_h) +GEN_VEXT_VV_RM(vnclip_wv_w) RVVCALL(OPIVX2_RM, vnclip_wx_b, NOP_SSS_B, H1, H2, vnclip8) RVVCALL(OPIVX2_RM, vnclip_wx_h, NOP_SSS_H, H2, H4, vnclip16) RVVCALL(OPIVX2_RM, vnclip_wx_w, NOP_SSS_W, H4, H8, vnclip32) -GEN_VEXT_VX_RM(vnclip_wx_b, 1, 1) -GEN_VEXT_VX_RM(vnclip_wx_h, 2, 2) -GEN_VEXT_VX_RM(vnclip_wx_w, 4, 4) +GEN_VEXT_VX_RM(vnclip_wx_b) +GEN_VEXT_VX_RM(vnclip_wx_h) +GEN_VEXT_VX_RM(vnclip_wx_w) static inline uint8_t vnclipu8(CPURISCVState *env, int vxrm, uint16_t a, uint8_t b) @@ -2782,16 +2780,16 @@ vnclipu32(CPURISCVState *env, int vxrm, uint64_t a, uint32_t b) RVVCALL(OPIVV2_RM, vnclipu_wv_b, NOP_UUU_B, H1, H2, H1, vnclipu8) RVVCALL(OPIVV2_RM, vnclipu_wv_h, NOP_UUU_H, H2, H4, H2, vnclipu16) RVVCALL(OPIVV2_RM, vnclipu_wv_w, NOP_UUU_W, H4, H8, H4, vnclipu32) -GEN_VEXT_VV_RM(vnclipu_wv_b, 1, 1) -GEN_VEXT_VV_RM(vnclipu_wv_h, 2, 2) -GEN_VEXT_VV_RM(vnclipu_wv_w, 4, 4) +GEN_VEXT_VV_RM(vnclipu_wv_b) +GEN_VEXT_VV_RM(vnclipu_wv_h) +GEN_VEXT_VV_RM(vnclipu_wv_w) RVVCALL(OPIVX2_RM, vnclipu_wx_b, NOP_UUU_B, H1, H2, vnclipu8) RVVCALL(OPIVX2_RM, vnclipu_wx_h, NOP_UUU_H, H2, H4, vnclipu16) RVVCALL(OPIVX2_RM, vnclipu_wx_w, NOP_UUU_W, H4, H8, vnclipu32) -GEN_VEXT_VX_RM(vnclipu_wx_b, 1, 1) -GEN_VEXT_VX_RM(vnclipu_wx_h, 2, 2) -GEN_VEXT_VX_RM(vnclipu_wx_w, 4, 4) +GEN_VEXT_VX_RM(vnclipu_wx_b) +GEN_VEXT_VX_RM(vnclipu_wx_h) +GEN_VEXT_VX_RM(vnclipu_wx_w) /* *** Vector Float Point Arithmetic Instructions @@ -2806,7 +2804,7 @@ static void do_##NAME(void *vd, void *vs1, void *vs2, int i, \ *((TD *)vd + HD(i)) = OP(s2, s1, &env->fp_status); \ } -#define GEN_VEXT_VV_ENV(NAME, ESZ, DSZ) \ +#define GEN_VEXT_VV_ENV(NAME) \ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ void *vs2, CPURISCVState *env, \ uint32_t desc) \ @@ -2827,9 +2825,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ RVVCALL(OPFVV2, vfadd_vv_h, OP_UUU_H, H2, H2, H2, float16_add) RVVCALL(OPFVV2, vfadd_vv_w, OP_UUU_W, H4, H4, H4, float32_add) RVVCALL(OPFVV2, vfadd_vv_d, OP_UUU_D, H8, H8, H8, float64_add) -GEN_VEXT_VV_ENV(vfadd_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfadd_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfadd_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfadd_vv_h) +GEN_VEXT_VV_ENV(vfadd_vv_w) +GEN_VEXT_VV_ENV(vfadd_vv_d) #define OPFVF2(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \ static void do_##NAME(void *vd, uint64_t s1, void *vs2, int i, \ @@ -2839,7 +2837,7 @@ static void do_##NAME(void *vd, uint64_t s1, void *vs2, int i, \ *((TD *)vd + HD(i)) = OP(s2, (TX1)(T1)s1, &env->fp_status);\ } -#define GEN_VEXT_VF(NAME, ESZ, DSZ) \ +#define GEN_VEXT_VF(NAME) \ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, \ void *vs2, CPURISCVState *env, \ uint32_t desc) \ @@ -2860,22 +2858,22 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, \ RVVCALL(OPFVF2, vfadd_vf_h, OP_UUU_H, H2, H2, float16_add) RVVCALL(OPFVF2, vfadd_vf_w, OP_UUU_W, H4, H4, float32_add) RVVCALL(OPFVF2, vfadd_vf_d, OP_UUU_D, H8, H8, float64_add) -GEN_VEXT_VF(vfadd_vf_h, 2, 2) -GEN_VEXT_VF(vfadd_vf_w, 4, 4) -GEN_VEXT_VF(vfadd_vf_d, 8, 8) +GEN_VEXT_VF(vfadd_vf_h) +GEN_VEXT_VF(vfadd_vf_w) +GEN_VEXT_VF(vfadd_vf_d) RVVCALL(OPFVV2, vfsub_vv_h, OP_UUU_H, H2, H2, H2, float16_sub) RVVCALL(OPFVV2, vfsub_vv_w, OP_UUU_W, H4, H4, H4, float32_sub) RVVCALL(OPFVV2, vfsub_vv_d, OP_UUU_D, H8, H8, H8, float64_sub) -GEN_VEXT_VV_ENV(vfsub_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfsub_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfsub_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfsub_vv_h) +GEN_VEXT_VV_ENV(vfsub_vv_w) +GEN_VEXT_VV_ENV(vfsub_vv_d) RVVCALL(OPFVF2, vfsub_vf_h, OP_UUU_H, H2, H2, float16_sub) RVVCALL(OPFVF2, vfsub_vf_w, OP_UUU_W, H4, H4, float32_sub) RVVCALL(OPFVF2, vfsub_vf_d, OP_UUU_D, H8, H8, float64_sub) -GEN_VEXT_VF(vfsub_vf_h, 2, 2) -GEN_VEXT_VF(vfsub_vf_w, 4, 4) -GEN_VEXT_VF(vfsub_vf_d, 8, 8) +GEN_VEXT_VF(vfsub_vf_h) +GEN_VEXT_VF(vfsub_vf_w) +GEN_VEXT_VF(vfsub_vf_d) static uint16_t float16_rsub(uint16_t a, uint16_t b, float_status *s) { @@ -2895,9 +2893,9 @@ static uint64_t float64_rsub(uint64_t a, uint64_t b, float_status *s) RVVCALL(OPFVF2, vfrsub_vf_h, OP_UUU_H, H2, H2, float16_rsub) RVVCALL(OPFVF2, vfrsub_vf_w, OP_UUU_W, H4, H4, float32_rsub) RVVCALL(OPFVF2, vfrsub_vf_d, OP_UUU_D, H8, H8, float64_rsub) -GEN_VEXT_VF(vfrsub_vf_h, 2, 2) -GEN_VEXT_VF(vfrsub_vf_w, 4, 4) -GEN_VEXT_VF(vfrsub_vf_d, 8, 8) +GEN_VEXT_VF(vfrsub_vf_h) +GEN_VEXT_VF(vfrsub_vf_w) +GEN_VEXT_VF(vfrsub_vf_d) /* Vector Widening Floating-Point Add/Subtract Instructions */ static uint32_t vfwadd16(uint16_t a, uint16_t b, float_status *s) @@ -2915,12 +2913,12 @@ static uint64_t vfwadd32(uint32_t a, uint32_t b, float_status *s) RVVCALL(OPFVV2, vfwadd_vv_h, WOP_UUU_H, H4, H2, H2, vfwadd16) RVVCALL(OPFVV2, vfwadd_vv_w, WOP_UUU_W, H8, H4, H4, vfwadd32) -GEN_VEXT_VV_ENV(vfwadd_vv_h, 2, 4) -GEN_VEXT_VV_ENV(vfwadd_vv_w, 4, 8) +GEN_VEXT_VV_ENV(vfwadd_vv_h) +GEN_VEXT_VV_ENV(vfwadd_vv_w) RVVCALL(OPFVF2, vfwadd_vf_h, WOP_UUU_H, H4, H2, vfwadd16) RVVCALL(OPFVF2, vfwadd_vf_w, WOP_UUU_W, H8, H4, vfwadd32) -GEN_VEXT_VF(vfwadd_vf_h, 2, 4) -GEN_VEXT_VF(vfwadd_vf_w, 4, 8) +GEN_VEXT_VF(vfwadd_vf_h) +GEN_VEXT_VF(vfwadd_vf_w) static uint32_t vfwsub16(uint16_t a, uint16_t b, float_status *s) { @@ -2937,12 +2935,12 @@ static uint64_t vfwsub32(uint32_t a, uint32_t b, float_status *s) RVVCALL(OPFVV2, vfwsub_vv_h, WOP_UUU_H, H4, H2, H2, vfwsub16) RVVCALL(OPFVV2, vfwsub_vv_w, WOP_UUU_W, H8, H4, H4, vfwsub32) -GEN_VEXT_VV_ENV(vfwsub_vv_h, 2, 4) -GEN_VEXT_VV_ENV(vfwsub_vv_w, 4, 8) +GEN_VEXT_VV_ENV(vfwsub_vv_h) +GEN_VEXT_VV_ENV(vfwsub_vv_w) RVVCALL(OPFVF2, vfwsub_vf_h, WOP_UUU_H, H4, H2, vfwsub16) RVVCALL(OPFVF2, vfwsub_vf_w, WOP_UUU_W, H8, H4, vfwsub32) -GEN_VEXT_VF(vfwsub_vf_h, 2, 4) -GEN_VEXT_VF(vfwsub_vf_w, 4, 8) +GEN_VEXT_VF(vfwsub_vf_h) +GEN_VEXT_VF(vfwsub_vf_w) static uint32_t vfwaddw16(uint32_t a, uint16_t b, float_status *s) { @@ -2956,12 +2954,12 @@ static uint64_t vfwaddw32(uint64_t a, uint32_t b, float_status *s) RVVCALL(OPFVV2, vfwadd_wv_h, WOP_WUUU_H, H4, H2, H2, vfwaddw16) RVVCALL(OPFVV2, vfwadd_wv_w, WOP_WUUU_W, H8, H4, H4, vfwaddw32) -GEN_VEXT_VV_ENV(vfwadd_wv_h, 2, 4) -GEN_VEXT_VV_ENV(vfwadd_wv_w, 4, 8) +GEN_VEXT_VV_ENV(vfwadd_wv_h) +GEN_VEXT_VV_ENV(vfwadd_wv_w) RVVCALL(OPFVF2, vfwadd_wf_h, WOP_WUUU_H, H4, H2, vfwaddw16) RVVCALL(OPFVF2, vfwadd_wf_w, WOP_WUUU_W, H8, H4, vfwaddw32) -GEN_VEXT_VF(vfwadd_wf_h, 2, 4) -GEN_VEXT_VF(vfwadd_wf_w, 4, 8) +GEN_VEXT_VF(vfwadd_wf_h) +GEN_VEXT_VF(vfwadd_wf_w) static uint32_t vfwsubw16(uint32_t a, uint16_t b, float_status *s) { @@ -2975,39 +2973,39 @@ static uint64_t vfwsubw32(uint64_t a, uint32_t b, float_status *s) RVVCALL(OPFVV2, vfwsub_wv_h, WOP_WUUU_H, H4, H2, H2, vfwsubw16) RVVCALL(OPFVV2, vfwsub_wv_w, WOP_WUUU_W, H8, H4, H4, vfwsubw32) -GEN_VEXT_VV_ENV(vfwsub_wv_h, 2, 4) -GEN_VEXT_VV_ENV(vfwsub_wv_w, 4, 8) +GEN_VEXT_VV_ENV(vfwsub_wv_h) +GEN_VEXT_VV_ENV(vfwsub_wv_w) RVVCALL(OPFVF2, vfwsub_wf_h, WOP_WUUU_H, H4, H2, vfwsubw16) RVVCALL(OPFVF2, vfwsub_wf_w, WOP_WUUU_W, H8, H4, vfwsubw32) -GEN_VEXT_VF(vfwsub_wf_h, 2, 4) -GEN_VEXT_VF(vfwsub_wf_w, 4, 8) +GEN_VEXT_VF(vfwsub_wf_h) +GEN_VEXT_VF(vfwsub_wf_w) /* Vector Single-Width Floating-Point Multiply/Divide Instructions */ RVVCALL(OPFVV2, vfmul_vv_h, OP_UUU_H, H2, H2, H2, float16_mul) RVVCALL(OPFVV2, vfmul_vv_w, OP_UUU_W, H4, H4, H4, float32_mul) RVVCALL(OPFVV2, vfmul_vv_d, OP_UUU_D, H8, H8, H8, float64_mul) -GEN_VEXT_VV_ENV(vfmul_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfmul_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfmul_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfmul_vv_h) +GEN_VEXT_VV_ENV(vfmul_vv_w) +GEN_VEXT_VV_ENV(vfmul_vv_d) RVVCALL(OPFVF2, vfmul_vf_h, OP_UUU_H, H2, H2, float16_mul) RVVCALL(OPFVF2, vfmul_vf_w, OP_UUU_W, H4, H4, float32_mul) RVVCALL(OPFVF2, vfmul_vf_d, OP_UUU_D, H8, H8, float64_mul) -GEN_VEXT_VF(vfmul_vf_h, 2, 2) -GEN_VEXT_VF(vfmul_vf_w, 4, 4) -GEN_VEXT_VF(vfmul_vf_d, 8, 8) +GEN_VEXT_VF(vfmul_vf_h) +GEN_VEXT_VF(vfmul_vf_w) +GEN_VEXT_VF(vfmul_vf_d) RVVCALL(OPFVV2, vfdiv_vv_h, OP_UUU_H, H2, H2, H2, float16_div) RVVCALL(OPFVV2, vfdiv_vv_w, OP_UUU_W, H4, H4, H4, float32_div) RVVCALL(OPFVV2, vfdiv_vv_d, OP_UUU_D, H8, H8, H8, float64_div) -GEN_VEXT_VV_ENV(vfdiv_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfdiv_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfdiv_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfdiv_vv_h) +GEN_VEXT_VV_ENV(vfdiv_vv_w) +GEN_VEXT_VV_ENV(vfdiv_vv_d) RVVCALL(OPFVF2, vfdiv_vf_h, OP_UUU_H, H2, H2, float16_div) RVVCALL(OPFVF2, vfdiv_vf_w, OP_UUU_W, H4, H4, float32_div) RVVCALL(OPFVF2, vfdiv_vf_d, OP_UUU_D, H8, H8, float64_div) -GEN_VEXT_VF(vfdiv_vf_h, 2, 2) -GEN_VEXT_VF(vfdiv_vf_w, 4, 4) -GEN_VEXT_VF(vfdiv_vf_d, 8, 8) +GEN_VEXT_VF(vfdiv_vf_h) +GEN_VEXT_VF(vfdiv_vf_w) +GEN_VEXT_VF(vfdiv_vf_d) static uint16_t float16_rdiv(uint16_t a, uint16_t b, float_status *s) { @@ -3027,9 +3025,9 @@ static uint64_t float64_rdiv(uint64_t a, uint64_t b, float_status *s) RVVCALL(OPFVF2, vfrdiv_vf_h, OP_UUU_H, H2, H2, float16_rdiv) RVVCALL(OPFVF2, vfrdiv_vf_w, OP_UUU_W, H4, H4, float32_rdiv) RVVCALL(OPFVF2, vfrdiv_vf_d, OP_UUU_D, H8, H8, float64_rdiv) -GEN_VEXT_VF(vfrdiv_vf_h, 2, 2) -GEN_VEXT_VF(vfrdiv_vf_w, 4, 4) -GEN_VEXT_VF(vfrdiv_vf_d, 8, 8) +GEN_VEXT_VF(vfrdiv_vf_h) +GEN_VEXT_VF(vfrdiv_vf_w) +GEN_VEXT_VF(vfrdiv_vf_d) /* Vector Widening Floating-Point Multiply */ static uint32_t vfwmul16(uint16_t a, uint16_t b, float_status *s) @@ -3046,12 +3044,12 @@ static uint64_t vfwmul32(uint32_t a, uint32_t b, float_status *s) } RVVCALL(OPFVV2, vfwmul_vv_h, WOP_UUU_H, H4, H2, H2, vfwmul16) RVVCALL(OPFVV2, vfwmul_vv_w, WOP_UUU_W, H8, H4, H4, vfwmul32) -GEN_VEXT_VV_ENV(vfwmul_vv_h, 2, 4) -GEN_VEXT_VV_ENV(vfwmul_vv_w, 4, 8) +GEN_VEXT_VV_ENV(vfwmul_vv_h) +GEN_VEXT_VV_ENV(vfwmul_vv_w) RVVCALL(OPFVF2, vfwmul_vf_h, WOP_UUU_H, H4, H2, vfwmul16) RVVCALL(OPFVF2, vfwmul_vf_w, WOP_UUU_W, H8, H4, vfwmul32) -GEN_VEXT_VF(vfwmul_vf_h, 2, 4) -GEN_VEXT_VF(vfwmul_vf_w, 4, 8) +GEN_VEXT_VF(vfwmul_vf_h) +GEN_VEXT_VF(vfwmul_vf_w) /* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */ #define OPFVV3(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \ @@ -3082,9 +3080,9 @@ static uint64_t fmacc64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfmacc_vv_h, OP_UUU_H, H2, H2, H2, fmacc16) RVVCALL(OPFVV3, vfmacc_vv_w, OP_UUU_W, H4, H4, H4, fmacc32) RVVCALL(OPFVV3, vfmacc_vv_d, OP_UUU_D, H8, H8, H8, fmacc64) -GEN_VEXT_VV_ENV(vfmacc_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfmacc_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfmacc_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfmacc_vv_h) +GEN_VEXT_VV_ENV(vfmacc_vv_w) +GEN_VEXT_VV_ENV(vfmacc_vv_d) #define OPFVF3(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \ static void do_##NAME(void *vd, uint64_t s1, void *vs2, int i, \ @@ -3098,9 +3096,9 @@ static void do_##NAME(void *vd, uint64_t s1, void *vs2, int i, \ RVVCALL(OPFVF3, vfmacc_vf_h, OP_UUU_H, H2, H2, fmacc16) RVVCALL(OPFVF3, vfmacc_vf_w, OP_UUU_W, H4, H4, fmacc32) RVVCALL(OPFVF3, vfmacc_vf_d, OP_UUU_D, H8, H8, fmacc64) -GEN_VEXT_VF(vfmacc_vf_h, 2, 2) -GEN_VEXT_VF(vfmacc_vf_w, 4, 4) -GEN_VEXT_VF(vfmacc_vf_d, 8, 8) +GEN_VEXT_VF(vfmacc_vf_h) +GEN_VEXT_VF(vfmacc_vf_w) +GEN_VEXT_VF(vfmacc_vf_d) static uint16_t fnmacc16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3123,15 +3121,15 @@ static uint64_t fnmacc64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfnmacc_vv_h, OP_UUU_H, H2, H2, H2, fnmacc16) RVVCALL(OPFVV3, vfnmacc_vv_w, OP_UUU_W, H4, H4, H4, fnmacc32) RVVCALL(OPFVV3, vfnmacc_vv_d, OP_UUU_D, H8, H8, H8, fnmacc64) -GEN_VEXT_VV_ENV(vfnmacc_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfnmacc_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfnmacc_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfnmacc_vv_h) +GEN_VEXT_VV_ENV(vfnmacc_vv_w) +GEN_VEXT_VV_ENV(vfnmacc_vv_d) RVVCALL(OPFVF3, vfnmacc_vf_h, OP_UUU_H, H2, H2, fnmacc16) RVVCALL(OPFVF3, vfnmacc_vf_w, OP_UUU_W, H4, H4, fnmacc32) RVVCALL(OPFVF3, vfnmacc_vf_d, OP_UUU_D, H8, H8, fnmacc64) -GEN_VEXT_VF(vfnmacc_vf_h, 2, 2) -GEN_VEXT_VF(vfnmacc_vf_w, 4, 4) -GEN_VEXT_VF(vfnmacc_vf_d, 8, 8) +GEN_VEXT_VF(vfnmacc_vf_h) +GEN_VEXT_VF(vfnmacc_vf_w) +GEN_VEXT_VF(vfnmacc_vf_d) static uint16_t fmsac16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3151,15 +3149,15 @@ static uint64_t fmsac64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfmsac_vv_h, OP_UUU_H, H2, H2, H2, fmsac16) RVVCALL(OPFVV3, vfmsac_vv_w, OP_UUU_W, H4, H4, H4, fmsac32) RVVCALL(OPFVV3, vfmsac_vv_d, OP_UUU_D, H8, H8, H8, fmsac64) -GEN_VEXT_VV_ENV(vfmsac_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfmsac_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfmsac_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfmsac_vv_h) +GEN_VEXT_VV_ENV(vfmsac_vv_w) +GEN_VEXT_VV_ENV(vfmsac_vv_d) RVVCALL(OPFVF3, vfmsac_vf_h, OP_UUU_H, H2, H2, fmsac16) RVVCALL(OPFVF3, vfmsac_vf_w, OP_UUU_W, H4, H4, fmsac32) RVVCALL(OPFVF3, vfmsac_vf_d, OP_UUU_D, H8, H8, fmsac64) -GEN_VEXT_VF(vfmsac_vf_h, 2, 2) -GEN_VEXT_VF(vfmsac_vf_w, 4, 4) -GEN_VEXT_VF(vfmsac_vf_d, 8, 8) +GEN_VEXT_VF(vfmsac_vf_h) +GEN_VEXT_VF(vfmsac_vf_w) +GEN_VEXT_VF(vfmsac_vf_d) static uint16_t fnmsac16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3179,15 +3177,15 @@ static uint64_t fnmsac64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfnmsac_vv_h, OP_UUU_H, H2, H2, H2, fnmsac16) RVVCALL(OPFVV3, vfnmsac_vv_w, OP_UUU_W, H4, H4, H4, fnmsac32) RVVCALL(OPFVV3, vfnmsac_vv_d, OP_UUU_D, H8, H8, H8, fnmsac64) -GEN_VEXT_VV_ENV(vfnmsac_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfnmsac_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfnmsac_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfnmsac_vv_h) +GEN_VEXT_VV_ENV(vfnmsac_vv_w) +GEN_VEXT_VV_ENV(vfnmsac_vv_d) RVVCALL(OPFVF3, vfnmsac_vf_h, OP_UUU_H, H2, H2, fnmsac16) RVVCALL(OPFVF3, vfnmsac_vf_w, OP_UUU_W, H4, H4, fnmsac32) RVVCALL(OPFVF3, vfnmsac_vf_d, OP_UUU_D, H8, H8, fnmsac64) -GEN_VEXT_VF(vfnmsac_vf_h, 2, 2) -GEN_VEXT_VF(vfnmsac_vf_w, 4, 4) -GEN_VEXT_VF(vfnmsac_vf_d, 8, 8) +GEN_VEXT_VF(vfnmsac_vf_h) +GEN_VEXT_VF(vfnmsac_vf_w) +GEN_VEXT_VF(vfnmsac_vf_d) static uint16_t fmadd16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3207,15 +3205,15 @@ static uint64_t fmadd64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfmadd_vv_h, OP_UUU_H, H2, H2, H2, fmadd16) RVVCALL(OPFVV3, vfmadd_vv_w, OP_UUU_W, H4, H4, H4, fmadd32) RVVCALL(OPFVV3, vfmadd_vv_d, OP_UUU_D, H8, H8, H8, fmadd64) -GEN_VEXT_VV_ENV(vfmadd_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfmadd_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfmadd_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfmadd_vv_h) +GEN_VEXT_VV_ENV(vfmadd_vv_w) +GEN_VEXT_VV_ENV(vfmadd_vv_d) RVVCALL(OPFVF3, vfmadd_vf_h, OP_UUU_H, H2, H2, fmadd16) RVVCALL(OPFVF3, vfmadd_vf_w, OP_UUU_W, H4, H4, fmadd32) RVVCALL(OPFVF3, vfmadd_vf_d, OP_UUU_D, H8, H8, fmadd64) -GEN_VEXT_VF(vfmadd_vf_h, 2, 2) -GEN_VEXT_VF(vfmadd_vf_w, 4, 4) -GEN_VEXT_VF(vfmadd_vf_d, 8, 8) +GEN_VEXT_VF(vfmadd_vf_h) +GEN_VEXT_VF(vfmadd_vf_w) +GEN_VEXT_VF(vfmadd_vf_d) static uint16_t fnmadd16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3238,15 +3236,15 @@ static uint64_t fnmadd64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfnmadd_vv_h, OP_UUU_H, H2, H2, H2, fnmadd16) RVVCALL(OPFVV3, vfnmadd_vv_w, OP_UUU_W, H4, H4, H4, fnmadd32) RVVCALL(OPFVV3, vfnmadd_vv_d, OP_UUU_D, H8, H8, H8, fnmadd64) -GEN_VEXT_VV_ENV(vfnmadd_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfnmadd_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfnmadd_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfnmadd_vv_h) +GEN_VEXT_VV_ENV(vfnmadd_vv_w) +GEN_VEXT_VV_ENV(vfnmadd_vv_d) RVVCALL(OPFVF3, vfnmadd_vf_h, OP_UUU_H, H2, H2, fnmadd16) RVVCALL(OPFVF3, vfnmadd_vf_w, OP_UUU_W, H4, H4, fnmadd32) RVVCALL(OPFVF3, vfnmadd_vf_d, OP_UUU_D, H8, H8, fnmadd64) -GEN_VEXT_VF(vfnmadd_vf_h, 2, 2) -GEN_VEXT_VF(vfnmadd_vf_w, 4, 4) -GEN_VEXT_VF(vfnmadd_vf_d, 8, 8) +GEN_VEXT_VF(vfnmadd_vf_h) +GEN_VEXT_VF(vfnmadd_vf_w) +GEN_VEXT_VF(vfnmadd_vf_d) static uint16_t fmsub16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3266,15 +3264,15 @@ static uint64_t fmsub64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfmsub_vv_h, OP_UUU_H, H2, H2, H2, fmsub16) RVVCALL(OPFVV3, vfmsub_vv_w, OP_UUU_W, H4, H4, H4, fmsub32) RVVCALL(OPFVV3, vfmsub_vv_d, OP_UUU_D, H8, H8, H8, fmsub64) -GEN_VEXT_VV_ENV(vfmsub_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfmsub_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfmsub_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfmsub_vv_h) +GEN_VEXT_VV_ENV(vfmsub_vv_w) +GEN_VEXT_VV_ENV(vfmsub_vv_d) RVVCALL(OPFVF3, vfmsub_vf_h, OP_UUU_H, H2, H2, fmsub16) RVVCALL(OPFVF3, vfmsub_vf_w, OP_UUU_W, H4, H4, fmsub32) RVVCALL(OPFVF3, vfmsub_vf_d, OP_UUU_D, H8, H8, fmsub64) -GEN_VEXT_VF(vfmsub_vf_h, 2, 2) -GEN_VEXT_VF(vfmsub_vf_w, 4, 4) -GEN_VEXT_VF(vfmsub_vf_d, 8, 8) +GEN_VEXT_VF(vfmsub_vf_h) +GEN_VEXT_VF(vfmsub_vf_w) +GEN_VEXT_VF(vfmsub_vf_d) static uint16_t fnmsub16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3294,15 +3292,15 @@ static uint64_t fnmsub64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfnmsub_vv_h, OP_UUU_H, H2, H2, H2, fnmsub16) RVVCALL(OPFVV3, vfnmsub_vv_w, OP_UUU_W, H4, H4, H4, fnmsub32) RVVCALL(OPFVV3, vfnmsub_vv_d, OP_UUU_D, H8, H8, H8, fnmsub64) -GEN_VEXT_VV_ENV(vfnmsub_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfnmsub_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfnmsub_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfnmsub_vv_h) +GEN_VEXT_VV_ENV(vfnmsub_vv_w) +GEN_VEXT_VV_ENV(vfnmsub_vv_d) RVVCALL(OPFVF3, vfnmsub_vf_h, OP_UUU_H, H2, H2, fnmsub16) RVVCALL(OPFVF3, vfnmsub_vf_w, OP_UUU_W, H4, H4, fnmsub32) RVVCALL(OPFVF3, vfnmsub_vf_d, OP_UUU_D, H8, H8, fnmsub64) -GEN_VEXT_VF(vfnmsub_vf_h, 2, 2) -GEN_VEXT_VF(vfnmsub_vf_w, 4, 4) -GEN_VEXT_VF(vfnmsub_vf_d, 8, 8) +GEN_VEXT_VF(vfnmsub_vf_h) +GEN_VEXT_VF(vfnmsub_vf_w) +GEN_VEXT_VF(vfnmsub_vf_d) /* Vector Widening Floating-Point Fused Multiply-Add Instructions */ static uint32_t fwmacc16(uint16_t a, uint16_t b, uint32_t d, float_status *s) @@ -3319,12 +3317,12 @@ static uint64_t fwmacc32(uint32_t a, uint32_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfwmacc_vv_h, WOP_UUU_H, H4, H2, H2, fwmacc16) RVVCALL(OPFVV3, vfwmacc_vv_w, WOP_UUU_W, H8, H4, H4, fwmacc32) -GEN_VEXT_VV_ENV(vfwmacc_vv_h, 2, 4) -GEN_VEXT_VV_ENV(vfwmacc_vv_w, 4, 8) +GEN_VEXT_VV_ENV(vfwmacc_vv_h) +GEN_VEXT_VV_ENV(vfwmacc_vv_w) RVVCALL(OPFVF3, vfwmacc_vf_h, WOP_UUU_H, H4, H2, fwmacc16) RVVCALL(OPFVF3, vfwmacc_vf_w, WOP_UUU_W, H8, H4, fwmacc32) -GEN_VEXT_VF(vfwmacc_vf_h, 2, 4) -GEN_VEXT_VF(vfwmacc_vf_w, 4, 8) +GEN_VEXT_VF(vfwmacc_vf_h) +GEN_VEXT_VF(vfwmacc_vf_w) static uint32_t fwnmacc16(uint16_t a, uint16_t b, uint32_t d, float_status *s) { @@ -3342,12 +3340,12 @@ static uint64_t fwnmacc32(uint32_t a, uint32_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfwnmacc_vv_h, WOP_UUU_H, H4, H2, H2, fwnmacc16) RVVCALL(OPFVV3, vfwnmacc_vv_w, WOP_UUU_W, H8, H4, H4, fwnmacc32) -GEN_VEXT_VV_ENV(vfwnmacc_vv_h, 2, 4) -GEN_VEXT_VV_ENV(vfwnmacc_vv_w, 4, 8) +GEN_VEXT_VV_ENV(vfwnmacc_vv_h) +GEN_VEXT_VV_ENV(vfwnmacc_vv_w) RVVCALL(OPFVF3, vfwnmacc_vf_h, WOP_UUU_H, H4, H2, fwnmacc16) RVVCALL(OPFVF3, vfwnmacc_vf_w, WOP_UUU_W, H8, H4, fwnmacc32) -GEN_VEXT_VF(vfwnmacc_vf_h, 2, 4) -GEN_VEXT_VF(vfwnmacc_vf_w, 4, 8) +GEN_VEXT_VF(vfwnmacc_vf_h) +GEN_VEXT_VF(vfwnmacc_vf_w) static uint32_t fwmsac16(uint16_t a, uint16_t b, uint32_t d, float_status *s) { @@ -3365,12 +3363,12 @@ static uint64_t fwmsac32(uint32_t a, uint32_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfwmsac_vv_h, WOP_UUU_H, H4, H2, H2, fwmsac16) RVVCALL(OPFVV3, vfwmsac_vv_w, WOP_UUU_W, H8, H4, H4, fwmsac32) -GEN_VEXT_VV_ENV(vfwmsac_vv_h, 2, 4) -GEN_VEXT_VV_ENV(vfwmsac_vv_w, 4, 8) +GEN_VEXT_VV_ENV(vfwmsac_vv_h) +GEN_VEXT_VV_ENV(vfwmsac_vv_w) RVVCALL(OPFVF3, vfwmsac_vf_h, WOP_UUU_H, H4, H2, fwmsac16) RVVCALL(OPFVF3, vfwmsac_vf_w, WOP_UUU_W, H8, H4, fwmsac32) -GEN_VEXT_VF(vfwmsac_vf_h, 2, 4) -GEN_VEXT_VF(vfwmsac_vf_w, 4, 8) +GEN_VEXT_VF(vfwmsac_vf_h) +GEN_VEXT_VF(vfwmsac_vf_w) static uint32_t fwnmsac16(uint16_t a, uint16_t b, uint32_t d, float_status *s) { @@ -3388,12 +3386,12 @@ static uint64_t fwnmsac32(uint32_t a, uint32_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfwnmsac_vv_h, WOP_UUU_H, H4, H2, H2, fwnmsac16) RVVCALL(OPFVV3, vfwnmsac_vv_w, WOP_UUU_W, H8, H4, H4, fwnmsac32) -GEN_VEXT_VV_ENV(vfwnmsac_vv_h, 2, 4) -GEN_VEXT_VV_ENV(vfwnmsac_vv_w, 4, 8) +GEN_VEXT_VV_ENV(vfwnmsac_vv_h) +GEN_VEXT_VV_ENV(vfwnmsac_vv_w) RVVCALL(OPFVF3, vfwnmsac_vf_h, WOP_UUU_H, H4, H2, fwnmsac16) RVVCALL(OPFVF3, vfwnmsac_vf_w, WOP_UUU_W, H8, H4, fwnmsac32) -GEN_VEXT_VF(vfwnmsac_vf_h, 2, 4) -GEN_VEXT_VF(vfwnmsac_vf_w, 4, 8) +GEN_VEXT_VF(vfwnmsac_vf_h) +GEN_VEXT_VF(vfwnmsac_vf_w) /* Vector Floating-Point Square-Root Instruction */ /* (TD, T2, TX2) */ @@ -3409,7 +3407,7 @@ static void do_##NAME(void *vd, void *vs2, int i, \ *((TD *)vd + HD(i)) = OP(s2, &env->fp_status); \ } -#define GEN_VEXT_V_ENV(NAME, ESZ, DSZ) \ +#define GEN_VEXT_V_ENV(NAME) \ void HELPER(NAME)(void *vd, void *v0, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ @@ -3432,9 +3430,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \ RVVCALL(OPFVV1, vfsqrt_v_h, OP_UU_H, H2, H2, float16_sqrt) RVVCALL(OPFVV1, vfsqrt_v_w, OP_UU_W, H4, H4, float32_sqrt) RVVCALL(OPFVV1, vfsqrt_v_d, OP_UU_D, H8, H8, float64_sqrt) -GEN_VEXT_V_ENV(vfsqrt_v_h, 2, 2) -GEN_VEXT_V_ENV(vfsqrt_v_w, 4, 4) -GEN_VEXT_V_ENV(vfsqrt_v_d, 8, 8) +GEN_VEXT_V_ENV(vfsqrt_v_h) +GEN_VEXT_V_ENV(vfsqrt_v_w) +GEN_VEXT_V_ENV(vfsqrt_v_d) /* * Vector Floating-Point Reciprocal Square-Root Estimate Instruction @@ -3614,9 +3612,9 @@ static float64 frsqrt7_d(float64 f, float_status *s) RVVCALL(OPFVV1, vfrsqrt7_v_h, OP_UU_H, H2, H2, frsqrt7_h) RVVCALL(OPFVV1, vfrsqrt7_v_w, OP_UU_W, H4, H4, frsqrt7_s) RVVCALL(OPFVV1, vfrsqrt7_v_d, OP_UU_D, H8, H8, frsqrt7_d) -GEN_VEXT_V_ENV(vfrsqrt7_v_h, 2, 2) -GEN_VEXT_V_ENV(vfrsqrt7_v_w, 4, 4) -GEN_VEXT_V_ENV(vfrsqrt7_v_d, 8, 8) +GEN_VEXT_V_ENV(vfrsqrt7_v_h) +GEN_VEXT_V_ENV(vfrsqrt7_v_w) +GEN_VEXT_V_ENV(vfrsqrt7_v_d) /* * Vector Floating-Point Reciprocal Estimate Instruction @@ -3805,36 +3803,36 @@ static float64 frec7_d(float64 f, float_status *s) RVVCALL(OPFVV1, vfrec7_v_h, OP_UU_H, H2, H2, frec7_h) RVVCALL(OPFVV1, vfrec7_v_w, OP_UU_W, H4, H4, frec7_s) RVVCALL(OPFVV1, vfrec7_v_d, OP_UU_D, H8, H8, frec7_d) -GEN_VEXT_V_ENV(vfrec7_v_h, 2, 2) -GEN_VEXT_V_ENV(vfrec7_v_w, 4, 4) -GEN_VEXT_V_ENV(vfrec7_v_d, 8, 8) +GEN_VEXT_V_ENV(vfrec7_v_h) +GEN_VEXT_V_ENV(vfrec7_v_w) +GEN_VEXT_V_ENV(vfrec7_v_d) /* Vector Floating-Point MIN/MAX Instructions */ RVVCALL(OPFVV2, vfmin_vv_h, OP_UUU_H, H2, H2, H2, float16_minimum_number) RVVCALL(OPFVV2, vfmin_vv_w, OP_UUU_W, H4, H4, H4, float32_minimum_number) RVVCALL(OPFVV2, vfmin_vv_d, OP_UUU_D, H8, H8, H8, float64_minimum_number) -GEN_VEXT_VV_ENV(vfmin_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfmin_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfmin_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfmin_vv_h) +GEN_VEXT_VV_ENV(vfmin_vv_w) +GEN_VEXT_VV_ENV(vfmin_vv_d) RVVCALL(OPFVF2, vfmin_vf_h, OP_UUU_H, H2, H2, float16_minimum_number) RVVCALL(OPFVF2, vfmin_vf_w, OP_UUU_W, H4, H4, float32_minimum_number) RVVCALL(OPFVF2, vfmin_vf_d, OP_UUU_D, H8, H8, float64_minimum_number) -GEN_VEXT_VF(vfmin_vf_h, 2, 2) -GEN_VEXT_VF(vfmin_vf_w, 4, 4) -GEN_VEXT_VF(vfmin_vf_d, 8, 8) +GEN_VEXT_VF(vfmin_vf_h) +GEN_VEXT_VF(vfmin_vf_w) +GEN_VEXT_VF(vfmin_vf_d) RVVCALL(OPFVV2, vfmax_vv_h, OP_UUU_H, H2, H2, H2, float16_maximum_number) RVVCALL(OPFVV2, vfmax_vv_w, OP_UUU_W, H4, H4, H4, float32_maximum_number) RVVCALL(OPFVV2, vfmax_vv_d, OP_UUU_D, H8, H8, H8, float64_maximum_number) -GEN_VEXT_VV_ENV(vfmax_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfmax_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfmax_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfmax_vv_h) +GEN_VEXT_VV_ENV(vfmax_vv_w) +GEN_VEXT_VV_ENV(vfmax_vv_d) RVVCALL(OPFVF2, vfmax_vf_h, OP_UUU_H, H2, H2, float16_maximum_number) RVVCALL(OPFVF2, vfmax_vf_w, OP_UUU_W, H4, H4, float32_maximum_number) RVVCALL(OPFVF2, vfmax_vf_d, OP_UUU_D, H8, H8, float64_maximum_number) -GEN_VEXT_VF(vfmax_vf_h, 2, 2) -GEN_VEXT_VF(vfmax_vf_w, 4, 4) -GEN_VEXT_VF(vfmax_vf_d, 8, 8) +GEN_VEXT_VF(vfmax_vf_h) +GEN_VEXT_VF(vfmax_vf_w) +GEN_VEXT_VF(vfmax_vf_d) /* Vector Floating-Point Sign-Injection Instructions */ static uint16_t fsgnj16(uint16_t a, uint16_t b, float_status *s) @@ -3855,15 +3853,15 @@ static uint64_t fsgnj64(uint64_t a, uint64_t b, float_status *s) RVVCALL(OPFVV2, vfsgnj_vv_h, OP_UUU_H, H2, H2, H2, fsgnj16) RVVCALL(OPFVV2, vfsgnj_vv_w, OP_UUU_W, H4, H4, H4, fsgnj32) RVVCALL(OPFVV2, vfsgnj_vv_d, OP_UUU_D, H8, H8, H8, fsgnj64) -GEN_VEXT_VV_ENV(vfsgnj_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfsgnj_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfsgnj_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfsgnj_vv_h) +GEN_VEXT_VV_ENV(vfsgnj_vv_w) +GEN_VEXT_VV_ENV(vfsgnj_vv_d) RVVCALL(OPFVF2, vfsgnj_vf_h, OP_UUU_H, H2, H2, fsgnj16) RVVCALL(OPFVF2, vfsgnj_vf_w, OP_UUU_W, H4, H4, fsgnj32) RVVCALL(OPFVF2, vfsgnj_vf_d, OP_UUU_D, H8, H8, fsgnj64) -GEN_VEXT_VF(vfsgnj_vf_h, 2, 2) -GEN_VEXT_VF(vfsgnj_vf_w, 4, 4) -GEN_VEXT_VF(vfsgnj_vf_d, 8, 8) +GEN_VEXT_VF(vfsgnj_vf_h) +GEN_VEXT_VF(vfsgnj_vf_w) +GEN_VEXT_VF(vfsgnj_vf_d) static uint16_t fsgnjn16(uint16_t a, uint16_t b, float_status *s) { @@ -3883,15 +3881,15 @@ static uint64_t fsgnjn64(uint64_t a, uint64_t b, float_status *s) RVVCALL(OPFVV2, vfsgnjn_vv_h, OP_UUU_H, H2, H2, H2, fsgnjn16) RVVCALL(OPFVV2, vfsgnjn_vv_w, OP_UUU_W, H4, H4, H4, fsgnjn32) RVVCALL(OPFVV2, vfsgnjn_vv_d, OP_UUU_D, H8, H8, H8, fsgnjn64) -GEN_VEXT_VV_ENV(vfsgnjn_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfsgnjn_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfsgnjn_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfsgnjn_vv_h) +GEN_VEXT_VV_ENV(vfsgnjn_vv_w) +GEN_VEXT_VV_ENV(vfsgnjn_vv_d) RVVCALL(OPFVF2, vfsgnjn_vf_h, OP_UUU_H, H2, H2, fsgnjn16) RVVCALL(OPFVF2, vfsgnjn_vf_w, OP_UUU_W, H4, H4, fsgnjn32) RVVCALL(OPFVF2, vfsgnjn_vf_d, OP_UUU_D, H8, H8, fsgnjn64) -GEN_VEXT_VF(vfsgnjn_vf_h, 2, 2) -GEN_VEXT_VF(vfsgnjn_vf_w, 4, 4) -GEN_VEXT_VF(vfsgnjn_vf_d, 8, 8) +GEN_VEXT_VF(vfsgnjn_vf_h) +GEN_VEXT_VF(vfsgnjn_vf_w) +GEN_VEXT_VF(vfsgnjn_vf_d) static uint16_t fsgnjx16(uint16_t a, uint16_t b, float_status *s) { @@ -3911,15 +3909,15 @@ static uint64_t fsgnjx64(uint64_t a, uint64_t b, float_status *s) RVVCALL(OPFVV2, vfsgnjx_vv_h, OP_UUU_H, H2, H2, H2, fsgnjx16) RVVCALL(OPFVV2, vfsgnjx_vv_w, OP_UUU_W, H4, H4, H4, fsgnjx32) RVVCALL(OPFVV2, vfsgnjx_vv_d, OP_UUU_D, H8, H8, H8, fsgnjx64) -GEN_VEXT_VV_ENV(vfsgnjx_vv_h, 2, 2) -GEN_VEXT_VV_ENV(vfsgnjx_vv_w, 4, 4) -GEN_VEXT_VV_ENV(vfsgnjx_vv_d, 8, 8) +GEN_VEXT_VV_ENV(vfsgnjx_vv_h) +GEN_VEXT_VV_ENV(vfsgnjx_vv_w) +GEN_VEXT_VV_ENV(vfsgnjx_vv_d) RVVCALL(OPFVF2, vfsgnjx_vf_h, OP_UUU_H, H2, H2, fsgnjx16) RVVCALL(OPFVF2, vfsgnjx_vf_w, OP_UUU_W, H4, H4, fsgnjx32) RVVCALL(OPFVF2, vfsgnjx_vf_d, OP_UUU_D, H8, H8, fsgnjx64) -GEN_VEXT_VF(vfsgnjx_vf_h, 2, 2) -GEN_VEXT_VF(vfsgnjx_vf_w, 4, 4) -GEN_VEXT_VF(vfsgnjx_vf_d, 8, 8) +GEN_VEXT_VF(vfsgnjx_vf_h) +GEN_VEXT_VF(vfsgnjx_vf_w) +GEN_VEXT_VF(vfsgnjx_vf_d) /* Vector Floating-Point Compare Instructions */ #define GEN_VEXT_CMP_VV_ENV(NAME, ETYPE, H, DO_OP) \ @@ -4063,7 +4061,7 @@ static void do_##NAME(void *vd, void *vs2, int i) \ *((TD *)vd + HD(i)) = OP(s2); \ } -#define GEN_VEXT_V(NAME, ESZ, DSZ) \ +#define GEN_VEXT_V(NAME) \ void HELPER(NAME)(void *vd, void *v0, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ @@ -4140,9 +4138,9 @@ target_ulong fclass_d(uint64_t frs1) RVVCALL(OPIVV1, vfclass_v_h, OP_UU_H, H2, H2, fclass_h) RVVCALL(OPIVV1, vfclass_v_w, OP_UU_W, H4, H4, fclass_s) RVVCALL(OPIVV1, vfclass_v_d, OP_UU_D, H8, H8, fclass_d) -GEN_VEXT_V(vfclass_v_h, 2, 2) -GEN_VEXT_V(vfclass_v_w, 4, 4) -GEN_VEXT_V(vfclass_v_d, 8, 8) +GEN_VEXT_V(vfclass_v_h) +GEN_VEXT_V(vfclass_v_w) +GEN_VEXT_V(vfclass_v_d) /* Vector Floating-Point Merge Instruction */ #define GEN_VFMERGE_VF(NAME, ETYPE, H) \ @@ -4170,33 +4168,33 @@ GEN_VFMERGE_VF(vfmerge_vfm_d, int64_t, H8) RVVCALL(OPFVV1, vfcvt_xu_f_v_h, OP_UU_H, H2, H2, float16_to_uint16) RVVCALL(OPFVV1, vfcvt_xu_f_v_w, OP_UU_W, H4, H4, float32_to_uint32) RVVCALL(OPFVV1, vfcvt_xu_f_v_d, OP_UU_D, H8, H8, float64_to_uint64) -GEN_VEXT_V_ENV(vfcvt_xu_f_v_h, 2, 2) -GEN_VEXT_V_ENV(vfcvt_xu_f_v_w, 4, 4) -GEN_VEXT_V_ENV(vfcvt_xu_f_v_d, 8, 8) +GEN_VEXT_V_ENV(vfcvt_xu_f_v_h) +GEN_VEXT_V_ENV(vfcvt_xu_f_v_w) +GEN_VEXT_V_ENV(vfcvt_xu_f_v_d) /* vfcvt.x.f.v vd, vs2, vm # Convert float to signed integer. */ RVVCALL(OPFVV1, vfcvt_x_f_v_h, OP_UU_H, H2, H2, float16_to_int16) RVVCALL(OPFVV1, vfcvt_x_f_v_w, OP_UU_W, H4, H4, float32_to_int32) RVVCALL(OPFVV1, vfcvt_x_f_v_d, OP_UU_D, H8, H8, float64_to_int64) -GEN_VEXT_V_ENV(vfcvt_x_f_v_h, 2, 2) -GEN_VEXT_V_ENV(vfcvt_x_f_v_w, 4, 4) -GEN_VEXT_V_ENV(vfcvt_x_f_v_d, 8, 8) +GEN_VEXT_V_ENV(vfcvt_x_f_v_h) +GEN_VEXT_V_ENV(vfcvt_x_f_v_w) +GEN_VEXT_V_ENV(vfcvt_x_f_v_d) /* vfcvt.f.xu.v vd, vs2, vm # Convert unsigned integer to float. */ RVVCALL(OPFVV1, vfcvt_f_xu_v_h, OP_UU_H, H2, H2, uint16_to_float16) RVVCALL(OPFVV1, vfcvt_f_xu_v_w, OP_UU_W, H4, H4, uint32_to_float32) RVVCALL(OPFVV1, vfcvt_f_xu_v_d, OP_UU_D, H8, H8, uint64_to_float64) -GEN_VEXT_V_ENV(vfcvt_f_xu_v_h, 2, 2) -GEN_VEXT_V_ENV(vfcvt_f_xu_v_w, 4, 4) -GEN_VEXT_V_ENV(vfcvt_f_xu_v_d, 8, 8) +GEN_VEXT_V_ENV(vfcvt_f_xu_v_h) +GEN_VEXT_V_ENV(vfcvt_f_xu_v_w) +GEN_VEXT_V_ENV(vfcvt_f_xu_v_d) /* vfcvt.f.x.v vd, vs2, vm # Convert integer to float. */ RVVCALL(OPFVV1, vfcvt_f_x_v_h, OP_UU_H, H2, H2, int16_to_float16) RVVCALL(OPFVV1, vfcvt_f_x_v_w, OP_UU_W, H4, H4, int32_to_float32) RVVCALL(OPFVV1, vfcvt_f_x_v_d, OP_UU_D, H8, H8, int64_to_float64) -GEN_VEXT_V_ENV(vfcvt_f_x_v_h, 2, 2) -GEN_VEXT_V_ENV(vfcvt_f_x_v_w, 4, 4) -GEN_VEXT_V_ENV(vfcvt_f_x_v_d, 8, 8) +GEN_VEXT_V_ENV(vfcvt_f_x_v_h) +GEN_VEXT_V_ENV(vfcvt_f_x_v_w) +GEN_VEXT_V_ENV(vfcvt_f_x_v_d) /* Widening Floating-Point/Integer Type-Convert Instructions */ /* (TD, T2, TX2) */ @@ -4206,30 +4204,30 @@ GEN_VEXT_V_ENV(vfcvt_f_x_v_d, 8, 8) /* vfwcvt.xu.f.v vd, vs2, vm # Convert float to double-width unsigned integer.*/ RVVCALL(OPFVV1, vfwcvt_xu_f_v_h, WOP_UU_H, H4, H2, float16_to_uint32) RVVCALL(OPFVV1, vfwcvt_xu_f_v_w, WOP_UU_W, H8, H4, float32_to_uint64) -GEN_VEXT_V_ENV(vfwcvt_xu_f_v_h, 2, 4) -GEN_VEXT_V_ENV(vfwcvt_xu_f_v_w, 4, 8) +GEN_VEXT_V_ENV(vfwcvt_xu_f_v_h) +GEN_VEXT_V_ENV(vfwcvt_xu_f_v_w) /* vfwcvt.x.f.v vd, vs2, vm # Convert float to double-width signed integer. */ RVVCALL(OPFVV1, vfwcvt_x_f_v_h, WOP_UU_H, H4, H2, float16_to_int32) RVVCALL(OPFVV1, vfwcvt_x_f_v_w, WOP_UU_W, H8, H4, float32_to_int64) -GEN_VEXT_V_ENV(vfwcvt_x_f_v_h, 2, 4) -GEN_VEXT_V_ENV(vfwcvt_x_f_v_w, 4, 8) +GEN_VEXT_V_ENV(vfwcvt_x_f_v_h) +GEN_VEXT_V_ENV(vfwcvt_x_f_v_w) /* vfwcvt.f.xu.v vd, vs2, vm # Convert unsigned integer to double-width float */ RVVCALL(OPFVV1, vfwcvt_f_xu_v_b, WOP_UU_B, H2, H1, uint8_to_float16) RVVCALL(OPFVV1, vfwcvt_f_xu_v_h, WOP_UU_H, H4, H2, uint16_to_float32) RVVCALL(OPFVV1, vfwcvt_f_xu_v_w, WOP_UU_W, H8, H4, uint32_to_float64) -GEN_VEXT_V_ENV(vfwcvt_f_xu_v_b, 1, 2) -GEN_VEXT_V_ENV(vfwcvt_f_xu_v_h, 2, 4) -GEN_VEXT_V_ENV(vfwcvt_f_xu_v_w, 4, 8) +GEN_VEXT_V_ENV(vfwcvt_f_xu_v_b) +GEN_VEXT_V_ENV(vfwcvt_f_xu_v_h) +GEN_VEXT_V_ENV(vfwcvt_f_xu_v_w) /* vfwcvt.f.x.v vd, vs2, vm # Convert integer to double-width float. */ RVVCALL(OPFVV1, vfwcvt_f_x_v_b, WOP_UU_B, H2, H1, int8_to_float16) RVVCALL(OPFVV1, vfwcvt_f_x_v_h, WOP_UU_H, H4, H2, int16_to_float32) RVVCALL(OPFVV1, vfwcvt_f_x_v_w, WOP_UU_W, H8, H4, int32_to_float64) -GEN_VEXT_V_ENV(vfwcvt_f_x_v_b, 1, 2) -GEN_VEXT_V_ENV(vfwcvt_f_x_v_h, 2, 4) -GEN_VEXT_V_ENV(vfwcvt_f_x_v_w, 4, 8) +GEN_VEXT_V_ENV(vfwcvt_f_x_v_b) +GEN_VEXT_V_ENV(vfwcvt_f_x_v_h) +GEN_VEXT_V_ENV(vfwcvt_f_x_v_w) /* * vfwcvt.f.f.v vd, vs2, vm @@ -4242,8 +4240,8 @@ static uint32_t vfwcvtffv16(uint16_t a, float_status *s) RVVCALL(OPFVV1, vfwcvt_f_f_v_h, WOP_UU_H, H4, H2, vfwcvtffv16) RVVCALL(OPFVV1, vfwcvt_f_f_v_w, WOP_UU_W, H8, H4, float32_to_float64) -GEN_VEXT_V_ENV(vfwcvt_f_f_v_h, 2, 4) -GEN_VEXT_V_ENV(vfwcvt_f_f_v_w, 4, 8) +GEN_VEXT_V_ENV(vfwcvt_f_f_v_h) +GEN_VEXT_V_ENV(vfwcvt_f_f_v_w) /* Narrowing Floating-Point/Integer Type-Convert Instructions */ /* (TD, T2, TX2) */ @@ -4254,29 +4252,29 @@ GEN_VEXT_V_ENV(vfwcvt_f_f_v_w, 4, 8) RVVCALL(OPFVV1, vfncvt_xu_f_w_b, NOP_UU_B, H1, H2, float16_to_uint8) RVVCALL(OPFVV1, vfncvt_xu_f_w_h, NOP_UU_H, H2, H4, float32_to_uint16) RVVCALL(OPFVV1, vfncvt_xu_f_w_w, NOP_UU_W, H4, H8, float64_to_uint32) -GEN_VEXT_V_ENV(vfncvt_xu_f_w_b, 1, 1) -GEN_VEXT_V_ENV(vfncvt_xu_f_w_h, 2, 2) -GEN_VEXT_V_ENV(vfncvt_xu_f_w_w, 4, 4) +GEN_VEXT_V_ENV(vfncvt_xu_f_w_b) +GEN_VEXT_V_ENV(vfncvt_xu_f_w_h) +GEN_VEXT_V_ENV(vfncvt_xu_f_w_w) /* vfncvt.x.f.v vd, vs2, vm # Convert double-width float to signed integer. */ RVVCALL(OPFVV1, vfncvt_x_f_w_b, NOP_UU_B, H1, H2, float16_to_int8) RVVCALL(OPFVV1, vfncvt_x_f_w_h, NOP_UU_H, H2, H4, float32_to_int16) RVVCALL(OPFVV1, vfncvt_x_f_w_w, NOP_UU_W, H4, H8, float64_to_int32) -GEN_VEXT_V_ENV(vfncvt_x_f_w_b, 1, 1) -GEN_VEXT_V_ENV(vfncvt_x_f_w_h, 2, 2) -GEN_VEXT_V_ENV(vfncvt_x_f_w_w, 4, 4) +GEN_VEXT_V_ENV(vfncvt_x_f_w_b) +GEN_VEXT_V_ENV(vfncvt_x_f_w_h) +GEN_VEXT_V_ENV(vfncvt_x_f_w_w) /* vfncvt.f.xu.v vd, vs2, vm # Convert double-width unsigned integer to float */ RVVCALL(OPFVV1, vfncvt_f_xu_w_h, NOP_UU_H, H2, H4, uint32_to_float16) RVVCALL(OPFVV1, vfncvt_f_xu_w_w, NOP_UU_W, H4, H8, uint64_to_float32) -GEN_VEXT_V_ENV(vfncvt_f_xu_w_h, 2, 2) -GEN_VEXT_V_ENV(vfncvt_f_xu_w_w, 4, 4) +GEN_VEXT_V_ENV(vfncvt_f_xu_w_h) +GEN_VEXT_V_ENV(vfncvt_f_xu_w_w) /* vfncvt.f.x.v vd, vs2, vm # Convert double-width integer to float. */ RVVCALL(OPFVV1, vfncvt_f_x_w_h, NOP_UU_H, H2, H4, int32_to_float16) RVVCALL(OPFVV1, vfncvt_f_x_w_w, NOP_UU_W, H4, H8, int64_to_float32) -GEN_VEXT_V_ENV(vfncvt_f_x_w_h, 2, 2) -GEN_VEXT_V_ENV(vfncvt_f_x_w_w, 4, 4) +GEN_VEXT_V_ENV(vfncvt_f_x_w_h) +GEN_VEXT_V_ENV(vfncvt_f_x_w_w) /* vfncvt.f.f.v vd, vs2, vm # Convert double float to single-width float. */ static uint16_t vfncvtffv16(uint32_t a, float_status *s) @@ -4286,8 +4284,8 @@ static uint16_t vfncvtffv16(uint32_t a, float_status *s) RVVCALL(OPFVV1, vfncvt_f_f_w_h, NOP_UU_H, H2, H4, vfncvtffv16) RVVCALL(OPFVV1, vfncvt_f_f_w_w, NOP_UU_W, H4, H8, float64_to_float32) -GEN_VEXT_V_ENV(vfncvt_f_f_w_h, 2, 2) -GEN_VEXT_V_ENV(vfncvt_f_f_w_w, 4, 4) +GEN_VEXT_V_ENV(vfncvt_f_f_w_h) +GEN_VEXT_V_ENV(vfncvt_f_f_w_w) /* *** Vector Reduction Operations From 25eae0486db6e24f86550e3c42af2b17cc43ddbf Mon Sep 17 00:00:00 2001 From: eopXD Date: Mon, 6 Jun 2022 06:16:16 +0000 Subject: [PATCH 919/935] target/riscv: rvv: Prune redundant access_type parameter passed No functional change intended in this commit. Signed-off-by: eop Chen Reviewed-by: Alistair Francis Message-Id: <165449614532.19704.7000832880482980398-2@git.sr.ht> Signed-off-by: Alistair Francis --- target/riscv/vector_helper.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 85dd611cd9..60840325c4 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -231,7 +231,7 @@ vext_ldst_stride(void *vd, void *v0, target_ulong base, target_ulong stride, CPURISCVState *env, uint32_t desc, uint32_t vm, vext_ldst_elem_fn *ldst_elem, - uint32_t esz, uintptr_t ra, MMUAccessType access_type) + uint32_t esz, uintptr_t ra) { uint32_t i, k; uint32_t nf = vext_nf(desc); @@ -259,7 +259,7 @@ void HELPER(NAME)(void *vd, void * v0, target_ulong base, \ { \ uint32_t vm = vext_vm(desc); \ vext_ldst_stride(vd, v0, base, stride, env, desc, vm, LOAD_FN, \ - ctzl(sizeof(ETYPE)), GETPC(), MMU_DATA_LOAD); \ + ctzl(sizeof(ETYPE)), GETPC()); \ } GEN_VEXT_LD_STRIDE(vlse8_v, int8_t, lde_b) @@ -274,7 +274,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong base, \ { \ uint32_t vm = vext_vm(desc); \ vext_ldst_stride(vd, v0, base, stride, env, desc, vm, STORE_FN, \ - ctzl(sizeof(ETYPE)), GETPC(), MMU_DATA_STORE); \ + ctzl(sizeof(ETYPE)), GETPC()); \ } GEN_VEXT_ST_STRIDE(vsse8_v, int8_t, ste_b) @@ -290,7 +290,7 @@ GEN_VEXT_ST_STRIDE(vsse64_v, int64_t, ste_d) static void vext_ldst_us(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, vext_ldst_elem_fn *ldst_elem, uint32_t esz, uint32_t evl, - uintptr_t ra, MMUAccessType access_type) + uintptr_t ra) { uint32_t i, k; uint32_t nf = vext_nf(desc); @@ -319,14 +319,14 @@ void HELPER(NAME##_mask)(void *vd, void *v0, target_ulong base, \ { \ uint32_t stride = vext_nf(desc) << ctzl(sizeof(ETYPE)); \ vext_ldst_stride(vd, v0, base, stride, env, desc, false, LOAD_FN, \ - ctzl(sizeof(ETYPE)), GETPC(), MMU_DATA_LOAD); \ + ctzl(sizeof(ETYPE)), GETPC()); \ } \ \ void HELPER(NAME)(void *vd, void *v0, target_ulong base, \ CPURISCVState *env, uint32_t desc) \ { \ vext_ldst_us(vd, base, env, desc, LOAD_FN, \ - ctzl(sizeof(ETYPE)), env->vl, GETPC(), MMU_DATA_LOAD); \ + ctzl(sizeof(ETYPE)), env->vl, GETPC()); \ } GEN_VEXT_LD_US(vle8_v, int8_t, lde_b) @@ -340,14 +340,14 @@ void HELPER(NAME##_mask)(void *vd, void *v0, target_ulong base, \ { \ uint32_t stride = vext_nf(desc) << ctzl(sizeof(ETYPE)); \ vext_ldst_stride(vd, v0, base, stride, env, desc, false, STORE_FN, \ - ctzl(sizeof(ETYPE)), GETPC(), MMU_DATA_STORE); \ + ctzl(sizeof(ETYPE)), GETPC()); \ } \ \ void HELPER(NAME)(void *vd, void *v0, target_ulong base, \ CPURISCVState *env, uint32_t desc) \ { \ vext_ldst_us(vd, base, env, desc, STORE_FN, \ - ctzl(sizeof(ETYPE)), env->vl, GETPC(), MMU_DATA_STORE); \ + ctzl(sizeof(ETYPE)), env->vl, GETPC()); \ } GEN_VEXT_ST_US(vse8_v, int8_t, ste_b) @@ -364,7 +364,7 @@ void HELPER(vlm_v)(void *vd, void *v0, target_ulong base, /* evl = ceil(vl/8) */ uint8_t evl = (env->vl + 7) >> 3; vext_ldst_us(vd, base, env, desc, lde_b, - 0, evl, GETPC(), MMU_DATA_LOAD); + 0, evl, GETPC()); } void HELPER(vsm_v)(void *vd, void *v0, target_ulong base, @@ -373,7 +373,7 @@ void HELPER(vsm_v)(void *vd, void *v0, target_ulong base, /* evl = ceil(vl/8) */ uint8_t evl = (env->vl + 7) >> 3; vext_ldst_us(vd, base, env, desc, ste_b, - 0, evl, GETPC(), MMU_DATA_STORE); + 0, evl, GETPC()); } /* @@ -399,7 +399,7 @@ vext_ldst_index(void *vd, void *v0, target_ulong base, void *vs2, CPURISCVState *env, uint32_t desc, vext_get_index_addr get_index_addr, vext_ldst_elem_fn *ldst_elem, - uint32_t esz, uintptr_t ra, MMUAccessType access_type) + uint32_t esz, uintptr_t ra) { uint32_t i, k; uint32_t nf = vext_nf(desc); @@ -427,7 +427,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong base, \ void *vs2, CPURISCVState *env, uint32_t desc) \ { \ vext_ldst_index(vd, v0, base, vs2, env, desc, INDEX_FN, \ - LOAD_FN, ctzl(sizeof(ETYPE)), GETPC(), MMU_DATA_LOAD); \ + LOAD_FN, ctzl(sizeof(ETYPE)), GETPC()); \ } GEN_VEXT_LD_INDEX(vlxei8_8_v, int8_t, idx_b, lde_b) @@ -453,7 +453,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong base, \ { \ vext_ldst_index(vd, v0, base, vs2, env, desc, INDEX_FN, \ STORE_FN, ctzl(sizeof(ETYPE)), \ - GETPC(), MMU_DATA_STORE); \ + GETPC()); \ } GEN_VEXT_ST_INDEX(vsxei8_8_v, int8_t, idx_b, ste_b) @@ -576,8 +576,7 @@ GEN_VEXT_LDFF(vle64ff_v, int64_t, lde_d) */ static void vext_ldst_whole(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, - vext_ldst_elem_fn *ldst_elem, uint32_t esz, uintptr_t ra, - MMUAccessType access_type) + vext_ldst_elem_fn *ldst_elem, uint32_t esz, uintptr_t ra) { uint32_t i, k, off, pos; uint32_t nf = vext_nf(desc); @@ -612,8 +611,7 @@ void HELPER(NAME)(void *vd, target_ulong base, \ CPURISCVState *env, uint32_t desc) \ { \ vext_ldst_whole(vd, base, env, desc, LOAD_FN, \ - ctzl(sizeof(ETYPE)), GETPC(), \ - MMU_DATA_LOAD); \ + ctzl(sizeof(ETYPE)), GETPC()); \ } GEN_VEXT_LD_WHOLE(vl1re8_v, int8_t, lde_b) @@ -638,8 +636,7 @@ void HELPER(NAME)(void *vd, target_ulong base, \ CPURISCVState *env, uint32_t desc) \ { \ vext_ldst_whole(vd, base, env, desc, STORE_FN, \ - ctzl(sizeof(ETYPE)), GETPC(), \ - MMU_DATA_STORE); \ + ctzl(sizeof(ETYPE)), GETPC()); \ } GEN_VEXT_ST_WHOLE(vs1r_v, int8_t, ste_b) From c7b8a4213b0dba710e31d633e17e661151c3d23a Mon Sep 17 00:00:00 2001 From: eopXD Date: Mon, 6 Jun 2022 06:16:16 +0000 Subject: [PATCH 920/935] target/riscv: rvv: Rename ambiguous esz No functional change intended in this commit. Signed-off-by: eop Chen Reviewed-by: Frank Chang Reviewed-by: Weiwei Li Reviewed-by: Alistair Francis Message-Id: <165449614532.19704.7000832880482980398-3@git.sr.ht> Signed-off-by: Alistair Francis --- target/riscv/vector_helper.c | 76 ++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 60840325c4..3b79b9cbc2 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -125,9 +125,9 @@ static inline int32_t vext_lmul(uint32_t desc) /* * Get the maximum number of elements can be operated. * - * esz: log2 of element size in bytes. + * log2_esz: log2 of element size in bytes. */ -static inline uint32_t vext_max_elems(uint32_t desc, uint32_t esz) +static inline uint32_t vext_max_elems(uint32_t desc, uint32_t log2_esz) { /* * As simd_desc support at most 2048 bytes, the max vlen is 1024 bits. @@ -136,7 +136,7 @@ static inline uint32_t vext_max_elems(uint32_t desc, uint32_t esz) uint32_t vlenb = simd_maxsz(desc); /* Return VLMAX */ - int scale = vext_lmul(desc) - esz; + int scale = vext_lmul(desc) - log2_esz; return scale < 0 ? vlenb >> -scale : vlenb << scale; } @@ -231,11 +231,11 @@ vext_ldst_stride(void *vd, void *v0, target_ulong base, target_ulong stride, CPURISCVState *env, uint32_t desc, uint32_t vm, vext_ldst_elem_fn *ldst_elem, - uint32_t esz, uintptr_t ra) + uint32_t log2_esz, uintptr_t ra) { uint32_t i, k; uint32_t nf = vext_nf(desc); - uint32_t max_elems = vext_max_elems(desc, esz); + uint32_t max_elems = vext_max_elems(desc, log2_esz); for (i = env->vstart; i < env->vl; i++, env->vstart++) { if (!vm && !vext_elem_mask(v0, i)) { @@ -244,7 +244,7 @@ vext_ldst_stride(void *vd, void *v0, target_ulong base, k = 0; while (k < nf) { - target_ulong addr = base + stride * i + (k << esz); + target_ulong addr = base + stride * i + (k << log2_esz); ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); k++; } @@ -289,18 +289,18 @@ GEN_VEXT_ST_STRIDE(vsse64_v, int64_t, ste_d) /* unmasked unit-stride load and store operation*/ static void vext_ldst_us(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, - vext_ldst_elem_fn *ldst_elem, uint32_t esz, uint32_t evl, + vext_ldst_elem_fn *ldst_elem, uint32_t log2_esz, uint32_t evl, uintptr_t ra) { uint32_t i, k; uint32_t nf = vext_nf(desc); - uint32_t max_elems = vext_max_elems(desc, esz); + uint32_t max_elems = vext_max_elems(desc, log2_esz); /* load bytes from guest memory */ for (i = env->vstart; i < evl; i++, env->vstart++) { k = 0; while (k < nf) { - target_ulong addr = base + ((i * nf + k) << esz); + target_ulong addr = base + ((i * nf + k) << log2_esz); ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); k++; } @@ -399,12 +399,12 @@ vext_ldst_index(void *vd, void *v0, target_ulong base, void *vs2, CPURISCVState *env, uint32_t desc, vext_get_index_addr get_index_addr, vext_ldst_elem_fn *ldst_elem, - uint32_t esz, uintptr_t ra) + uint32_t log2_esz, uintptr_t ra) { uint32_t i, k; uint32_t nf = vext_nf(desc); uint32_t vm = vext_vm(desc); - uint32_t max_elems = vext_max_elems(desc, esz); + uint32_t max_elems = vext_max_elems(desc, log2_esz); /* load bytes from guest memory */ for (i = env->vstart; i < env->vl; i++, env->vstart++) { @@ -414,7 +414,7 @@ vext_ldst_index(void *vd, void *v0, target_ulong base, k = 0; while (k < nf) { - abi_ptr addr = get_index_addr(base, i, vs2) + (k << esz); + abi_ptr addr = get_index_addr(base, i, vs2) + (k << log2_esz); ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); k++; } @@ -480,13 +480,13 @@ static inline void vext_ldff(void *vd, void *v0, target_ulong base, CPURISCVState *env, uint32_t desc, vext_ldst_elem_fn *ldst_elem, - uint32_t esz, uintptr_t ra) + uint32_t log2_esz, uintptr_t ra) { void *host; uint32_t i, k, vl = 0; uint32_t nf = vext_nf(desc); uint32_t vm = vext_vm(desc); - uint32_t max_elems = vext_max_elems(desc, esz); + uint32_t max_elems = vext_max_elems(desc, log2_esz); target_ulong addr, offset, remain; /* probe every access*/ @@ -494,12 +494,12 @@ vext_ldff(void *vd, void *v0, target_ulong base, if (!vm && !vext_elem_mask(v0, i)) { continue; } - addr = adjust_addr(env, base + i * (nf << esz)); + addr = adjust_addr(env, base + i * (nf << log2_esz)); if (i == 0) { - probe_pages(env, addr, nf << esz, ra, MMU_DATA_LOAD); + probe_pages(env, addr, nf << log2_esz, ra, MMU_DATA_LOAD); } else { /* if it triggers an exception, no need to check watchpoint */ - remain = nf << esz; + remain = nf << log2_esz; while (remain > 0) { offset = -(addr | TARGET_PAGE_MASK); host = tlb_vaddr_to_host(env, addr, MMU_DATA_LOAD, @@ -536,7 +536,7 @@ ProbeSuccess: continue; } while (k < nf) { - target_ulong addr = base + ((i * nf + k) << esz); + target_ulong addr = base + ((i * nf + k) << log2_esz); ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); k++; } @@ -576,12 +576,12 @@ GEN_VEXT_LDFF(vle64ff_v, int64_t, lde_d) */ static void vext_ldst_whole(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, - vext_ldst_elem_fn *ldst_elem, uint32_t esz, uintptr_t ra) + vext_ldst_elem_fn *ldst_elem, uint32_t log2_esz, uintptr_t ra) { uint32_t i, k, off, pos; uint32_t nf = vext_nf(desc); uint32_t vlenb = env_archcpu(env)->cfg.vlen >> 3; - uint32_t max_elems = vlenb >> esz; + uint32_t max_elems = vlenb >> log2_esz; k = env->vstart / max_elems; off = env->vstart % max_elems; @@ -589,7 +589,7 @@ vext_ldst_whole(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, if (off) { /* load/store rest of elements of current segment pointed by vstart */ for (pos = off; pos < max_elems; pos++, env->vstart++) { - target_ulong addr = base + ((pos + k * max_elems) << esz); + target_ulong addr = base + ((pos + k * max_elems) << log2_esz); ldst_elem(env, adjust_addr(env, addr), pos + k * max_elems, vd, ra); } k++; @@ -598,7 +598,7 @@ vext_ldst_whole(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, /* load/store elements for rest of segments */ for (; k < nf; k++) { for (i = 0; i < max_elems; i++, env->vstart++) { - target_ulong addr = base + ((i + k * max_elems) << esz); + target_ulong addr = base + ((i + k * max_elems) << log2_esz); ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); } } @@ -4688,11 +4688,11 @@ GEN_VEXT_VSLIDEDOWN_VX(vslidedown_vx_h, uint16_t, H2) GEN_VEXT_VSLIDEDOWN_VX(vslidedown_vx_w, uint32_t, H4) GEN_VEXT_VSLIDEDOWN_VX(vslidedown_vx_d, uint64_t, H8) -#define GEN_VEXT_VSLIE1UP(ESZ, H) \ -static void vslide1up_##ESZ(void *vd, void *v0, target_ulong s1, void *vs2, \ - CPURISCVState *env, uint32_t desc) \ +#define GEN_VEXT_VSLIE1UP(BITWIDTH, H) \ +static void vslide1up_##BITWIDTH(void *vd, void *v0, target_ulong s1, \ + void *vs2, CPURISCVState *env, uint32_t desc) \ { \ - typedef uint##ESZ##_t ETYPE; \ + typedef uint##BITWIDTH##_t ETYPE; \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ uint32_t i; \ @@ -4715,11 +4715,11 @@ GEN_VEXT_VSLIE1UP(16, H2) GEN_VEXT_VSLIE1UP(32, H4) GEN_VEXT_VSLIE1UP(64, H8) -#define GEN_VEXT_VSLIDE1UP_VX(NAME, ESZ) \ +#define GEN_VEXT_VSLIDE1UP_VX(NAME, BITWIDTH) \ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ - vslide1up_##ESZ(vd, v0, s1, vs2, env, desc); \ + vslide1up_##BITWIDTH(vd, v0, s1, vs2, env, desc); \ } /* vslide1up.vx vd, vs2, rs1, vm # vd[0]=x[rs1], vd[i+1] = vs2[i] */ @@ -4728,11 +4728,11 @@ GEN_VEXT_VSLIDE1UP_VX(vslide1up_vx_h, 16) GEN_VEXT_VSLIDE1UP_VX(vslide1up_vx_w, 32) GEN_VEXT_VSLIDE1UP_VX(vslide1up_vx_d, 64) -#define GEN_VEXT_VSLIDE1DOWN(ESZ, H) \ -static void vslide1down_##ESZ(void *vd, void *v0, target_ulong s1, void *vs2, \ - CPURISCVState *env, uint32_t desc) \ +#define GEN_VEXT_VSLIDE1DOWN(BITWIDTH, H) \ +static void vslide1down_##BITWIDTH(void *vd, void *v0, target_ulong s1, \ + void *vs2, CPURISCVState *env, uint32_t desc) \ { \ - typedef uint##ESZ##_t ETYPE; \ + typedef uint##BITWIDTH##_t ETYPE; \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ uint32_t i; \ @@ -4755,11 +4755,11 @@ GEN_VEXT_VSLIDE1DOWN(16, H2) GEN_VEXT_VSLIDE1DOWN(32, H4) GEN_VEXT_VSLIDE1DOWN(64, H8) -#define GEN_VEXT_VSLIDE1DOWN_VX(NAME, ESZ) \ +#define GEN_VEXT_VSLIDE1DOWN_VX(NAME, BITWIDTH) \ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ - vslide1down_##ESZ(vd, v0, s1, vs2, env, desc); \ + vslide1down_##BITWIDTH(vd, v0, s1, vs2, env, desc); \ } /* vslide1down.vx vd, vs2, rs1, vm # vd[i] = vs2[i+1], vd[vl-1]=x[rs1] */ @@ -4769,11 +4769,11 @@ GEN_VEXT_VSLIDE1DOWN_VX(vslide1down_vx_w, 32) GEN_VEXT_VSLIDE1DOWN_VX(vslide1down_vx_d, 64) /* Vector Floating-Point Slide Instructions */ -#define GEN_VEXT_VFSLIDE1UP_VF(NAME, ESZ) \ +#define GEN_VEXT_VFSLIDE1UP_VF(NAME, BITWIDTH) \ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ - vslide1up_##ESZ(vd, v0, s1, vs2, env, desc); \ + vslide1up_##BITWIDTH(vd, v0, s1, vs2, env, desc); \ } /* vfslide1up.vf vd, vs2, rs1, vm # vd[0]=f[rs1], vd[i+1] = vs2[i] */ @@ -4781,11 +4781,11 @@ GEN_VEXT_VFSLIDE1UP_VF(vfslide1up_vf_h, 16) GEN_VEXT_VFSLIDE1UP_VF(vfslide1up_vf_w, 32) GEN_VEXT_VFSLIDE1UP_VF(vfslide1up_vf_d, 64) -#define GEN_VEXT_VFSLIDE1DOWN_VF(NAME, ESZ) \ +#define GEN_VEXT_VFSLIDE1DOWN_VF(NAME, BITWIDTH) \ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ - vslide1down_##ESZ(vd, v0, s1, vs2, env, desc); \ + vslide1down_##BITWIDTH(vd, v0, s1, vs2, env, desc); \ } /* vfslide1down.vf vd, vs2, rs1, vm # vd[i] = vs2[i+1], vd[vl-1]=f[rs1] */ From 41d3d7f76aa7060c0cbc1c8b3a9767a5997b231a Mon Sep 17 00:00:00 2001 From: eopXD Date: Mon, 6 Jun 2022 06:16:16 +0000 Subject: [PATCH 921/935] target/riscv: rvv: Early exit when vstart >= vl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to v-spec (section 5.4): When vstart ≥ vl, there are no body elements, and no elements are updated in any destination vector register group, including that no tail elements are updated with agnostic values. vmsbf.m, vmsif.m, vmsof.m, viota.m, vcompress instructions themselves require vstart to be zero. So they don't need the early exit. Signed-off-by: eop Chen Reviewed-by: Frank Chang Reviewed-by: Weiwei Li Acked-by: Alistair Francis Message-Id: <165449614532.19704.7000832880482980398-4@git.sr.ht> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.c.inc | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 391c61fe93..6750f5d04a 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -652,6 +652,7 @@ static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data, TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); dest = tcg_temp_new_ptr(); mask = tcg_temp_new_ptr(); @@ -818,6 +819,7 @@ static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2, TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); dest = tcg_temp_new_ptr(); mask = tcg_temp_new_ptr(); @@ -925,6 +927,7 @@ static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); dest = tcg_temp_new_ptr(); mask = tcg_temp_new_ptr(); @@ -1067,6 +1070,7 @@ static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data, TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); dest = tcg_temp_new_ptr(); mask = tcg_temp_new_ptr(); @@ -1225,6 +1229,7 @@ do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn, } tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); if (a->vm && s->vl_eq_vlmax) { gvec_fn(s->sew, vreg_ofs(s, a->rd), @@ -1272,6 +1277,7 @@ static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm, TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); dest = tcg_temp_new_ptr(); mask = tcg_temp_new_ptr(); @@ -1436,6 +1442,7 @@ static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm, TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); dest = tcg_temp_new_ptr(); mask = tcg_temp_new_ptr(); @@ -1522,6 +1529,7 @@ static bool do_opivv_widen(DisasContext *s, arg_rmrr *a, uint32_t data = 0; TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); @@ -1602,6 +1610,7 @@ static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a, uint32_t data = 0; TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); @@ -1679,6 +1688,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ }; \ TCGLabel *over = gen_new_label(); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ @@ -1860,6 +1870,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ }; \ TCGLabel *over = gen_new_label(); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ @@ -2070,6 +2081,7 @@ static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a) }; TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), cpu_env, s->cfg_ptr->vlen / 8, @@ -2093,6 +2105,7 @@ static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a) TCGv s1; TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); s1 = get_gpr(s, a->rs1, EXT_SIGN); @@ -2148,6 +2161,7 @@ static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a) }; TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); s1 = tcg_constant_i64(simm); dest = tcg_temp_new_ptr(); @@ -2300,6 +2314,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ TCGLabel *over = gen_new_label(); \ gen_set_rm(s, RISCV_FRM_DYN); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ @@ -2330,6 +2345,7 @@ static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); dest = tcg_temp_new_ptr(); mask = tcg_temp_new_ptr(); @@ -2418,6 +2434,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ TCGLabel *over = gen_new_label(); \ gen_set_rm(s, RISCV_FRM_DYN); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);\ \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ @@ -2492,6 +2509,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ TCGLabel *over = gen_new_label(); \ gen_set_rm(s, RISCV_FRM_DYN); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ @@ -2613,6 +2631,7 @@ static bool do_opfv(DisasContext *s, arg_rmr *a, TCGLabel *over = gen_new_label(); gen_set_rm(s, rm); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); @@ -2726,6 +2745,7 @@ static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) }; TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); t1 = tcg_temp_new_i64(); /* NaN-box f[rs1] */ @@ -2814,6 +2834,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ TCGLabel *over = gen_new_label(); \ gen_set_rm(s, FRM); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ @@ -2865,6 +2886,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ TCGLabel *over = gen_new_label(); \ gen_set_rm(s, RISCV_FRM_DYN); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ @@ -2930,6 +2952,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ TCGLabel *over = gen_new_label(); \ gen_set_rm(s, FRM); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ @@ -2983,6 +3006,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ TCGLabel *over = gen_new_label(); \ gen_set_rm(s, FRM); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ @@ -3070,6 +3094,7 @@ static bool trans_##NAME(DisasContext *s, arg_r *a) \ gen_helper_gvec_4_ptr *fn = gen_helper_##NAME; \ TCGLabel *over = gen_new_label(); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ @@ -3238,6 +3263,7 @@ static bool trans_vid_v(DisasContext *s, arg_vid_v *a) uint32_t data = 0; TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); @@ -3748,6 +3774,7 @@ static bool int_ext_op(DisasContext *s, arg_rmr *a, uint8_t seq) gen_helper_gvec_3_ptr *fn; TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); static gen_helper_gvec_3_ptr * const fns[6][4] = { { From f1eed927fb3a1212af8e324cf242cf6f4bd6fd04 Mon Sep 17 00:00:00 2001 From: eopXD Date: Mon, 6 Jun 2022 06:16:16 +0000 Subject: [PATCH 922/935] target/riscv: rvv: Add tail agnostic for vv instructions According to v-spec, tail agnostic behavior can be either kept as undisturbed or set elements' bits to all 1s. To distinguish the difference of tail policies, QEMU should be able to simulate the tail agnostic behavior as "set tail elements' bits to all 1s". There are multiple possibility for agnostic elements according to v-spec. The main intent of this patch-set tries to add option that can distinguish between tail policies. Setting agnostic elements to all 1s allows QEMU to express this. This is the first commit regarding the optional tail agnostic behavior. Follow-up commits will add this optional behavior for all rvv instructions. Signed-off-by: eop Chen Reviewed-by: Frank Chang Reviewed-by: Weiwei Li Acked-by: Alistair Francis Message-Id: <165449614532.19704.7000832880482980398-5@git.sr.ht> Signed-off-by: Alistair Francis --- target/riscv/cpu.h | 2 + target/riscv/cpu_helper.c | 2 + target/riscv/insn_trans/trans_rvv.c.inc | 3 +- target/riscv/internals.h | 5 +- target/riscv/translate.c | 2 + target/riscv/vector_helper.c | 296 +++++++++++++----------- 6 files changed, 178 insertions(+), 132 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 194a58d760..7d6397acdf 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -412,6 +412,7 @@ struct RISCVCPUConfig { bool ext_zve32f; bool ext_zve64f; bool ext_zmmul; + bool rvv_ta_all_1s; uint32_t mvendorid; uint64_t marchid; @@ -567,6 +568,7 @@ FIELD(TB_FLAGS, XL, 20, 2) /* If PointerMasking should be applied */ FIELD(TB_FLAGS, PM_MASK_ENABLED, 22, 1) FIELD(TB_FLAGS, PM_BASE_ENABLED, 23, 1) +FIELD(TB_FLAGS, VTA, 24, 1) #ifdef TARGET_RISCV32 #define riscv_cpu_mxl(env) ((void)(env), MXL_RV32) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 16c6045459..4a6700c890 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -65,6 +65,8 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, flags = FIELD_DP32(flags, TB_FLAGS, LMUL, FIELD_EX64(env->vtype, VTYPE, VLMUL)); flags = FIELD_DP32(flags, TB_FLAGS, VL_EQ_VLMAX, vl_eq_vlmax); + flags = FIELD_DP32(flags, TB_FLAGS, VTA, + FIELD_EX64(env->vtype, VTYPE, VTA)); } else { flags = FIELD_DP32(flags, TB_FLAGS, VILL, 1); } diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 6750f5d04a..bf9886a93d 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -1231,7 +1231,7 @@ do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn, tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); - if (a->vm && s->vl_eq_vlmax) { + if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), vreg_ofs(s, a->rs1), MAXSZ(s), MAXSZ(s)); @@ -1240,6 +1240,7 @@ do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn, data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, VTA, s->vta); tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), cpu_env, s->cfg_ptr->vlen / 8, diff --git a/target/riscv/internals.h b/target/riscv/internals.h index dbb322bfa7..512c6c30cf 100644 --- a/target/riscv/internals.h +++ b/target/riscv/internals.h @@ -24,8 +24,9 @@ /* share data between vector helpers and decode code */ FIELD(VDATA, VM, 0, 1) FIELD(VDATA, LMUL, 1, 3) -FIELD(VDATA, NF, 4, 4) -FIELD(VDATA, WD, 4, 1) +FIELD(VDATA, VTA, 4, 1) +FIELD(VDATA, NF, 5, 4) +FIELD(VDATA, WD, 5, 1) /* float point classify helpers */ target_ulong fclass_h(uint64_t frs1); diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 55a4713af2..59f0ee9a50 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -94,6 +94,7 @@ typedef struct DisasContext { */ int8_t lmul; uint8_t sew; + uint8_t vta; target_ulong vstart; bool vl_eq_vlmax; uint8_t ntemp; @@ -1099,6 +1100,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->vill = FIELD_EX32(tb_flags, TB_FLAGS, VILL); ctx->sew = FIELD_EX32(tb_flags, TB_FLAGS, SEW); ctx->lmul = sextract32(FIELD_EX32(tb_flags, TB_FLAGS, LMUL), 0, 3); + ctx->vta = FIELD_EX32(tb_flags, TB_FLAGS, VTA) && cpu->cfg.rvv_ta_all_1s; ctx->vstart = env->vstart; ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX); ctx->misa_mxl_max = env->misa_mxl_max; diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 3b79b9cbc2..e2a2979bad 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -122,6 +122,11 @@ static inline int32_t vext_lmul(uint32_t desc) return sextract32(FIELD_EX32(simd_data(desc), VDATA, LMUL), 0, 3); } +static inline uint32_t vext_vta(uint32_t desc) +{ + return FIELD_EX32(simd_data(desc), VDATA, VTA); +} + /* * Get the maximum number of elements can be operated. * @@ -140,6 +145,21 @@ static inline uint32_t vext_max_elems(uint32_t desc, uint32_t log2_esz) return scale < 0 ? vlenb >> -scale : vlenb << scale; } +/* + * Get number of total elements, including prestart, body and tail elements. + * Note that when LMUL < 1, the tail includes the elements past VLMAX that + * are held in the same vector register. + */ +static inline uint32_t vext_get_total_elems(CPURISCVState *env, uint32_t desc, + uint32_t esz) +{ + uint32_t vlenb = simd_maxsz(desc); + uint32_t sew = 1 << FIELD_EX64(env->vtype, VTYPE, VSEW); + int8_t emul = ctzl(esz) - ctzl(sew) + vext_lmul(desc) < 0 ? 0 : + ctzl(esz) - ctzl(sew) + vext_lmul(desc); + return (vlenb << emul) / esz; +} + static inline target_ulong adjust_addr(CPURISCVState *env, target_ulong addr) { return (addr & env->cur_pmmask) | env->cur_pmbase; @@ -172,6 +192,20 @@ static void probe_pages(CPURISCVState *env, target_ulong addr, } } +/* set agnostic elements to 1s */ +static void vext_set_elems_1s(void *base, uint32_t is_agnostic, uint32_t cnt, + uint32_t tot) +{ + if (is_agnostic == 0) { + /* policy undisturbed */ + return; + } + if (tot - cnt == 0) { + return ; + } + memset(base + cnt, -1, tot - cnt); +} + static inline void vext_set_elem_mask(void *v0, int index, uint8_t value) { @@ -707,10 +741,12 @@ RVVCALL(OPIVV2, vsub_vv_d, OP_SSS_D, H8, H8, H8, DO_SUB) static void do_vext_vv(void *vd, void *v0, void *vs1, void *vs2, CPURISCVState *env, uint32_t desc, - opivv2_fn *fn) + opivv2_fn *fn, uint32_t esz) { uint32_t vm = vext_vm(desc); uint32_t vl = env->vl; + uint32_t total_elems = vext_get_total_elems(env, desc, esz); + uint32_t vta = vext_vta(desc); uint32_t i; for (i = env->vstart; i < vl; i++) { @@ -720,26 +756,28 @@ static void do_vext_vv(void *vd, void *v0, void *vs1, void *vs2, fn(vd, vs1, vs2, i); } env->vstart = 0; + /* set tail elements to 1s */ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); } /* generate the helpers for OPIVV */ -#define GEN_VEXT_VV(NAME) \ +#define GEN_VEXT_VV(NAME, ESZ) \ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ void *vs2, CPURISCVState *env, \ uint32_t desc) \ { \ do_vext_vv(vd, v0, vs1, vs2, env, desc, \ - do_##NAME); \ + do_##NAME, ESZ); \ } -GEN_VEXT_VV(vadd_vv_b) -GEN_VEXT_VV(vadd_vv_h) -GEN_VEXT_VV(vadd_vv_w) -GEN_VEXT_VV(vadd_vv_d) -GEN_VEXT_VV(vsub_vv_b) -GEN_VEXT_VV(vsub_vv_h) -GEN_VEXT_VV(vsub_vv_w) -GEN_VEXT_VV(vsub_vv_d) +GEN_VEXT_VV(vadd_vv_b, 1) +GEN_VEXT_VV(vadd_vv_h, 2) +GEN_VEXT_VV(vadd_vv_w, 4) +GEN_VEXT_VV(vadd_vv_d, 8) +GEN_VEXT_VV(vsub_vv_b, 1) +GEN_VEXT_VV(vsub_vv_h, 2) +GEN_VEXT_VV(vsub_vv_w, 4) +GEN_VEXT_VV(vsub_vv_d, 8) typedef void opivx2_fn(void *vd, target_long s1, void *vs2, int i); @@ -884,30 +922,30 @@ RVVCALL(OPIVV2, vwadd_wv_w, WOP_WSSS_W, H8, H4, H4, DO_ADD) RVVCALL(OPIVV2, vwsub_wv_b, WOP_WSSS_B, H2, H1, H1, DO_SUB) RVVCALL(OPIVV2, vwsub_wv_h, WOP_WSSS_H, H4, H2, H2, DO_SUB) RVVCALL(OPIVV2, vwsub_wv_w, WOP_WSSS_W, H8, H4, H4, DO_SUB) -GEN_VEXT_VV(vwaddu_vv_b) -GEN_VEXT_VV(vwaddu_vv_h) -GEN_VEXT_VV(vwaddu_vv_w) -GEN_VEXT_VV(vwsubu_vv_b) -GEN_VEXT_VV(vwsubu_vv_h) -GEN_VEXT_VV(vwsubu_vv_w) -GEN_VEXT_VV(vwadd_vv_b) -GEN_VEXT_VV(vwadd_vv_h) -GEN_VEXT_VV(vwadd_vv_w) -GEN_VEXT_VV(vwsub_vv_b) -GEN_VEXT_VV(vwsub_vv_h) -GEN_VEXT_VV(vwsub_vv_w) -GEN_VEXT_VV(vwaddu_wv_b) -GEN_VEXT_VV(vwaddu_wv_h) -GEN_VEXT_VV(vwaddu_wv_w) -GEN_VEXT_VV(vwsubu_wv_b) -GEN_VEXT_VV(vwsubu_wv_h) -GEN_VEXT_VV(vwsubu_wv_w) -GEN_VEXT_VV(vwadd_wv_b) -GEN_VEXT_VV(vwadd_wv_h) -GEN_VEXT_VV(vwadd_wv_w) -GEN_VEXT_VV(vwsub_wv_b) -GEN_VEXT_VV(vwsub_wv_h) -GEN_VEXT_VV(vwsub_wv_w) +GEN_VEXT_VV(vwaddu_vv_b, 2) +GEN_VEXT_VV(vwaddu_vv_h, 4) +GEN_VEXT_VV(vwaddu_vv_w, 8) +GEN_VEXT_VV(vwsubu_vv_b, 2) +GEN_VEXT_VV(vwsubu_vv_h, 4) +GEN_VEXT_VV(vwsubu_vv_w, 8) +GEN_VEXT_VV(vwadd_vv_b, 2) +GEN_VEXT_VV(vwadd_vv_h, 4) +GEN_VEXT_VV(vwadd_vv_w, 8) +GEN_VEXT_VV(vwsub_vv_b, 2) +GEN_VEXT_VV(vwsub_vv_h, 4) +GEN_VEXT_VV(vwsub_vv_w, 8) +GEN_VEXT_VV(vwaddu_wv_b, 2) +GEN_VEXT_VV(vwaddu_wv_h, 4) +GEN_VEXT_VV(vwaddu_wv_w, 8) +GEN_VEXT_VV(vwsubu_wv_b, 2) +GEN_VEXT_VV(vwsubu_wv_h, 4) +GEN_VEXT_VV(vwsubu_wv_w, 8) +GEN_VEXT_VV(vwadd_wv_b, 2) +GEN_VEXT_VV(vwadd_wv_h, 4) +GEN_VEXT_VV(vwadd_wv_w, 8) +GEN_VEXT_VV(vwsub_wv_b, 2) +GEN_VEXT_VV(vwsub_wv_h, 4) +GEN_VEXT_VV(vwsub_wv_w, 8) RVVCALL(OPIVX2, vwaddu_vx_b, WOP_UUU_B, H2, H1, DO_ADD) RVVCALL(OPIVX2, vwaddu_vx_h, WOP_UUU_H, H4, H2, DO_ADD) @@ -1086,18 +1124,18 @@ RVVCALL(OPIVV2, vxor_vv_b, OP_SSS_B, H1, H1, H1, DO_XOR) RVVCALL(OPIVV2, vxor_vv_h, OP_SSS_H, H2, H2, H2, DO_XOR) RVVCALL(OPIVV2, vxor_vv_w, OP_SSS_W, H4, H4, H4, DO_XOR) RVVCALL(OPIVV2, vxor_vv_d, OP_SSS_D, H8, H8, H8, DO_XOR) -GEN_VEXT_VV(vand_vv_b) -GEN_VEXT_VV(vand_vv_h) -GEN_VEXT_VV(vand_vv_w) -GEN_VEXT_VV(vand_vv_d) -GEN_VEXT_VV(vor_vv_b) -GEN_VEXT_VV(vor_vv_h) -GEN_VEXT_VV(vor_vv_w) -GEN_VEXT_VV(vor_vv_d) -GEN_VEXT_VV(vxor_vv_b) -GEN_VEXT_VV(vxor_vv_h) -GEN_VEXT_VV(vxor_vv_w) -GEN_VEXT_VV(vxor_vv_d) +GEN_VEXT_VV(vand_vv_b, 1) +GEN_VEXT_VV(vand_vv_h, 2) +GEN_VEXT_VV(vand_vv_w, 4) +GEN_VEXT_VV(vand_vv_d, 8) +GEN_VEXT_VV(vor_vv_b, 1) +GEN_VEXT_VV(vor_vv_h, 2) +GEN_VEXT_VV(vor_vv_w, 4) +GEN_VEXT_VV(vor_vv_d, 8) +GEN_VEXT_VV(vxor_vv_b, 1) +GEN_VEXT_VV(vxor_vv_h, 2) +GEN_VEXT_VV(vxor_vv_w, 4) +GEN_VEXT_VV(vxor_vv_d, 8) RVVCALL(OPIVX2, vand_vx_b, OP_SSS_B, H1, H1, DO_AND) RVVCALL(OPIVX2, vand_vx_h, OP_SSS_H, H2, H2, DO_AND) @@ -1343,22 +1381,22 @@ RVVCALL(OPIVV2, vmax_vv_b, OP_SSS_B, H1, H1, H1, DO_MAX) RVVCALL(OPIVV2, vmax_vv_h, OP_SSS_H, H2, H2, H2, DO_MAX) RVVCALL(OPIVV2, vmax_vv_w, OP_SSS_W, H4, H4, H4, DO_MAX) RVVCALL(OPIVV2, vmax_vv_d, OP_SSS_D, H8, H8, H8, DO_MAX) -GEN_VEXT_VV(vminu_vv_b) -GEN_VEXT_VV(vminu_vv_h) -GEN_VEXT_VV(vminu_vv_w) -GEN_VEXT_VV(vminu_vv_d) -GEN_VEXT_VV(vmin_vv_b) -GEN_VEXT_VV(vmin_vv_h) -GEN_VEXT_VV(vmin_vv_w) -GEN_VEXT_VV(vmin_vv_d) -GEN_VEXT_VV(vmaxu_vv_b) -GEN_VEXT_VV(vmaxu_vv_h) -GEN_VEXT_VV(vmaxu_vv_w) -GEN_VEXT_VV(vmaxu_vv_d) -GEN_VEXT_VV(vmax_vv_b) -GEN_VEXT_VV(vmax_vv_h) -GEN_VEXT_VV(vmax_vv_w) -GEN_VEXT_VV(vmax_vv_d) +GEN_VEXT_VV(vminu_vv_b, 1) +GEN_VEXT_VV(vminu_vv_h, 2) +GEN_VEXT_VV(vminu_vv_w, 4) +GEN_VEXT_VV(vminu_vv_d, 8) +GEN_VEXT_VV(vmin_vv_b, 1) +GEN_VEXT_VV(vmin_vv_h, 2) +GEN_VEXT_VV(vmin_vv_w, 4) +GEN_VEXT_VV(vmin_vv_d, 8) +GEN_VEXT_VV(vmaxu_vv_b, 1) +GEN_VEXT_VV(vmaxu_vv_h, 2) +GEN_VEXT_VV(vmaxu_vv_w, 4) +GEN_VEXT_VV(vmaxu_vv_d, 8) +GEN_VEXT_VV(vmax_vv_b, 1) +GEN_VEXT_VV(vmax_vv_h, 2) +GEN_VEXT_VV(vmax_vv_w, 4) +GEN_VEXT_VV(vmax_vv_d, 8) RVVCALL(OPIVX2, vminu_vx_b, OP_UUU_B, H1, H1, DO_MIN) RVVCALL(OPIVX2, vminu_vx_h, OP_UUU_H, H2, H2, DO_MIN) @@ -1399,10 +1437,10 @@ RVVCALL(OPIVV2, vmul_vv_b, OP_SSS_B, H1, H1, H1, DO_MUL) RVVCALL(OPIVV2, vmul_vv_h, OP_SSS_H, H2, H2, H2, DO_MUL) RVVCALL(OPIVV2, vmul_vv_w, OP_SSS_W, H4, H4, H4, DO_MUL) RVVCALL(OPIVV2, vmul_vv_d, OP_SSS_D, H8, H8, H8, DO_MUL) -GEN_VEXT_VV(vmul_vv_b) -GEN_VEXT_VV(vmul_vv_h) -GEN_VEXT_VV(vmul_vv_w) -GEN_VEXT_VV(vmul_vv_d) +GEN_VEXT_VV(vmul_vv_b, 1) +GEN_VEXT_VV(vmul_vv_h, 2) +GEN_VEXT_VV(vmul_vv_w, 4) +GEN_VEXT_VV(vmul_vv_d, 8) static int8_t do_mulh_b(int8_t s2, int8_t s1) { @@ -1506,18 +1544,18 @@ RVVCALL(OPIVV2, vmulhsu_vv_b, OP_SUS_B, H1, H1, H1, do_mulhsu_b) RVVCALL(OPIVV2, vmulhsu_vv_h, OP_SUS_H, H2, H2, H2, do_mulhsu_h) RVVCALL(OPIVV2, vmulhsu_vv_w, OP_SUS_W, H4, H4, H4, do_mulhsu_w) RVVCALL(OPIVV2, vmulhsu_vv_d, OP_SUS_D, H8, H8, H8, do_mulhsu_d) -GEN_VEXT_VV(vmulh_vv_b) -GEN_VEXT_VV(vmulh_vv_h) -GEN_VEXT_VV(vmulh_vv_w) -GEN_VEXT_VV(vmulh_vv_d) -GEN_VEXT_VV(vmulhu_vv_b) -GEN_VEXT_VV(vmulhu_vv_h) -GEN_VEXT_VV(vmulhu_vv_w) -GEN_VEXT_VV(vmulhu_vv_d) -GEN_VEXT_VV(vmulhsu_vv_b) -GEN_VEXT_VV(vmulhsu_vv_h) -GEN_VEXT_VV(vmulhsu_vv_w) -GEN_VEXT_VV(vmulhsu_vv_d) +GEN_VEXT_VV(vmulh_vv_b, 1) +GEN_VEXT_VV(vmulh_vv_h, 2) +GEN_VEXT_VV(vmulh_vv_w, 4) +GEN_VEXT_VV(vmulh_vv_d, 8) +GEN_VEXT_VV(vmulhu_vv_b, 1) +GEN_VEXT_VV(vmulhu_vv_h, 2) +GEN_VEXT_VV(vmulhu_vv_w, 4) +GEN_VEXT_VV(vmulhu_vv_d, 8) +GEN_VEXT_VV(vmulhsu_vv_b, 1) +GEN_VEXT_VV(vmulhsu_vv_h, 2) +GEN_VEXT_VV(vmulhsu_vv_w, 4) +GEN_VEXT_VV(vmulhsu_vv_d, 8) RVVCALL(OPIVX2, vmul_vx_b, OP_SSS_B, H1, H1, DO_MUL) RVVCALL(OPIVX2, vmul_vx_h, OP_SSS_H, H2, H2, DO_MUL) @@ -1576,22 +1614,22 @@ RVVCALL(OPIVV2, vrem_vv_b, OP_SSS_B, H1, H1, H1, DO_REM) RVVCALL(OPIVV2, vrem_vv_h, OP_SSS_H, H2, H2, H2, DO_REM) RVVCALL(OPIVV2, vrem_vv_w, OP_SSS_W, H4, H4, H4, DO_REM) RVVCALL(OPIVV2, vrem_vv_d, OP_SSS_D, H8, H8, H8, DO_REM) -GEN_VEXT_VV(vdivu_vv_b) -GEN_VEXT_VV(vdivu_vv_h) -GEN_VEXT_VV(vdivu_vv_w) -GEN_VEXT_VV(vdivu_vv_d) -GEN_VEXT_VV(vdiv_vv_b) -GEN_VEXT_VV(vdiv_vv_h) -GEN_VEXT_VV(vdiv_vv_w) -GEN_VEXT_VV(vdiv_vv_d) -GEN_VEXT_VV(vremu_vv_b) -GEN_VEXT_VV(vremu_vv_h) -GEN_VEXT_VV(vremu_vv_w) -GEN_VEXT_VV(vremu_vv_d) -GEN_VEXT_VV(vrem_vv_b) -GEN_VEXT_VV(vrem_vv_h) -GEN_VEXT_VV(vrem_vv_w) -GEN_VEXT_VV(vrem_vv_d) +GEN_VEXT_VV(vdivu_vv_b, 1) +GEN_VEXT_VV(vdivu_vv_h, 2) +GEN_VEXT_VV(vdivu_vv_w, 4) +GEN_VEXT_VV(vdivu_vv_d, 8) +GEN_VEXT_VV(vdiv_vv_b, 1) +GEN_VEXT_VV(vdiv_vv_h, 2) +GEN_VEXT_VV(vdiv_vv_w, 4) +GEN_VEXT_VV(vdiv_vv_d, 8) +GEN_VEXT_VV(vremu_vv_b, 1) +GEN_VEXT_VV(vremu_vv_h, 2) +GEN_VEXT_VV(vremu_vv_w, 4) +GEN_VEXT_VV(vremu_vv_d, 8) +GEN_VEXT_VV(vrem_vv_b, 1) +GEN_VEXT_VV(vrem_vv_h, 2) +GEN_VEXT_VV(vrem_vv_w, 4) +GEN_VEXT_VV(vrem_vv_d, 8) RVVCALL(OPIVX2, vdivu_vx_b, OP_UUU_B, H1, H1, DO_DIVU) RVVCALL(OPIVX2, vdivu_vx_h, OP_UUU_H, H2, H2, DO_DIVU) @@ -1636,15 +1674,15 @@ RVVCALL(OPIVV2, vwmulu_vv_w, WOP_UUU_W, H8, H4, H4, DO_MUL) RVVCALL(OPIVV2, vwmulsu_vv_b, WOP_SUS_B, H2, H1, H1, DO_MUL) RVVCALL(OPIVV2, vwmulsu_vv_h, WOP_SUS_H, H4, H2, H2, DO_MUL) RVVCALL(OPIVV2, vwmulsu_vv_w, WOP_SUS_W, H8, H4, H4, DO_MUL) -GEN_VEXT_VV(vwmul_vv_b) -GEN_VEXT_VV(vwmul_vv_h) -GEN_VEXT_VV(vwmul_vv_w) -GEN_VEXT_VV(vwmulu_vv_b) -GEN_VEXT_VV(vwmulu_vv_h) -GEN_VEXT_VV(vwmulu_vv_w) -GEN_VEXT_VV(vwmulsu_vv_b) -GEN_VEXT_VV(vwmulsu_vv_h) -GEN_VEXT_VV(vwmulsu_vv_w) +GEN_VEXT_VV(vwmul_vv_b, 2) +GEN_VEXT_VV(vwmul_vv_h, 4) +GEN_VEXT_VV(vwmul_vv_w, 8) +GEN_VEXT_VV(vwmulu_vv_b, 2) +GEN_VEXT_VV(vwmulu_vv_h, 4) +GEN_VEXT_VV(vwmulu_vv_w, 8) +GEN_VEXT_VV(vwmulsu_vv_b, 2) +GEN_VEXT_VV(vwmulsu_vv_h, 4) +GEN_VEXT_VV(vwmulsu_vv_w, 8) RVVCALL(OPIVX2, vwmul_vx_b, WOP_SSS_B, H2, H1, DO_MUL) RVVCALL(OPIVX2, vwmul_vx_h, WOP_SSS_H, H4, H2, DO_MUL) @@ -1695,22 +1733,22 @@ RVVCALL(OPIVV3, vnmsub_vv_b, OP_SSS_B, H1, H1, H1, DO_NMSUB) RVVCALL(OPIVV3, vnmsub_vv_h, OP_SSS_H, H2, H2, H2, DO_NMSUB) RVVCALL(OPIVV3, vnmsub_vv_w, OP_SSS_W, H4, H4, H4, DO_NMSUB) RVVCALL(OPIVV3, vnmsub_vv_d, OP_SSS_D, H8, H8, H8, DO_NMSUB) -GEN_VEXT_VV(vmacc_vv_b) -GEN_VEXT_VV(vmacc_vv_h) -GEN_VEXT_VV(vmacc_vv_w) -GEN_VEXT_VV(vmacc_vv_d) -GEN_VEXT_VV(vnmsac_vv_b) -GEN_VEXT_VV(vnmsac_vv_h) -GEN_VEXT_VV(vnmsac_vv_w) -GEN_VEXT_VV(vnmsac_vv_d) -GEN_VEXT_VV(vmadd_vv_b) -GEN_VEXT_VV(vmadd_vv_h) -GEN_VEXT_VV(vmadd_vv_w) -GEN_VEXT_VV(vmadd_vv_d) -GEN_VEXT_VV(vnmsub_vv_b) -GEN_VEXT_VV(vnmsub_vv_h) -GEN_VEXT_VV(vnmsub_vv_w) -GEN_VEXT_VV(vnmsub_vv_d) +GEN_VEXT_VV(vmacc_vv_b, 1) +GEN_VEXT_VV(vmacc_vv_h, 2) +GEN_VEXT_VV(vmacc_vv_w, 4) +GEN_VEXT_VV(vmacc_vv_d, 8) +GEN_VEXT_VV(vnmsac_vv_b, 1) +GEN_VEXT_VV(vnmsac_vv_h, 2) +GEN_VEXT_VV(vnmsac_vv_w, 4) +GEN_VEXT_VV(vnmsac_vv_d, 8) +GEN_VEXT_VV(vmadd_vv_b, 1) +GEN_VEXT_VV(vmadd_vv_h, 2) +GEN_VEXT_VV(vmadd_vv_w, 4) +GEN_VEXT_VV(vmadd_vv_d, 8) +GEN_VEXT_VV(vnmsub_vv_b, 1) +GEN_VEXT_VV(vnmsub_vv_h, 2) +GEN_VEXT_VV(vnmsub_vv_w, 4) +GEN_VEXT_VV(vnmsub_vv_d, 8) #define OPIVX3(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \ static void do_##NAME(void *vd, target_long s1, void *vs2, int i) \ @@ -1763,15 +1801,15 @@ RVVCALL(OPIVV3, vwmacc_vv_w, WOP_SSS_W, H8, H4, H4, DO_MACC) RVVCALL(OPIVV3, vwmaccsu_vv_b, WOP_SSU_B, H2, H1, H1, DO_MACC) RVVCALL(OPIVV3, vwmaccsu_vv_h, WOP_SSU_H, H4, H2, H2, DO_MACC) RVVCALL(OPIVV3, vwmaccsu_vv_w, WOP_SSU_W, H8, H4, H4, DO_MACC) -GEN_VEXT_VV(vwmaccu_vv_b) -GEN_VEXT_VV(vwmaccu_vv_h) -GEN_VEXT_VV(vwmaccu_vv_w) -GEN_VEXT_VV(vwmacc_vv_b) -GEN_VEXT_VV(vwmacc_vv_h) -GEN_VEXT_VV(vwmacc_vv_w) -GEN_VEXT_VV(vwmaccsu_vv_b) -GEN_VEXT_VV(vwmaccsu_vv_h) -GEN_VEXT_VV(vwmaccsu_vv_w) +GEN_VEXT_VV(vwmaccu_vv_b, 2) +GEN_VEXT_VV(vwmaccu_vv_h, 4) +GEN_VEXT_VV(vwmaccu_vv_w, 8) +GEN_VEXT_VV(vwmacc_vv_b, 2) +GEN_VEXT_VV(vwmacc_vv_h, 4) +GEN_VEXT_VV(vwmacc_vv_w, 8) +GEN_VEXT_VV(vwmaccsu_vv_b, 2) +GEN_VEXT_VV(vwmaccsu_vv_h, 4) +GEN_VEXT_VV(vwmaccsu_vv_w, 8) RVVCALL(OPIVX3, vwmaccu_vx_b, WOP_UUU_B, H2, H1, DO_MACC) RVVCALL(OPIVX3, vwmaccu_vx_h, WOP_UUU_H, H4, H2, DO_MACC) From 752614cab8e61bb6ba96cee1ec127eba6c35398e Mon Sep 17 00:00:00 2001 From: eopXD Date: Mon, 6 Jun 2022 06:16:16 +0000 Subject: [PATCH 923/935] target/riscv: rvv: Add tail agnostic for vector load / store instructions Destination register of unit-stride mask load and store instructions are always written with a tail-agnostic policy. A vector segment load / store instruction may contain fractional lmul with nf * lmul > 1. The rest of the elements in the last register should be treated as tail elements. Signed-off-by: eop Chen Reviewed-by: Frank Chang Reviewed-by: Weiwei Li Acked-by: Alistair Francis Message-Id: <165449614532.19704.7000832880482980398-6@git.sr.ht> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.c.inc | 6 +++ target/riscv/translate.c | 2 + target/riscv/vector_helper.c | 60 +++++++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index bf9886a93d..cd73fd6119 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -711,6 +711,7 @@ static bool ld_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew) data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, emul); data = FIELD_DP32(data, VDATA, NF, a->nf); + data = FIELD_DP32(data, VDATA, VTA, s->vta); return ldst_us_trans(a->rd, a->rs1, data, fn, s, false); } @@ -774,6 +775,8 @@ static bool ld_us_mask_op(DisasContext *s, arg_vlm_v *a, uint8_t eew) /* EMUL = 1, NFIELDS = 1 */ data = FIELD_DP32(data, VDATA, LMUL, 0); data = FIELD_DP32(data, VDATA, NF, 1); + /* Mask destination register are always tail-agnostic */ + data = FIELD_DP32(data, VDATA, VTA, s->cfg_vta_all_1s); return ldst_us_trans(a->rd, a->rs1, data, fn, s, false); } @@ -862,6 +865,7 @@ static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, emul); data = FIELD_DP32(data, VDATA, NF, a->nf); + data = FIELD_DP32(data, VDATA, VTA, s->vta); return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s, false); } @@ -991,6 +995,7 @@ static bool ld_index_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, emul); data = FIELD_DP32(data, VDATA, NF, a->nf); + data = FIELD_DP32(data, VDATA, VTA, s->vta); return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s, false); } @@ -1108,6 +1113,7 @@ static bool ldff_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew) data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, emul); data = FIELD_DP32(data, VDATA, NF, a->nf); + data = FIELD_DP32(data, VDATA, VTA, s->vta); return ldff_trans(a->rd, a->rs1, data, fn, s); } diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 59f0ee9a50..b151c20674 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -95,6 +95,7 @@ typedef struct DisasContext { int8_t lmul; uint8_t sew; uint8_t vta; + bool cfg_vta_all_1s; target_ulong vstart; bool vl_eq_vlmax; uint8_t ntemp; @@ -1101,6 +1102,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->sew = FIELD_EX32(tb_flags, TB_FLAGS, SEW); ctx->lmul = sextract32(FIELD_EX32(tb_flags, TB_FLAGS, LMUL), 0, 3); ctx->vta = FIELD_EX32(tb_flags, TB_FLAGS, VTA) && cpu->cfg.rvv_ta_all_1s; + ctx->cfg_vta_all_1s = cpu->cfg.rvv_ta_all_1s; ctx->vstart = env->vstart; ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX); ctx->misa_mxl_max = env->misa_mxl_max; diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index e2a2979bad..ee28e1b92d 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -270,6 +270,9 @@ vext_ldst_stride(void *vd, void *v0, target_ulong base, uint32_t i, k; uint32_t nf = vext_nf(desc); uint32_t max_elems = vext_max_elems(desc, log2_esz); + uint32_t esz = 1 << log2_esz; + uint32_t total_elems = vext_get_total_elems(env, desc, esz); + uint32_t vta = vext_vta(desc); for (i = env->vstart; i < env->vl; i++, env->vstart++) { if (!vm && !vext_elem_mask(v0, i)) { @@ -284,6 +287,18 @@ vext_ldst_stride(void *vd, void *v0, target_ulong base, } } env->vstart = 0; + /* set tail elements to 1s */ + for (k = 0; k < nf; ++k) { + vext_set_elems_1s(vd, vta, (k * max_elems + env->vl) * esz, + (k * max_elems + max_elems) * esz); + } + if (nf * max_elems % total_elems != 0) { + uint32_t vlenb = env_archcpu(env)->cfg.vlen >> 3; + uint32_t registers_used = + ((nf * max_elems) * esz + (vlenb - 1)) / vlenb; + vext_set_elems_1s(vd, vta, (nf * max_elems) * esz, + registers_used * vlenb); + } } #define GEN_VEXT_LD_STRIDE(NAME, ETYPE, LOAD_FN) \ @@ -329,6 +344,9 @@ vext_ldst_us(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, uint32_t i, k; uint32_t nf = vext_nf(desc); uint32_t max_elems = vext_max_elems(desc, log2_esz); + uint32_t esz = 1 << log2_esz; + uint32_t total_elems = vext_get_total_elems(env, desc, esz); + uint32_t vta = vext_vta(desc); /* load bytes from guest memory */ for (i = env->vstart; i < evl; i++, env->vstart++) { @@ -340,6 +358,18 @@ vext_ldst_us(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, } } env->vstart = 0; + /* set tail elements to 1s */ + for (k = 0; k < nf; ++k) { + vext_set_elems_1s(vd, vta, (k * max_elems + evl) * esz, + (k * max_elems + max_elems) * esz); + } + if (nf * max_elems % total_elems != 0) { + uint32_t vlenb = env_archcpu(env)->cfg.vlen >> 3; + uint32_t registers_used = + ((nf * max_elems) * esz + (vlenb - 1)) / vlenb; + vext_set_elems_1s(vd, vta, (nf * max_elems) * esz, + registers_used * vlenb); + } } /* @@ -439,6 +469,9 @@ vext_ldst_index(void *vd, void *v0, target_ulong base, uint32_t nf = vext_nf(desc); uint32_t vm = vext_vm(desc); uint32_t max_elems = vext_max_elems(desc, log2_esz); + uint32_t esz = 1 << log2_esz; + uint32_t total_elems = vext_get_total_elems(env, desc, esz); + uint32_t vta = vext_vta(desc); /* load bytes from guest memory */ for (i = env->vstart; i < env->vl; i++, env->vstart++) { @@ -454,6 +487,18 @@ vext_ldst_index(void *vd, void *v0, target_ulong base, } } env->vstart = 0; + /* set tail elements to 1s */ + for (k = 0; k < nf; ++k) { + vext_set_elems_1s(vd, vta, (k * max_elems + env->vl) * esz, + (k * max_elems + max_elems) * esz); + } + if (nf * max_elems % total_elems != 0) { + uint32_t vlenb = env_archcpu(env)->cfg.vlen >> 3; + uint32_t registers_used = + ((nf * max_elems) * esz + (vlenb - 1)) / vlenb; + vext_set_elems_1s(vd, vta, (nf * max_elems) * esz, + registers_used * vlenb); + } } #define GEN_VEXT_LD_INDEX(NAME, ETYPE, INDEX_FN, LOAD_FN) \ @@ -521,6 +566,9 @@ vext_ldff(void *vd, void *v0, target_ulong base, uint32_t nf = vext_nf(desc); uint32_t vm = vext_vm(desc); uint32_t max_elems = vext_max_elems(desc, log2_esz); + uint32_t esz = 1 << log2_esz; + uint32_t total_elems = vext_get_total_elems(env, desc, esz); + uint32_t vta = vext_vta(desc); target_ulong addr, offset, remain; /* probe every access*/ @@ -576,6 +624,18 @@ ProbeSuccess: } } env->vstart = 0; + /* set tail elements to 1s */ + for (k = 0; k < nf; ++k) { + vext_set_elems_1s(vd, vta, (k * max_elems + env->vl) * esz, + (k * max_elems + max_elems) * esz); + } + if (nf * max_elems % total_elems != 0) { + uint32_t vlenb = env_archcpu(env)->cfg.vlen >> 3; + uint32_t registers_used = + ((nf * max_elems) * esz + (vlenb - 1)) / vlenb; + vext_set_elems_1s(vd, vta, (nf * max_elems) * esz, + registers_used * vlenb); + } } #define GEN_VEXT_LDFF(NAME, ETYPE, LOAD_FN) \ From 5c19fc156e5cea2516085c487eb72cdb331c54b6 Mon Sep 17 00:00:00 2001 From: eopXD Date: Mon, 6 Jun 2022 06:16:38 +0000 Subject: [PATCH 924/935] target/riscv: rvv: Add tail agnostic for vx, vvm, vxm instructions `vmadc` and `vmsbc` produces a mask value, they always operate with a tail agnostic policy. Signed-off-by: eop Chen Reviewed-by: Frank Chang Reviewed-by: Weiwei Li Acked-by: Alistair Francis Message-Id: <165449614532.19704.7000832880482980398-7@git.sr.ht> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.c.inc | 13 +- target/riscv/internals.h | 5 +- target/riscv/vector_helper.c | 310 +++++++++++++----------- 3 files changed, 188 insertions(+), 140 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index cd73fd6119..22edf6228d 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -1293,6 +1293,8 @@ static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm, data = FIELD_DP32(data, VDATA, VM, vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, VTA, s->vta); + data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s); desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); @@ -1328,7 +1330,7 @@ do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn, return false; } - if (a->vm && s->vl_eq_vlmax) { + if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { TCGv_i64 src1 = tcg_temp_new_i64(); tcg_gen_ext_tl_i64(src1, get_gpr(s, a->rs1, EXT_SIGN)); @@ -1458,6 +1460,8 @@ static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm, data = FIELD_DP32(data, VDATA, VM, vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, VTA, s->vta); + data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s); desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); @@ -1486,7 +1490,7 @@ do_opivi_gvec(DisasContext *s, arg_rmrr *a, GVecGen2iFn *gvec_fn, return false; } - if (a->vm && s->vl_eq_vlmax) { + if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), extract_imm(s, a->rs1, imm_mode), MAXSZ(s), MAXSZ(s)); mark_vs_dirty(s); @@ -1540,6 +1544,7 @@ static bool do_opivv_widen(DisasContext *s, arg_rmrr *a, data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, VTA, s->vta); tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), @@ -1621,6 +1626,7 @@ static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a, data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, VTA, s->vta); tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), @@ -1699,6 +1705,9 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + data = FIELD_DP32(data, VDATA, VTA, s->vta); \ + data = \ + FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ vreg_ofs(s, a->rs2), cpu_env, \ diff --git a/target/riscv/internals.h b/target/riscv/internals.h index 512c6c30cf..193ce57a6d 100644 --- a/target/riscv/internals.h +++ b/target/riscv/internals.h @@ -25,8 +25,9 @@ FIELD(VDATA, VM, 0, 1) FIELD(VDATA, LMUL, 1, 3) FIELD(VDATA, VTA, 4, 1) -FIELD(VDATA, NF, 5, 4) -FIELD(VDATA, WD, 5, 1) +FIELD(VDATA, VTA_ALL_1S, 5, 1) +FIELD(VDATA, NF, 6, 4) +FIELD(VDATA, WD, 6, 1) /* float point classify helpers */ target_ulong fclass_h(uint64_t frs1); diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index ee28e1b92d..7cdb5d12af 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -127,6 +127,11 @@ static inline uint32_t vext_vta(uint32_t desc) return FIELD_EX32(simd_data(desc), VDATA, VTA); } +static inline uint32_t vext_vta_all_1s(uint32_t desc) +{ + return FIELD_EX32(simd_data(desc), VDATA, VTA_ALL_1S); +} + /* * Get the maximum number of elements can be operated. * @@ -867,10 +872,12 @@ RVVCALL(OPIVX2, vrsub_vx_d, OP_SSS_D, H8, H8, DO_RSUB) static void do_vext_vx(void *vd, void *v0, target_long s1, void *vs2, CPURISCVState *env, uint32_t desc, - opivx2_fn fn) + opivx2_fn fn, uint32_t esz) { uint32_t vm = vext_vm(desc); uint32_t vl = env->vl; + uint32_t total_elems = vext_get_total_elems(env, desc, esz); + uint32_t vta = vext_vta(desc); uint32_t i; for (i = env->vstart; i < vl; i++) { @@ -880,30 +887,32 @@ static void do_vext_vx(void *vd, void *v0, target_long s1, void *vs2, fn(vd, s1, vs2, i); } env->vstart = 0; + /* set tail elements to 1s */ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); } /* generate the helpers for OPIVX */ -#define GEN_VEXT_VX(NAME) \ +#define GEN_VEXT_VX(NAME, ESZ) \ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ void *vs2, CPURISCVState *env, \ uint32_t desc) \ { \ do_vext_vx(vd, v0, s1, vs2, env, desc, \ - do_##NAME); \ + do_##NAME, ESZ); \ } -GEN_VEXT_VX(vadd_vx_b) -GEN_VEXT_VX(vadd_vx_h) -GEN_VEXT_VX(vadd_vx_w) -GEN_VEXT_VX(vadd_vx_d) -GEN_VEXT_VX(vsub_vx_b) -GEN_VEXT_VX(vsub_vx_h) -GEN_VEXT_VX(vsub_vx_w) -GEN_VEXT_VX(vsub_vx_d) -GEN_VEXT_VX(vrsub_vx_b) -GEN_VEXT_VX(vrsub_vx_h) -GEN_VEXT_VX(vrsub_vx_w) -GEN_VEXT_VX(vrsub_vx_d) +GEN_VEXT_VX(vadd_vx_b, 1) +GEN_VEXT_VX(vadd_vx_h, 2) +GEN_VEXT_VX(vadd_vx_w, 4) +GEN_VEXT_VX(vadd_vx_d, 8) +GEN_VEXT_VX(vsub_vx_b, 1) +GEN_VEXT_VX(vsub_vx_h, 2) +GEN_VEXT_VX(vsub_vx_w, 4) +GEN_VEXT_VX(vsub_vx_d, 8) +GEN_VEXT_VX(vrsub_vx_b, 1) +GEN_VEXT_VX(vrsub_vx_h, 2) +GEN_VEXT_VX(vrsub_vx_w, 4) +GEN_VEXT_VX(vrsub_vx_d, 8) void HELPER(vec_rsubs8)(void *d, void *a, uint64_t b, uint32_t desc) { @@ -1031,30 +1040,30 @@ RVVCALL(OPIVX2, vwadd_wx_w, WOP_WSSS_W, H8, H4, DO_ADD) RVVCALL(OPIVX2, vwsub_wx_b, WOP_WSSS_B, H2, H1, DO_SUB) RVVCALL(OPIVX2, vwsub_wx_h, WOP_WSSS_H, H4, H2, DO_SUB) RVVCALL(OPIVX2, vwsub_wx_w, WOP_WSSS_W, H8, H4, DO_SUB) -GEN_VEXT_VX(vwaddu_vx_b) -GEN_VEXT_VX(vwaddu_vx_h) -GEN_VEXT_VX(vwaddu_vx_w) -GEN_VEXT_VX(vwsubu_vx_b) -GEN_VEXT_VX(vwsubu_vx_h) -GEN_VEXT_VX(vwsubu_vx_w) -GEN_VEXT_VX(vwadd_vx_b) -GEN_VEXT_VX(vwadd_vx_h) -GEN_VEXT_VX(vwadd_vx_w) -GEN_VEXT_VX(vwsub_vx_b) -GEN_VEXT_VX(vwsub_vx_h) -GEN_VEXT_VX(vwsub_vx_w) -GEN_VEXT_VX(vwaddu_wx_b) -GEN_VEXT_VX(vwaddu_wx_h) -GEN_VEXT_VX(vwaddu_wx_w) -GEN_VEXT_VX(vwsubu_wx_b) -GEN_VEXT_VX(vwsubu_wx_h) -GEN_VEXT_VX(vwsubu_wx_w) -GEN_VEXT_VX(vwadd_wx_b) -GEN_VEXT_VX(vwadd_wx_h) -GEN_VEXT_VX(vwadd_wx_w) -GEN_VEXT_VX(vwsub_wx_b) -GEN_VEXT_VX(vwsub_wx_h) -GEN_VEXT_VX(vwsub_wx_w) +GEN_VEXT_VX(vwaddu_vx_b, 2) +GEN_VEXT_VX(vwaddu_vx_h, 4) +GEN_VEXT_VX(vwaddu_vx_w, 8) +GEN_VEXT_VX(vwsubu_vx_b, 2) +GEN_VEXT_VX(vwsubu_vx_h, 4) +GEN_VEXT_VX(vwsubu_vx_w, 8) +GEN_VEXT_VX(vwadd_vx_b, 2) +GEN_VEXT_VX(vwadd_vx_h, 4) +GEN_VEXT_VX(vwadd_vx_w, 8) +GEN_VEXT_VX(vwsub_vx_b, 2) +GEN_VEXT_VX(vwsub_vx_h, 4) +GEN_VEXT_VX(vwsub_vx_w, 8) +GEN_VEXT_VX(vwaddu_wx_b, 2) +GEN_VEXT_VX(vwaddu_wx_h, 4) +GEN_VEXT_VX(vwaddu_wx_w, 8) +GEN_VEXT_VX(vwsubu_wx_b, 2) +GEN_VEXT_VX(vwsubu_wx_h, 4) +GEN_VEXT_VX(vwsubu_wx_w, 8) +GEN_VEXT_VX(vwadd_wx_b, 2) +GEN_VEXT_VX(vwadd_wx_h, 4) +GEN_VEXT_VX(vwadd_wx_w, 8) +GEN_VEXT_VX(vwsub_wx_b, 2) +GEN_VEXT_VX(vwsub_wx_h, 4) +GEN_VEXT_VX(vwsub_wx_w, 8) /* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */ #define DO_VADC(N, M, C) (N + M + C) @@ -1065,6 +1074,10 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = \ + vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -1075,6 +1088,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ *((ETYPE *)vd + H(i)) = DO_OP(s2, s1, carry); \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VADC_VVM(vadc_vvm_b, uint8_t, H1, DO_VADC) @@ -1092,6 +1107,9 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -1101,6 +1119,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ *((ETYPE *)vd + H(i)) = DO_OP(s2, (ETYPE)(target_long)s1, carry);\ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VADC_VXM(vadc_vxm_b, uint8_t, H1, DO_VADC) @@ -1123,6 +1143,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ { \ uint32_t vl = env->vl; \ uint32_t vm = vext_vm(desc); \ + uint32_t total_elems = env_archcpu(env)->cfg.vlen; \ + uint32_t vta_all_1s = vext_vta_all_1s(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -1132,6 +1154,13 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ vext_set_elem_mask(vd, i, DO_OP(s2, s1, carry)); \ } \ env->vstart = 0; \ + /* mask destination register are always tail-agnostic */ \ + /* set tail elements to 1s */ \ + if (vta_all_1s) { \ + for (; i < total_elems; i++) { \ + vext_set_elem_mask(vd, i, 1); \ + } \ + } \ } GEN_VEXT_VMADC_VVM(vmadc_vvm_b, uint8_t, H1, DO_MADC) @@ -1150,6 +1179,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ { \ uint32_t vl = env->vl; \ uint32_t vm = vext_vm(desc); \ + uint32_t total_elems = env_archcpu(env)->cfg.vlen; \ + uint32_t vta_all_1s = vext_vta_all_1s(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -1159,6 +1190,13 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ DO_OP(s2, (ETYPE)(target_long)s1, carry)); \ } \ env->vstart = 0; \ + /* mask destination register are always tail-agnostic */ \ + /* set tail elements to 1s */ \ + if (vta_all_1s) { \ + for (; i < total_elems; i++) { \ + vext_set_elem_mask(vd, i, 1); \ + } \ + } \ } GEN_VEXT_VMADC_VXM(vmadc_vxm_b, uint8_t, H1, DO_MADC) @@ -1209,18 +1247,18 @@ RVVCALL(OPIVX2, vxor_vx_b, OP_SSS_B, H1, H1, DO_XOR) RVVCALL(OPIVX2, vxor_vx_h, OP_SSS_H, H2, H2, DO_XOR) RVVCALL(OPIVX2, vxor_vx_w, OP_SSS_W, H4, H4, DO_XOR) RVVCALL(OPIVX2, vxor_vx_d, OP_SSS_D, H8, H8, DO_XOR) -GEN_VEXT_VX(vand_vx_b) -GEN_VEXT_VX(vand_vx_h) -GEN_VEXT_VX(vand_vx_w) -GEN_VEXT_VX(vand_vx_d) -GEN_VEXT_VX(vor_vx_b) -GEN_VEXT_VX(vor_vx_h) -GEN_VEXT_VX(vor_vx_w) -GEN_VEXT_VX(vor_vx_d) -GEN_VEXT_VX(vxor_vx_b) -GEN_VEXT_VX(vxor_vx_h) -GEN_VEXT_VX(vxor_vx_w) -GEN_VEXT_VX(vxor_vx_d) +GEN_VEXT_VX(vand_vx_b, 1) +GEN_VEXT_VX(vand_vx_h, 2) +GEN_VEXT_VX(vand_vx_w, 4) +GEN_VEXT_VX(vand_vx_d, 8) +GEN_VEXT_VX(vor_vx_b, 1) +GEN_VEXT_VX(vor_vx_h, 2) +GEN_VEXT_VX(vor_vx_w, 4) +GEN_VEXT_VX(vor_vx_d, 8) +GEN_VEXT_VX(vxor_vx_b, 1) +GEN_VEXT_VX(vxor_vx_h, 2) +GEN_VEXT_VX(vxor_vx_w, 4) +GEN_VEXT_VX(vxor_vx_d, 8) /* Vector Single-Width Bit Shift Instructions */ #define DO_SLL(N, M) (N << (M)) @@ -1474,22 +1512,22 @@ RVVCALL(OPIVX2, vmax_vx_b, OP_SSS_B, H1, H1, DO_MAX) RVVCALL(OPIVX2, vmax_vx_h, OP_SSS_H, H2, H2, DO_MAX) RVVCALL(OPIVX2, vmax_vx_w, OP_SSS_W, H4, H4, DO_MAX) RVVCALL(OPIVX2, vmax_vx_d, OP_SSS_D, H8, H8, DO_MAX) -GEN_VEXT_VX(vminu_vx_b) -GEN_VEXT_VX(vminu_vx_h) -GEN_VEXT_VX(vminu_vx_w) -GEN_VEXT_VX(vminu_vx_d) -GEN_VEXT_VX(vmin_vx_b) -GEN_VEXT_VX(vmin_vx_h) -GEN_VEXT_VX(vmin_vx_w) -GEN_VEXT_VX(vmin_vx_d) -GEN_VEXT_VX(vmaxu_vx_b) -GEN_VEXT_VX(vmaxu_vx_h) -GEN_VEXT_VX(vmaxu_vx_w) -GEN_VEXT_VX(vmaxu_vx_d) -GEN_VEXT_VX(vmax_vx_b) -GEN_VEXT_VX(vmax_vx_h) -GEN_VEXT_VX(vmax_vx_w) -GEN_VEXT_VX(vmax_vx_d) +GEN_VEXT_VX(vminu_vx_b, 1) +GEN_VEXT_VX(vminu_vx_h, 2) +GEN_VEXT_VX(vminu_vx_w, 4) +GEN_VEXT_VX(vminu_vx_d, 8) +GEN_VEXT_VX(vmin_vx_b, 1) +GEN_VEXT_VX(vmin_vx_h, 2) +GEN_VEXT_VX(vmin_vx_w, 4) +GEN_VEXT_VX(vmin_vx_d, 8) +GEN_VEXT_VX(vmaxu_vx_b, 1) +GEN_VEXT_VX(vmaxu_vx_h, 2) +GEN_VEXT_VX(vmaxu_vx_w, 4) +GEN_VEXT_VX(vmaxu_vx_d, 8) +GEN_VEXT_VX(vmax_vx_b, 1) +GEN_VEXT_VX(vmax_vx_h, 2) +GEN_VEXT_VX(vmax_vx_w, 4) +GEN_VEXT_VX(vmax_vx_d, 8) /* Vector Single-Width Integer Multiply Instructions */ #define DO_MUL(N, M) (N * M) @@ -1633,22 +1671,22 @@ RVVCALL(OPIVX2, vmulhsu_vx_b, OP_SUS_B, H1, H1, do_mulhsu_b) RVVCALL(OPIVX2, vmulhsu_vx_h, OP_SUS_H, H2, H2, do_mulhsu_h) RVVCALL(OPIVX2, vmulhsu_vx_w, OP_SUS_W, H4, H4, do_mulhsu_w) RVVCALL(OPIVX2, vmulhsu_vx_d, OP_SUS_D, H8, H8, do_mulhsu_d) -GEN_VEXT_VX(vmul_vx_b) -GEN_VEXT_VX(vmul_vx_h) -GEN_VEXT_VX(vmul_vx_w) -GEN_VEXT_VX(vmul_vx_d) -GEN_VEXT_VX(vmulh_vx_b) -GEN_VEXT_VX(vmulh_vx_h) -GEN_VEXT_VX(vmulh_vx_w) -GEN_VEXT_VX(vmulh_vx_d) -GEN_VEXT_VX(vmulhu_vx_b) -GEN_VEXT_VX(vmulhu_vx_h) -GEN_VEXT_VX(vmulhu_vx_w) -GEN_VEXT_VX(vmulhu_vx_d) -GEN_VEXT_VX(vmulhsu_vx_b) -GEN_VEXT_VX(vmulhsu_vx_h) -GEN_VEXT_VX(vmulhsu_vx_w) -GEN_VEXT_VX(vmulhsu_vx_d) +GEN_VEXT_VX(vmul_vx_b, 1) +GEN_VEXT_VX(vmul_vx_h, 2) +GEN_VEXT_VX(vmul_vx_w, 4) +GEN_VEXT_VX(vmul_vx_d, 8) +GEN_VEXT_VX(vmulh_vx_b, 1) +GEN_VEXT_VX(vmulh_vx_h, 2) +GEN_VEXT_VX(vmulh_vx_w, 4) +GEN_VEXT_VX(vmulh_vx_d, 8) +GEN_VEXT_VX(vmulhu_vx_b, 1) +GEN_VEXT_VX(vmulhu_vx_h, 2) +GEN_VEXT_VX(vmulhu_vx_w, 4) +GEN_VEXT_VX(vmulhu_vx_d, 8) +GEN_VEXT_VX(vmulhsu_vx_b, 1) +GEN_VEXT_VX(vmulhsu_vx_h, 2) +GEN_VEXT_VX(vmulhsu_vx_w, 4) +GEN_VEXT_VX(vmulhsu_vx_d, 8) /* Vector Integer Divide Instructions */ #define DO_DIVU(N, M) (unlikely(M == 0) ? (__typeof(N))(-1) : N / M) @@ -1707,22 +1745,22 @@ RVVCALL(OPIVX2, vrem_vx_b, OP_SSS_B, H1, H1, DO_REM) RVVCALL(OPIVX2, vrem_vx_h, OP_SSS_H, H2, H2, DO_REM) RVVCALL(OPIVX2, vrem_vx_w, OP_SSS_W, H4, H4, DO_REM) RVVCALL(OPIVX2, vrem_vx_d, OP_SSS_D, H8, H8, DO_REM) -GEN_VEXT_VX(vdivu_vx_b) -GEN_VEXT_VX(vdivu_vx_h) -GEN_VEXT_VX(vdivu_vx_w) -GEN_VEXT_VX(vdivu_vx_d) -GEN_VEXT_VX(vdiv_vx_b) -GEN_VEXT_VX(vdiv_vx_h) -GEN_VEXT_VX(vdiv_vx_w) -GEN_VEXT_VX(vdiv_vx_d) -GEN_VEXT_VX(vremu_vx_b) -GEN_VEXT_VX(vremu_vx_h) -GEN_VEXT_VX(vremu_vx_w) -GEN_VEXT_VX(vremu_vx_d) -GEN_VEXT_VX(vrem_vx_b) -GEN_VEXT_VX(vrem_vx_h) -GEN_VEXT_VX(vrem_vx_w) -GEN_VEXT_VX(vrem_vx_d) +GEN_VEXT_VX(vdivu_vx_b, 1) +GEN_VEXT_VX(vdivu_vx_h, 2) +GEN_VEXT_VX(vdivu_vx_w, 4) +GEN_VEXT_VX(vdivu_vx_d, 8) +GEN_VEXT_VX(vdiv_vx_b, 1) +GEN_VEXT_VX(vdiv_vx_h, 2) +GEN_VEXT_VX(vdiv_vx_w, 4) +GEN_VEXT_VX(vdiv_vx_d, 8) +GEN_VEXT_VX(vremu_vx_b, 1) +GEN_VEXT_VX(vremu_vx_h, 2) +GEN_VEXT_VX(vremu_vx_w, 4) +GEN_VEXT_VX(vremu_vx_d, 8) +GEN_VEXT_VX(vrem_vx_b, 1) +GEN_VEXT_VX(vrem_vx_h, 2) +GEN_VEXT_VX(vrem_vx_w, 4) +GEN_VEXT_VX(vrem_vx_d, 8) /* Vector Widening Integer Multiply Instructions */ RVVCALL(OPIVV2, vwmul_vv_b, WOP_SSS_B, H2, H1, H1, DO_MUL) @@ -1753,15 +1791,15 @@ RVVCALL(OPIVX2, vwmulu_vx_w, WOP_UUU_W, H8, H4, DO_MUL) RVVCALL(OPIVX2, vwmulsu_vx_b, WOP_SUS_B, H2, H1, DO_MUL) RVVCALL(OPIVX2, vwmulsu_vx_h, WOP_SUS_H, H4, H2, DO_MUL) RVVCALL(OPIVX2, vwmulsu_vx_w, WOP_SUS_W, H8, H4, DO_MUL) -GEN_VEXT_VX(vwmul_vx_b) -GEN_VEXT_VX(vwmul_vx_h) -GEN_VEXT_VX(vwmul_vx_w) -GEN_VEXT_VX(vwmulu_vx_b) -GEN_VEXT_VX(vwmulu_vx_h) -GEN_VEXT_VX(vwmulu_vx_w) -GEN_VEXT_VX(vwmulsu_vx_b) -GEN_VEXT_VX(vwmulsu_vx_h) -GEN_VEXT_VX(vwmulsu_vx_w) +GEN_VEXT_VX(vwmul_vx_b, 2) +GEN_VEXT_VX(vwmul_vx_h, 4) +GEN_VEXT_VX(vwmul_vx_w, 8) +GEN_VEXT_VX(vwmulu_vx_b, 2) +GEN_VEXT_VX(vwmulu_vx_h, 4) +GEN_VEXT_VX(vwmulu_vx_w, 8) +GEN_VEXT_VX(vwmulsu_vx_b, 2) +GEN_VEXT_VX(vwmulsu_vx_h, 4) +GEN_VEXT_VX(vwmulsu_vx_w, 8) /* Vector Single-Width Integer Multiply-Add Instructions */ #define OPIVV3(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \ @@ -1834,22 +1872,22 @@ RVVCALL(OPIVX3, vnmsub_vx_b, OP_SSS_B, H1, H1, DO_NMSUB) RVVCALL(OPIVX3, vnmsub_vx_h, OP_SSS_H, H2, H2, DO_NMSUB) RVVCALL(OPIVX3, vnmsub_vx_w, OP_SSS_W, H4, H4, DO_NMSUB) RVVCALL(OPIVX3, vnmsub_vx_d, OP_SSS_D, H8, H8, DO_NMSUB) -GEN_VEXT_VX(vmacc_vx_b) -GEN_VEXT_VX(vmacc_vx_h) -GEN_VEXT_VX(vmacc_vx_w) -GEN_VEXT_VX(vmacc_vx_d) -GEN_VEXT_VX(vnmsac_vx_b) -GEN_VEXT_VX(vnmsac_vx_h) -GEN_VEXT_VX(vnmsac_vx_w) -GEN_VEXT_VX(vnmsac_vx_d) -GEN_VEXT_VX(vmadd_vx_b) -GEN_VEXT_VX(vmadd_vx_h) -GEN_VEXT_VX(vmadd_vx_w) -GEN_VEXT_VX(vmadd_vx_d) -GEN_VEXT_VX(vnmsub_vx_b) -GEN_VEXT_VX(vnmsub_vx_h) -GEN_VEXT_VX(vnmsub_vx_w) -GEN_VEXT_VX(vnmsub_vx_d) +GEN_VEXT_VX(vmacc_vx_b, 1) +GEN_VEXT_VX(vmacc_vx_h, 2) +GEN_VEXT_VX(vmacc_vx_w, 4) +GEN_VEXT_VX(vmacc_vx_d, 8) +GEN_VEXT_VX(vnmsac_vx_b, 1) +GEN_VEXT_VX(vnmsac_vx_h, 2) +GEN_VEXT_VX(vnmsac_vx_w, 4) +GEN_VEXT_VX(vnmsac_vx_d, 8) +GEN_VEXT_VX(vmadd_vx_b, 1) +GEN_VEXT_VX(vmadd_vx_h, 2) +GEN_VEXT_VX(vmadd_vx_w, 4) +GEN_VEXT_VX(vmadd_vx_d, 8) +GEN_VEXT_VX(vnmsub_vx_b, 1) +GEN_VEXT_VX(vnmsub_vx_h, 2) +GEN_VEXT_VX(vnmsub_vx_w, 4) +GEN_VEXT_VX(vnmsub_vx_d, 8) /* Vector Widening Integer Multiply-Add Instructions */ RVVCALL(OPIVV3, vwmaccu_vv_b, WOP_UUU_B, H2, H1, H1, DO_MACC) @@ -1883,18 +1921,18 @@ RVVCALL(OPIVX3, vwmaccsu_vx_w, WOP_SSU_W, H8, H4, DO_MACC) RVVCALL(OPIVX3, vwmaccus_vx_b, WOP_SUS_B, H2, H1, DO_MACC) RVVCALL(OPIVX3, vwmaccus_vx_h, WOP_SUS_H, H4, H2, DO_MACC) RVVCALL(OPIVX3, vwmaccus_vx_w, WOP_SUS_W, H8, H4, DO_MACC) -GEN_VEXT_VX(vwmaccu_vx_b) -GEN_VEXT_VX(vwmaccu_vx_h) -GEN_VEXT_VX(vwmaccu_vx_w) -GEN_VEXT_VX(vwmacc_vx_b) -GEN_VEXT_VX(vwmacc_vx_h) -GEN_VEXT_VX(vwmacc_vx_w) -GEN_VEXT_VX(vwmaccsu_vx_b) -GEN_VEXT_VX(vwmaccsu_vx_h) -GEN_VEXT_VX(vwmaccsu_vx_w) -GEN_VEXT_VX(vwmaccus_vx_b) -GEN_VEXT_VX(vwmaccus_vx_h) -GEN_VEXT_VX(vwmaccus_vx_w) +GEN_VEXT_VX(vwmaccu_vx_b, 2) +GEN_VEXT_VX(vwmaccu_vx_h, 4) +GEN_VEXT_VX(vwmaccu_vx_w, 8) +GEN_VEXT_VX(vwmacc_vx_b, 2) +GEN_VEXT_VX(vwmacc_vx_h, 4) +GEN_VEXT_VX(vwmacc_vx_w, 8) +GEN_VEXT_VX(vwmaccsu_vx_b, 2) +GEN_VEXT_VX(vwmaccsu_vx_h, 4) +GEN_VEXT_VX(vwmaccsu_vx_w, 8) +GEN_VEXT_VX(vwmaccus_vx_b, 2) +GEN_VEXT_VX(vwmaccus_vx_h, 4) +GEN_VEXT_VX(vwmaccus_vx_w, 8) /* Vector Integer Merge and Move Instructions */ #define GEN_VEXT_VMV_VV(NAME, ETYPE, H) \ From 7b1bff41c1524e5dc1c2815f68b0454656539993 Mon Sep 17 00:00:00 2001 From: eopXD Date: Mon, 6 Jun 2022 06:16:33 +0000 Subject: [PATCH 925/935] target/riscv: rvv: Add tail agnostic for vector integer shift instructions Signed-off-by: eop Chen Reviewed-by: Frank Chang Reviewed-by: Weiwei Li Acked-by: Alistair Francis Message-Id: <165449614532.19704.7000832880482980398-8@git.sr.ht> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.c.inc | 3 ++- target/riscv/vector_helper.c | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 22edf6228d..dbe687fb73 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -1831,7 +1831,7 @@ do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn, return false; } - if (a->vm && s->vl_eq_vlmax) { + if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { TCGv_i32 src1 = tcg_temp_new_i32(); tcg_gen_trunc_tl_i32(src1, get_gpr(s, a->rs1, EXT_NONE)); @@ -1890,6 +1890,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + data = FIELD_DP32(data, VDATA, VTA, s->vta); \ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ vreg_ofs(s, a->rs2), cpu_env, \ diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 7cdb5d12af..056c2a1c7e 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -1271,6 +1271,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(TS1); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -1282,6 +1285,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ *((TS1 *)vd + HS1(i)) = OP(s2, s1 & MASK); \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_SHIFT_VV(vsll_vv_b, uint8_t, uint8_t, H1, H1, DO_SLL, 0x7) @@ -1306,6 +1311,10 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(TD); \ + uint32_t total_elems = \ + vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -1316,6 +1325,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ *((TD *)vd + HD(i)) = OP(s2, s1 & MASK); \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz);\ } GEN_VEXT_SHIFT_VX(vsll_vx_b, uint8_t, int8_t, H1, H1, DO_SLL, 0x7) From 38581e5c9a99d2ff9244709cb3577b06a1310006 Mon Sep 17 00:00:00 2001 From: eopXD Date: Mon, 6 Jun 2022 06:16:51 +0000 Subject: [PATCH 926/935] target/riscv: rvv: Add tail agnostic for vector integer comparison instructions Compares write mask registers, and so always operate under a tail- agnostic policy. Signed-off-by: eop Chen Reviewed-by: Frank Chang Reviewed-by: Weiwei Li Acked-by: Alistair Francis Message-Id: <165449614532.19704.7000832880482980398-9@git.sr.ht> Signed-off-by: Alistair Francis --- target/riscv/vector_helper.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 056c2a1c7e..a64506bf02 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -1371,6 +1371,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t total_elems = env_archcpu(env)->cfg.vlen; \ + uint32_t vta_all_1s = vext_vta_all_1s(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -1382,6 +1384,13 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ vext_set_elem_mask(vd, i, DO_OP(s2, s1)); \ } \ env->vstart = 0; \ + /* mask destination register are always tail-agnostic */ \ + /* set tail elements to 1s */ \ + if (vta_all_1s) { \ + for (; i < total_elems; i++) { \ + vext_set_elem_mask(vd, i, 1); \ + } \ + } \ } GEN_VEXT_CMP_VV(vmseq_vv_b, uint8_t, H1, DO_MSEQ) @@ -1420,6 +1429,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t total_elems = env_archcpu(env)->cfg.vlen; \ + uint32_t vta_all_1s = vext_vta_all_1s(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -1431,6 +1442,13 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ DO_OP(s2, (ETYPE)(target_long)s1)); \ } \ env->vstart = 0; \ + /* mask destination register are always tail-agnostic */ \ + /* set tail elements to 1s */ \ + if (vta_all_1s) { \ + for (; i < total_elems; i++) { \ + vext_set_elem_mask(vd, i, 1); \ + } \ + } \ } GEN_VEXT_CMP_VX(vmseq_vx_b, uint8_t, H1, DO_MSEQ) From 89a32de2d57591006d4a5d76e664b0b01c6998dc Mon Sep 17 00:00:00 2001 From: eopXD Date: Mon, 6 Jun 2022 06:16:51 +0000 Subject: [PATCH 927/935] target/riscv: rvv: Add tail agnostic for vector integer merge and move instructions Signed-off-by: eop Chen Reviewed-by: Frank Chang Reviewed-by: Weiwei Li Acked-by: Alistair Francis Message-Id: <165449614532.19704.7000832880482980398-10@git.sr.ht> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.c.inc | 12 ++++++++---- target/riscv/vector_helper.c | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index dbe687fb73..e75a2fd196 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -2086,12 +2086,13 @@ static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a) vext_check_isa_ill(s) && /* vmv.v.v has rs2 = 0 and vm = 1 */ vext_check_sss(s, a->rd, a->rs1, 0, 1)) { - if (s->vl_eq_vlmax) { + if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), MAXSZ(s), MAXSZ(s)); } else { uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, VTA, s->vta); static gen_helper_gvec_2_ptr * const fns[4] = { gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h, gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d, @@ -2126,7 +2127,7 @@ static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a) s1 = get_gpr(s, a->rs1, EXT_SIGN); - if (s->vl_eq_vlmax) { + if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd), MAXSZ(s), MAXSZ(s), s1); } else { @@ -2134,6 +2135,7 @@ static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a) TCGv_i64 s1_i64 = tcg_temp_new_i64(); TCGv_ptr dest = tcg_temp_new_ptr(); uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, VTA, s->vta); static gen_helper_vmv_vx * const fns[4] = { gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, @@ -2163,7 +2165,7 @@ static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a) /* vmv.v.i has rs2 = 0 and vm = 1 */ vext_check_ss(s, a->rd, 0, 1)) { int64_t simm = sextract64(a->rs1, 0, 5); - if (s->vl_eq_vlmax) { + if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd), MAXSZ(s), MAXSZ(s), simm); mark_vs_dirty(s); @@ -2172,6 +2174,7 @@ static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a) TCGv_i64 s1; TCGv_ptr dest; uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, VTA, s->vta); static gen_helper_vmv_vx * const fns[4] = { gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, @@ -2743,7 +2746,7 @@ static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) TCGv_i64 t1; - if (s->vl_eq_vlmax) { + if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { t1 = tcg_temp_new_i64(); /* NaN-box f[rs1] */ do_nanbox(s, t1, cpu_fpr[a->rs1]); @@ -2755,6 +2758,7 @@ static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) TCGv_ptr dest; TCGv_i32 desc; uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, VTA, s->vta); static gen_helper_vmv_vx * const fns[3] = { gen_helper_vmv_v_x_h, gen_helper_vmv_v_x_w, diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index a64506bf02..128238786e 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -1969,6 +1969,9 @@ void HELPER(NAME)(void *vd, void *vs1, CPURISCVState *env, \ uint32_t desc) \ { \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -1976,6 +1979,8 @@ void HELPER(NAME)(void *vd, void *vs1, CPURISCVState *env, \ *((ETYPE *)vd + H(i)) = s1; \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VMV_VV(vmv_v_v_b, int8_t, H1) @@ -1988,12 +1993,17 @@ void HELPER(NAME)(void *vd, uint64_t s1, CPURISCVState *env, \ uint32_t desc) \ { \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ *((ETYPE *)vd + H(i)) = (ETYPE)s1; \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VMV_VX(vmv_v_x_b, int8_t, H1) @@ -2006,6 +2016,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -2013,6 +2026,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ *((ETYPE *)vd + H(i)) = *(vt + H(i)); \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VMERGE_VV(vmerge_vvm_b, int8_t, H1) @@ -2025,6 +2040,9 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ void *vs2, CPURISCVState *env, uint32_t desc) \ { \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -2034,6 +2052,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ *((ETYPE *)vd + H(i)) = d; \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VMERGE_VX(vmerge_vxm_b, int8_t, H1) From 09106eed3041d5eb57dd768332146abe6d86e0e4 Mon Sep 17 00:00:00 2001 From: eopXD Date: Mon, 6 Jun 2022 06:16:38 +0000 Subject: [PATCH 928/935] target/riscv: rvv: Add tail agnostic for vector fix-point arithmetic instructions Signed-off-by: eop Chen Reviewed-by: Frank Chang Reviewed-by: Weiwei Li Acked-by: Alistair Francis Message-Id: <165449614532.19704.7000832880482980398-11@git.sr.ht> Signed-off-by: Alistair Francis --- target/riscv/vector_helper.c | 220 ++++++++++++++++++----------------- 1 file changed, 114 insertions(+), 106 deletions(-) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 128238786e..1fa93cf1f0 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -2103,10 +2103,12 @@ static inline void vext_vv_rm_2(void *vd, void *v0, void *vs1, void *vs2, CPURISCVState *env, uint32_t desc, - opivv2_rm_fn *fn) + opivv2_rm_fn *fn, uint32_t esz) { uint32_t vm = vext_vm(desc); uint32_t vl = env->vl; + uint32_t total_elems = vext_get_total_elems(env, desc, esz); + uint32_t vta = vext_vta(desc); switch (env->vxrm) { case 0: /* rnu */ @@ -2126,15 +2128,17 @@ vext_vv_rm_2(void *vd, void *v0, void *vs1, void *vs2, env, vl, vm, 3, fn); break; } + /* set tail elements to 1s */ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); } /* generate helpers for fixed point instructions with OPIVV format */ -#define GEN_VEXT_VV_RM(NAME) \ +#define GEN_VEXT_VV_RM(NAME, ESZ) \ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ vext_vv_rm_2(vd, v0, vs1, vs2, env, desc, \ - do_##NAME); \ + do_##NAME, ESZ); \ } static inline uint8_t saddu8(CPURISCVState *env, int vxrm, uint8_t a, uint8_t b) @@ -2184,10 +2188,10 @@ RVVCALL(OPIVV2_RM, vsaddu_vv_b, OP_UUU_B, H1, H1, H1, saddu8) RVVCALL(OPIVV2_RM, vsaddu_vv_h, OP_UUU_H, H2, H2, H2, saddu16) RVVCALL(OPIVV2_RM, vsaddu_vv_w, OP_UUU_W, H4, H4, H4, saddu32) RVVCALL(OPIVV2_RM, vsaddu_vv_d, OP_UUU_D, H8, H8, H8, saddu64) -GEN_VEXT_VV_RM(vsaddu_vv_b) -GEN_VEXT_VV_RM(vsaddu_vv_h) -GEN_VEXT_VV_RM(vsaddu_vv_w) -GEN_VEXT_VV_RM(vsaddu_vv_d) +GEN_VEXT_VV_RM(vsaddu_vv_b, 1) +GEN_VEXT_VV_RM(vsaddu_vv_h, 2) +GEN_VEXT_VV_RM(vsaddu_vv_w, 4) +GEN_VEXT_VV_RM(vsaddu_vv_d, 8) typedef void opivx2_rm_fn(void *vd, target_long s1, void *vs2, int i, CPURISCVState *env, int vxrm); @@ -2220,10 +2224,12 @@ static inline void vext_vx_rm_2(void *vd, void *v0, target_long s1, void *vs2, CPURISCVState *env, uint32_t desc, - opivx2_rm_fn *fn) + opivx2_rm_fn *fn, uint32_t esz) { uint32_t vm = vext_vm(desc); uint32_t vl = env->vl; + uint32_t total_elems = vext_get_total_elems(env, desc, esz); + uint32_t vta = vext_vta(desc); switch (env->vxrm) { case 0: /* rnu */ @@ -2243,25 +2249,27 @@ vext_vx_rm_2(void *vd, void *v0, target_long s1, void *vs2, env, vl, vm, 3, fn); break; } + /* set tail elements to 1s */ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); } /* generate helpers for fixed point instructions with OPIVX format */ -#define GEN_VEXT_VX_RM(NAME) \ +#define GEN_VEXT_VX_RM(NAME, ESZ) \ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ void *vs2, CPURISCVState *env, uint32_t desc) \ { \ vext_vx_rm_2(vd, v0, s1, vs2, env, desc, \ - do_##NAME); \ + do_##NAME, ESZ); \ } RVVCALL(OPIVX2_RM, vsaddu_vx_b, OP_UUU_B, H1, H1, saddu8) RVVCALL(OPIVX2_RM, vsaddu_vx_h, OP_UUU_H, H2, H2, saddu16) RVVCALL(OPIVX2_RM, vsaddu_vx_w, OP_UUU_W, H4, H4, saddu32) RVVCALL(OPIVX2_RM, vsaddu_vx_d, OP_UUU_D, H8, H8, saddu64) -GEN_VEXT_VX_RM(vsaddu_vx_b) -GEN_VEXT_VX_RM(vsaddu_vx_h) -GEN_VEXT_VX_RM(vsaddu_vx_w) -GEN_VEXT_VX_RM(vsaddu_vx_d) +GEN_VEXT_VX_RM(vsaddu_vx_b, 1) +GEN_VEXT_VX_RM(vsaddu_vx_h, 2) +GEN_VEXT_VX_RM(vsaddu_vx_w, 4) +GEN_VEXT_VX_RM(vsaddu_vx_d, 8) static inline int8_t sadd8(CPURISCVState *env, int vxrm, int8_t a, int8_t b) { @@ -2307,19 +2315,19 @@ RVVCALL(OPIVV2_RM, vsadd_vv_b, OP_SSS_B, H1, H1, H1, sadd8) RVVCALL(OPIVV2_RM, vsadd_vv_h, OP_SSS_H, H2, H2, H2, sadd16) RVVCALL(OPIVV2_RM, vsadd_vv_w, OP_SSS_W, H4, H4, H4, sadd32) RVVCALL(OPIVV2_RM, vsadd_vv_d, OP_SSS_D, H8, H8, H8, sadd64) -GEN_VEXT_VV_RM(vsadd_vv_b) -GEN_VEXT_VV_RM(vsadd_vv_h) -GEN_VEXT_VV_RM(vsadd_vv_w) -GEN_VEXT_VV_RM(vsadd_vv_d) +GEN_VEXT_VV_RM(vsadd_vv_b, 1) +GEN_VEXT_VV_RM(vsadd_vv_h, 2) +GEN_VEXT_VV_RM(vsadd_vv_w, 4) +GEN_VEXT_VV_RM(vsadd_vv_d, 8) RVVCALL(OPIVX2_RM, vsadd_vx_b, OP_SSS_B, H1, H1, sadd8) RVVCALL(OPIVX2_RM, vsadd_vx_h, OP_SSS_H, H2, H2, sadd16) RVVCALL(OPIVX2_RM, vsadd_vx_w, OP_SSS_W, H4, H4, sadd32) RVVCALL(OPIVX2_RM, vsadd_vx_d, OP_SSS_D, H8, H8, sadd64) -GEN_VEXT_VX_RM(vsadd_vx_b) -GEN_VEXT_VX_RM(vsadd_vx_h) -GEN_VEXT_VX_RM(vsadd_vx_w) -GEN_VEXT_VX_RM(vsadd_vx_d) +GEN_VEXT_VX_RM(vsadd_vx_b, 1) +GEN_VEXT_VX_RM(vsadd_vx_h, 2) +GEN_VEXT_VX_RM(vsadd_vx_w, 4) +GEN_VEXT_VX_RM(vsadd_vx_d, 8) static inline uint8_t ssubu8(CPURISCVState *env, int vxrm, uint8_t a, uint8_t b) { @@ -2368,19 +2376,19 @@ RVVCALL(OPIVV2_RM, vssubu_vv_b, OP_UUU_B, H1, H1, H1, ssubu8) RVVCALL(OPIVV2_RM, vssubu_vv_h, OP_UUU_H, H2, H2, H2, ssubu16) RVVCALL(OPIVV2_RM, vssubu_vv_w, OP_UUU_W, H4, H4, H4, ssubu32) RVVCALL(OPIVV2_RM, vssubu_vv_d, OP_UUU_D, H8, H8, H8, ssubu64) -GEN_VEXT_VV_RM(vssubu_vv_b) -GEN_VEXT_VV_RM(vssubu_vv_h) -GEN_VEXT_VV_RM(vssubu_vv_w) -GEN_VEXT_VV_RM(vssubu_vv_d) +GEN_VEXT_VV_RM(vssubu_vv_b, 1) +GEN_VEXT_VV_RM(vssubu_vv_h, 2) +GEN_VEXT_VV_RM(vssubu_vv_w, 4) +GEN_VEXT_VV_RM(vssubu_vv_d, 8) RVVCALL(OPIVX2_RM, vssubu_vx_b, OP_UUU_B, H1, H1, ssubu8) RVVCALL(OPIVX2_RM, vssubu_vx_h, OP_UUU_H, H2, H2, ssubu16) RVVCALL(OPIVX2_RM, vssubu_vx_w, OP_UUU_W, H4, H4, ssubu32) RVVCALL(OPIVX2_RM, vssubu_vx_d, OP_UUU_D, H8, H8, ssubu64) -GEN_VEXT_VX_RM(vssubu_vx_b) -GEN_VEXT_VX_RM(vssubu_vx_h) -GEN_VEXT_VX_RM(vssubu_vx_w) -GEN_VEXT_VX_RM(vssubu_vx_d) +GEN_VEXT_VX_RM(vssubu_vx_b, 1) +GEN_VEXT_VX_RM(vssubu_vx_h, 2) +GEN_VEXT_VX_RM(vssubu_vx_w, 4) +GEN_VEXT_VX_RM(vssubu_vx_d, 8) static inline int8_t ssub8(CPURISCVState *env, int vxrm, int8_t a, int8_t b) { @@ -2426,19 +2434,19 @@ RVVCALL(OPIVV2_RM, vssub_vv_b, OP_SSS_B, H1, H1, H1, ssub8) RVVCALL(OPIVV2_RM, vssub_vv_h, OP_SSS_H, H2, H2, H2, ssub16) RVVCALL(OPIVV2_RM, vssub_vv_w, OP_SSS_W, H4, H4, H4, ssub32) RVVCALL(OPIVV2_RM, vssub_vv_d, OP_SSS_D, H8, H8, H8, ssub64) -GEN_VEXT_VV_RM(vssub_vv_b) -GEN_VEXT_VV_RM(vssub_vv_h) -GEN_VEXT_VV_RM(vssub_vv_w) -GEN_VEXT_VV_RM(vssub_vv_d) +GEN_VEXT_VV_RM(vssub_vv_b, 1) +GEN_VEXT_VV_RM(vssub_vv_h, 2) +GEN_VEXT_VV_RM(vssub_vv_w, 4) +GEN_VEXT_VV_RM(vssub_vv_d, 8) RVVCALL(OPIVX2_RM, vssub_vx_b, OP_SSS_B, H1, H1, ssub8) RVVCALL(OPIVX2_RM, vssub_vx_h, OP_SSS_H, H2, H2, ssub16) RVVCALL(OPIVX2_RM, vssub_vx_w, OP_SSS_W, H4, H4, ssub32) RVVCALL(OPIVX2_RM, vssub_vx_d, OP_SSS_D, H8, H8, ssub64) -GEN_VEXT_VX_RM(vssub_vx_b) -GEN_VEXT_VX_RM(vssub_vx_h) -GEN_VEXT_VX_RM(vssub_vx_w) -GEN_VEXT_VX_RM(vssub_vx_d) +GEN_VEXT_VX_RM(vssub_vx_b, 1) +GEN_VEXT_VX_RM(vssub_vx_h, 2) +GEN_VEXT_VX_RM(vssub_vx_w, 4) +GEN_VEXT_VX_RM(vssub_vx_d, 8) /* Vector Single-Width Averaging Add and Subtract */ static inline uint8_t get_round(int vxrm, uint64_t v, uint8_t shift) @@ -2490,19 +2498,19 @@ RVVCALL(OPIVV2_RM, vaadd_vv_b, OP_SSS_B, H1, H1, H1, aadd32) RVVCALL(OPIVV2_RM, vaadd_vv_h, OP_SSS_H, H2, H2, H2, aadd32) RVVCALL(OPIVV2_RM, vaadd_vv_w, OP_SSS_W, H4, H4, H4, aadd32) RVVCALL(OPIVV2_RM, vaadd_vv_d, OP_SSS_D, H8, H8, H8, aadd64) -GEN_VEXT_VV_RM(vaadd_vv_b) -GEN_VEXT_VV_RM(vaadd_vv_h) -GEN_VEXT_VV_RM(vaadd_vv_w) -GEN_VEXT_VV_RM(vaadd_vv_d) +GEN_VEXT_VV_RM(vaadd_vv_b, 1) +GEN_VEXT_VV_RM(vaadd_vv_h, 2) +GEN_VEXT_VV_RM(vaadd_vv_w, 4) +GEN_VEXT_VV_RM(vaadd_vv_d, 8) RVVCALL(OPIVX2_RM, vaadd_vx_b, OP_SSS_B, H1, H1, aadd32) RVVCALL(OPIVX2_RM, vaadd_vx_h, OP_SSS_H, H2, H2, aadd32) RVVCALL(OPIVX2_RM, vaadd_vx_w, OP_SSS_W, H4, H4, aadd32) RVVCALL(OPIVX2_RM, vaadd_vx_d, OP_SSS_D, H8, H8, aadd64) -GEN_VEXT_VX_RM(vaadd_vx_b) -GEN_VEXT_VX_RM(vaadd_vx_h) -GEN_VEXT_VX_RM(vaadd_vx_w) -GEN_VEXT_VX_RM(vaadd_vx_d) +GEN_VEXT_VX_RM(vaadd_vx_b, 1) +GEN_VEXT_VX_RM(vaadd_vx_h, 2) +GEN_VEXT_VX_RM(vaadd_vx_w, 4) +GEN_VEXT_VX_RM(vaadd_vx_d, 8) static inline uint32_t aaddu32(CPURISCVState *env, int vxrm, uint32_t a, uint32_t b) @@ -2527,19 +2535,19 @@ RVVCALL(OPIVV2_RM, vaaddu_vv_b, OP_UUU_B, H1, H1, H1, aaddu32) RVVCALL(OPIVV2_RM, vaaddu_vv_h, OP_UUU_H, H2, H2, H2, aaddu32) RVVCALL(OPIVV2_RM, vaaddu_vv_w, OP_UUU_W, H4, H4, H4, aaddu32) RVVCALL(OPIVV2_RM, vaaddu_vv_d, OP_UUU_D, H8, H8, H8, aaddu64) -GEN_VEXT_VV_RM(vaaddu_vv_b) -GEN_VEXT_VV_RM(vaaddu_vv_h) -GEN_VEXT_VV_RM(vaaddu_vv_w) -GEN_VEXT_VV_RM(vaaddu_vv_d) +GEN_VEXT_VV_RM(vaaddu_vv_b, 1) +GEN_VEXT_VV_RM(vaaddu_vv_h, 2) +GEN_VEXT_VV_RM(vaaddu_vv_w, 4) +GEN_VEXT_VV_RM(vaaddu_vv_d, 8) RVVCALL(OPIVX2_RM, vaaddu_vx_b, OP_UUU_B, H1, H1, aaddu32) RVVCALL(OPIVX2_RM, vaaddu_vx_h, OP_UUU_H, H2, H2, aaddu32) RVVCALL(OPIVX2_RM, vaaddu_vx_w, OP_UUU_W, H4, H4, aaddu32) RVVCALL(OPIVX2_RM, vaaddu_vx_d, OP_UUU_D, H8, H8, aaddu64) -GEN_VEXT_VX_RM(vaaddu_vx_b) -GEN_VEXT_VX_RM(vaaddu_vx_h) -GEN_VEXT_VX_RM(vaaddu_vx_w) -GEN_VEXT_VX_RM(vaaddu_vx_d) +GEN_VEXT_VX_RM(vaaddu_vx_b, 1) +GEN_VEXT_VX_RM(vaaddu_vx_h, 2) +GEN_VEXT_VX_RM(vaaddu_vx_w, 4) +GEN_VEXT_VX_RM(vaaddu_vx_d, 8) static inline int32_t asub32(CPURISCVState *env, int vxrm, int32_t a, int32_t b) { @@ -2563,19 +2571,19 @@ RVVCALL(OPIVV2_RM, vasub_vv_b, OP_SSS_B, H1, H1, H1, asub32) RVVCALL(OPIVV2_RM, vasub_vv_h, OP_SSS_H, H2, H2, H2, asub32) RVVCALL(OPIVV2_RM, vasub_vv_w, OP_SSS_W, H4, H4, H4, asub32) RVVCALL(OPIVV2_RM, vasub_vv_d, OP_SSS_D, H8, H8, H8, asub64) -GEN_VEXT_VV_RM(vasub_vv_b) -GEN_VEXT_VV_RM(vasub_vv_h) -GEN_VEXT_VV_RM(vasub_vv_w) -GEN_VEXT_VV_RM(vasub_vv_d) +GEN_VEXT_VV_RM(vasub_vv_b, 1) +GEN_VEXT_VV_RM(vasub_vv_h, 2) +GEN_VEXT_VV_RM(vasub_vv_w, 4) +GEN_VEXT_VV_RM(vasub_vv_d, 8) RVVCALL(OPIVX2_RM, vasub_vx_b, OP_SSS_B, H1, H1, asub32) RVVCALL(OPIVX2_RM, vasub_vx_h, OP_SSS_H, H2, H2, asub32) RVVCALL(OPIVX2_RM, vasub_vx_w, OP_SSS_W, H4, H4, asub32) RVVCALL(OPIVX2_RM, vasub_vx_d, OP_SSS_D, H8, H8, asub64) -GEN_VEXT_VX_RM(vasub_vx_b) -GEN_VEXT_VX_RM(vasub_vx_h) -GEN_VEXT_VX_RM(vasub_vx_w) -GEN_VEXT_VX_RM(vasub_vx_d) +GEN_VEXT_VX_RM(vasub_vx_b, 1) +GEN_VEXT_VX_RM(vasub_vx_h, 2) +GEN_VEXT_VX_RM(vasub_vx_w, 4) +GEN_VEXT_VX_RM(vasub_vx_d, 8) static inline uint32_t asubu32(CPURISCVState *env, int vxrm, uint32_t a, uint32_t b) @@ -2600,19 +2608,19 @@ RVVCALL(OPIVV2_RM, vasubu_vv_b, OP_UUU_B, H1, H1, H1, asubu32) RVVCALL(OPIVV2_RM, vasubu_vv_h, OP_UUU_H, H2, H2, H2, asubu32) RVVCALL(OPIVV2_RM, vasubu_vv_w, OP_UUU_W, H4, H4, H4, asubu32) RVVCALL(OPIVV2_RM, vasubu_vv_d, OP_UUU_D, H8, H8, H8, asubu64) -GEN_VEXT_VV_RM(vasubu_vv_b) -GEN_VEXT_VV_RM(vasubu_vv_h) -GEN_VEXT_VV_RM(vasubu_vv_w) -GEN_VEXT_VV_RM(vasubu_vv_d) +GEN_VEXT_VV_RM(vasubu_vv_b, 1) +GEN_VEXT_VV_RM(vasubu_vv_h, 2) +GEN_VEXT_VV_RM(vasubu_vv_w, 4) +GEN_VEXT_VV_RM(vasubu_vv_d, 8) RVVCALL(OPIVX2_RM, vasubu_vx_b, OP_UUU_B, H1, H1, asubu32) RVVCALL(OPIVX2_RM, vasubu_vx_h, OP_UUU_H, H2, H2, asubu32) RVVCALL(OPIVX2_RM, vasubu_vx_w, OP_UUU_W, H4, H4, asubu32) RVVCALL(OPIVX2_RM, vasubu_vx_d, OP_UUU_D, H8, H8, asubu64) -GEN_VEXT_VX_RM(vasubu_vx_b) -GEN_VEXT_VX_RM(vasubu_vx_h) -GEN_VEXT_VX_RM(vasubu_vx_w) -GEN_VEXT_VX_RM(vasubu_vx_d) +GEN_VEXT_VX_RM(vasubu_vx_b, 1) +GEN_VEXT_VX_RM(vasubu_vx_h, 2) +GEN_VEXT_VX_RM(vasubu_vx_w, 4) +GEN_VEXT_VX_RM(vasubu_vx_d, 8) /* Vector Single-Width Fractional Multiply with Rounding and Saturation */ static inline int8_t vsmul8(CPURISCVState *env, int vxrm, int8_t a, int8_t b) @@ -2707,19 +2715,19 @@ RVVCALL(OPIVV2_RM, vsmul_vv_b, OP_SSS_B, H1, H1, H1, vsmul8) RVVCALL(OPIVV2_RM, vsmul_vv_h, OP_SSS_H, H2, H2, H2, vsmul16) RVVCALL(OPIVV2_RM, vsmul_vv_w, OP_SSS_W, H4, H4, H4, vsmul32) RVVCALL(OPIVV2_RM, vsmul_vv_d, OP_SSS_D, H8, H8, H8, vsmul64) -GEN_VEXT_VV_RM(vsmul_vv_b) -GEN_VEXT_VV_RM(vsmul_vv_h) -GEN_VEXT_VV_RM(vsmul_vv_w) -GEN_VEXT_VV_RM(vsmul_vv_d) +GEN_VEXT_VV_RM(vsmul_vv_b, 1) +GEN_VEXT_VV_RM(vsmul_vv_h, 2) +GEN_VEXT_VV_RM(vsmul_vv_w, 4) +GEN_VEXT_VV_RM(vsmul_vv_d, 8) RVVCALL(OPIVX2_RM, vsmul_vx_b, OP_SSS_B, H1, H1, vsmul8) RVVCALL(OPIVX2_RM, vsmul_vx_h, OP_SSS_H, H2, H2, vsmul16) RVVCALL(OPIVX2_RM, vsmul_vx_w, OP_SSS_W, H4, H4, vsmul32) RVVCALL(OPIVX2_RM, vsmul_vx_d, OP_SSS_D, H8, H8, vsmul64) -GEN_VEXT_VX_RM(vsmul_vx_b) -GEN_VEXT_VX_RM(vsmul_vx_h) -GEN_VEXT_VX_RM(vsmul_vx_w) -GEN_VEXT_VX_RM(vsmul_vx_d) +GEN_VEXT_VX_RM(vsmul_vx_b, 1) +GEN_VEXT_VX_RM(vsmul_vx_h, 2) +GEN_VEXT_VX_RM(vsmul_vx_w, 4) +GEN_VEXT_VX_RM(vsmul_vx_d, 8) /* Vector Single-Width Scaling Shift Instructions */ static inline uint8_t @@ -2766,19 +2774,19 @@ RVVCALL(OPIVV2_RM, vssrl_vv_b, OP_UUU_B, H1, H1, H1, vssrl8) RVVCALL(OPIVV2_RM, vssrl_vv_h, OP_UUU_H, H2, H2, H2, vssrl16) RVVCALL(OPIVV2_RM, vssrl_vv_w, OP_UUU_W, H4, H4, H4, vssrl32) RVVCALL(OPIVV2_RM, vssrl_vv_d, OP_UUU_D, H8, H8, H8, vssrl64) -GEN_VEXT_VV_RM(vssrl_vv_b) -GEN_VEXT_VV_RM(vssrl_vv_h) -GEN_VEXT_VV_RM(vssrl_vv_w) -GEN_VEXT_VV_RM(vssrl_vv_d) +GEN_VEXT_VV_RM(vssrl_vv_b, 1) +GEN_VEXT_VV_RM(vssrl_vv_h, 2) +GEN_VEXT_VV_RM(vssrl_vv_w, 4) +GEN_VEXT_VV_RM(vssrl_vv_d, 8) RVVCALL(OPIVX2_RM, vssrl_vx_b, OP_UUU_B, H1, H1, vssrl8) RVVCALL(OPIVX2_RM, vssrl_vx_h, OP_UUU_H, H2, H2, vssrl16) RVVCALL(OPIVX2_RM, vssrl_vx_w, OP_UUU_W, H4, H4, vssrl32) RVVCALL(OPIVX2_RM, vssrl_vx_d, OP_UUU_D, H8, H8, vssrl64) -GEN_VEXT_VX_RM(vssrl_vx_b) -GEN_VEXT_VX_RM(vssrl_vx_h) -GEN_VEXT_VX_RM(vssrl_vx_w) -GEN_VEXT_VX_RM(vssrl_vx_d) +GEN_VEXT_VX_RM(vssrl_vx_b, 1) +GEN_VEXT_VX_RM(vssrl_vx_h, 2) +GEN_VEXT_VX_RM(vssrl_vx_w, 4) +GEN_VEXT_VX_RM(vssrl_vx_d, 8) static inline int8_t vssra8(CPURISCVState *env, int vxrm, int8_t a, int8_t b) @@ -2825,19 +2833,19 @@ RVVCALL(OPIVV2_RM, vssra_vv_b, OP_SSS_B, H1, H1, H1, vssra8) RVVCALL(OPIVV2_RM, vssra_vv_h, OP_SSS_H, H2, H2, H2, vssra16) RVVCALL(OPIVV2_RM, vssra_vv_w, OP_SSS_W, H4, H4, H4, vssra32) RVVCALL(OPIVV2_RM, vssra_vv_d, OP_SSS_D, H8, H8, H8, vssra64) -GEN_VEXT_VV_RM(vssra_vv_b) -GEN_VEXT_VV_RM(vssra_vv_h) -GEN_VEXT_VV_RM(vssra_vv_w) -GEN_VEXT_VV_RM(vssra_vv_d) +GEN_VEXT_VV_RM(vssra_vv_b, 1) +GEN_VEXT_VV_RM(vssra_vv_h, 2) +GEN_VEXT_VV_RM(vssra_vv_w, 4) +GEN_VEXT_VV_RM(vssra_vv_d, 8) RVVCALL(OPIVX2_RM, vssra_vx_b, OP_SSS_B, H1, H1, vssra8) RVVCALL(OPIVX2_RM, vssra_vx_h, OP_SSS_H, H2, H2, vssra16) RVVCALL(OPIVX2_RM, vssra_vx_w, OP_SSS_W, H4, H4, vssra32) RVVCALL(OPIVX2_RM, vssra_vx_d, OP_SSS_D, H8, H8, vssra64) -GEN_VEXT_VX_RM(vssra_vx_b) -GEN_VEXT_VX_RM(vssra_vx_h) -GEN_VEXT_VX_RM(vssra_vx_w) -GEN_VEXT_VX_RM(vssra_vx_d) +GEN_VEXT_VX_RM(vssra_vx_b, 1) +GEN_VEXT_VX_RM(vssra_vx_h, 2) +GEN_VEXT_VX_RM(vssra_vx_w, 4) +GEN_VEXT_VX_RM(vssra_vx_d, 8) /* Vector Narrowing Fixed-Point Clip Instructions */ static inline int8_t @@ -2900,16 +2908,16 @@ vnclip32(CPURISCVState *env, int vxrm, int64_t a, int32_t b) RVVCALL(OPIVV2_RM, vnclip_wv_b, NOP_SSS_B, H1, H2, H1, vnclip8) RVVCALL(OPIVV2_RM, vnclip_wv_h, NOP_SSS_H, H2, H4, H2, vnclip16) RVVCALL(OPIVV2_RM, vnclip_wv_w, NOP_SSS_W, H4, H8, H4, vnclip32) -GEN_VEXT_VV_RM(vnclip_wv_b) -GEN_VEXT_VV_RM(vnclip_wv_h) -GEN_VEXT_VV_RM(vnclip_wv_w) +GEN_VEXT_VV_RM(vnclip_wv_b, 1) +GEN_VEXT_VV_RM(vnclip_wv_h, 2) +GEN_VEXT_VV_RM(vnclip_wv_w, 4) RVVCALL(OPIVX2_RM, vnclip_wx_b, NOP_SSS_B, H1, H2, vnclip8) RVVCALL(OPIVX2_RM, vnclip_wx_h, NOP_SSS_H, H2, H4, vnclip16) RVVCALL(OPIVX2_RM, vnclip_wx_w, NOP_SSS_W, H4, H8, vnclip32) -GEN_VEXT_VX_RM(vnclip_wx_b) -GEN_VEXT_VX_RM(vnclip_wx_h) -GEN_VEXT_VX_RM(vnclip_wx_w) +GEN_VEXT_VX_RM(vnclip_wx_b, 1) +GEN_VEXT_VX_RM(vnclip_wx_h, 2) +GEN_VEXT_VX_RM(vnclip_wx_w, 4) static inline uint8_t vnclipu8(CPURISCVState *env, int vxrm, uint16_t a, uint8_t b) @@ -2962,16 +2970,16 @@ vnclipu32(CPURISCVState *env, int vxrm, uint64_t a, uint32_t b) RVVCALL(OPIVV2_RM, vnclipu_wv_b, NOP_UUU_B, H1, H2, H1, vnclipu8) RVVCALL(OPIVV2_RM, vnclipu_wv_h, NOP_UUU_H, H2, H4, H2, vnclipu16) RVVCALL(OPIVV2_RM, vnclipu_wv_w, NOP_UUU_W, H4, H8, H4, vnclipu32) -GEN_VEXT_VV_RM(vnclipu_wv_b) -GEN_VEXT_VV_RM(vnclipu_wv_h) -GEN_VEXT_VV_RM(vnclipu_wv_w) +GEN_VEXT_VV_RM(vnclipu_wv_b, 1) +GEN_VEXT_VV_RM(vnclipu_wv_h, 2) +GEN_VEXT_VV_RM(vnclipu_wv_w, 4) RVVCALL(OPIVX2_RM, vnclipu_wx_b, NOP_UUU_B, H1, H2, vnclipu8) RVVCALL(OPIVX2_RM, vnclipu_wx_h, NOP_UUU_H, H2, H4, vnclipu16) RVVCALL(OPIVX2_RM, vnclipu_wx_w, NOP_UUU_W, H4, H8, vnclipu32) -GEN_VEXT_VX_RM(vnclipu_wx_b) -GEN_VEXT_VX_RM(vnclipu_wx_h) -GEN_VEXT_VX_RM(vnclipu_wx_w) +GEN_VEXT_VX_RM(vnclipu_wx_b, 1) +GEN_VEXT_VX_RM(vnclipu_wx_h, 2) +GEN_VEXT_VX_RM(vnclipu_wx_w, 4) /* *** Vector Float Point Arithmetic Instructions From 5eacf7d8a0fb19ea4d87eb678462fdb9a29b9190 Mon Sep 17 00:00:00 2001 From: eopXD Date: Mon, 6 Jun 2022 06:16:56 +0000 Subject: [PATCH 929/935] target/riscv: rvv: Add tail agnostic for vector floating-point instructions Compares write mask registers, and so always operate under a tail- agnostic policy. Signed-off-by: eop Chen Reviewed-by: Frank Chang Reviewed-by: Weiwei Li Acked-by: Alistair Francis Message-Id: <165449614532.19704.7000832880482980398-12@git.sr.ht> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.c.inc | 17 + target/riscv/vector_helper.c | 440 +++++++++++++----------- 2 files changed, 261 insertions(+), 196 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index e75a2fd196..1add4cb655 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -2338,6 +2338,9 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + data = FIELD_DP32(data, VDATA, VTA, s->vta); \ + data = \ + FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ vreg_ofs(s, a->rs2), cpu_env, \ @@ -2420,6 +2423,9 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ gen_set_rm(s, RISCV_FRM_DYN); \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + data = FIELD_DP32(data, VDATA, VTA, s->vta); \ + data = FIELD_DP32(data, VDATA, VTA_ALL_1S, \ + s->cfg_vta_all_1s); \ return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ fns[s->sew - 1], s); \ } \ @@ -2458,6 +2464,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + data = FIELD_DP32(data, VDATA, VTA, s->vta); \ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ vreg_ofs(s, a->rs2), cpu_env, \ @@ -2497,6 +2504,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ gen_set_rm(s, RISCV_FRM_DYN); \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + data = FIELD_DP32(data, VDATA, VTA, s->vta); \ return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ fns[s->sew - 1], s); \ } \ @@ -2533,6 +2541,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + data = FIELD_DP32(data, VDATA, VTA, s->vta); \ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ vreg_ofs(s, a->rs2), cpu_env, \ @@ -2572,6 +2581,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ gen_set_rm(s, RISCV_FRM_DYN); \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + data = FIELD_DP32(data, VDATA, VTA, s->vta); \ return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ fns[s->sew - 1], s); \ } \ @@ -2655,6 +2665,7 @@ static bool do_opfv(DisasContext *s, arg_rmr *a, data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, VTA, s->vta); tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs2), cpu_env, s->cfg_ptr->vlen / 8, @@ -2859,6 +2870,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + data = FIELD_DP32(data, VDATA, VTA, s->vta); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs2), cpu_env, \ s->cfg_ptr->vlen / 8, \ @@ -2910,6 +2922,8 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + data = FIELD_DP32(data, VDATA, VTA, s->vta); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs2), cpu_env, \ s->cfg_ptr->vlen / 8, \ @@ -2977,6 +2991,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + data = FIELD_DP32(data, VDATA, VTA, s->vta); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs2), cpu_env, \ s->cfg_ptr->vlen / 8, \ @@ -3030,6 +3045,8 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + data = FIELD_DP32(data, VDATA, VTA, s->vta); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs2), cpu_env, \ s->cfg_ptr->vlen / 8, \ diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 1fa93cf1f0..17390d8d06 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -2994,13 +2994,16 @@ static void do_##NAME(void *vd, void *vs1, void *vs2, int i, \ *((TD *)vd + HD(i)) = OP(s2, s1, &env->fp_status); \ } -#define GEN_VEXT_VV_ENV(NAME) \ +#define GEN_VEXT_VV_ENV(NAME, ESZ) \ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ void *vs2, CPURISCVState *env, \ uint32_t desc) \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t total_elems = \ + vext_get_total_elems(env, desc, ESZ); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -3010,14 +3013,17 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ do_##NAME(vd, vs1, vs2, i, env); \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * ESZ, \ + total_elems * ESZ); \ } RVVCALL(OPFVV2, vfadd_vv_h, OP_UUU_H, H2, H2, H2, float16_add) RVVCALL(OPFVV2, vfadd_vv_w, OP_UUU_W, H4, H4, H4, float32_add) RVVCALL(OPFVV2, vfadd_vv_d, OP_UUU_D, H8, H8, H8, float64_add) -GEN_VEXT_VV_ENV(vfadd_vv_h) -GEN_VEXT_VV_ENV(vfadd_vv_w) -GEN_VEXT_VV_ENV(vfadd_vv_d) +GEN_VEXT_VV_ENV(vfadd_vv_h, 2) +GEN_VEXT_VV_ENV(vfadd_vv_w, 4) +GEN_VEXT_VV_ENV(vfadd_vv_d, 8) #define OPFVF2(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \ static void do_##NAME(void *vd, uint64_t s1, void *vs2, int i, \ @@ -3027,13 +3033,16 @@ static void do_##NAME(void *vd, uint64_t s1, void *vs2, int i, \ *((TD *)vd + HD(i)) = OP(s2, (TX1)(T1)s1, &env->fp_status);\ } -#define GEN_VEXT_VF(NAME) \ +#define GEN_VEXT_VF(NAME, ESZ) \ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, \ void *vs2, CPURISCVState *env, \ uint32_t desc) \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t total_elems = \ + vext_get_total_elems(env, desc, ESZ); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -3043,27 +3052,30 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, \ do_##NAME(vd, s1, vs2, i, env); \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * ESZ, \ + total_elems * ESZ); \ } RVVCALL(OPFVF2, vfadd_vf_h, OP_UUU_H, H2, H2, float16_add) RVVCALL(OPFVF2, vfadd_vf_w, OP_UUU_W, H4, H4, float32_add) RVVCALL(OPFVF2, vfadd_vf_d, OP_UUU_D, H8, H8, float64_add) -GEN_VEXT_VF(vfadd_vf_h) -GEN_VEXT_VF(vfadd_vf_w) -GEN_VEXT_VF(vfadd_vf_d) +GEN_VEXT_VF(vfadd_vf_h, 2) +GEN_VEXT_VF(vfadd_vf_w, 4) +GEN_VEXT_VF(vfadd_vf_d, 8) RVVCALL(OPFVV2, vfsub_vv_h, OP_UUU_H, H2, H2, H2, float16_sub) RVVCALL(OPFVV2, vfsub_vv_w, OP_UUU_W, H4, H4, H4, float32_sub) RVVCALL(OPFVV2, vfsub_vv_d, OP_UUU_D, H8, H8, H8, float64_sub) -GEN_VEXT_VV_ENV(vfsub_vv_h) -GEN_VEXT_VV_ENV(vfsub_vv_w) -GEN_VEXT_VV_ENV(vfsub_vv_d) +GEN_VEXT_VV_ENV(vfsub_vv_h, 2) +GEN_VEXT_VV_ENV(vfsub_vv_w, 4) +GEN_VEXT_VV_ENV(vfsub_vv_d, 8) RVVCALL(OPFVF2, vfsub_vf_h, OP_UUU_H, H2, H2, float16_sub) RVVCALL(OPFVF2, vfsub_vf_w, OP_UUU_W, H4, H4, float32_sub) RVVCALL(OPFVF2, vfsub_vf_d, OP_UUU_D, H8, H8, float64_sub) -GEN_VEXT_VF(vfsub_vf_h) -GEN_VEXT_VF(vfsub_vf_w) -GEN_VEXT_VF(vfsub_vf_d) +GEN_VEXT_VF(vfsub_vf_h, 2) +GEN_VEXT_VF(vfsub_vf_w, 4) +GEN_VEXT_VF(vfsub_vf_d, 8) static uint16_t float16_rsub(uint16_t a, uint16_t b, float_status *s) { @@ -3083,9 +3095,9 @@ static uint64_t float64_rsub(uint64_t a, uint64_t b, float_status *s) RVVCALL(OPFVF2, vfrsub_vf_h, OP_UUU_H, H2, H2, float16_rsub) RVVCALL(OPFVF2, vfrsub_vf_w, OP_UUU_W, H4, H4, float32_rsub) RVVCALL(OPFVF2, vfrsub_vf_d, OP_UUU_D, H8, H8, float64_rsub) -GEN_VEXT_VF(vfrsub_vf_h) -GEN_VEXT_VF(vfrsub_vf_w) -GEN_VEXT_VF(vfrsub_vf_d) +GEN_VEXT_VF(vfrsub_vf_h, 2) +GEN_VEXT_VF(vfrsub_vf_w, 4) +GEN_VEXT_VF(vfrsub_vf_d, 8) /* Vector Widening Floating-Point Add/Subtract Instructions */ static uint32_t vfwadd16(uint16_t a, uint16_t b, float_status *s) @@ -3103,12 +3115,12 @@ static uint64_t vfwadd32(uint32_t a, uint32_t b, float_status *s) RVVCALL(OPFVV2, vfwadd_vv_h, WOP_UUU_H, H4, H2, H2, vfwadd16) RVVCALL(OPFVV2, vfwadd_vv_w, WOP_UUU_W, H8, H4, H4, vfwadd32) -GEN_VEXT_VV_ENV(vfwadd_vv_h) -GEN_VEXT_VV_ENV(vfwadd_vv_w) +GEN_VEXT_VV_ENV(vfwadd_vv_h, 4) +GEN_VEXT_VV_ENV(vfwadd_vv_w, 8) RVVCALL(OPFVF2, vfwadd_vf_h, WOP_UUU_H, H4, H2, vfwadd16) RVVCALL(OPFVF2, vfwadd_vf_w, WOP_UUU_W, H8, H4, vfwadd32) -GEN_VEXT_VF(vfwadd_vf_h) -GEN_VEXT_VF(vfwadd_vf_w) +GEN_VEXT_VF(vfwadd_vf_h, 4) +GEN_VEXT_VF(vfwadd_vf_w, 8) static uint32_t vfwsub16(uint16_t a, uint16_t b, float_status *s) { @@ -3125,12 +3137,12 @@ static uint64_t vfwsub32(uint32_t a, uint32_t b, float_status *s) RVVCALL(OPFVV2, vfwsub_vv_h, WOP_UUU_H, H4, H2, H2, vfwsub16) RVVCALL(OPFVV2, vfwsub_vv_w, WOP_UUU_W, H8, H4, H4, vfwsub32) -GEN_VEXT_VV_ENV(vfwsub_vv_h) -GEN_VEXT_VV_ENV(vfwsub_vv_w) +GEN_VEXT_VV_ENV(vfwsub_vv_h, 4) +GEN_VEXT_VV_ENV(vfwsub_vv_w, 8) RVVCALL(OPFVF2, vfwsub_vf_h, WOP_UUU_H, H4, H2, vfwsub16) RVVCALL(OPFVF2, vfwsub_vf_w, WOP_UUU_W, H8, H4, vfwsub32) -GEN_VEXT_VF(vfwsub_vf_h) -GEN_VEXT_VF(vfwsub_vf_w) +GEN_VEXT_VF(vfwsub_vf_h, 4) +GEN_VEXT_VF(vfwsub_vf_w, 8) static uint32_t vfwaddw16(uint32_t a, uint16_t b, float_status *s) { @@ -3144,12 +3156,12 @@ static uint64_t vfwaddw32(uint64_t a, uint32_t b, float_status *s) RVVCALL(OPFVV2, vfwadd_wv_h, WOP_WUUU_H, H4, H2, H2, vfwaddw16) RVVCALL(OPFVV2, vfwadd_wv_w, WOP_WUUU_W, H8, H4, H4, vfwaddw32) -GEN_VEXT_VV_ENV(vfwadd_wv_h) -GEN_VEXT_VV_ENV(vfwadd_wv_w) +GEN_VEXT_VV_ENV(vfwadd_wv_h, 4) +GEN_VEXT_VV_ENV(vfwadd_wv_w, 8) RVVCALL(OPFVF2, vfwadd_wf_h, WOP_WUUU_H, H4, H2, vfwaddw16) RVVCALL(OPFVF2, vfwadd_wf_w, WOP_WUUU_W, H8, H4, vfwaddw32) -GEN_VEXT_VF(vfwadd_wf_h) -GEN_VEXT_VF(vfwadd_wf_w) +GEN_VEXT_VF(vfwadd_wf_h, 4) +GEN_VEXT_VF(vfwadd_wf_w, 8) static uint32_t vfwsubw16(uint32_t a, uint16_t b, float_status *s) { @@ -3163,39 +3175,39 @@ static uint64_t vfwsubw32(uint64_t a, uint32_t b, float_status *s) RVVCALL(OPFVV2, vfwsub_wv_h, WOP_WUUU_H, H4, H2, H2, vfwsubw16) RVVCALL(OPFVV2, vfwsub_wv_w, WOP_WUUU_W, H8, H4, H4, vfwsubw32) -GEN_VEXT_VV_ENV(vfwsub_wv_h) -GEN_VEXT_VV_ENV(vfwsub_wv_w) +GEN_VEXT_VV_ENV(vfwsub_wv_h, 4) +GEN_VEXT_VV_ENV(vfwsub_wv_w, 8) RVVCALL(OPFVF2, vfwsub_wf_h, WOP_WUUU_H, H4, H2, vfwsubw16) RVVCALL(OPFVF2, vfwsub_wf_w, WOP_WUUU_W, H8, H4, vfwsubw32) -GEN_VEXT_VF(vfwsub_wf_h) -GEN_VEXT_VF(vfwsub_wf_w) +GEN_VEXT_VF(vfwsub_wf_h, 4) +GEN_VEXT_VF(vfwsub_wf_w, 8) /* Vector Single-Width Floating-Point Multiply/Divide Instructions */ RVVCALL(OPFVV2, vfmul_vv_h, OP_UUU_H, H2, H2, H2, float16_mul) RVVCALL(OPFVV2, vfmul_vv_w, OP_UUU_W, H4, H4, H4, float32_mul) RVVCALL(OPFVV2, vfmul_vv_d, OP_UUU_D, H8, H8, H8, float64_mul) -GEN_VEXT_VV_ENV(vfmul_vv_h) -GEN_VEXT_VV_ENV(vfmul_vv_w) -GEN_VEXT_VV_ENV(vfmul_vv_d) +GEN_VEXT_VV_ENV(vfmul_vv_h, 2) +GEN_VEXT_VV_ENV(vfmul_vv_w, 4) +GEN_VEXT_VV_ENV(vfmul_vv_d, 8) RVVCALL(OPFVF2, vfmul_vf_h, OP_UUU_H, H2, H2, float16_mul) RVVCALL(OPFVF2, vfmul_vf_w, OP_UUU_W, H4, H4, float32_mul) RVVCALL(OPFVF2, vfmul_vf_d, OP_UUU_D, H8, H8, float64_mul) -GEN_VEXT_VF(vfmul_vf_h) -GEN_VEXT_VF(vfmul_vf_w) -GEN_VEXT_VF(vfmul_vf_d) +GEN_VEXT_VF(vfmul_vf_h, 2) +GEN_VEXT_VF(vfmul_vf_w, 4) +GEN_VEXT_VF(vfmul_vf_d, 8) RVVCALL(OPFVV2, vfdiv_vv_h, OP_UUU_H, H2, H2, H2, float16_div) RVVCALL(OPFVV2, vfdiv_vv_w, OP_UUU_W, H4, H4, H4, float32_div) RVVCALL(OPFVV2, vfdiv_vv_d, OP_UUU_D, H8, H8, H8, float64_div) -GEN_VEXT_VV_ENV(vfdiv_vv_h) -GEN_VEXT_VV_ENV(vfdiv_vv_w) -GEN_VEXT_VV_ENV(vfdiv_vv_d) +GEN_VEXT_VV_ENV(vfdiv_vv_h, 2) +GEN_VEXT_VV_ENV(vfdiv_vv_w, 4) +GEN_VEXT_VV_ENV(vfdiv_vv_d, 8) RVVCALL(OPFVF2, vfdiv_vf_h, OP_UUU_H, H2, H2, float16_div) RVVCALL(OPFVF2, vfdiv_vf_w, OP_UUU_W, H4, H4, float32_div) RVVCALL(OPFVF2, vfdiv_vf_d, OP_UUU_D, H8, H8, float64_div) -GEN_VEXT_VF(vfdiv_vf_h) -GEN_VEXT_VF(vfdiv_vf_w) -GEN_VEXT_VF(vfdiv_vf_d) +GEN_VEXT_VF(vfdiv_vf_h, 2) +GEN_VEXT_VF(vfdiv_vf_w, 4) +GEN_VEXT_VF(vfdiv_vf_d, 8) static uint16_t float16_rdiv(uint16_t a, uint16_t b, float_status *s) { @@ -3215,9 +3227,9 @@ static uint64_t float64_rdiv(uint64_t a, uint64_t b, float_status *s) RVVCALL(OPFVF2, vfrdiv_vf_h, OP_UUU_H, H2, H2, float16_rdiv) RVVCALL(OPFVF2, vfrdiv_vf_w, OP_UUU_W, H4, H4, float32_rdiv) RVVCALL(OPFVF2, vfrdiv_vf_d, OP_UUU_D, H8, H8, float64_rdiv) -GEN_VEXT_VF(vfrdiv_vf_h) -GEN_VEXT_VF(vfrdiv_vf_w) -GEN_VEXT_VF(vfrdiv_vf_d) +GEN_VEXT_VF(vfrdiv_vf_h, 2) +GEN_VEXT_VF(vfrdiv_vf_w, 4) +GEN_VEXT_VF(vfrdiv_vf_d, 8) /* Vector Widening Floating-Point Multiply */ static uint32_t vfwmul16(uint16_t a, uint16_t b, float_status *s) @@ -3234,12 +3246,12 @@ static uint64_t vfwmul32(uint32_t a, uint32_t b, float_status *s) } RVVCALL(OPFVV2, vfwmul_vv_h, WOP_UUU_H, H4, H2, H2, vfwmul16) RVVCALL(OPFVV2, vfwmul_vv_w, WOP_UUU_W, H8, H4, H4, vfwmul32) -GEN_VEXT_VV_ENV(vfwmul_vv_h) -GEN_VEXT_VV_ENV(vfwmul_vv_w) +GEN_VEXT_VV_ENV(vfwmul_vv_h, 4) +GEN_VEXT_VV_ENV(vfwmul_vv_w, 8) RVVCALL(OPFVF2, vfwmul_vf_h, WOP_UUU_H, H4, H2, vfwmul16) RVVCALL(OPFVF2, vfwmul_vf_w, WOP_UUU_W, H8, H4, vfwmul32) -GEN_VEXT_VF(vfwmul_vf_h) -GEN_VEXT_VF(vfwmul_vf_w) +GEN_VEXT_VF(vfwmul_vf_h, 4) +GEN_VEXT_VF(vfwmul_vf_w, 8) /* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */ #define OPFVV3(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \ @@ -3270,9 +3282,9 @@ static uint64_t fmacc64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfmacc_vv_h, OP_UUU_H, H2, H2, H2, fmacc16) RVVCALL(OPFVV3, vfmacc_vv_w, OP_UUU_W, H4, H4, H4, fmacc32) RVVCALL(OPFVV3, vfmacc_vv_d, OP_UUU_D, H8, H8, H8, fmacc64) -GEN_VEXT_VV_ENV(vfmacc_vv_h) -GEN_VEXT_VV_ENV(vfmacc_vv_w) -GEN_VEXT_VV_ENV(vfmacc_vv_d) +GEN_VEXT_VV_ENV(vfmacc_vv_h, 2) +GEN_VEXT_VV_ENV(vfmacc_vv_w, 4) +GEN_VEXT_VV_ENV(vfmacc_vv_d, 8) #define OPFVF3(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \ static void do_##NAME(void *vd, uint64_t s1, void *vs2, int i, \ @@ -3286,9 +3298,9 @@ static void do_##NAME(void *vd, uint64_t s1, void *vs2, int i, \ RVVCALL(OPFVF3, vfmacc_vf_h, OP_UUU_H, H2, H2, fmacc16) RVVCALL(OPFVF3, vfmacc_vf_w, OP_UUU_W, H4, H4, fmacc32) RVVCALL(OPFVF3, vfmacc_vf_d, OP_UUU_D, H8, H8, fmacc64) -GEN_VEXT_VF(vfmacc_vf_h) -GEN_VEXT_VF(vfmacc_vf_w) -GEN_VEXT_VF(vfmacc_vf_d) +GEN_VEXT_VF(vfmacc_vf_h, 2) +GEN_VEXT_VF(vfmacc_vf_w, 4) +GEN_VEXT_VF(vfmacc_vf_d, 8) static uint16_t fnmacc16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3311,15 +3323,15 @@ static uint64_t fnmacc64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfnmacc_vv_h, OP_UUU_H, H2, H2, H2, fnmacc16) RVVCALL(OPFVV3, vfnmacc_vv_w, OP_UUU_W, H4, H4, H4, fnmacc32) RVVCALL(OPFVV3, vfnmacc_vv_d, OP_UUU_D, H8, H8, H8, fnmacc64) -GEN_VEXT_VV_ENV(vfnmacc_vv_h) -GEN_VEXT_VV_ENV(vfnmacc_vv_w) -GEN_VEXT_VV_ENV(vfnmacc_vv_d) +GEN_VEXT_VV_ENV(vfnmacc_vv_h, 2) +GEN_VEXT_VV_ENV(vfnmacc_vv_w, 4) +GEN_VEXT_VV_ENV(vfnmacc_vv_d, 8) RVVCALL(OPFVF3, vfnmacc_vf_h, OP_UUU_H, H2, H2, fnmacc16) RVVCALL(OPFVF3, vfnmacc_vf_w, OP_UUU_W, H4, H4, fnmacc32) RVVCALL(OPFVF3, vfnmacc_vf_d, OP_UUU_D, H8, H8, fnmacc64) -GEN_VEXT_VF(vfnmacc_vf_h) -GEN_VEXT_VF(vfnmacc_vf_w) -GEN_VEXT_VF(vfnmacc_vf_d) +GEN_VEXT_VF(vfnmacc_vf_h, 2) +GEN_VEXT_VF(vfnmacc_vf_w, 4) +GEN_VEXT_VF(vfnmacc_vf_d, 8) static uint16_t fmsac16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3339,15 +3351,15 @@ static uint64_t fmsac64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfmsac_vv_h, OP_UUU_H, H2, H2, H2, fmsac16) RVVCALL(OPFVV3, vfmsac_vv_w, OP_UUU_W, H4, H4, H4, fmsac32) RVVCALL(OPFVV3, vfmsac_vv_d, OP_UUU_D, H8, H8, H8, fmsac64) -GEN_VEXT_VV_ENV(vfmsac_vv_h) -GEN_VEXT_VV_ENV(vfmsac_vv_w) -GEN_VEXT_VV_ENV(vfmsac_vv_d) +GEN_VEXT_VV_ENV(vfmsac_vv_h, 2) +GEN_VEXT_VV_ENV(vfmsac_vv_w, 4) +GEN_VEXT_VV_ENV(vfmsac_vv_d, 8) RVVCALL(OPFVF3, vfmsac_vf_h, OP_UUU_H, H2, H2, fmsac16) RVVCALL(OPFVF3, vfmsac_vf_w, OP_UUU_W, H4, H4, fmsac32) RVVCALL(OPFVF3, vfmsac_vf_d, OP_UUU_D, H8, H8, fmsac64) -GEN_VEXT_VF(vfmsac_vf_h) -GEN_VEXT_VF(vfmsac_vf_w) -GEN_VEXT_VF(vfmsac_vf_d) +GEN_VEXT_VF(vfmsac_vf_h, 2) +GEN_VEXT_VF(vfmsac_vf_w, 4) +GEN_VEXT_VF(vfmsac_vf_d, 8) static uint16_t fnmsac16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3367,15 +3379,15 @@ static uint64_t fnmsac64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfnmsac_vv_h, OP_UUU_H, H2, H2, H2, fnmsac16) RVVCALL(OPFVV3, vfnmsac_vv_w, OP_UUU_W, H4, H4, H4, fnmsac32) RVVCALL(OPFVV3, vfnmsac_vv_d, OP_UUU_D, H8, H8, H8, fnmsac64) -GEN_VEXT_VV_ENV(vfnmsac_vv_h) -GEN_VEXT_VV_ENV(vfnmsac_vv_w) -GEN_VEXT_VV_ENV(vfnmsac_vv_d) +GEN_VEXT_VV_ENV(vfnmsac_vv_h, 2) +GEN_VEXT_VV_ENV(vfnmsac_vv_w, 4) +GEN_VEXT_VV_ENV(vfnmsac_vv_d, 8) RVVCALL(OPFVF3, vfnmsac_vf_h, OP_UUU_H, H2, H2, fnmsac16) RVVCALL(OPFVF3, vfnmsac_vf_w, OP_UUU_W, H4, H4, fnmsac32) RVVCALL(OPFVF3, vfnmsac_vf_d, OP_UUU_D, H8, H8, fnmsac64) -GEN_VEXT_VF(vfnmsac_vf_h) -GEN_VEXT_VF(vfnmsac_vf_w) -GEN_VEXT_VF(vfnmsac_vf_d) +GEN_VEXT_VF(vfnmsac_vf_h, 2) +GEN_VEXT_VF(vfnmsac_vf_w, 4) +GEN_VEXT_VF(vfnmsac_vf_d, 8) static uint16_t fmadd16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3395,15 +3407,15 @@ static uint64_t fmadd64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfmadd_vv_h, OP_UUU_H, H2, H2, H2, fmadd16) RVVCALL(OPFVV3, vfmadd_vv_w, OP_UUU_W, H4, H4, H4, fmadd32) RVVCALL(OPFVV3, vfmadd_vv_d, OP_UUU_D, H8, H8, H8, fmadd64) -GEN_VEXT_VV_ENV(vfmadd_vv_h) -GEN_VEXT_VV_ENV(vfmadd_vv_w) -GEN_VEXT_VV_ENV(vfmadd_vv_d) +GEN_VEXT_VV_ENV(vfmadd_vv_h, 2) +GEN_VEXT_VV_ENV(vfmadd_vv_w, 4) +GEN_VEXT_VV_ENV(vfmadd_vv_d, 8) RVVCALL(OPFVF3, vfmadd_vf_h, OP_UUU_H, H2, H2, fmadd16) RVVCALL(OPFVF3, vfmadd_vf_w, OP_UUU_W, H4, H4, fmadd32) RVVCALL(OPFVF3, vfmadd_vf_d, OP_UUU_D, H8, H8, fmadd64) -GEN_VEXT_VF(vfmadd_vf_h) -GEN_VEXT_VF(vfmadd_vf_w) -GEN_VEXT_VF(vfmadd_vf_d) +GEN_VEXT_VF(vfmadd_vf_h, 2) +GEN_VEXT_VF(vfmadd_vf_w, 4) +GEN_VEXT_VF(vfmadd_vf_d, 8) static uint16_t fnmadd16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3426,15 +3438,15 @@ static uint64_t fnmadd64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfnmadd_vv_h, OP_UUU_H, H2, H2, H2, fnmadd16) RVVCALL(OPFVV3, vfnmadd_vv_w, OP_UUU_W, H4, H4, H4, fnmadd32) RVVCALL(OPFVV3, vfnmadd_vv_d, OP_UUU_D, H8, H8, H8, fnmadd64) -GEN_VEXT_VV_ENV(vfnmadd_vv_h) -GEN_VEXT_VV_ENV(vfnmadd_vv_w) -GEN_VEXT_VV_ENV(vfnmadd_vv_d) +GEN_VEXT_VV_ENV(vfnmadd_vv_h, 2) +GEN_VEXT_VV_ENV(vfnmadd_vv_w, 4) +GEN_VEXT_VV_ENV(vfnmadd_vv_d, 8) RVVCALL(OPFVF3, vfnmadd_vf_h, OP_UUU_H, H2, H2, fnmadd16) RVVCALL(OPFVF3, vfnmadd_vf_w, OP_UUU_W, H4, H4, fnmadd32) RVVCALL(OPFVF3, vfnmadd_vf_d, OP_UUU_D, H8, H8, fnmadd64) -GEN_VEXT_VF(vfnmadd_vf_h) -GEN_VEXT_VF(vfnmadd_vf_w) -GEN_VEXT_VF(vfnmadd_vf_d) +GEN_VEXT_VF(vfnmadd_vf_h, 2) +GEN_VEXT_VF(vfnmadd_vf_w, 4) +GEN_VEXT_VF(vfnmadd_vf_d, 8) static uint16_t fmsub16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3454,15 +3466,15 @@ static uint64_t fmsub64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfmsub_vv_h, OP_UUU_H, H2, H2, H2, fmsub16) RVVCALL(OPFVV3, vfmsub_vv_w, OP_UUU_W, H4, H4, H4, fmsub32) RVVCALL(OPFVV3, vfmsub_vv_d, OP_UUU_D, H8, H8, H8, fmsub64) -GEN_VEXT_VV_ENV(vfmsub_vv_h) -GEN_VEXT_VV_ENV(vfmsub_vv_w) -GEN_VEXT_VV_ENV(vfmsub_vv_d) +GEN_VEXT_VV_ENV(vfmsub_vv_h, 2) +GEN_VEXT_VV_ENV(vfmsub_vv_w, 4) +GEN_VEXT_VV_ENV(vfmsub_vv_d, 8) RVVCALL(OPFVF3, vfmsub_vf_h, OP_UUU_H, H2, H2, fmsub16) RVVCALL(OPFVF3, vfmsub_vf_w, OP_UUU_W, H4, H4, fmsub32) RVVCALL(OPFVF3, vfmsub_vf_d, OP_UUU_D, H8, H8, fmsub64) -GEN_VEXT_VF(vfmsub_vf_h) -GEN_VEXT_VF(vfmsub_vf_w) -GEN_VEXT_VF(vfmsub_vf_d) +GEN_VEXT_VF(vfmsub_vf_h, 2) +GEN_VEXT_VF(vfmsub_vf_w, 4) +GEN_VEXT_VF(vfmsub_vf_d, 8) static uint16_t fnmsub16(uint16_t a, uint16_t b, uint16_t d, float_status *s) { @@ -3482,15 +3494,15 @@ static uint64_t fnmsub64(uint64_t a, uint64_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfnmsub_vv_h, OP_UUU_H, H2, H2, H2, fnmsub16) RVVCALL(OPFVV3, vfnmsub_vv_w, OP_UUU_W, H4, H4, H4, fnmsub32) RVVCALL(OPFVV3, vfnmsub_vv_d, OP_UUU_D, H8, H8, H8, fnmsub64) -GEN_VEXT_VV_ENV(vfnmsub_vv_h) -GEN_VEXT_VV_ENV(vfnmsub_vv_w) -GEN_VEXT_VV_ENV(vfnmsub_vv_d) +GEN_VEXT_VV_ENV(vfnmsub_vv_h, 2) +GEN_VEXT_VV_ENV(vfnmsub_vv_w, 4) +GEN_VEXT_VV_ENV(vfnmsub_vv_d, 8) RVVCALL(OPFVF3, vfnmsub_vf_h, OP_UUU_H, H2, H2, fnmsub16) RVVCALL(OPFVF3, vfnmsub_vf_w, OP_UUU_W, H4, H4, fnmsub32) RVVCALL(OPFVF3, vfnmsub_vf_d, OP_UUU_D, H8, H8, fnmsub64) -GEN_VEXT_VF(vfnmsub_vf_h) -GEN_VEXT_VF(vfnmsub_vf_w) -GEN_VEXT_VF(vfnmsub_vf_d) +GEN_VEXT_VF(vfnmsub_vf_h, 2) +GEN_VEXT_VF(vfnmsub_vf_w, 4) +GEN_VEXT_VF(vfnmsub_vf_d, 8) /* Vector Widening Floating-Point Fused Multiply-Add Instructions */ static uint32_t fwmacc16(uint16_t a, uint16_t b, uint32_t d, float_status *s) @@ -3507,12 +3519,12 @@ static uint64_t fwmacc32(uint32_t a, uint32_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfwmacc_vv_h, WOP_UUU_H, H4, H2, H2, fwmacc16) RVVCALL(OPFVV3, vfwmacc_vv_w, WOP_UUU_W, H8, H4, H4, fwmacc32) -GEN_VEXT_VV_ENV(vfwmacc_vv_h) -GEN_VEXT_VV_ENV(vfwmacc_vv_w) +GEN_VEXT_VV_ENV(vfwmacc_vv_h, 4) +GEN_VEXT_VV_ENV(vfwmacc_vv_w, 8) RVVCALL(OPFVF3, vfwmacc_vf_h, WOP_UUU_H, H4, H2, fwmacc16) RVVCALL(OPFVF3, vfwmacc_vf_w, WOP_UUU_W, H8, H4, fwmacc32) -GEN_VEXT_VF(vfwmacc_vf_h) -GEN_VEXT_VF(vfwmacc_vf_w) +GEN_VEXT_VF(vfwmacc_vf_h, 4) +GEN_VEXT_VF(vfwmacc_vf_w, 8) static uint32_t fwnmacc16(uint16_t a, uint16_t b, uint32_t d, float_status *s) { @@ -3530,12 +3542,12 @@ static uint64_t fwnmacc32(uint32_t a, uint32_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfwnmacc_vv_h, WOP_UUU_H, H4, H2, H2, fwnmacc16) RVVCALL(OPFVV3, vfwnmacc_vv_w, WOP_UUU_W, H8, H4, H4, fwnmacc32) -GEN_VEXT_VV_ENV(vfwnmacc_vv_h) -GEN_VEXT_VV_ENV(vfwnmacc_vv_w) +GEN_VEXT_VV_ENV(vfwnmacc_vv_h, 4) +GEN_VEXT_VV_ENV(vfwnmacc_vv_w, 8) RVVCALL(OPFVF3, vfwnmacc_vf_h, WOP_UUU_H, H4, H2, fwnmacc16) RVVCALL(OPFVF3, vfwnmacc_vf_w, WOP_UUU_W, H8, H4, fwnmacc32) -GEN_VEXT_VF(vfwnmacc_vf_h) -GEN_VEXT_VF(vfwnmacc_vf_w) +GEN_VEXT_VF(vfwnmacc_vf_h, 4) +GEN_VEXT_VF(vfwnmacc_vf_w, 8) static uint32_t fwmsac16(uint16_t a, uint16_t b, uint32_t d, float_status *s) { @@ -3553,12 +3565,12 @@ static uint64_t fwmsac32(uint32_t a, uint32_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfwmsac_vv_h, WOP_UUU_H, H4, H2, H2, fwmsac16) RVVCALL(OPFVV3, vfwmsac_vv_w, WOP_UUU_W, H8, H4, H4, fwmsac32) -GEN_VEXT_VV_ENV(vfwmsac_vv_h) -GEN_VEXT_VV_ENV(vfwmsac_vv_w) +GEN_VEXT_VV_ENV(vfwmsac_vv_h, 4) +GEN_VEXT_VV_ENV(vfwmsac_vv_w, 8) RVVCALL(OPFVF3, vfwmsac_vf_h, WOP_UUU_H, H4, H2, fwmsac16) RVVCALL(OPFVF3, vfwmsac_vf_w, WOP_UUU_W, H8, H4, fwmsac32) -GEN_VEXT_VF(vfwmsac_vf_h) -GEN_VEXT_VF(vfwmsac_vf_w) +GEN_VEXT_VF(vfwmsac_vf_h, 4) +GEN_VEXT_VF(vfwmsac_vf_w, 8) static uint32_t fwnmsac16(uint16_t a, uint16_t b, uint32_t d, float_status *s) { @@ -3576,12 +3588,12 @@ static uint64_t fwnmsac32(uint32_t a, uint32_t b, uint64_t d, float_status *s) RVVCALL(OPFVV3, vfwnmsac_vv_h, WOP_UUU_H, H4, H2, H2, fwnmsac16) RVVCALL(OPFVV3, vfwnmsac_vv_w, WOP_UUU_W, H8, H4, H4, fwnmsac32) -GEN_VEXT_VV_ENV(vfwnmsac_vv_h) -GEN_VEXT_VV_ENV(vfwnmsac_vv_w) +GEN_VEXT_VV_ENV(vfwnmsac_vv_h, 4) +GEN_VEXT_VV_ENV(vfwnmsac_vv_w, 8) RVVCALL(OPFVF3, vfwnmsac_vf_h, WOP_UUU_H, H4, H2, fwnmsac16) RVVCALL(OPFVF3, vfwnmsac_vf_w, WOP_UUU_W, H8, H4, fwnmsac32) -GEN_VEXT_VF(vfwnmsac_vf_h) -GEN_VEXT_VF(vfwnmsac_vf_w) +GEN_VEXT_VF(vfwnmsac_vf_h, 4) +GEN_VEXT_VF(vfwnmsac_vf_w, 8) /* Vector Floating-Point Square-Root Instruction */ /* (TD, T2, TX2) */ @@ -3597,12 +3609,15 @@ static void do_##NAME(void *vd, void *vs2, int i, \ *((TD *)vd + HD(i)) = OP(s2, &env->fp_status); \ } -#define GEN_VEXT_V_ENV(NAME) \ +#define GEN_VEXT_V_ENV(NAME, ESZ) \ void HELPER(NAME)(void *vd, void *v0, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t total_elems = \ + vext_get_total_elems(env, desc, ESZ); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ if (vl == 0) { \ @@ -3615,14 +3630,16 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \ do_##NAME(vd, vs2, i, env); \ } \ env->vstart = 0; \ + vext_set_elems_1s(vd, vta, vl * ESZ, \ + total_elems * ESZ); \ } RVVCALL(OPFVV1, vfsqrt_v_h, OP_UU_H, H2, H2, float16_sqrt) RVVCALL(OPFVV1, vfsqrt_v_w, OP_UU_W, H4, H4, float32_sqrt) RVVCALL(OPFVV1, vfsqrt_v_d, OP_UU_D, H8, H8, float64_sqrt) -GEN_VEXT_V_ENV(vfsqrt_v_h) -GEN_VEXT_V_ENV(vfsqrt_v_w) -GEN_VEXT_V_ENV(vfsqrt_v_d) +GEN_VEXT_V_ENV(vfsqrt_v_h, 2) +GEN_VEXT_V_ENV(vfsqrt_v_w, 4) +GEN_VEXT_V_ENV(vfsqrt_v_d, 8) /* * Vector Floating-Point Reciprocal Square-Root Estimate Instruction @@ -3802,9 +3819,9 @@ static float64 frsqrt7_d(float64 f, float_status *s) RVVCALL(OPFVV1, vfrsqrt7_v_h, OP_UU_H, H2, H2, frsqrt7_h) RVVCALL(OPFVV1, vfrsqrt7_v_w, OP_UU_W, H4, H4, frsqrt7_s) RVVCALL(OPFVV1, vfrsqrt7_v_d, OP_UU_D, H8, H8, frsqrt7_d) -GEN_VEXT_V_ENV(vfrsqrt7_v_h) -GEN_VEXT_V_ENV(vfrsqrt7_v_w) -GEN_VEXT_V_ENV(vfrsqrt7_v_d) +GEN_VEXT_V_ENV(vfrsqrt7_v_h, 2) +GEN_VEXT_V_ENV(vfrsqrt7_v_w, 4) +GEN_VEXT_V_ENV(vfrsqrt7_v_d, 8) /* * Vector Floating-Point Reciprocal Estimate Instruction @@ -3993,36 +4010,36 @@ static float64 frec7_d(float64 f, float_status *s) RVVCALL(OPFVV1, vfrec7_v_h, OP_UU_H, H2, H2, frec7_h) RVVCALL(OPFVV1, vfrec7_v_w, OP_UU_W, H4, H4, frec7_s) RVVCALL(OPFVV1, vfrec7_v_d, OP_UU_D, H8, H8, frec7_d) -GEN_VEXT_V_ENV(vfrec7_v_h) -GEN_VEXT_V_ENV(vfrec7_v_w) -GEN_VEXT_V_ENV(vfrec7_v_d) +GEN_VEXT_V_ENV(vfrec7_v_h, 2) +GEN_VEXT_V_ENV(vfrec7_v_w, 4) +GEN_VEXT_V_ENV(vfrec7_v_d, 8) /* Vector Floating-Point MIN/MAX Instructions */ RVVCALL(OPFVV2, vfmin_vv_h, OP_UUU_H, H2, H2, H2, float16_minimum_number) RVVCALL(OPFVV2, vfmin_vv_w, OP_UUU_W, H4, H4, H4, float32_minimum_number) RVVCALL(OPFVV2, vfmin_vv_d, OP_UUU_D, H8, H8, H8, float64_minimum_number) -GEN_VEXT_VV_ENV(vfmin_vv_h) -GEN_VEXT_VV_ENV(vfmin_vv_w) -GEN_VEXT_VV_ENV(vfmin_vv_d) +GEN_VEXT_VV_ENV(vfmin_vv_h, 2) +GEN_VEXT_VV_ENV(vfmin_vv_w, 4) +GEN_VEXT_VV_ENV(vfmin_vv_d, 8) RVVCALL(OPFVF2, vfmin_vf_h, OP_UUU_H, H2, H2, float16_minimum_number) RVVCALL(OPFVF2, vfmin_vf_w, OP_UUU_W, H4, H4, float32_minimum_number) RVVCALL(OPFVF2, vfmin_vf_d, OP_UUU_D, H8, H8, float64_minimum_number) -GEN_VEXT_VF(vfmin_vf_h) -GEN_VEXT_VF(vfmin_vf_w) -GEN_VEXT_VF(vfmin_vf_d) +GEN_VEXT_VF(vfmin_vf_h, 2) +GEN_VEXT_VF(vfmin_vf_w, 4) +GEN_VEXT_VF(vfmin_vf_d, 8) RVVCALL(OPFVV2, vfmax_vv_h, OP_UUU_H, H2, H2, H2, float16_maximum_number) RVVCALL(OPFVV2, vfmax_vv_w, OP_UUU_W, H4, H4, H4, float32_maximum_number) RVVCALL(OPFVV2, vfmax_vv_d, OP_UUU_D, H8, H8, H8, float64_maximum_number) -GEN_VEXT_VV_ENV(vfmax_vv_h) -GEN_VEXT_VV_ENV(vfmax_vv_w) -GEN_VEXT_VV_ENV(vfmax_vv_d) +GEN_VEXT_VV_ENV(vfmax_vv_h, 2) +GEN_VEXT_VV_ENV(vfmax_vv_w, 4) +GEN_VEXT_VV_ENV(vfmax_vv_d, 8) RVVCALL(OPFVF2, vfmax_vf_h, OP_UUU_H, H2, H2, float16_maximum_number) RVVCALL(OPFVF2, vfmax_vf_w, OP_UUU_W, H4, H4, float32_maximum_number) RVVCALL(OPFVF2, vfmax_vf_d, OP_UUU_D, H8, H8, float64_maximum_number) -GEN_VEXT_VF(vfmax_vf_h) -GEN_VEXT_VF(vfmax_vf_w) -GEN_VEXT_VF(vfmax_vf_d) +GEN_VEXT_VF(vfmax_vf_h, 2) +GEN_VEXT_VF(vfmax_vf_w, 4) +GEN_VEXT_VF(vfmax_vf_d, 8) /* Vector Floating-Point Sign-Injection Instructions */ static uint16_t fsgnj16(uint16_t a, uint16_t b, float_status *s) @@ -4043,15 +4060,15 @@ static uint64_t fsgnj64(uint64_t a, uint64_t b, float_status *s) RVVCALL(OPFVV2, vfsgnj_vv_h, OP_UUU_H, H2, H2, H2, fsgnj16) RVVCALL(OPFVV2, vfsgnj_vv_w, OP_UUU_W, H4, H4, H4, fsgnj32) RVVCALL(OPFVV2, vfsgnj_vv_d, OP_UUU_D, H8, H8, H8, fsgnj64) -GEN_VEXT_VV_ENV(vfsgnj_vv_h) -GEN_VEXT_VV_ENV(vfsgnj_vv_w) -GEN_VEXT_VV_ENV(vfsgnj_vv_d) +GEN_VEXT_VV_ENV(vfsgnj_vv_h, 2) +GEN_VEXT_VV_ENV(vfsgnj_vv_w, 4) +GEN_VEXT_VV_ENV(vfsgnj_vv_d, 8) RVVCALL(OPFVF2, vfsgnj_vf_h, OP_UUU_H, H2, H2, fsgnj16) RVVCALL(OPFVF2, vfsgnj_vf_w, OP_UUU_W, H4, H4, fsgnj32) RVVCALL(OPFVF2, vfsgnj_vf_d, OP_UUU_D, H8, H8, fsgnj64) -GEN_VEXT_VF(vfsgnj_vf_h) -GEN_VEXT_VF(vfsgnj_vf_w) -GEN_VEXT_VF(vfsgnj_vf_d) +GEN_VEXT_VF(vfsgnj_vf_h, 2) +GEN_VEXT_VF(vfsgnj_vf_w, 4) +GEN_VEXT_VF(vfsgnj_vf_d, 8) static uint16_t fsgnjn16(uint16_t a, uint16_t b, float_status *s) { @@ -4071,15 +4088,15 @@ static uint64_t fsgnjn64(uint64_t a, uint64_t b, float_status *s) RVVCALL(OPFVV2, vfsgnjn_vv_h, OP_UUU_H, H2, H2, H2, fsgnjn16) RVVCALL(OPFVV2, vfsgnjn_vv_w, OP_UUU_W, H4, H4, H4, fsgnjn32) RVVCALL(OPFVV2, vfsgnjn_vv_d, OP_UUU_D, H8, H8, H8, fsgnjn64) -GEN_VEXT_VV_ENV(vfsgnjn_vv_h) -GEN_VEXT_VV_ENV(vfsgnjn_vv_w) -GEN_VEXT_VV_ENV(vfsgnjn_vv_d) +GEN_VEXT_VV_ENV(vfsgnjn_vv_h, 2) +GEN_VEXT_VV_ENV(vfsgnjn_vv_w, 4) +GEN_VEXT_VV_ENV(vfsgnjn_vv_d, 8) RVVCALL(OPFVF2, vfsgnjn_vf_h, OP_UUU_H, H2, H2, fsgnjn16) RVVCALL(OPFVF2, vfsgnjn_vf_w, OP_UUU_W, H4, H4, fsgnjn32) RVVCALL(OPFVF2, vfsgnjn_vf_d, OP_UUU_D, H8, H8, fsgnjn64) -GEN_VEXT_VF(vfsgnjn_vf_h) -GEN_VEXT_VF(vfsgnjn_vf_w) -GEN_VEXT_VF(vfsgnjn_vf_d) +GEN_VEXT_VF(vfsgnjn_vf_h, 2) +GEN_VEXT_VF(vfsgnjn_vf_w, 4) +GEN_VEXT_VF(vfsgnjn_vf_d, 8) static uint16_t fsgnjx16(uint16_t a, uint16_t b, float_status *s) { @@ -4099,15 +4116,15 @@ static uint64_t fsgnjx64(uint64_t a, uint64_t b, float_status *s) RVVCALL(OPFVV2, vfsgnjx_vv_h, OP_UUU_H, H2, H2, H2, fsgnjx16) RVVCALL(OPFVV2, vfsgnjx_vv_w, OP_UUU_W, H4, H4, H4, fsgnjx32) RVVCALL(OPFVV2, vfsgnjx_vv_d, OP_UUU_D, H8, H8, H8, fsgnjx64) -GEN_VEXT_VV_ENV(vfsgnjx_vv_h) -GEN_VEXT_VV_ENV(vfsgnjx_vv_w) -GEN_VEXT_VV_ENV(vfsgnjx_vv_d) +GEN_VEXT_VV_ENV(vfsgnjx_vv_h, 2) +GEN_VEXT_VV_ENV(vfsgnjx_vv_w, 4) +GEN_VEXT_VV_ENV(vfsgnjx_vv_d, 8) RVVCALL(OPFVF2, vfsgnjx_vf_h, OP_UUU_H, H2, H2, fsgnjx16) RVVCALL(OPFVF2, vfsgnjx_vf_w, OP_UUU_W, H4, H4, fsgnjx32) RVVCALL(OPFVF2, vfsgnjx_vf_d, OP_UUU_D, H8, H8, fsgnjx64) -GEN_VEXT_VF(vfsgnjx_vf_h) -GEN_VEXT_VF(vfsgnjx_vf_w) -GEN_VEXT_VF(vfsgnjx_vf_d) +GEN_VEXT_VF(vfsgnjx_vf_h, 2) +GEN_VEXT_VF(vfsgnjx_vf_w, 4) +GEN_VEXT_VF(vfsgnjx_vf_d, 8) /* Vector Floating-Point Compare Instructions */ #define GEN_VEXT_CMP_VV_ENV(NAME, ETYPE, H, DO_OP) \ @@ -4116,6 +4133,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t total_elems = env_archcpu(env)->cfg.vlen; \ + uint32_t vta_all_1s = vext_vta_all_1s(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -4128,6 +4147,13 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ DO_OP(s2, s1, &env->fp_status)); \ } \ env->vstart = 0; \ + /* mask destination register are always tail-agnostic */ \ + /* set tail elements to 1s */ \ + if (vta_all_1s) { \ + for (; i < total_elems; i++) { \ + vext_set_elem_mask(vd, i, 1); \ + } \ + } \ } GEN_VEXT_CMP_VV_ENV(vmfeq_vv_h, uint16_t, H2, float16_eq_quiet) @@ -4140,6 +4166,8 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t total_elems = env_archcpu(env)->cfg.vlen; \ + uint32_t vta_all_1s = vext_vta_all_1s(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -4151,6 +4179,13 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \ DO_OP(s2, (ETYPE)s1, &env->fp_status)); \ } \ env->vstart = 0; \ + /* mask destination register are always tail-agnostic */ \ + /* set tail elements to 1s */ \ + if (vta_all_1s) { \ + for (; i < total_elems; i++) { \ + vext_set_elem_mask(vd, i, 1); \ + } \ + } \ } GEN_VEXT_CMP_VF(vmfeq_vf_h, uint16_t, H2, float16_eq_quiet) @@ -4251,12 +4286,15 @@ static void do_##NAME(void *vd, void *vs2, int i) \ *((TD *)vd + HD(i)) = OP(s2); \ } -#define GEN_VEXT_V(NAME) \ +#define GEN_VEXT_V(NAME, ESZ) \ void HELPER(NAME)(void *vd, void *v0, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t total_elems = \ + vext_get_total_elems(env, desc, ESZ); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -4266,6 +4304,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \ do_##NAME(vd, vs2, i); \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * ESZ, \ + total_elems * ESZ); \ } target_ulong fclass_h(uint64_t frs1) @@ -4328,17 +4369,22 @@ target_ulong fclass_d(uint64_t frs1) RVVCALL(OPIVV1, vfclass_v_h, OP_UU_H, H2, H2, fclass_h) RVVCALL(OPIVV1, vfclass_v_w, OP_UU_W, H4, H4, fclass_s) RVVCALL(OPIVV1, vfclass_v_d, OP_UU_D, H8, H8, fclass_d) -GEN_VEXT_V(vfclass_v_h) -GEN_VEXT_V(vfclass_v_w) -GEN_VEXT_V(vfclass_v_d) +GEN_VEXT_V(vfclass_v_h, 2) +GEN_VEXT_V(vfclass_v_w, 4) +GEN_VEXT_V(vfclass_v_d, 8) /* Vector Floating-Point Merge Instruction */ + #define GEN_VFMERGE_VF(NAME, ETYPE, H) \ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = \ + vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -4347,6 +4393,8 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \ = (!vm && !vext_elem_mask(v0, i) ? s2 : s1); \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VFMERGE_VF(vfmerge_vfm_h, int16_t, H2) @@ -4358,33 +4406,33 @@ GEN_VFMERGE_VF(vfmerge_vfm_d, int64_t, H8) RVVCALL(OPFVV1, vfcvt_xu_f_v_h, OP_UU_H, H2, H2, float16_to_uint16) RVVCALL(OPFVV1, vfcvt_xu_f_v_w, OP_UU_W, H4, H4, float32_to_uint32) RVVCALL(OPFVV1, vfcvt_xu_f_v_d, OP_UU_D, H8, H8, float64_to_uint64) -GEN_VEXT_V_ENV(vfcvt_xu_f_v_h) -GEN_VEXT_V_ENV(vfcvt_xu_f_v_w) -GEN_VEXT_V_ENV(vfcvt_xu_f_v_d) +GEN_VEXT_V_ENV(vfcvt_xu_f_v_h, 2) +GEN_VEXT_V_ENV(vfcvt_xu_f_v_w, 4) +GEN_VEXT_V_ENV(vfcvt_xu_f_v_d, 8) /* vfcvt.x.f.v vd, vs2, vm # Convert float to signed integer. */ RVVCALL(OPFVV1, vfcvt_x_f_v_h, OP_UU_H, H2, H2, float16_to_int16) RVVCALL(OPFVV1, vfcvt_x_f_v_w, OP_UU_W, H4, H4, float32_to_int32) RVVCALL(OPFVV1, vfcvt_x_f_v_d, OP_UU_D, H8, H8, float64_to_int64) -GEN_VEXT_V_ENV(vfcvt_x_f_v_h) -GEN_VEXT_V_ENV(vfcvt_x_f_v_w) -GEN_VEXT_V_ENV(vfcvt_x_f_v_d) +GEN_VEXT_V_ENV(vfcvt_x_f_v_h, 2) +GEN_VEXT_V_ENV(vfcvt_x_f_v_w, 4) +GEN_VEXT_V_ENV(vfcvt_x_f_v_d, 8) /* vfcvt.f.xu.v vd, vs2, vm # Convert unsigned integer to float. */ RVVCALL(OPFVV1, vfcvt_f_xu_v_h, OP_UU_H, H2, H2, uint16_to_float16) RVVCALL(OPFVV1, vfcvt_f_xu_v_w, OP_UU_W, H4, H4, uint32_to_float32) RVVCALL(OPFVV1, vfcvt_f_xu_v_d, OP_UU_D, H8, H8, uint64_to_float64) -GEN_VEXT_V_ENV(vfcvt_f_xu_v_h) -GEN_VEXT_V_ENV(vfcvt_f_xu_v_w) -GEN_VEXT_V_ENV(vfcvt_f_xu_v_d) +GEN_VEXT_V_ENV(vfcvt_f_xu_v_h, 2) +GEN_VEXT_V_ENV(vfcvt_f_xu_v_w, 4) +GEN_VEXT_V_ENV(vfcvt_f_xu_v_d, 8) /* vfcvt.f.x.v vd, vs2, vm # Convert integer to float. */ RVVCALL(OPFVV1, vfcvt_f_x_v_h, OP_UU_H, H2, H2, int16_to_float16) RVVCALL(OPFVV1, vfcvt_f_x_v_w, OP_UU_W, H4, H4, int32_to_float32) RVVCALL(OPFVV1, vfcvt_f_x_v_d, OP_UU_D, H8, H8, int64_to_float64) -GEN_VEXT_V_ENV(vfcvt_f_x_v_h) -GEN_VEXT_V_ENV(vfcvt_f_x_v_w) -GEN_VEXT_V_ENV(vfcvt_f_x_v_d) +GEN_VEXT_V_ENV(vfcvt_f_x_v_h, 2) +GEN_VEXT_V_ENV(vfcvt_f_x_v_w, 4) +GEN_VEXT_V_ENV(vfcvt_f_x_v_d, 8) /* Widening Floating-Point/Integer Type-Convert Instructions */ /* (TD, T2, TX2) */ @@ -4394,30 +4442,30 @@ GEN_VEXT_V_ENV(vfcvt_f_x_v_d) /* vfwcvt.xu.f.v vd, vs2, vm # Convert float to double-width unsigned integer.*/ RVVCALL(OPFVV1, vfwcvt_xu_f_v_h, WOP_UU_H, H4, H2, float16_to_uint32) RVVCALL(OPFVV1, vfwcvt_xu_f_v_w, WOP_UU_W, H8, H4, float32_to_uint64) -GEN_VEXT_V_ENV(vfwcvt_xu_f_v_h) -GEN_VEXT_V_ENV(vfwcvt_xu_f_v_w) +GEN_VEXT_V_ENV(vfwcvt_xu_f_v_h, 4) +GEN_VEXT_V_ENV(vfwcvt_xu_f_v_w, 8) /* vfwcvt.x.f.v vd, vs2, vm # Convert float to double-width signed integer. */ RVVCALL(OPFVV1, vfwcvt_x_f_v_h, WOP_UU_H, H4, H2, float16_to_int32) RVVCALL(OPFVV1, vfwcvt_x_f_v_w, WOP_UU_W, H8, H4, float32_to_int64) -GEN_VEXT_V_ENV(vfwcvt_x_f_v_h) -GEN_VEXT_V_ENV(vfwcvt_x_f_v_w) +GEN_VEXT_V_ENV(vfwcvt_x_f_v_h, 4) +GEN_VEXT_V_ENV(vfwcvt_x_f_v_w, 8) /* vfwcvt.f.xu.v vd, vs2, vm # Convert unsigned integer to double-width float */ RVVCALL(OPFVV1, vfwcvt_f_xu_v_b, WOP_UU_B, H2, H1, uint8_to_float16) RVVCALL(OPFVV1, vfwcvt_f_xu_v_h, WOP_UU_H, H4, H2, uint16_to_float32) RVVCALL(OPFVV1, vfwcvt_f_xu_v_w, WOP_UU_W, H8, H4, uint32_to_float64) -GEN_VEXT_V_ENV(vfwcvt_f_xu_v_b) -GEN_VEXT_V_ENV(vfwcvt_f_xu_v_h) -GEN_VEXT_V_ENV(vfwcvt_f_xu_v_w) +GEN_VEXT_V_ENV(vfwcvt_f_xu_v_b, 2) +GEN_VEXT_V_ENV(vfwcvt_f_xu_v_h, 4) +GEN_VEXT_V_ENV(vfwcvt_f_xu_v_w, 8) /* vfwcvt.f.x.v vd, vs2, vm # Convert integer to double-width float. */ RVVCALL(OPFVV1, vfwcvt_f_x_v_b, WOP_UU_B, H2, H1, int8_to_float16) RVVCALL(OPFVV1, vfwcvt_f_x_v_h, WOP_UU_H, H4, H2, int16_to_float32) RVVCALL(OPFVV1, vfwcvt_f_x_v_w, WOP_UU_W, H8, H4, int32_to_float64) -GEN_VEXT_V_ENV(vfwcvt_f_x_v_b) -GEN_VEXT_V_ENV(vfwcvt_f_x_v_h) -GEN_VEXT_V_ENV(vfwcvt_f_x_v_w) +GEN_VEXT_V_ENV(vfwcvt_f_x_v_b, 2) +GEN_VEXT_V_ENV(vfwcvt_f_x_v_h, 4) +GEN_VEXT_V_ENV(vfwcvt_f_x_v_w, 8) /* * vfwcvt.f.f.v vd, vs2, vm @@ -4430,8 +4478,8 @@ static uint32_t vfwcvtffv16(uint16_t a, float_status *s) RVVCALL(OPFVV1, vfwcvt_f_f_v_h, WOP_UU_H, H4, H2, vfwcvtffv16) RVVCALL(OPFVV1, vfwcvt_f_f_v_w, WOP_UU_W, H8, H4, float32_to_float64) -GEN_VEXT_V_ENV(vfwcvt_f_f_v_h) -GEN_VEXT_V_ENV(vfwcvt_f_f_v_w) +GEN_VEXT_V_ENV(vfwcvt_f_f_v_h, 4) +GEN_VEXT_V_ENV(vfwcvt_f_f_v_w, 8) /* Narrowing Floating-Point/Integer Type-Convert Instructions */ /* (TD, T2, TX2) */ @@ -4442,29 +4490,29 @@ GEN_VEXT_V_ENV(vfwcvt_f_f_v_w) RVVCALL(OPFVV1, vfncvt_xu_f_w_b, NOP_UU_B, H1, H2, float16_to_uint8) RVVCALL(OPFVV1, vfncvt_xu_f_w_h, NOP_UU_H, H2, H4, float32_to_uint16) RVVCALL(OPFVV1, vfncvt_xu_f_w_w, NOP_UU_W, H4, H8, float64_to_uint32) -GEN_VEXT_V_ENV(vfncvt_xu_f_w_b) -GEN_VEXT_V_ENV(vfncvt_xu_f_w_h) -GEN_VEXT_V_ENV(vfncvt_xu_f_w_w) +GEN_VEXT_V_ENV(vfncvt_xu_f_w_b, 1) +GEN_VEXT_V_ENV(vfncvt_xu_f_w_h, 2) +GEN_VEXT_V_ENV(vfncvt_xu_f_w_w, 4) /* vfncvt.x.f.v vd, vs2, vm # Convert double-width float to signed integer. */ RVVCALL(OPFVV1, vfncvt_x_f_w_b, NOP_UU_B, H1, H2, float16_to_int8) RVVCALL(OPFVV1, vfncvt_x_f_w_h, NOP_UU_H, H2, H4, float32_to_int16) RVVCALL(OPFVV1, vfncvt_x_f_w_w, NOP_UU_W, H4, H8, float64_to_int32) -GEN_VEXT_V_ENV(vfncvt_x_f_w_b) -GEN_VEXT_V_ENV(vfncvt_x_f_w_h) -GEN_VEXT_V_ENV(vfncvt_x_f_w_w) +GEN_VEXT_V_ENV(vfncvt_x_f_w_b, 1) +GEN_VEXT_V_ENV(vfncvt_x_f_w_h, 2) +GEN_VEXT_V_ENV(vfncvt_x_f_w_w, 4) /* vfncvt.f.xu.v vd, vs2, vm # Convert double-width unsigned integer to float */ RVVCALL(OPFVV1, vfncvt_f_xu_w_h, NOP_UU_H, H2, H4, uint32_to_float16) RVVCALL(OPFVV1, vfncvt_f_xu_w_w, NOP_UU_W, H4, H8, uint64_to_float32) -GEN_VEXT_V_ENV(vfncvt_f_xu_w_h) -GEN_VEXT_V_ENV(vfncvt_f_xu_w_w) +GEN_VEXT_V_ENV(vfncvt_f_xu_w_h, 2) +GEN_VEXT_V_ENV(vfncvt_f_xu_w_w, 4) /* vfncvt.f.x.v vd, vs2, vm # Convert double-width integer to float. */ RVVCALL(OPFVV1, vfncvt_f_x_w_h, NOP_UU_H, H2, H4, int32_to_float16) RVVCALL(OPFVV1, vfncvt_f_x_w_w, NOP_UU_W, H4, H8, int64_to_float32) -GEN_VEXT_V_ENV(vfncvt_f_x_w_h) -GEN_VEXT_V_ENV(vfncvt_f_x_w_w) +GEN_VEXT_V_ENV(vfncvt_f_x_w_h, 2) +GEN_VEXT_V_ENV(vfncvt_f_x_w_w, 4) /* vfncvt.f.f.v vd, vs2, vm # Convert double float to single-width float. */ static uint16_t vfncvtffv16(uint32_t a, float_status *s) @@ -4474,8 +4522,8 @@ static uint16_t vfncvtffv16(uint32_t a, float_status *s) RVVCALL(OPFVV1, vfncvt_f_f_w_h, NOP_UU_H, H2, H4, vfncvtffv16) RVVCALL(OPFVV1, vfncvt_f_f_w_w, NOP_UU_W, H4, H8, float64_to_float32) -GEN_VEXT_V_ENV(vfncvt_f_f_w_h) -GEN_VEXT_V_ENV(vfncvt_f_f_w_w) +GEN_VEXT_V_ENV(vfncvt_f_f_w_h, 2) +GEN_VEXT_V_ENV(vfncvt_f_f_w_w, 4) /* *** Vector Reduction Operations From df4f52a7582c5cd8d2d2f73684996ebc18ac72e3 Mon Sep 17 00:00:00 2001 From: eopXD Date: Mon, 6 Jun 2022 06:16:16 +0000 Subject: [PATCH 930/935] target/riscv: rvv: Add tail agnostic for vector reduction instructions Signed-off-by: eop Chen Reviewed-by: Frank Chang Reviewed-by: Weiwei Li Acked-by: Alistair Francis Message-Id: <165449614532.19704.7000832880482980398-13@git.sr.ht> Signed-off-by: Alistair Francis --- target/riscv/vector_helper.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 17390d8d06..174a548ac2 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4535,6 +4535,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(TD); \ + uint32_t vlenb = simd_maxsz(desc); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ TD s1 = *((TD *)vs1 + HD(0)); \ \ @@ -4547,6 +4550,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ } \ *((TD *)vd + HD(0)) = s1; \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, esz, vlenb); \ } /* vd[0] = sum(vs1[0], vs2[*]) */ @@ -4616,6 +4621,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(TD); \ + uint32_t vlenb = simd_maxsz(desc); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ TD s1 = *((TD *)vs1 + HD(0)); \ \ @@ -4628,6 +4636,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ } \ *((TD *)vd + HD(0)) = s1; \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, esz, vlenb); \ } /* Unordered sum */ @@ -4652,6 +4662,9 @@ void HELPER(vfwredsum_vs_h)(void *vd, void *v0, void *vs1, { uint32_t vm = vext_vm(desc); uint32_t vl = env->vl; + uint32_t esz = sizeof(uint32_t); + uint32_t vlenb = simd_maxsz(desc); + uint32_t vta = vext_vta(desc); uint32_t i; uint32_t s1 = *((uint32_t *)vs1 + H4(0)); @@ -4665,6 +4678,8 @@ void HELPER(vfwredsum_vs_h)(void *vd, void *v0, void *vs1, } *((uint32_t *)vd + H4(0)) = s1; env->vstart = 0; + /* set tail elements to 1s */ + vext_set_elems_1s(vd, vta, esz, vlenb); } void HELPER(vfwredsum_vs_w)(void *vd, void *v0, void *vs1, @@ -4672,6 +4687,9 @@ void HELPER(vfwredsum_vs_w)(void *vd, void *v0, void *vs1, { uint32_t vm = vext_vm(desc); uint32_t vl = env->vl; + uint32_t esz = sizeof(uint64_t); + uint32_t vlenb = simd_maxsz(desc); + uint32_t vta = vext_vta(desc); uint32_t i; uint64_t s1 = *((uint64_t *)vs1); @@ -4685,6 +4703,8 @@ void HELPER(vfwredsum_vs_w)(void *vd, void *v0, void *vs1, } *((uint64_t *)vd) = s1; env->vstart = 0; + /* set tail elements to 1s */ + vext_set_elems_1s(vd, vta, esz, vlenb); } /* From acc6ffd482f6b0435bea7434eb5b13441c6d4a33 Mon Sep 17 00:00:00 2001 From: eopXD Date: Mon, 6 Jun 2022 06:16:35 +0000 Subject: [PATCH 931/935] target/riscv: rvv: Add tail agnostic for vector mask instructions The tail elements in the destination mask register are updated under a tail-agnostic policy. Signed-off-by: eop Chen Reviewed-by: Frank Chang Reviewed-by: Weiwei Li Acked-by: Alistair Francis Message-Id: <165449614532.19704.7000832880482980398-14@git.sr.ht> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.c.inc | 6 +++++ target/riscv/vector_helper.c | 30 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 1add4cb655..a94e634a6b 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -3135,6 +3135,8 @@ static bool trans_##NAME(DisasContext *s, arg_r *a) \ tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + data = \ + FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ vreg_ofs(s, a->rs2), cpu_env, \ @@ -3239,6 +3241,8 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + data = \ + FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \ vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \ cpu_env, s->cfg_ptr->vlen / 8, \ @@ -3276,6 +3280,7 @@ static bool trans_viota_m(DisasContext *s, arg_viota_m *a) data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, VTA, s->vta); static gen_helper_gvec_3_ptr * const fns[4] = { gen_helper_viota_m_b, gen_helper_viota_m_h, gen_helper_viota_m_w, gen_helper_viota_m_d, @@ -3305,6 +3310,7 @@ static bool trans_vid_v(DisasContext *s, arg_vid_v *a) data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, VTA, s->vta); static gen_helper_gvec_2_ptr * const fns[4] = { gen_helper_vid_v_b, gen_helper_vid_v_h, gen_helper_vid_v_w, gen_helper_vid_v_d, diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 174a548ac2..75b59cf917 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4717,6 +4717,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ uint32_t desc) \ { \ uint32_t vl = env->vl; \ + uint32_t total_elems = env_archcpu(env)->cfg.vlen; \ + uint32_t vta_all_1s = vext_vta_all_1s(desc); \ uint32_t i; \ int a, b; \ \ @@ -4726,6 +4728,15 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ vext_set_elem_mask(vd, i, OP(b, a)); \ } \ env->vstart = 0; \ + /* mask destination register are always tail- \ + * agnostic \ + */ \ + /* set tail elements to 1s */ \ + if (vta_all_1s) { \ + for (; i < total_elems; i++) { \ + vext_set_elem_mask(vd, i, 1); \ + } \ + } \ } #define DO_NAND(N, M) (!(N & M)) @@ -4793,6 +4804,8 @@ static void vmsetm(void *vd, void *v0, void *vs2, CPURISCVState *env, { uint32_t vm = vext_vm(desc); uint32_t vl = env->vl; + uint32_t total_elems = env_archcpu(env)->cfg.vlen; + uint32_t vta_all_1s = vext_vta_all_1s(desc); int i; bool first_mask_bit = false; @@ -4821,6 +4834,13 @@ static void vmsetm(void *vd, void *v0, void *vs2, CPURISCVState *env, } } env->vstart = 0; + /* mask destination register are always tail-agnostic */ + /* set tail elements to 1s */ + if (vta_all_1s) { + for (; i < total_elems; i++) { + vext_set_elem_mask(vd, i, 1); + } + } } void HELPER(vmsbf_m)(void *vd, void *v0, void *vs2, CPURISCVState *env, @@ -4848,6 +4868,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, CPURISCVState *env, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t sum = 0; \ int i; \ \ @@ -4861,6 +4884,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, CPURISCVState *env, \ } \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VIOTA_M(viota_m_b, uint8_t, H1) @@ -4874,6 +4899,9 @@ void HELPER(NAME)(void *vd, void *v0, CPURISCVState *env, uint32_t desc) \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ int i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -4883,6 +4911,8 @@ void HELPER(NAME)(void *vd, void *v0, CPURISCVState *env, uint32_t desc) \ *((ETYPE *)vd + H(i)) = i; \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VID_V(vid_v_b, uint8_t, H1) From 803963f7cb7220be0c80d9acd87a0ebea167f35e Mon Sep 17 00:00:00 2001 From: eopXD Date: Mon, 6 Jun 2022 06:16:56 +0000 Subject: [PATCH 932/935] target/riscv: rvv: Add tail agnostic for vector permutation instructions Signed-off-by: eop Chen Reviewed-by: Frank Chang Reviewed-by: Weiwei Li Acked-by: Alistair Francis Message-Id: <165449614532.19704.7000832880482980398-15@git.sr.ht> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.c.inc | 7 +++-- target/riscv/vector_helper.c | 40 +++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index a94e634a6b..4f84d4878a 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -3669,7 +3669,7 @@ static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a) return false; } - if (a->vm && s->vl_eq_vlmax) { + if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { int scale = s->lmul - (s->sew + 3); int vlmax = s->cfg_ptr->vlen >> -scale; TCGv_i64 dest = tcg_temp_new_i64(); @@ -3701,7 +3701,7 @@ static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a) return false; } - if (a->vm && s->vl_eq_vlmax) { + if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { int scale = s->lmul - (s->sew + 3); int vlmax = s->cfg_ptr->vlen >> -scale; if (a->rs1 >= vlmax) { @@ -3753,6 +3753,7 @@ static bool trans_vcompress_vm(DisasContext *s, arg_r *a) tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, VTA, s->vta); tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), cpu_env, s->cfg_ptr->vlen / 8, @@ -3853,6 +3854,8 @@ static bool int_ext_op(DisasContext *s, arg_rmr *a, uint8_t seq) } data = FIELD_DP32(data, VDATA, VM, a->vm); + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, VTA, s->vta); tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs2), cpu_env, diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 75b59cf917..a96fc49c71 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4931,6 +4931,9 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ target_ulong offset = s1, i_min, i; \ \ i_min = MAX(env->vstart, offset); \ @@ -4940,6 +4943,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ } \ *((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(i - offset)); \ } \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } /* vslideup.vx vd, vs2, rs1, vm # vd[i+rs1] = vs2[i] */ @@ -4955,6 +4960,9 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ uint32_t vlmax = vext_max_elems(desc, ctzl(sizeof(ETYPE))); \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ target_ulong i_max, i; \ \ i_max = MAX(MIN(s1 < vlmax ? vlmax - s1 : 0, vl), env->vstart); \ @@ -4971,6 +4979,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ } \ \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } /* vslidedown.vx vd, vs2, rs1, vm # vd[i] = vs2[i+rs1] */ @@ -4986,6 +4996,9 @@ static void vslide1up_##BITWIDTH(void *vd, void *v0, target_ulong s1, \ typedef uint##BITWIDTH##_t ETYPE; \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -4999,6 +5012,8 @@ static void vslide1up_##BITWIDTH(void *vd, void *v0, target_ulong s1, \ } \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VSLIE1UP(8, H1) @@ -5026,6 +5041,9 @@ static void vslide1down_##BITWIDTH(void *vd, void *v0, target_ulong s1, \ typedef uint##BITWIDTH##_t ETYPE; \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -5039,6 +5057,8 @@ static void vslide1down_##BITWIDTH(void *vd, void *v0, target_ulong s1, \ } \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_VSLIDE1DOWN(8, H1) @@ -5092,6 +5112,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ uint32_t vlmax = vext_max_elems(desc, ctzl(sizeof(TS2))); \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(TS2); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint64_t index; \ uint32_t i; \ \ @@ -5107,6 +5130,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ } \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } /* vd[i] = (vs1[i] >= VLMAX) ? 0 : vs2[vs1[i]]; */ @@ -5127,6 +5152,9 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ uint32_t vlmax = vext_max_elems(desc, ctzl(sizeof(ETYPE))); \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint64_t index = s1; \ uint32_t i; \ \ @@ -5141,6 +5169,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ } \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } /* vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */ @@ -5155,6 +5185,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ { \ uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t num = 0, i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -5165,6 +5198,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ num++; \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } /* Compress into vd elements of vs2 where vs1 is enabled */ @@ -5196,6 +5231,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \ { \ uint32_t vl = env->vl; \ uint32_t vm = vext_vm(desc); \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ + uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ @@ -5205,6 +5243,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \ *((ETYPE *)vd + HD(i)) = *((DTYPE *)vs2 + HS1(i)); \ } \ env->vstart = 0; \ + /* set tail elements to 1s */ \ + vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \ } GEN_VEXT_INT_EXT(vzext_vf2_h, uint16_t, uint8_t, H2, H1) From b8312675d62b878d6647065f01c2c1337a74d4ee Mon Sep 17 00:00:00 2001 From: eopXD Date: Mon, 6 Jun 2022 06:16:56 +0000 Subject: [PATCH 933/935] target/riscv: rvv: Add option 'rvv_ta_all_1s' to enable optional tail agnostic behavior According to v-spec, tail agnostic behavior can be either kept as undisturbed or set elements' bits to all 1s. To distinguish the difference of tail policies, QEMU should be able to simulate the tail agnostic behavior as "set tail elements' bits to all 1s". There are multiple possibility for agnostic elements according to v-spec. The main intent of this patch-set tries to add option that can distinguish between tail policies. Setting agnostic elements to all 1s allows QEMU to express this. This commit adds option 'rvv_ta_all_1s' is added to enable the behavior, it is default as disabled. Signed-off-by: eop Chen Reviewed-by: Frank Chang Reviewed-by: Weiwei Li Reviewed-by: Alistair Francis Message-Id: <165449614532.19704.7000832880482980398-16@git.sr.ht> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 0497af45cc..e5aa1e9c1b 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -918,6 +918,8 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC), DEFINE_PROP_BOOL("short-isa-string", RISCVCPU, cfg.short_isa_string, false), + + DEFINE_PROP_BOOL("rvv_ta_all_1s", RISCVCPU, cfg.rvv_ta_all_1s, false), DEFINE_PROP_END_OF_LIST(), }; From 26b2bc58599c02b35e55afbd1bd050faa3d187c2 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 8 Jun 2022 16:14:37 +1000 Subject: [PATCH 934/935] target/riscv: Don't expose the CPU properties on names CPUs There are currently two types of RISC-V CPUs: - Generic CPUs (base or any) that allow complete custimisation - "Named" CPUs that match existing hardware Users can use the base CPUs to custimise the extensions that they want, for example -cpu rv64,v=true. We originally exposed these as part of the named CPUs as well, but that was by accident. Exposing the CPU properties to named CPUs means that we accidently enable extensions that don't exist on the CPUs by default. For example the SiFive E CPU currently support the zba extension, which is a bug. This patch instead only exposes the CPU extensions to the generic CPUs. Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Message-Id: <20220608061437.314434-1-alistair.francis@opensource.wdc.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 57 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index e5aa1e9c1b..05e6521351 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -118,6 +118,8 @@ static const char * const riscv_intr_names[] = { "reserved" }; +static void register_cpu_props(DeviceState *dev); + const char *riscv_cpu_get_trap_name(target_ulong cause, bool async) { if (async) { @@ -161,6 +163,7 @@ static void riscv_any_cpu_init(Object *obj) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); #endif set_priv_version(env, PRIV_VERSION_1_12_0); + register_cpu_props(DEVICE(obj)); } #if defined(TARGET_RISCV64) @@ -169,6 +172,7 @@ static void rv64_base_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV64, 0); + register_cpu_props(DEVICE(obj)); } static void rv64_sifive_u_cpu_init(Object *obj) @@ -181,9 +185,11 @@ static void rv64_sifive_u_cpu_init(Object *obj) static void rv64_sifive_e_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; + RISCVCPU *cpu = RISCV_CPU(obj); + set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); - qdev_prop_set_bit(DEVICE(obj), "mmu", false); + cpu->cfg.mmu = false; } static void rv128_base_cpu_init(Object *obj) @@ -197,6 +203,7 @@ static void rv128_base_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV128, 0); + register_cpu_props(DEVICE(obj)); } #else static void rv32_base_cpu_init(Object *obj) @@ -204,6 +211,7 @@ static void rv32_base_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV32, 0); + register_cpu_props(DEVICE(obj)); } static void rv32_sifive_u_cpu_init(Object *obj) @@ -216,27 +224,33 @@ static void rv32_sifive_u_cpu_init(Object *obj) static void rv32_sifive_e_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; + RISCVCPU *cpu = RISCV_CPU(obj); + set_misa(env, MXL_RV32, RVI | RVM | RVA | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); - qdev_prop_set_bit(DEVICE(obj), "mmu", false); + cpu->cfg.mmu = false; } static void rv32_ibex_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; + RISCVCPU *cpu = RISCV_CPU(obj); + set_misa(env, MXL_RV32, RVI | RVM | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); - qdev_prop_set_bit(DEVICE(obj), "mmu", false); - qdev_prop_set_bit(DEVICE(obj), "x-epmp", true); + cpu->cfg.mmu = false; + cpu->cfg.epmp = true; } static void rv32_imafcu_nommu_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; + RISCVCPU *cpu = RISCV_CPU(obj); + set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); set_resetvec(env, DEFAULT_RSTVEC); - qdev_prop_set_bit(DEVICE(obj), "mmu", false); + cpu->cfg.mmu = false; } #endif @@ -249,6 +263,7 @@ static void riscv_host_cpu_init(Object *obj) #elif defined(TARGET_RISCV64) set_misa(env, MXL_RV64, 0); #endif + register_cpu_props(DEVICE(obj)); } #endif @@ -836,6 +851,12 @@ static void riscv_cpu_init(Object *obj) { RISCVCPU *cpu = RISCV_CPU(obj); + cpu->cfg.ext_counters = true; + cpu->cfg.ext_ifencei = true; + cpu->cfg.ext_icsr = true; + cpu->cfg.mmu = true; + cpu->cfg.pmp = true; + cpu_set_cpustate_pointers(cpu); #ifndef CONFIG_USER_ONLY @@ -844,7 +865,7 @@ static void riscv_cpu_init(Object *obj) #endif /* CONFIG_USER_ONLY */ } -static Property riscv_cpu_properties[] = { +static Property riscv_cpu_extensions[] = { /* Defaults for standard extensions */ DEFINE_PROP_BOOL("i", RISCVCPU, cfg.ext_i, true), DEFINE_PROP_BOOL("e", RISCVCPU, cfg.ext_e, false), @@ -867,17 +888,12 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_BOOL("Zve64f", RISCVCPU, cfg.ext_zve64f, false), DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true), DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true), - DEFINE_PROP_BOOL("debug", RISCVCPU, cfg.debug, true), DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec), DEFINE_PROP_STRING("vext_spec", RISCVCPU, cfg.vext_spec), DEFINE_PROP_UINT16("vlen", RISCVCPU, cfg.vlen, 128), DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64), - DEFINE_PROP_UINT32("mvendorid", RISCVCPU, cfg.mvendorid, 0), - DEFINE_PROP_UINT64("marchid", RISCVCPU, cfg.marchid, RISCV_CPU_MARCHID), - DEFINE_PROP_UINT64("mimpid", RISCVCPU, cfg.mimpid, RISCV_CPU_MIMPID), - DEFINE_PROP_BOOL("svinval", RISCVCPU, cfg.ext_svinval, false), DEFINE_PROP_BOOL("svnapot", RISCVCPU, cfg.ext_svnapot, false), DEFINE_PROP_BOOL("svpbmt", RISCVCPU, cfg.ext_svpbmt, false), @@ -915,6 +931,25 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_BOOL("x-epmp", RISCVCPU, cfg.epmp, false), DEFINE_PROP_BOOL("x-aia", RISCVCPU, cfg.aia, false), + DEFINE_PROP_END_OF_LIST(), +}; + +static void register_cpu_props(DeviceState *dev) +{ + Property *prop; + + for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { + qdev_property_add_static(dev, prop); + } +} + +static Property riscv_cpu_properties[] = { + DEFINE_PROP_BOOL("debug", RISCVCPU, cfg.debug, true), + + DEFINE_PROP_UINT32("mvendorid", RISCVCPU, cfg.mvendorid, 0), + DEFINE_PROP_UINT64("marchid", RISCVCPU, cfg.marchid, RISCV_CPU_MARCHID), + DEFINE_PROP_UINT64("mimpid", RISCVCPU, cfg.mimpid, RISCV_CPU_MIMPID), + DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC), DEFINE_PROP_BOOL("short-isa-string", RISCVCPU, cfg.short_isa_string, false), From 07314158f6aa4d2589520c194a7531b9364a8d54 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 9 Jun 2022 09:47:01 +1000 Subject: [PATCH 935/935] target/riscv: trans_rvv: Avoid assert for RV32 and e64 When running a 32-bit guest, with a e64 vmv.v.x and vl_eq_vlmax set to true the `tcg_debug_assert(vece <= MO_32)` will be triggered inside tcg_gen_gvec_dup_i32(). This patch checks that condition and instead uses tcg_gen_gvec_dup_i64() is required. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1028 Suggested-by: Robert Bu Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson Message-Id: <20220608234701.369536-1-alistair.francis@opensource.wdc.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.c.inc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 4f84d4878a..6c091824b6 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -2128,8 +2128,16 @@ static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a) s1 = get_gpr(s, a->rs1, EXT_SIGN); if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { - tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd), - MAXSZ(s), MAXSZ(s), s1); + if (get_xl(s) == MXL_RV32 && s->sew == MO_64) { + TCGv_i64 s1_i64 = tcg_temp_new_i64(); + tcg_gen_ext_tl_i64(s1_i64, s1); + tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), + MAXSZ(s), MAXSZ(s), s1_i64); + tcg_temp_free_i64(s1_i64); + } else { + tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd), + MAXSZ(s), MAXSZ(s), s1); + } } else { TCGv_i32 desc; TCGv_i64 s1_i64 = tcg_temp_new_i64();