diff --git a/Fixed-integer-overflow-in-e1000e.patch b/Fixed-integer-overflow-in-e1000e.patch new file mode 100644 index 0000000000000000000000000000000000000000..004390fc5a3d60d2aaf4912d0679c4fa471d28a2 --- /dev/null +++ b/Fixed-integer-overflow-in-e1000e.patch @@ -0,0 +1,40 @@ +From 41077af2c4283c15c0a822017ea51612d15b68f8 Mon Sep 17 00:00:00 2001 +From: Andrew Melnychenko +Date: Wed, 4 Mar 2020 16:20:58 +0200 +Subject: [PATCH 1/5] Fixed integer overflow in e1000e +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1737400 +Fixed setting max_queue_num if there are no peers in +NICConf. qemu_new_nic() creates NICState with 1 NetClientState(index +0) without peers, set max_queue_num to 0 - It prevents undefined +behavior and possible crashes, especially during pcie hotplug. + +Fixes: 6f3fbe4ed06 ("net: Introduce e1000e device emulation") +Signed-off-by: Andrew Melnychenko +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Dmitry Fleytman +Signed-off-by: Jason Wang +Signed-off-by: Zhenyu Ye +--- + hw/net/e1000e.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c +index 581f7d03..1e827c4f 100644 +--- a/hw/net/e1000e.c ++++ b/hw/net/e1000e.c +@@ -325,7 +325,7 @@ e1000e_init_net_peer(E1000EState *s, PCIDevice *pci_dev, uint8_t *macaddr) + s->nic = qemu_new_nic(&net_e1000e_info, &s->conf, + object_get_typename(OBJECT(s)), dev->id, s); + +- s->core.max_queue_num = s->conf.peers.queues - 1; ++ s->core.max_queue_num = s->conf.peers.queues ? s->conf.peers.queues - 1 : 0; + + trace_e1000e_mac_set_permanent(MAC_ARG(macaddr)); + memcpy(s->core.permanent_mac, macaddr, sizeof(s->core.permanent_mac)); +-- +2.22.0.windows.1 + diff --git a/block-Avoid-memleak-on-qcow2-image-info-failure.patch b/block-Avoid-memleak-on-qcow2-image-info-failure.patch new file mode 100644 index 0000000000000000000000000000000000000000..13917f5b61ed267f584feac9041450e6fe9bbca6 --- /dev/null +++ b/block-Avoid-memleak-on-qcow2-image-info-failure.patch @@ -0,0 +1,35 @@ +From 6a39af8880c18fb3bcbfb715aef909c64286524e Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Fri, 20 Mar 2020 13:36:20 -0500 +Subject: [PATCH 04/14] block: Avoid memleak on qcow2 image info failure + +If we fail to get bitmap info, we must not leak the encryption info. + +Fixes: b8968c875f403 +Fixes: Coverity CID 1421894 +Signed-off-by: Eric Blake +Message-Id: <20200320183620.1112123-1-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Andrey Shinkevich +Tested-by: Andrey Shinkevich +Signed-off-by: Max Reitz +Signed-off-by: Peng Liang +--- + block/qcow2.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/block/qcow2.c b/block/qcow2.c +index 27c54b9905aa..0f4b0940d457 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -4588,6 +4588,7 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs, + if (local_err) { + error_propagate(errp, local_err); + qapi_free_ImageInfoSpecific(spec_info); ++ qapi_free_QCryptoBlockInfo(encrypt_info); + return NULL; + } + *spec_info->u.qcow2.data = (ImageInfoSpecificQCow2){ +-- +2.26.2 + diff --git a/block-bdrv_set_backing_bs-fix-use-after-free.patch b/block-bdrv_set_backing_bs-fix-use-after-free.patch new file mode 100644 index 0000000000000000000000000000000000000000..93ac72169d8518a8fcadc82c7ee01fcfdfcf94fc --- /dev/null +++ b/block-bdrv_set_backing_bs-fix-use-after-free.patch @@ -0,0 +1,116 @@ +From 3754525eb383f91869634766ccd041cfe40bbf17 Mon Sep 17 00:00:00 2001 +From: Vladimir Sementsov-Ogievskiy +Date: Mon, 16 Mar 2020 09:06:30 +0300 +Subject: [PATCH 05/14] block: bdrv_set_backing_bs: fix use-after-free +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There is a use-after-free possible: bdrv_unref_child() leaves +bs->backing freed but not NULL. bdrv_attach_child may produce nested +polling loop due to drain, than access of freed pointer is possible. + +I've produced the following crash on 30 iotest with modified code. It +does not reproduce on master, but still seems possible: + + #0 __strcmp_avx2 () at /lib64/libc.so.6 + #1 bdrv_backing_overridden (bs=0x55c9d3cc2060) at block.c:6350 + #2 bdrv_refresh_filename (bs=0x55c9d3cc2060) at block.c:6404 + #3 bdrv_backing_attach (c=0x55c9d48e5520) at block.c:1063 + #4 bdrv_replace_child_noperm + (child=child@entry=0x55c9d48e5520, + new_bs=new_bs@entry=0x55c9d3cc2060) at block.c:2290 + #5 bdrv_replace_child + (child=child@entry=0x55c9d48e5520, + new_bs=new_bs@entry=0x55c9d3cc2060) at block.c:2320 + #6 bdrv_root_attach_child + (child_bs=child_bs@entry=0x55c9d3cc2060, + child_name=child_name@entry=0x55c9d241d478 "backing", + child_role=child_role@entry=0x55c9d26ecee0 , + ctx=, perm=, shared_perm=21, + opaque=0x55c9d3c5a3d0, errp=0x7ffd117108e0) at block.c:2424 + #7 bdrv_attach_child + (parent_bs=parent_bs@entry=0x55c9d3c5a3d0, + child_bs=child_bs@entry=0x55c9d3cc2060, + child_name=child_name@entry=0x55c9d241d478 "backing", + child_role=child_role@entry=0x55c9d26ecee0 , + errp=errp@entry=0x7ffd117108e0) at block.c:5876 + #8 in bdrv_set_backing_hd + (bs=bs@entry=0x55c9d3c5a3d0, + backing_hd=backing_hd@entry=0x55c9d3cc2060, + errp=errp@entry=0x7ffd117108e0) + at block.c:2576 + #9 stream_prepare (job=0x55c9d49d84a0) at block/stream.c:150 + #10 job_prepare (job=0x55c9d49d84a0) at job.c:761 + #11 job_txn_apply (txn=, fn=) at + job.c:145 + #12 job_do_finalize (job=0x55c9d49d84a0) at job.c:778 + #13 job_completed_txn_success (job=0x55c9d49d84a0) at job.c:832 + #14 job_completed (job=0x55c9d49d84a0) at job.c:845 + #15 job_completed (job=0x55c9d49d84a0) at job.c:836 + #16 job_exit (opaque=0x55c9d49d84a0) at job.c:864 + #17 aio_bh_call (bh=0x55c9d471a160) at util/async.c:117 + #18 aio_bh_poll (ctx=ctx@entry=0x55c9d3c46720) at util/async.c:117 + #19 aio_poll (ctx=ctx@entry=0x55c9d3c46720, + blocking=blocking@entry=true) + at util/aio-posix.c:728 + #20 bdrv_parent_drained_begin_single (poll=true, c=0x55c9d3d558f0) + at block/io.c:121 + #21 bdrv_parent_drained_begin_single (c=c@entry=0x55c9d3d558f0, + poll=poll@entry=true) + at block/io.c:114 + #22 bdrv_replace_child_noperm + (child=child@entry=0x55c9d3d558f0, + new_bs=new_bs@entry=0x55c9d3d27300) at block.c:2258 + #23 bdrv_replace_child + (child=child@entry=0x55c9d3d558f0, + new_bs=new_bs@entry=0x55c9d3d27300) at block.c:2320 + #24 bdrv_root_attach_child + (child_bs=child_bs@entry=0x55c9d3d27300, + child_name=child_name@entry=0x55c9d241d478 "backing", + child_role=child_role@entry=0x55c9d26ecee0 , + ctx=, perm=, shared_perm=21, + opaque=0x55c9d3cc2060, errp=0x7ffd11710c60) at block.c:2424 + #25 bdrv_attach_child + (parent_bs=parent_bs@entry=0x55c9d3cc2060, + child_bs=child_bs@entry=0x55c9d3d27300, + child_name=child_name@entry=0x55c9d241d478 "backing", + child_role=child_role@entry=0x55c9d26ecee0 , + errp=errp@entry=0x7ffd11710c60) at block.c:5876 + #26 bdrv_set_backing_hd + (bs=bs@entry=0x55c9d3cc2060, + backing_hd=backing_hd@entry=0x55c9d3d27300, + errp=errp@entry=0x7ffd11710c60) + at block.c:2576 + #27 stream_prepare (job=0x55c9d495ead0) at block/stream.c:150 + ... + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20200316060631.30052-2-vsementsov@virtuozzo.com> +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: John Snow +Signed-off-by: Max Reitz +Signed-off-by: Peng Liang +--- + block.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block.c b/block.c +index 29e504b86aff..e834102c87f7 100644 +--- a/block.c ++++ b/block.c +@@ -2549,10 +2549,10 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, + + if (bs->backing) { + bdrv_unref_child(bs, bs->backing); ++ bs->backing = NULL; + } + + if (!backing_hd) { +- bs->backing = NULL; + goto out; + } + +-- +2.26.2 + diff --git a/block-fix-bdrv_root_attach_child-forget-to-unref-chi.patch b/block-fix-bdrv_root_attach_child-forget-to-unref-chi.patch new file mode 100644 index 0000000000000000000000000000000000000000..d901f1062659223d2899ab5520759a6a5065545a --- /dev/null +++ b/block-fix-bdrv_root_attach_child-forget-to-unref-chi.patch @@ -0,0 +1,33 @@ +From 5060ef71fa4621061101a30fa9e0d1690696c5c1 Mon Sep 17 00:00:00 2001 +From: Vladimir Sementsov-Ogievskiy +Date: Tue, 24 Mar 2020 18:59:21 +0300 +Subject: [PATCH 10/14] block: fix bdrv_root_attach_child forget to unref + child_bs + +bdrv_root_attach_child promises to drop child_bs reference on failure. +It does it on first handled failure path, but not on the second. Fix +that. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20200324155921.23822-1-vsementsov@virtuozzo.com> +Signed-off-by: Kevin Wolf +Signed-off-by: Peng Liang +--- + block.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/block.c b/block.c +index e834102c87f7..38880eabf801 100644 +--- a/block.c ++++ b/block.c +@@ -2399,6 +2399,7 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, + error_propagate(errp, local_err); + g_free(child); + bdrv_abort_perm_update(child_bs); ++ bdrv_unref(child_bs); + return NULL; + } + } +-- +2.26.2 + diff --git a/block-mirror-fix-use-after-free-of-local_err.patch b/block-mirror-fix-use-after-free-of-local_err.patch new file mode 100644 index 0000000000000000000000000000000000000000..ea2f739410164f7df43f020192cd60653a3b8cf0 --- /dev/null +++ b/block-mirror-fix-use-after-free-of-local_err.patch @@ -0,0 +1,34 @@ +From 682d23829adf0a872d5a3ca6eb4b31c424f558fc Mon Sep 17 00:00:00 2001 +From: Vladimir Sementsov-Ogievskiy +Date: Tue, 24 Mar 2020 18:36:26 +0300 +Subject: [PATCH 09/14] block/mirror: fix use after free of local_err + +local_err is used again in mirror_exit_common() after +bdrv_set_backing_hd(), so we must zero it. Otherwise try to set +non-NULL local_err will crash. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20200324153630.11882-3-vsementsov@virtuozzo.com> +Reviewed-by: Eric Blake +Reviewed-by: John Snow +Signed-off-by: Max Reitz +Signed-off-by: Peng Liang +--- + block/mirror.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/block/mirror.c b/block/mirror.c +index 681b305de650..ef6c958ff9b3 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -674,6 +674,7 @@ static int mirror_exit_common(Job *job) + bdrv_set_backing_hd(target_bs, backing, &local_err); + if (local_err) { + error_report_err(local_err); ++ local_err = NULL; + ret = -EPERM; + } + } +-- +2.26.2 + diff --git a/block-qcow2-do-free-crypto_opts-in-qcow2_close.patch b/block-qcow2-do-free-crypto_opts-in-qcow2_close.patch new file mode 100644 index 0000000000000000000000000000000000000000..44b0ea19e95b95bbd583034e9c830e3dd6d647e6 --- /dev/null +++ b/block-qcow2-do-free-crypto_opts-in-qcow2_close.patch @@ -0,0 +1,54 @@ +From 88ef4e1862987227f8b87228cff94be3af66d054 Mon Sep 17 00:00:00 2001 +From: Pan Nengyuan +Date: Thu, 27 Feb 2020 09:29:49 +0800 +Subject: [PATCH 01/14] block/qcow2: do free crypto_opts in qcow2_close() + +'crypto_opts' forgot to free in qcow2_close(), this patch fix the bellow leak stack: + +Direct leak of 24 byte(s) in 1 object(s) allocated from: + #0 0x7f0edd81f970 in __interceptor_calloc (/lib64/libasan.so.5+0xef970) + #1 0x7f0edc6d149d in g_malloc0 (/lib64/libglib-2.0.so.0+0x5249d) + #2 0x55d7eaede63d in qobject_input_start_struct /mnt/sdb/qemu-new/qemu_test/qemu/qapi/qobject-input-visitor.c:295 + #3 0x55d7eaed78b8 in visit_start_struct /mnt/sdb/qemu-new/qemu_test/qemu/qapi/qapi-visit-core.c:49 + #4 0x55d7eaf5140b in visit_type_QCryptoBlockOpenOptions qapi/qapi-visit-crypto.c:290 + #5 0x55d7eae43af3 in block_crypto_open_opts_init /mnt/sdb/qemu-new/qemu_test/qemu/block/crypto.c:163 + #6 0x55d7eacd2924 in qcow2_update_options_prepare /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1148 + #7 0x55d7eacd33f7 in qcow2_update_options /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1232 + #8 0x55d7eacd9680 in qcow2_do_open /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1512 + #9 0x55d7eacdc55e in qcow2_open_entry /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1792 + #10 0x55d7eacdc8fe in qcow2_open /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:1819 + #11 0x55d7eac3742d in bdrv_open_driver /mnt/sdb/qemu-new/qemu_test/qemu/block.c:1317 + #12 0x55d7eac3e990 in bdrv_open_common /mnt/sdb/qemu-new/qemu_test/qemu/block.c:1575 + #13 0x55d7eac4442c in bdrv_open_inherit /mnt/sdb/qemu-new/qemu_test/qemu/block.c:3126 + #14 0x55d7eac45c3f in bdrv_open /mnt/sdb/qemu-new/qemu_test/qemu/block.c:3219 + #15 0x55d7ead8e8a4 in blk_new_open /mnt/sdb/qemu-new/qemu_test/qemu/block/block-backend.c:397 + #16 0x55d7eacde74c in qcow2_co_create /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:3534 + #17 0x55d7eacdfa6d in qcow2_co_create_opts /mnt/sdb/qemu-new/qemu_test/qemu/block/qcow2.c:3668 + #18 0x55d7eac1c678 in bdrv_create_co_entry /mnt/sdb/qemu-new/qemu_test/qemu/block.c:485 + #19 0x55d7eb0024d2 in coroutine_trampoline /mnt/sdb/qemu-new/qemu_test/qemu/util/coroutine-ucontext.c:115 + +Reported-by: Euler Robot +Signed-off-by: Pan Nengyuan +Reviewed-by: Max Reitz +Message-Id: <20200227012950.12256-2-pannengyuan@huawei.com> +Signed-off-by: Max Reitz +Signed-off-by: Peng Liang +--- + block/qcow2.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/block/qcow2.c b/block/qcow2.c +index 1909df6e1d24..27c54b9905aa 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -2408,6 +2408,7 @@ static void qcow2_close(BlockDriverState *bs) + + qcrypto_block_free(s->crypto); + s->crypto = NULL; ++ qapi_free_QCryptoBlockOpenOptions(s->crypto_opts); + + g_free(s->unknown_header_fields); + cleanup_unknown_header_ext(bs); +-- +2.26.2 + diff --git a/block-qcow2-threads-fix-qcow2_decompress.patch b/block-qcow2-threads-fix-qcow2_decompress.patch new file mode 100644 index 0000000000000000000000000000000000000000..d2fd9ee74fc5b57fb57ee1f655763895f1fe4356 --- /dev/null +++ b/block-qcow2-threads-fix-qcow2_decompress.patch @@ -0,0 +1,75 @@ +From a583b6b616b086d3fdce93e255d24ab2c865efd3 Mon Sep 17 00:00:00 2001 +From: Vladimir Sementsov-Ogievskiy +Date: Mon, 2 Mar 2020 18:09:30 +0300 +Subject: [PATCH 03/14] block/qcow2-threads: fix qcow2_decompress +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +On success path we return what inflate() returns instead of 0. And it +most probably works for Z_STREAM_END as it is positive, but is +definitely broken for Z_BUF_ERROR. + +While being here, switch to errno return code, to be closer to +qcow2_compress API (and usual expectations). + +Revert condition in if to be more positive. Drop dead initialization of +ret. + +Cc: qemu-stable@nongnu.org # v4.0 +Fixes: 341926ab83e2b +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20200302150930.16218-1-vsementsov@virtuozzo.com> +Reviewed-by: Alberto Garcia +Reviewed-by: Ján Tomko +Signed-off-by: Max Reitz +Signed-off-by: Peng Liang +--- + block/qcow2-threads.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c +index 3b1e63fe414d..449cd3c0a1f4 100644 +--- a/block/qcow2-threads.c ++++ b/block/qcow2-threads.c +@@ -128,12 +128,12 @@ static ssize_t qcow2_compress(void *dest, size_t dest_size, + * @src - source buffer, @src_size bytes + * + * Returns: 0 on success +- * -1 on fail ++ * -EIO on fail + */ + static ssize_t qcow2_decompress(void *dest, size_t dest_size, + const void *src, size_t src_size) + { +- int ret = 0; ++ int ret; + z_stream strm; + + memset(&strm, 0, sizeof(strm)); +@@ -144,17 +144,19 @@ static ssize_t qcow2_decompress(void *dest, size_t dest_size, + + ret = inflateInit2(&strm, -12); + if (ret != Z_OK) { +- return -1; ++ return -EIO; + } + + ret = inflate(&strm, Z_FINISH); +- if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) || strm.avail_out != 0) { ++ if ((ret == Z_STREAM_END || ret == Z_BUF_ERROR) && strm.avail_out == 0) { + /* + * We approve Z_BUF_ERROR because we need @dest buffer to be filled, but + * @src buffer may be processed partly (because in qcow2 we know size of + * compressed data with precision of one sector) + */ +- ret = -1; ++ ret = 0; ++ } else { ++ ret = -EIO; + } + + inflateEnd(&strm); +-- +2.26.2 + diff --git a/build-smt-processor-structure-to-support-smt-topolog.patch b/build-smt-processor-structure-to-support-smt-topolog.patch new file mode 100644 index 0000000000000000000000000000000000000000..ed01d38bb17dd4931a1f23b5a21127a2c5dd0425 --- /dev/null +++ b/build-smt-processor-structure-to-support-smt-topolog.patch @@ -0,0 +1,104 @@ +From af8740502815be450709e88df44ad322da2b071f Mon Sep 17 00:00:00 2001 +From: Henglong Fan +Date: Tue, 18 Aug 2020 21:42:33 +0800 +Subject: [PATCH] build smt processor structure to support smt topology + +if vcpu support smt, create new smt hierarchy according to +Processor Properties Topology Table(PPTT) in acpi spec 6.3. +Threads sharing a core must be grouped under a unique Processor +hierarchy node structure for each group of threads + +Signed-off-by: Henglong Fan +--- + hw/acpi/aml-build.c | 40 ++++++++++++++++++++++++++++++++-------- + 1 file changed, 32 insertions(+), 8 deletions(-) + +diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c +index 74e95005..8a3b51c8 100644 +--- a/hw/acpi/aml-build.c ++++ b/hw/acpi/aml-build.c +@@ -53,7 +53,7 @@ static void build_append_array(GArray *array, GArray *val) + } + + /* +- * ACPI 6.2 Processor Properties Topology Table (PPTT) ++ * ACPI 6.3 Processor Properties Topology Table (PPTT) + */ + #ifdef __aarch64__ + static void build_cache_head(GArray *tbl, uint32_t next_level) +@@ -126,7 +126,7 @@ static void build_arm_socket_hierarchy(GArray *tbl, + build_append_int_noprefix(tbl, offset, 4); + } + +-static void build_arm_cpu_hierarchy(GArray *tbl, ++static void build_arm_core_hierarchy(GArray *tbl, + struct offset_status *offset, uint32_t id) + { + if (!offset) { +@@ -144,18 +144,35 @@ static void build_arm_cpu_hierarchy(GArray *tbl, + build_append_int_noprefix(tbl, offset->l2_offset, 4); + } + ++static void build_arm_smt_hierarchy(GArray *tbl, ++ uint32_t offset, uint32_t id) ++{ ++ if (!offset) { ++ return; ++ } ++ build_append_byte(tbl, 0); /* Type 0 - processor */ ++ build_append_byte(tbl, 20); /* Length, add private resources */ ++ build_append_int_noprefix(tbl, 0, 2); /* Reserved */ ++ build_append_int_noprefix(tbl, 14, 4); /* Valid id*/ ++ build_append_int_noprefix(tbl, offset, 4); ++ build_append_int_noprefix(tbl, id, 4); ++ build_append_int_noprefix(tbl, 0, 4); /* Num private resources */ ++} ++ + void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus) + { + int pptt_start = table_data->len; +- int uid = 0, cpus = 0, socket; ++ int uid = 0, socket; ++ uint32_t core_offset; + struct offset_status offset; + const MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int smp_cores = ms->smp.cores; ++ unsigned int smp_sockets = ms->smp.cpus / (smp_cores * ms->smp.threads); + + acpi_data_push(table_data, sizeof(AcpiTableHeader)); + +- for (socket = 0; cpus < possible_cpus; socket++) { +- int core; ++ for (socket = 0; socket < smp_sockets; socket++) { ++ int core,thread; + uint32_t l3_offset = table_data->len - pptt_start; + build_cache_hierarchy(table_data, 0, ARM_L3_CACHE); + +@@ -169,14 +186,21 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus) + build_cache_hierarchy(table_data, offset.l2_offset, ARM_L1D_CACHE); + offset.l1i_offset = table_data->len - pptt_start; + build_cache_hierarchy(table_data, offset.l2_offset, ARM_L1I_CACHE); +- build_arm_cpu_hierarchy(table_data, &offset, uid++); +- cpus++; ++ core_offset = table_data->len - pptt_start; ++ if (ms->smp.threads <= 1) { ++ build_arm_core_hierarchy(table_data, &offset, uid++); ++ } else { ++ build_arm_core_hierarchy(table_data, &offset, core); ++ for (thread = 0; thread < ms->smp.threads; thread++) { ++ build_arm_smt_hierarchy(table_data, core_offset, uid++); ++ } ++ } + } + } + + build_header(linker, table_data, + (void *)(table_data->data + pptt_start), "PPTT", +- table_data->len - pptt_start, 1, NULL, NULL); ++ table_data->len - pptt_start, 2, NULL, NULL); + } + + #else +-- +2.23.0 + diff --git a/char-fix-use-after-free-with-dup-chardev-reconnect.patch b/char-fix-use-after-free-with-dup-chardev-reconnect.patch new file mode 100644 index 0000000000000000000000000000000000000000..fd81015a18beced443caef903d0ec1f2a1fd8850 --- /dev/null +++ b/char-fix-use-after-free-with-dup-chardev-reconnect.patch @@ -0,0 +1,126 @@ +From 902a8192600ff81681a162509e23bf95619d1f04 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Mon, 20 Apr 2020 13:20:12 +0200 +Subject: [PATCH] char: fix use-after-free with dup chardev & reconnect +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +With a reconnect socket, qemu_char_open() will start a background +thread. It should keep a reference on the chardev. + +Fixes invalid read: +READ of size 8 at 0x6040000ac858 thread T7 + #0 0x5555598d37b8 in unix_connect_saddr /home/elmarco/src/qq/util/qemu-sockets.c:954 + #1 0x5555598d4751 in socket_connect /home/elmarco/src/qq/util/qemu-sockets.c:1109 + #2 0x555559707c34 in qio_channel_socket_connect_sync /home/elmarco/src/qq/io/channel-socket.c:145 + #3 0x5555596adebb in tcp_chr_connect_client_task /home/elmarco/src/qq/chardev/char-socket.c:1104 + #4 0x555559723d55 in qio_task_thread_worker /home/elmarco/src/qq/io/task.c:123 + #5 0x5555598a6731 in qemu_thread_start /home/elmarco/src/qq/util/qemu-thread-posix.c:519 + #6 0x7ffff40d4431 in start_thread (/lib64/libpthread.so.0+0x9431) + #7 0x7ffff40029d2 in __clone (/lib64/libc.so.6+0x1019d2) + +Signed-off-by: Marc-André Lureau +Reviewed-by: Daniel P. Berrangé +Message-Id: <20200420112012.567284-1-marcandre.lureau@redhat.com> +Signed-off-by: Zhenyu Ye +--- + chardev/char-socket.c | 3 ++- + tests/test-char.c | 53 ++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 54 insertions(+), 2 deletions(-) + +diff --git a/chardev/char-socket.c b/chardev/char-socket.c +index 7ca5d97a..701b62f9 100644 +--- a/chardev/char-socket.c ++++ b/chardev/char-socket.c +@@ -1118,7 +1118,8 @@ static void tcp_chr_connect_client_async(Chardev *chr) + */ + s->connect_task = qio_task_new(OBJECT(sioc), + qemu_chr_socket_connected, +- chr, NULL); ++ object_ref(OBJECT(chr)), ++ (GDestroyNotify)object_unref); + qio_task_run_in_thread(s->connect_task, + tcp_chr_connect_client_task, + s->addr, +diff --git a/tests/test-char.c b/tests/test-char.c +index f9440cdc..0e4069fb 100644 +--- a/tests/test-char.c ++++ b/tests/test-char.c +@@ -871,6 +871,53 @@ typedef struct { + } CharSocketClientTestConfig; + + ++static void char_socket_client_dupid_test(gconstpointer opaque) ++{ ++ const CharSocketClientTestConfig *config = opaque; ++ QIOChannelSocket *ioc; ++ char *optstr; ++ Chardev *chr1, *chr2; ++ SocketAddress *addr; ++ QemuOpts *opts; ++ Error *local_err = NULL; ++ ++ /* ++ * Setup a listener socket and determine get its address ++ * so we know the TCP port for the client later ++ */ ++ ioc = qio_channel_socket_new(); ++ g_assert_nonnull(ioc); ++ qio_channel_socket_listen_sync(ioc, config->addr, &error_abort); ++ addr = qio_channel_socket_get_local_address(ioc, &error_abort); ++ g_assert_nonnull(addr); ++ ++ /* ++ * Populate the chardev address based on what the server ++ * is actually listening on ++ */ ++ optstr = char_socket_addr_to_opt_str(addr, ++ config->fd_pass, ++ config->reconnect, ++ false); ++ ++ opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), ++ optstr, true); ++ g_assert_nonnull(opts); ++ chr1 = qemu_chr_new_from_opts(opts, NULL, &error_abort); ++ g_assert_nonnull(chr1); ++ ++ chr2 = qemu_chr_new_from_opts(opts, NULL, &local_err); ++ g_assert_null(chr2); ++ error_free_or_abort(&local_err); ++ ++ object_unref(OBJECT(ioc)); ++ qemu_opts_del(opts); ++ object_unparent(OBJECT(chr1)); ++ qapi_free_SocketAddress(addr); ++ g_free(optstr); ++} ++ ++ + static void char_socket_client_test(gconstpointer opaque) + { + const CharSocketClientTestConfig *config = opaque; +@@ -1425,6 +1472,8 @@ int main(int argc, char **argv) + { addr, NULL, false, true }; \ + CharSocketClientTestConfig client6 ## name = \ + { addr, NULL, true, true }; \ ++ CharSocketClientTestConfig client7 ## name = \ ++ { addr, ",reconnect=1", false, false }; \ + g_test_add_data_func("/char/socket/client/mainloop/" # name, \ + &client1 ##name, char_socket_client_test); \ + g_test_add_data_func("/char/socket/client/wait-conn/" # name, \ +@@ -1436,7 +1485,9 @@ int main(int argc, char **argv) + g_test_add_data_func("/char/socket/client/mainloop-fdpass/" # name, \ + &client5 ##name, char_socket_client_test); \ + g_test_add_data_func("/char/socket/client/wait-conn-fdpass/" # name, \ +- &client6 ##name, char_socket_client_test) ++ &client6 ##name, char_socket_client_test); \ ++ g_test_add_data_func("/char/socket/client/dupid-reconnect/" # name, \ ++ &client7 ##name, char_socket_client_dupid_test) + + SOCKET_SERVER_TEST(tcp, &tcpaddr); + SOCKET_CLIENT_TEST(tcp, &tcpaddr); +-- +2.22.0.windows.1 + diff --git a/chardev-tcp-Fix-error-message-double-free-error.patch b/chardev-tcp-Fix-error-message-double-free-error.patch new file mode 100644 index 0000000000000000000000000000000000000000..175ddfe2dea85111016d162aa0cd95d79a49a492 --- /dev/null +++ b/chardev-tcp-Fix-error-message-double-free-error.patch @@ -0,0 +1,43 @@ +From 4488ab4700d344b049ddef808a64eda4b5867902 Mon Sep 17 00:00:00 2001 +From: lichun +Date: Mon, 22 Jun 2020 05:30:17 +0800 +Subject: [PATCH 06/11] chardev/tcp: Fix error message double free error + +Errors are already freed by error_report_err, so we only need to call +error_free when that function is not called. + +Cc: qemu-stable@nongnu.org +Signed-off-by: lichun +Message-Id: <20200621213017.17978-1-lichun@ruijie.com.cn> +Reviewed-by: Markus Armbruster +[Commit message improved, cc: qemu-stable] +Signed-off-by: Markus Armbruster +Signed-off-by: BiaoXiang Ye +--- + chardev/char-socket.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/chardev/char-socket.c b/chardev/char-socket.c +index 701b62f9..9b06c8aa 100644 +--- a/chardev/char-socket.c ++++ b/chardev/char-socket.c +@@ -141,6 +141,8 @@ static void check_report_connect_error(Chardev *chr, + error_report("Unable to connect character device %s: %s", + chr->label, error_get_pretty(err)); + s->connect_err_reported = true; ++ } else { ++ error_free(err); + } + qemu_chr_socket_restart_timer(chr); + } +@@ -1074,7 +1076,6 @@ static void qemu_chr_socket_connected(QIOTask *task, void *opaque) + if (qio_task_propagate_error(task, &err)) { + tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED); + check_report_connect_error(chr, err); +- error_free(err); + goto cleanup; + } + +-- +2.27.0.dirty + diff --git a/colo-compare-Fix-memory-leak-in-packet_enqueue.patch b/colo-compare-Fix-memory-leak-in-packet_enqueue.patch new file mode 100644 index 0000000000000000000000000000000000000000..ca5e43c49a6ad18fa7c6d204c1eabfac7ed6ddd5 --- /dev/null +++ b/colo-compare-Fix-memory-leak-in-packet_enqueue.patch @@ -0,0 +1,90 @@ +From 19afb1431bd730a1e4e09e3c0835c35572517268 Mon Sep 17 00:00:00 2001 +From: Derek Su +Date: Fri, 22 May 2020 15:53:57 +0800 +Subject: [PATCH 07/11] colo-compare: Fix memory leak in packet_enqueue() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The patch is to fix the "pkt" memory leak in packet_enqueue(). +The allocated "pkt" needs to be freed if the colo compare +primary or secondary queue is too big. + +Replace the error_report of full queue with a trace event. + +Signed-off-by: Derek Su +Reviewed-by: Zhang Chen +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Zhang Chen +Signed-off-by: Jason Wang +Signed-off-by: BiaoXiang Ye +--- + net/colo-compare.c | 23 +++++++++++++++-------- + net/trace-events | 1 + + 2 files changed, 16 insertions(+), 8 deletions(-) + +diff --git a/net/colo-compare.c b/net/colo-compare.c +index 7ee17f2c..3168407e 100644 +--- a/net/colo-compare.c ++++ b/net/colo-compare.c +@@ -120,6 +120,10 @@ enum { + SECONDARY_IN, + }; + ++static const char *colo_mode[] = { ++ [PRIMARY_IN] = "primary", ++ [SECONDARY_IN] = "secondary", ++}; + + static int compare_chr_send(CompareState *s, + const uint8_t *buf, +@@ -215,6 +219,7 @@ static int packet_enqueue(CompareState *s, int mode, Connection **con) + ConnectionKey key; + Packet *pkt = NULL; + Connection *conn; ++ int ret; + + if (mode == PRIMARY_IN) { + pkt = packet_new(s->pri_rs.buf, +@@ -243,16 +248,18 @@ static int packet_enqueue(CompareState *s, int mode, Connection **con) + } + + if (mode == PRIMARY_IN) { +- if (!colo_insert_packet(&conn->primary_list, pkt, &conn->pack)) { +- error_report("colo compare primary queue size too big," +- "drop packet"); +- } ++ ret = colo_insert_packet(&conn->primary_list, pkt, &conn->pack); + } else { +- if (!colo_insert_packet(&conn->secondary_list, pkt, &conn->sack)) { +- error_report("colo compare secondary queue size too big," +- "drop packet"); +- } ++ ret = colo_insert_packet(&conn->secondary_list, pkt, &conn->sack); + } ++ ++ if (!ret) { ++ trace_colo_compare_drop_packet(colo_mode[mode], ++ "queue size too big, drop packet"); ++ packet_destroy(pkt, NULL); ++ pkt = NULL; ++ } ++ + *con = conn; + + return 0; +diff --git a/net/trace-events b/net/trace-events +index ac570564..a9995387 100644 +--- a/net/trace-events ++++ b/net/trace-events +@@ -12,6 +12,7 @@ colo_proxy_main(const char *chr) ": %s" + + # colo-compare.c + colo_compare_main(const char *chr) ": %s" ++colo_compare_drop_packet(const char *queue, const char *chr) ": %s: %s" + colo_compare_udp_miscompare(const char *sta, int size) ": %s = %d" + colo_compare_icmp_miscompare(const char *sta, int size) ": %s = %d" + colo_compare_ip_info(int psize, const char *sta, const char *stb, int ssize, const char *stc, const char *std) "ppkt size = %d, ip_src = %s, ip_dst = %s, spkt size = %d, ip_src = %s, ip_dst = %s" +-- +2.27.0.dirty + diff --git a/cris-do-not-leak-struct-cris_disasm_data.patch b/cris-do-not-leak-struct-cris_disasm_data.patch new file mode 100644 index 0000000000000000000000000000000000000000..fa7623fe1878eca815805e853d64ff9b2d8a88a3 --- /dev/null +++ b/cris-do-not-leak-struct-cris_disasm_data.patch @@ -0,0 +1,139 @@ +From d0586065e67b5df2611f4cf61eb791d48b78ff77 Mon Sep 17 00:00:00 2001 +From: lizhengui +Date: Wed, 9 Sep 2020 14:42:59 +0800 +Subject: [PATCH] cris: do not leak struct cris_disasm_data + +Use a stack-allocated struct to avoid a memory leak. + +Signed-off-by: Paolo Bonzini +--- + disas/cris.c | 65 ++++++++++++++++++++++++++++------------------------ + 1 file changed, 35 insertions(+), 30 deletions(-) + +diff --git a/disas/cris.c b/disas/cris.c +index 2f43c9b2..f3ff44ba 100644 +--- a/disas/cris.c ++++ b/disas/cris.c +@@ -1294,24 +1294,17 @@ static int cris_constraint + /* Parse disassembler options and store state in info. FIXME: For the + time being, we abuse static variables. */ + +-static bfd_boolean +-cris_parse_disassembler_options (disassemble_info *info, ++static void ++cris_parse_disassembler_options (struct cris_disasm_data *disdata, ++ char *disassembler_options, + enum cris_disass_family distype) + { +- struct cris_disasm_data *disdata; +- +- info->private_data = calloc (1, sizeof (struct cris_disasm_data)); +- disdata = (struct cris_disasm_data *) info->private_data; +- if (disdata == NULL) +- return false; +- + /* Default true. */ + disdata->trace_case +- = (info->disassembler_options == NULL +- || (strcmp (info->disassembler_options, "nocase") != 0)); ++ = (disassembler_options == NULL ++ || (strcmp (disassembler_options, "nocase") != 0)); + + disdata->distype = distype; +- return true; + } + + static const struct cris_spec_reg * +@@ -2736,9 +2729,11 @@ static int + print_insn_cris_with_register_prefix (bfd_vma vma, + disassemble_info *info) + { +- if (info->private_data == NULL +- && !cris_parse_disassembler_options (info, cris_dis_v0_v10)) +- return -1; ++ struct cris_disasm_data disdata; ++ info->private_data = &disdata; ++ cris_parse_disassembler_options (&disdata, info->disassembler_options, ++ cris_dis_v0_v10); ++ + return print_insn_cris_generic (vma, info, true); + } + /* Disassemble, prefixing register names with `$'. CRIS v32. */ +@@ -2747,9 +2742,11 @@ static int + print_insn_crisv32_with_register_prefix (bfd_vma vma, + disassemble_info *info) + { +- if (info->private_data == NULL +- && !cris_parse_disassembler_options (info, cris_dis_v32)) +- return -1; ++ struct cris_disasm_data disdata; ++ info->private_data = &disdata; ++ cris_parse_disassembler_options (&disdata, info->disassembler_options, ++ cris_dis_v32); ++ + return print_insn_cris_generic (vma, info, true); + } + +@@ -2761,9 +2758,11 @@ static int + print_insn_crisv10_v32_with_register_prefix (bfd_vma vma, + disassemble_info *info) + { +- if (info->private_data == NULL +- && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32)) +- return -1; ++ struct cris_disasm_data disdata; ++ info->private_data = &disdata; ++ cris_parse_disassembler_options (&disdata, info->disassembler_options, ++ cris_dis_common_v10_v32); ++ + return print_insn_cris_generic (vma, info, true); + } + +@@ -2773,9 +2772,11 @@ static int + print_insn_cris_without_register_prefix (bfd_vma vma, + disassemble_info *info) + { +- if (info->private_data == NULL +- && !cris_parse_disassembler_options (info, cris_dis_v0_v10)) +- return -1; ++ struct cris_disasm_data disdata; ++ info->private_data = &disdata; ++ cris_parse_disassembler_options (&disdata, info->disassembler_options, ++ cris_dis_v0_v10); ++ + return print_insn_cris_generic (vma, info, false); + } + +@@ -2785,9 +2786,11 @@ static int + print_insn_crisv32_without_register_prefix (bfd_vma vma, + disassemble_info *info) + { +- if (info->private_data == NULL +- && !cris_parse_disassembler_options (info, cris_dis_v32)) +- return -1; ++ struct cris_disasm_data disdata; ++ info->private_data = &disdata; ++ cris_parse_disassembler_options (&disdata, info->disassembler_options, ++ cris_dis_v32); ++ + return print_insn_cris_generic (vma, info, false); + } + +@@ -2798,9 +2801,11 @@ static int + print_insn_crisv10_v32_without_register_prefix (bfd_vma vma, + disassemble_info *info) + { +- if (info->private_data == NULL +- && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32)) +- return -1; ++ struct cris_disasm_data disdata; ++ info->private_data = &disdata; ++ cris_parse_disassembler_options (&disdata, info->disassembler_options, ++ cris_dis_common_v10_v32); ++ + return print_insn_cris_generic (vma, info, false); + } + #endif +-- +2.19.1 + diff --git a/delete-the-in-tpm.txt.patch b/delete-the-in-tpm.txt.patch new file mode 100644 index 0000000000000000000000000000000000000000..01ce3ace541aca115bccd47100f5dbd954643764 --- /dev/null +++ b/delete-the-in-tpm.txt.patch @@ -0,0 +1,26 @@ +From 3020ae141ef40f06b17eb0f16d2a3c6d5872ff89 Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Wed, 29 Jul 2020 08:45:50 +0000 +Subject: [PATCH 05/19] delete the in tpm.txt + +Signed-off-by: jiangfangjie +--- + docs/specs/tpm.txt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt +index 5d8c26b1..9c8cca04 100644 +--- a/docs/specs/tpm.txt ++++ b/docs/specs/tpm.txt +@@ -89,7 +89,7 @@ TPM upon reboot. The PPI specification defines the operation requests and the + actions the firmware has to take. The system administrator passes the operation + request number to the firmware through an ACPI interface which writes this + number to a memory location that the firmware knows. Upon reboot, the firmware +-finds the number and sends commands to the the TPM. The firmware writes the TPM ++finds the number and sends commands to the TPM. The firmware writes the TPM + result code and the operation request number to a memory location that ACPI can + read from and pass the result on to the administrator. + +-- +2.23.0 + diff --git a/docs-specs-tpm-Document-TPM_TIS-sysbus-device-for-AR.patch b/docs-specs-tpm-Document-TPM_TIS-sysbus-device-for-AR.patch new file mode 100644 index 0000000000000000000000000000000000000000..f0be64a937fd5b1f78c54f5f74854f388c023786 --- /dev/null +++ b/docs-specs-tpm-Document-TPM_TIS-sysbus-device-for-AR.patch @@ -0,0 +1,66 @@ +From dd7f6cc3bcd71681920e3530f2c53041c812c5d3 Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 5 Mar 2020 17:51:46 +0100 +Subject: [PATCH 16/19] docs/specs/tpm: Document TPM_TIS sysbus device for ARM + +Update the documentation with recent changes related to the +sysbus TPM_TIS device addition and add the command line +to be used with arm VIRT. + +Signed-off-by: Eric Auger +Reviewed-by: Stefan Berger +Message-id: 20200305165149.618-8-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + docs/specs/tpm.rst | 25 ++++++++++++++++++++++++- + 1 file changed, 24 insertions(+), 1 deletion(-) + +diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst +index 2bdf637f..da9eb39c 100644 +--- a/docs/specs/tpm.rst ++++ b/docs/specs/tpm.rst +@@ -18,9 +18,15 @@ The TIS interface makes a memory mapped IO region in the area + 0xfed40000-0xfed44fff available to the guest operating system. + + QEMU files related to TPM TIS interface: +- - ``hw/tpm/tpm_tis.c`` ++ - ``hw/tpm/tpm_tis_common.c`` ++ - ``hw/tpm/tpm_tis_isa.c`` ++ - ``hw/tpm/tpm_tis_sysbus.c`` + - ``hw/tpm/tpm_tis.h`` + ++Both an ISA device and a sysbus device are available. The former is ++used with pc/q35 machine while the latter can be instantiated in the ++ARM virt machine. ++ + CRB interface + ------------- + +@@ -325,6 +331,23 @@ In case a pSeries machine is emulated, use the following command line: + -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \ + -drive file=test.img,format=raw,if=none,id=drive-virtio-disk0 + ++In case an ARM virt machine is emulated, use the following command line: ++ ++.. code-block:: console ++ ++ qemu-system-aarch64 -machine virt,gic-version=3,accel=kvm \ ++ -cpu host -m 4G \ ++ -nographic -no-acpi \ ++ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ ++ -tpmdev emulator,id=tpm0,chardev=chrtpm \ ++ -device tpm-tis-device,tpmdev=tpm0 \ ++ -device virtio-blk-pci,drive=drv0 \ ++ -drive format=qcow2,file=hda.qcow2,if=none,id=drv0 \ ++ -drive if=pflash,format=raw,file=flash0.img,readonly \ ++ -drive if=pflash,format=raw,file=flash1.img ++ ++ On ARM, ACPI boot with TPM is not yet supported. ++ + In case SeaBIOS is used as firmware, it should show the TPM menu item + after entering the menu with 'ESC'. + +-- +2.23.0 + diff --git a/docs-specs-tpm-reST-ify-TPM-documentation.patch b/docs-specs-tpm-reST-ify-TPM-documentation.patch new file mode 100644 index 0000000000000000000000000000000000000000..d4648994bde2fc4b68ce49f28f4a612f53e65551 --- /dev/null +++ b/docs-specs-tpm-reST-ify-TPM-documentation.patch @@ -0,0 +1,993 @@ +From 5d1865496ca39f08142a0c1eb2c9b14ec1ec9140 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 21 Jan 2020 10:29:35 -0500 +Subject: [PATCH 09/19] docs/specs/tpm: reST-ify TPM documentation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Marc-André Lureau +Reviewed-by: Stefan Berger +Message-Id: <20200121152935.649898-7-stefanb@linux.ibm.com> +Signed-off-by: David Gibson +Signed-off-by: jiangfangjie +--- + docs/specs/index.rst | 1 + + docs/specs/tpm.rst | 503 +++++++++++++++++++++++++++++++++++++++++++ + docs/specs/tpm.txt | 445 -------------------------------------- + 3 files changed, 504 insertions(+), 445 deletions(-) + create mode 100644 docs/specs/tpm.rst + delete mode 100644 docs/specs/tpm.txt + +diff --git a/docs/specs/index.rst b/docs/specs/index.rst +index 984ba440..de46a8b5 100644 +--- a/docs/specs/index.rst ++++ b/docs/specs/index.rst +@@ -13,3 +13,4 @@ Contents: + ppc-xive + ppc-spapr-xive + acpi_hw_reduced_hotplug ++ tpm +diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst +new file mode 100644 +index 00000000..2bdf637f +--- /dev/null ++++ b/docs/specs/tpm.rst +@@ -0,0 +1,503 @@ ++=============== ++QEMU TPM Device ++=============== ++ ++Guest-side hardware interface ++============================= ++ ++TIS interface ++------------- ++ ++The QEMU TPM emulation implements a TPM TIS hardware interface ++following the Trusted Computing Group's specification "TCG PC Client ++Specific TPM Interface Specification (TIS)", Specification Version ++1.3, 21 March 2013. (see the `TIS specification`_, or a later version ++of it). ++ ++The TIS interface makes a memory mapped IO region in the area ++0xfed40000-0xfed44fff available to the guest operating system. ++ ++QEMU files related to TPM TIS interface: ++ - ``hw/tpm/tpm_tis.c`` ++ - ``hw/tpm/tpm_tis.h`` ++ ++CRB interface ++------------- ++ ++QEMU also implements a TPM CRB interface following the Trusted ++Computing Group's specification "TCG PC Client Platform TPM Profile ++(PTP) Specification", Family "2.0", Level 00 Revision 01.03 v22, May ++22, 2017. (see the `CRB specification`_, or a later version of it) ++ ++The CRB interface makes a memory mapped IO region in the area ++0xfed40000-0xfed40fff (1 locality) available to the guest ++operating system. ++ ++QEMU files related to TPM CRB interface: ++ - ``hw/tpm/tpm_crb.c`` ++ ++SPAPR interface ++--------------- ++ ++pSeries (ppc64) machines offer a tpm-spapr device model. ++ ++QEMU files related to the SPAPR interface: ++ - ``hw/tpm/tpm_spapr.c`` ++ ++fw_cfg interface ++================ ++ ++The bios/firmware may read the ``"etc/tpm/config"`` fw_cfg entry for ++configuring the guest appropriately. ++ ++The entry of 6 bytes has the following content, in little-endian: ++ ++.. code-block:: c ++ ++ #define TPM_VERSION_UNSPEC 0 ++ #define TPM_VERSION_1_2 1 ++ #define TPM_VERSION_2_0 2 ++ ++ #define TPM_PPI_VERSION_NONE 0 ++ #define TPM_PPI_VERSION_1_30 1 ++ ++ struct FwCfgTPMConfig { ++ uint32_t tpmppi_address; /* PPI memory location */ ++ uint8_t tpm_version; /* TPM version */ ++ uint8_t tpmppi_version; /* PPI version */ ++ }; ++ ++ACPI interface ++============== ++ ++The TPM device is defined with ACPI ID "PNP0C31". QEMU builds a SSDT ++and passes it into the guest through the fw_cfg device. The device ++description contains the base address of the TIS interface 0xfed40000 ++and the size of the MMIO area (0x5000). In case a TPM2 is used by ++QEMU, a TPM2 ACPI table is also provided. The device is described to ++be used in polling mode rather than interrupt mode primarily because ++no unused IRQ could be found. ++ ++To support measurement logs to be written by the firmware, ++e.g. SeaBIOS, a TCPA table is implemented. This table provides a 64kb ++buffer where the firmware can write its log into. For TPM 2 only a ++more recent version of the TPM2 table provides support for ++measurements logs and a TCPA table does not need to be created. ++ ++The TCPA and TPM2 ACPI tables follow the Trusted Computing Group ++specification "TCG ACPI Specification" Family "1.2" and "2.0", Level ++00 Revision 00.37. (see the `ACPI specification`_, or a later version ++of it) ++ ++ACPI PPI Interface ++------------------ ++ ++QEMU supports the Physical Presence Interface (PPI) for TPM 1.2 and ++TPM 2. This interface requires ACPI and firmware support. (see the ++`PPI specification`_) ++ ++PPI enables a system administrator (root) to request a modification to ++the TPM upon reboot. The PPI specification defines the operation ++requests and the actions the firmware has to take. The system ++administrator passes the operation request number to the firmware ++through an ACPI interface which writes this number to a memory ++location that the firmware knows. Upon reboot, the firmware finds the ++number and sends commands to the TPM. The firmware writes the TPM ++result code and the operation request number to a memory location that ++ACPI can read from and pass the result on to the administrator. ++ ++The PPI specification defines a set of mandatory and optional ++operations for the firmware to implement. The ACPI interface also ++allows an administrator to list the supported operations. In QEMU the ++ACPI code is generated by QEMU, yet the firmware needs to implement ++support on a per-operations basis, and different firmwares may support ++a different subset. Therefore, QEMU introduces the virtual memory ++device for PPI where the firmware can indicate which operations it ++supports and ACPI can enable the ones that are supported and disable ++all others. This interface lies in main memory and has the following ++layout: ++ ++ +-------------+--------+--------+-------------------------------------------+ ++ | Field | Length | Offset | Description | ++ +=============+========+========+===========================================+ ++ | ``func`` | 0x100 | 0x000 | Firmware sets values for each supported | ++ | | | | operation. See defined values below. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``ppin`` | 0x1 | 0x100 | SMI interrupt to use. Set by firmware. | ++ | | | | Not supported. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``ppip`` | 0x4 | 0x101 | ACPI function index to pass to SMM code. | ++ | | | | Set by ACPI. Not supported. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``pprp`` | 0x4 | 0x105 | Result of last executed operation. Set by | ++ | | | | firmware. See function index 5 for values.| ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``pprq`` | 0x4 | 0x109 | Operation request number to execute. See | ++ | | | | 'Physical Presence Interface Operation | ++ | | | | Summary' tables in specs. Set by ACPI. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``pprm`` | 0x4 | 0x10d | Operation request optional parameter. | ++ | | | | Values depend on operation. Set by ACPI. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``lppr`` | 0x4 | 0x111 | Last executed operation request number. | ++ | | | | Copied from pprq field by firmware. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``fret`` | 0x4 | 0x115 | Result code from SMM function. | ++ | | | | Not supported. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``res1`` | 0x40 | 0x119 | Reserved for future use | ++ +-------------+--------+--------+-------------------------------------------+ ++ |``next_step``| 0x1 | 0x159 | Operation to execute after reboot by | ++ | | | | firmware. Used by firmware. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``movv`` | 0x1 | 0x15a | Memory overwrite variable | ++ +-------------+--------+--------+-------------------------------------------+ ++ ++The following values are supported for the ``func`` field. They ++correspond to the values used by ACPI function index 8. ++ ++ +----------+-------------------------------------------------------------+ ++ | Value | Description | ++ +==========+=============================================================+ ++ | 0 | Operation is not implemented. | ++ +----------+-------------------------------------------------------------+ ++ | 1 | Operation is only accessible through firmware. | ++ +----------+-------------------------------------------------------------+ ++ | 2 | Operation is blocked for OS by firmware configuration. | ++ +----------+-------------------------------------------------------------+ ++ | 3 | Operation is allowed and physically present user required. | ++ +----------+-------------------------------------------------------------+ ++ | 4 | Operation is allowed and physically present user is not | ++ | | required. | ++ +----------+-------------------------------------------------------------+ ++ ++The location of the table is given by the fw_cfg ``tpmppi_address`` ++field. The PPI memory region size is 0x400 (``TPM_PPI_ADDR_SIZE``) to ++leave enough room for future updates. ++ ++QEMU files related to TPM ACPI tables: ++ - ``hw/i386/acpi-build.c`` ++ - ``include/hw/acpi/tpm.h`` ++ ++TPM backend devices ++=================== ++ ++The TPM implementation is split into two parts, frontend and ++backend. The frontend part is the hardware interface, such as the TPM ++TIS interface described earlier, and the other part is the TPM backend ++interface. The backend interfaces implement the interaction with a TPM ++device, which may be a physical or an emulated device. The split ++between the front- and backend devices allows a frontend to be ++connected with any available backend. This enables the TIS interface ++to be used with the passthrough backend or the swtpm backend. ++ ++QEMU files related to TPM backends: ++ - ``backends/tpm.c`` ++ - ``include/sysemu/tpm_backend.h`` ++ - ``include/sysemu/tpm_backend_int.h`` ++ ++The QEMU TPM passthrough device ++------------------------------- ++ ++In case QEMU is run on Linux as the host operating system it is ++possible to make the hardware TPM device available to a single QEMU ++guest. In this case the user must make sure that no other program is ++using the device, e.g., /dev/tpm0, before trying to start QEMU with ++it. ++ ++The passthrough driver uses the host's TPM device for sending TPM ++commands and receiving responses from. Besides that it accesses the ++TPM device's sysfs entry for support of command cancellation. Since ++none of the state of a hardware TPM can be migrated between hosts, ++virtual machine migration is disabled when the TPM passthrough driver ++is used. ++ ++Since the host's TPM device will already be initialized by the host's ++firmware, certain commands, e.g. ``TPM_Startup()``, sent by the ++virtual firmware for device initialization, will fail. In this case ++the firmware should not use the TPM. ++ ++Sharing the device with the host is generally not a recommended usage ++scenario for a TPM device. The primary reason for this is that two ++operating systems can then access the device's single set of ++resources, such as platform configuration registers ++(PCRs). Applications or kernel security subsystems, such as the Linux ++Integrity Measurement Architecture (IMA), are not expecting to share ++PCRs. ++ ++QEMU files related to the TPM passthrough device: ++ - ``hw/tpm/tpm_passthrough.c`` ++ - ``hw/tpm/tpm_util.c`` ++ - ``hw/tpm/tpm_util.h`` ++ ++ ++Command line to start QEMU with the TPM passthrough device using the host's ++hardware TPM ``/dev/tpm0``: ++ ++.. code-block:: console ++ ++ qemu-system-x86_64 -display sdl -accel kvm \ ++ -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ ++ -tpmdev passthrough,id=tpm0,path=/dev/tpm0 \ ++ -device tpm-tis,tpmdev=tpm0 test.img ++ ++ ++The following commands should result in similar output inside the VM ++with a Linux kernel that either has the TPM TIS driver built-in or ++available as a module: ++ ++.. code-block:: console ++ ++ # dmesg | grep -i tpm ++ [ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) ++ ++ # dmesg | grep TCPA ++ [ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ ++ BXPCTCPA 0000001 BXPC 00000001) ++ ++ # ls -l /dev/tpm* ++ crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 ++ ++ # find /sys/devices/ | grep pcrs$ | xargs cat ++ PCR-00: 35 4E 3B CE 23 9F 38 59 ... ++ ... ++ PCR-23: 00 00 00 00 00 00 00 00 ... ++ ++The QEMU TPM emulator device ++---------------------------- ++ ++The TPM emulator device uses an external TPM emulator called 'swtpm' ++for sending TPM commands to and receiving responses from. The swtpm ++program must have been started before trying to access it through the ++TPM emulator with QEMU. ++ ++The TPM emulator implements a command channel for transferring TPM ++commands and responses as well as a control channel over which control ++commands can be sent. (see the `SWTPM protocol`_ specification) ++ ++The control channel serves the purpose of resetting, initializing, and ++migrating the TPM state, among other things. ++ ++The swtpm program behaves like a hardware TPM and therefore needs to ++be initialized by the firmware running inside the QEMU virtual ++machine. One necessary step for initializing the device is to send ++the TPM_Startup command to it. SeaBIOS, for example, has been ++instrumented to initialize a TPM 1.2 or TPM 2 device using this ++command. ++ ++QEMU files related to the TPM emulator device: ++ - ``hw/tpm/tpm_emulator.c`` ++ - ``hw/tpm/tpm_util.c`` ++ - ``hw/tpm/tpm_util.h`` ++ ++The following commands start the swtpm with a UnixIO control channel over ++a socket interface. They do not need to be run as root. ++ ++.. code-block:: console ++ ++ mkdir /tmp/mytpm1 ++ swtpm socket --tpmstate dir=/tmp/mytpm1 \ ++ --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ ++ --log level=20 ++ ++Command line to start QEMU with the TPM emulator device communicating ++with the swtpm (x86): ++ ++.. code-block:: console ++ ++ qemu-system-x86_64 -display sdl -accel kvm \ ++ -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ ++ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ ++ -tpmdev emulator,id=tpm0,chardev=chrtpm \ ++ -device tpm-tis,tpmdev=tpm0 test.img ++ ++In case a pSeries machine is emulated, use the following command line: ++ ++.. code-block:: console ++ ++ qemu-system-ppc64 -display sdl -machine pseries,accel=kvm \ ++ -m 1024 -bios slof.bin -boot menu=on \ ++ -nodefaults -device VGA -device pci-ohci -device usb-kbd \ ++ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ ++ -tpmdev emulator,id=tpm0,chardev=chrtpm \ ++ -device tpm-spapr,tpmdev=tpm0 \ ++ -device spapr-vscsi,id=scsi0,reg=0x00002000 \ ++ -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \ ++ -drive file=test.img,format=raw,if=none,id=drive-virtio-disk0 ++ ++In case SeaBIOS is used as firmware, it should show the TPM menu item ++after entering the menu with 'ESC'. ++ ++.. code-block:: console ++ ++ Select boot device: ++ 1. DVD/CD [ata1-0: QEMU DVD-ROM ATAPI-4 DVD/CD] ++ [...] ++ 5. Legacy option rom ++ ++ t. TPM Configuration ++ ++The following commands should result in similar output inside the VM ++with a Linux kernel that either has the TPM TIS driver built-in or ++available as a module: ++ ++.. code-block:: console ++ ++ # dmesg | grep -i tpm ++ [ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) ++ ++ # dmesg | grep TCPA ++ [ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ ++ BXPCTCPA 0000001 BXPC 00000001) ++ ++ # ls -l /dev/tpm* ++ crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 ++ ++ # find /sys/devices/ | grep pcrs$ | xargs cat ++ PCR-00: 35 4E 3B CE 23 9F 38 59 ... ++ ... ++ PCR-23: 00 00 00 00 00 00 00 00 ... ++ ++Migration with the TPM emulator ++=============================== ++ ++The TPM emulator supports the following types of virtual machine ++migration: ++ ++- VM save / restore (migration into a file) ++- Network migration ++- Snapshotting (migration into storage like QoW2 or QED) ++ ++The following command sequences can be used to test VM save / restore. ++ ++In a 1st terminal start an instance of a swtpm using the following command: ++ ++.. code-block:: console ++ ++ mkdir /tmp/mytpm1 ++ swtpm socket --tpmstate dir=/tmp/mytpm1 \ ++ --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ ++ --log level=20 --tpm2 ++ ++In a 2nd terminal start the VM: ++ ++.. code-block:: console ++ ++ qemu-system-x86_64 -display sdl -accel kvm \ ++ -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ ++ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ ++ -tpmdev emulator,id=tpm0,chardev=chrtpm \ ++ -device tpm-tis,tpmdev=tpm0 \ ++ -monitor stdio \ ++ test.img ++ ++Verify that the attached TPM is working as expected using applications ++inside the VM. ++ ++To store the state of the VM use the following command in the QEMU ++monitor in the 2nd terminal: ++ ++.. code-block:: console ++ ++ (qemu) migrate "exec:cat > testvm.bin" ++ (qemu) quit ++ ++At this point a file called ``testvm.bin`` should exists and the swtpm ++and QEMU processes should have ended. ++ ++To test 'VM restore' you have to start the swtpm with the same ++parameters as before. If previously a TPM 2 [--tpm2] was saved, --tpm2 ++must now be passed again on the command line. ++ ++In the 1st terminal restart the swtpm with the same command line as ++before: ++ ++.. code-block:: console ++ ++ swtpm socket --tpmstate dir=/tmp/mytpm1 \ ++ --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ ++ --log level=20 --tpm2 ++ ++In the 2nd terminal restore the state of the VM using the additional ++'-incoming' option. ++ ++.. code-block:: console ++ ++ qemu-system-x86_64 -display sdl -accel kvm \ ++ -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ ++ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ ++ -tpmdev emulator,id=tpm0,chardev=chrtpm \ ++ -device tpm-tis,tpmdev=tpm0 \ ++ -incoming "exec:cat < testvm.bin" \ ++ test.img ++ ++Troubleshooting migration ++------------------------- ++ ++There are several reasons why migration may fail. In case of problems, ++please ensure that the command lines adhere to the following rules ++and, if possible, that identical versions of QEMU and swtpm are used ++at all times. ++ ++VM save and restore: ++ ++ - QEMU command line parameters should be identical apart from the ++ '-incoming' option on VM restore ++ ++ - swtpm command line parameters should be identical ++ ++VM migration to 'localhost': ++ ++ - QEMU command line parameters should be identical apart from the ++ '-incoming' option on the destination side ++ ++ - swtpm command line parameters should point to two different ++ directories on the source and destination swtpm (--tpmstate dir=...) ++ (especially if different versions of libtpms were to be used on the ++ same machine). ++ ++VM migration across the network: ++ ++ - QEMU command line parameters should be identical apart from the ++ '-incoming' option on the destination side ++ ++ - swtpm command line parameters should be identical ++ ++VM Snapshotting: ++ - QEMU command line parameters should be identical ++ ++ - swtpm command line parameters should be identical ++ ++ ++Besides that, migration failure reasons on the swtpm level may include ++the following: ++ ++ - the versions of the swtpm on the source and destination sides are ++ incompatible ++ ++ - downgrading of TPM state may not be supported ++ ++ - the source and destination libtpms were compiled with different ++ compile-time options and the destination side refuses to accept the ++ state ++ ++ - different migration keys are used on the source and destination side ++ and the destination side cannot decrypt the migrated state ++ (swtpm ... --migration-key ... ) ++ ++ ++.. _TIS specification: ++ https://trustedcomputinggroup.org/pc-client-work-group-pc-client-specific-tpm-interface-specification-tis/ ++ ++.. _CRB specification: ++ https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/ ++ ++ ++.. _ACPI specification: ++ https://trustedcomputinggroup.org/tcg-acpi-specification/ ++ ++.. _PPI specification: ++ https://trustedcomputinggroup.org/resource/tcg-physical-presence-interface-specification/ ++ ++.. _SWTPM protocol: ++ https://github.com/stefanberger/swtpm/blob/master/man/man3/swtpm_ioctls.pod +diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt +deleted file mode 100644 +index 9c3e67d8..00000000 +--- a/docs/specs/tpm.txt ++++ /dev/null +@@ -1,445 +0,0 @@ +-QEMU TPM Device +-=============== +- +-= Guest-side Hardware Interface = +- +-The QEMU TPM emulation implements a TPM TIS hardware interface following the +-Trusted Computing Group's specification "TCG PC Client Specific TPM Interface +-Specification (TIS)", Specification Version 1.3, 21 March 2013. This +-specification, or a later version of it, can be accessed from the following +-URL: +- +-https://trustedcomputinggroup.org/pc-client-work-group-pc-client-specific-tpm-interface-specification-tis/ +- +-The TIS interface makes a memory mapped IO region in the area 0xfed40000 - +-0xfed44fff available to the guest operating system. +- +- +-QEMU files related to TPM TIS interface: +- - hw/tpm/tpm_tis.c +- - hw/tpm/tpm_tis.h +- +- +-QEMU also implements a TPM CRB interface following the Trusted Computing +-Group's specification "TCG PC Client Platform TPM Profile (PTP) +-Specification", Family "2.0", Level 00 Revision 01.03 v22, May 22, 2017. +-This specification, or a later version of it, can be accessed from the +-following URL: +- +-https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/ +- +-The CRB interface makes a memory mapped IO region in the area 0xfed40000 - +-0xfed40fff (1 locality) available to the guest operating system. +- +-QEMU files related to TPM CRB interface: +- - hw/tpm/tpm_crb.c +- +- +-pSeries (ppc64) machines offer a tpm-spapr device model. +- +-QEMU files related to the SPAPR interface: +- - hw/tpm/tpm_spapr.c +- +-= fw_cfg interface = +- +-The bios/firmware may read the "etc/tpm/config" fw_cfg entry for +-configuring the guest appropriately. +- +-The entry of 6 bytes has the following content, in little-endian: +- +- #define TPM_VERSION_UNSPEC 0 +- #define TPM_VERSION_1_2 1 +- #define TPM_VERSION_2_0 2 +- +- #define TPM_PPI_VERSION_NONE 0 +- #define TPM_PPI_VERSION_1_30 1 +- +- struct FwCfgTPMConfig { +- uint32_t tpmppi_address; /* PPI memory location */ +- uint8_t tpm_version; /* TPM version */ +- uint8_t tpmppi_version; /* PPI version */ +- }; +- +-= ACPI Interface = +- +-The TPM device is defined with ACPI ID "PNP0C31". QEMU builds a SSDT and passes +-it into the guest through the fw_cfg device. The device description contains +-the base address of the TIS interface 0xfed40000 and the size of the MMIO area +-(0x5000). In case a TPM2 is used by QEMU, a TPM2 ACPI table is also provided. +-The device is described to be used in polling mode rather than interrupt mode +-primarily because no unused IRQ could be found. +- +-To support measurement logs to be written by the firmware, e.g. SeaBIOS, a TCPA +-table is implemented. This table provides a 64kb buffer where the firmware can +-write its log into. For TPM 2 only a more recent version of the TPM2 table +-provides support for measurements logs and a TCPA table does not need to be +-created. +- +-The TCPA and TPM2 ACPI tables follow the Trusted Computing Group specification +-"TCG ACPI Specification" Family "1.2" and "2.0", Level 00 Revision 00.37. This +-specification, or a later version of it, can be accessed from the following +-URL: +- +-https://trustedcomputinggroup.org/tcg-acpi-specification/ +- +-== ACPI PPI Interface == +- +-QEMU supports the Physical Presence Interface (PPI) for TPM 1.2 and TPM 2. This +-interface requires ACPI and firmware support. The specification can be found at +-the following URL: +- +-https://trustedcomputinggroup.org/resource/tcg-physical-presence-interface-specification/ +- +-PPI enables a system administrator (root) to request a modification to the +-TPM upon reboot. The PPI specification defines the operation requests and the +-actions the firmware has to take. The system administrator passes the operation +-request number to the firmware through an ACPI interface which writes this +-number to a memory location that the firmware knows. Upon reboot, the firmware +-finds the number and sends commands to the TPM. The firmware writes the TPM +-result code and the operation request number to a memory location that ACPI can +-read from and pass the result on to the administrator. +- +-The PPI specification defines a set of mandatory and optional operations for +-the firmware to implement. The ACPI interface also allows an administrator to +-list the supported operations. In QEMU the ACPI code is generated by QEMU, yet +-the firmware needs to implement support on a per-operations basis, and +-different firmwares may support a different subset. Therefore, QEMU introduces +-the virtual memory device for PPI where the firmware can indicate which +-operations it supports and ACPI can enable the ones that are supported and +-disable all others. This interface lies in main memory and has the following +-layout: +- +- +----------+--------+--------+-------------------------------------------+ +- | Field | Length | Offset | Description | +- +----------+--------+--------+-------------------------------------------+ +- | func | 0x100 | 0x000 | Firmware sets values for each supported | +- | | | | operation. See defined values below. | +- +----------+--------+--------+-------------------------------------------+ +- | ppin | 0x1 | 0x100 | SMI interrupt to use. Set by firmware. | +- | | | | Not supported. | +- +----------+--------+--------+-------------------------------------------+ +- | ppip | 0x4 | 0x101 | ACPI function index to pass to SMM code. | +- | | | | Set by ACPI. Not supported. | +- +----------+--------+--------+-------------------------------------------+ +- | pprp | 0x4 | 0x105 | Result of last executed operation. Set by | +- | | | | firmware. See function index 5 for values.| +- +----------+--------+--------+-------------------------------------------+ +- | pprq | 0x4 | 0x109 | Operation request number to execute. See | +- | | | | 'Physical Presence Interface Operation | +- | | | | Summary' tables in specs. Set by ACPI. | +- +----------+--------+--------+-------------------------------------------+ +- | pprm | 0x4 | 0x10d | Operation request optional parameter. | +- | | | | Values depend on operation. Set by ACPI. | +- +----------+--------+--------+-------------------------------------------+ +- | lppr | 0x4 | 0x111 | Last executed operation request number. | +- | | | | Copied from pprq field by firmware. | +- +----------+--------+--------+-------------------------------------------+ +- | fret | 0x4 | 0x115 | Result code from SMM function. | +- | | | | Not supported. | +- +----------+--------+--------+-------------------------------------------+ +- | res1 | 0x40 | 0x119 | Reserved for future use | +- +----------+--------+--------+-------------------------------------------+ +- | next_step| 0x1 | 0x159 | Operation to execute after reboot by | +- | | | | firmware. Used by firmware. | +- +----------+--------+--------+-------------------------------------------+ +- | movv | 0x1 | 0x15a | Memory overwrite variable | +- +----------+--------+--------+-------------------------------------------+ +- +- The following values are supported for the 'func' field. They correspond +- to the values used by ACPI function index 8. +- +- +----------+-------------------------------------------------------------+ +- | value | Description | +- +----------+-------------------------------------------------------------+ +- | 0 | Operation is not implemented. | +- +----------+-------------------------------------------------------------+ +- | 1 | Operation is only accessible through firmware. | +- +----------+-------------------------------------------------------------+ +- | 2 | Operation is blocked for OS by firmware configuration. | +- +----------+-------------------------------------------------------------+ +- | 3 | Operation is allowed and physically present user required. | +- +----------+-------------------------------------------------------------+ +- | 4 | Operation is allowed and physically present user is not | +- | | required. | +- +----------+-------------------------------------------------------------+ +- +-The location of the table is given by the fw_cfg tpmppi_address field. +-The PPI memory region size is 0x400 (TPM_PPI_ADDR_SIZE) to leave +-enough room for future updates. +- +- +-QEMU files related to TPM ACPI tables: +- - hw/i386/acpi-build.c +- - include/hw/acpi/tpm.h +- +- +-= TPM backend devices = +- +-The TPM implementation is split into two parts, frontend and backend. The +-frontend part is the hardware interface, such as the TPM TIS interface +-described earlier, and the other part is the TPM backend interface. The backend +-interfaces implement the interaction with a TPM device, which may be a physical +-or an emulated device. The split between the front- and backend devices allows +-a frontend to be connected with any available backend. This enables the TIS +-interface to be used with the passthrough backend or the (future) swtpm backend. +- +- +-QEMU files related to TPM backends: +- - backends/tpm.c +- - include/sysemu/tpm_backend.h +- - include/sysemu/tpm_backend_int.h +- +- +-== The QEMU TPM passthrough device == +- +-In case QEMU is run on Linux as the host operating system it is possible to +-make the hardware TPM device available to a single QEMU guest. In this case the +-user must make sure that no other program is using the device, e.g., /dev/tpm0, +-before trying to start QEMU with it. +- +-The passthrough driver uses the host's TPM device for sending TPM commands +-and receiving responses from. Besides that it accesses the TPM device's sysfs +-entry for support of command cancellation. Since none of the state of a +-hardware TPM can be migrated between hosts, virtual machine migration is +-disabled when the TPM passthrough driver is used. +- +-Since the host's TPM device will already be initialized by the host's firmware, +-certain commands, e.g. TPM_Startup(), sent by the virtual firmware for device +-initialization, will fail. In this case the firmware should not use the TPM. +- +-Sharing the device with the host is generally not a recommended usage scenario +-for a TPM device. The primary reason for this is that two operating systems can +-then access the device's single set of resources, such as platform configuration +-registers (PCRs). Applications or kernel security subsystems, such as the +-Linux Integrity Measurement Architecture (IMA), are not expecting to share PCRs. +- +- +-QEMU files related to the TPM passthrough device: +- - hw/tpm/tpm_passthrough.c +- - hw/tpm/tpm_util.c +- - hw/tpm/tpm_util.h +- +- +-Command line to start QEMU with the TPM passthrough device using the host's +-hardware TPM /dev/tpm0: +- +-qemu-system-x86_64 -display sdl -accel kvm \ +- -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ +- -tpmdev passthrough,id=tpm0,path=/dev/tpm0 \ +- -device tpm-tis,tpmdev=tpm0 test.img +- +-The following commands should result in similar output inside the VM with a +-Linux kernel that either has the TPM TIS driver built-in or available as a +-module: +- +-#> dmesg | grep -i tpm +-[ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) +- +-#> dmesg | grep TCPA +-[ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ +- BXPCTCPA 0000001 BXPC 00000001) +- +-#> ls -l /dev/tpm* +-crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 +- +-#> find /sys/devices/ | grep pcrs$ | xargs cat +-PCR-00: 35 4E 3B CE 23 9F 38 59 ... +-... +-PCR-23: 00 00 00 00 00 00 00 00 ... +- +- +-== The QEMU TPM emulator device == +- +-The TPM emulator device uses an external TPM emulator called 'swtpm' for +-sending TPM commands to and receiving responses from. The swtpm program +-must have been started before trying to access it through the TPM emulator +-with QEMU. +- +-The TPM emulator implements a command channel for transferring TPM commands +-and responses as well as a control channel over which control commands can +-be sent. The specification for the control channel can be found here: +- +-https://github.com/stefanberger/swtpm/blob/master/man/man3/swtpm_ioctls.pod +- +- +-The control channel serves the purpose of resetting, initializing, and +-migrating the TPM state, among other things. +- +-The swtpm program behaves like a hardware TPM and therefore needs to be +-initialized by the firmware running inside the QEMU virtual machine. +-One necessary step for initializing the device is to send the TPM_Startup +-command to it. SeaBIOS, for example, has been instrumented to initialize +-a TPM 1.2 or TPM 2 device using this command. +- +- +-QEMU files related to the TPM emulator device: +- - hw/tpm/tpm_emulator.c +- - hw/tpm/tpm_util.c +- - hw/tpm/tpm_util.h +- +- +-The following commands start the swtpm with a UnixIO control channel over +-a socket interface. They do not need to be run as root. +- +-mkdir /tmp/mytpm1 +-swtpm socket --tpmstate dir=/tmp/mytpm1 \ +- --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ +- --log level=20 +- +-Command line to start QEMU with the TPM emulator device communicating with +-the swtpm (x86): +- +-qemu-system-x86_64 -display sdl -accel kvm \ +- -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ +- -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ +- -tpmdev emulator,id=tpm0,chardev=chrtpm \ +- -device tpm-tis,tpmdev=tpm0 test.img +- +-In case a pSeries machine is emulated, use the following command line: +- +-qemu-system-ppc64 -display sdl -machine pseries,accel=kvm \ +- -m 1024 -bios slof.bin -boot menu=on \ +- -nodefaults -device VGA -device pci-ohci -device usb-kbd \ +- -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ +- -tpmdev emulator,id=tpm0,chardev=chrtpm \ +- -device tpm-spapr,tpmdev=tpm0 \ +- -device spapr-vscsi,id=scsi0,reg=0x00002000 \ +- -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \ +- -drive file=test.img,format=raw,if=none,id=drive-virtio-disk0 +- +- +-In case SeaBIOS is used as firmware, it should show the TPM menu item +-after entering the menu with 'ESC'. +- +-Select boot device: +-1. DVD/CD [ata1-0: QEMU DVD-ROM ATAPI-4 DVD/CD] +-[...] +-5. Legacy option rom +- +-t. TPM Configuration +- +- +-The following commands should result in similar output inside the VM with a +-Linux kernel that either has the TPM TIS driver built-in or available as a +-module: +- +-#> dmesg | grep -i tpm +-[ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) +- +-#> dmesg | grep TCPA +-[ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ +- BXPCTCPA 0000001 BXPC 00000001) +- +-#> ls -l /dev/tpm* +-crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 +- +-#> find /sys/devices/ | grep pcrs$ | xargs cat +-PCR-00: 35 4E 3B CE 23 9F 38 59 ... +-... +-PCR-23: 00 00 00 00 00 00 00 00 ... +- +- +-=== Migration with the TPM emulator === +- +-The TPM emulator supports the following types of virtual machine migration: +- +-- VM save / restore (migration into a file) +-- Network migration +-- Snapshotting (migration into storage like QoW2 or QED) +- +-The following command sequences can be used to test VM save / restore. +- +- +-In a 1st terminal start an instance of a swtpm using the following command: +- +-mkdir /tmp/mytpm1 +-swtpm socket --tpmstate dir=/tmp/mytpm1 \ +- --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ +- --log level=20 --tpm2 +- +-In a 2nd terminal start the VM: +- +-qemu-system-x86_64 -display sdl -accel kvm \ +- -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ +- -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ +- -tpmdev emulator,id=tpm0,chardev=chrtpm \ +- -device tpm-tis,tpmdev=tpm0 \ +- -monitor stdio \ +- test.img +- +-Verify that the attached TPM is working as expected using applications inside +-the VM. +- +-To store the state of the VM use the following command in the QEMU monitor in +-the 2nd terminal: +- +-(qemu) migrate "exec:cat > testvm.bin" +-(qemu) quit +- +-At this point a file called 'testvm.bin' should exists and the swtpm and QEMU +-processes should have ended. +- +-To test 'VM restore' you have to start the swtpm with the same parameters +-as before. If previously a TPM 2 [--tpm2] was saved, --tpm2 must now be +-passed again on the command line. +- +-In the 1st terminal restart the swtpm with the same command line as before: +- +-swtpm socket --tpmstate dir=/tmp/mytpm1 \ +- --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ +- --log level=20 --tpm2 +- +-In the 2nd terminal restore the state of the VM using the additional +-'-incoming' option. +- +-qemu-system-x86_64 -display sdl -accel kvm \ +- -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ +- -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ +- -tpmdev emulator,id=tpm0,chardev=chrtpm \ +- -device tpm-tis,tpmdev=tpm0 \ +- -incoming "exec:cat < testvm.bin" \ +- test.img +- +- +-Troubleshooting migration: +- +-There are several reasons why migration may fail. In case of problems, +-please ensure that the command lines adhere to the following rules and, +-if possible, that identical versions of QEMU and swtpm are used at all +-times. +- +-VM save and restore: +- - QEMU command line parameters should be identical apart from the +- '-incoming' option on VM restore +- - swtpm command line parameters should be identical +- +-VM migration to 'localhost': +- - QEMU command line parameters should be identical apart from the +- '-incoming' option on the destination side +- - swtpm command line parameters should point to two different +- directories on the source and destination swtpm (--tpmstate dir=...) +- (especially if different versions of libtpms were to be used on the +- same machine). +- +-VM migration across the network: +- - QEMU command line parameters should be identical apart from the +- '-incoming' option on the destination side +- - swtpm command line parameters should be identical +- +-VM Snapshotting: +- - QEMU command line parameters should be identical +- - swtpm command line parameters should be identical +- +- +-Besides that, migration failure reasons on the swtpm level may include +-the following: +- +- - the versions of the swtpm on the source and destination sides are +- incompatible +- - downgrading of TPM state may not be supported +- - the source and destination libtpms were compiled with different +- compile-time options and the destination side refuses to accept the +- state +- - different migration keys are used on the source and destination side +- and the destination side cannot decrypt the migrated state +- (swtpm ... --migration-key ... ) +-- +2.23.0 + diff --git a/file-posix-Fix-leaked-fd-in-raw_open_common-error-pa.patch b/file-posix-Fix-leaked-fd-in-raw_open_common-error-pa.patch new file mode 100644 index 0000000000000000000000000000000000000000..28c1e3bc6837063888bb8c862fb1e629f70de8be --- /dev/null +++ b/file-posix-Fix-leaked-fd-in-raw_open_common-error-pa.patch @@ -0,0 +1,31 @@ +From 94be73a20d42482cdf30115e672c36af2fe9068d Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 17 Jul 2020 12:54:26 +0200 +Subject: [PATCH 5/5] file-posix: Fix leaked fd in raw_open_common() error path + +Signed-off-by: Kevin Wolf +Message-Id: <20200717105426.51134-4-kwolf@redhat.com> +Reviewed-by: Max Reitz +Signed-off-by: Kevin Wolf +Signed-off-by: Zhenyu Ye +--- + block/file-posix.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/block/file-posix.c b/block/file-posix.c +index 2184aa98..1259bf58 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -671,6 +671,9 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, + bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK; + ret = 0; + fail: ++ if (ret < 0 && s->fd != -1) { ++ qemu_close(s->fd); ++ } + if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) { + unlink(filename); + } +-- +2.22.0.windows.1 + diff --git a/fix-vhost_user_blk_watch-crash.patch b/fix-vhost_user_blk_watch-crash.patch new file mode 100644 index 0000000000000000000000000000000000000000..905cbe3c2542b7d59f8d69da720bf0639a4be9bb --- /dev/null +++ b/fix-vhost_user_blk_watch-crash.patch @@ -0,0 +1,81 @@ +From 0b77995819a596f96c621697643e83624126e668 Mon Sep 17 00:00:00 2001 +From: Li Feng +Date: Mon, 23 Mar 2020 13:29:24 +0800 +Subject: [PATCH 13/14] fix vhost_user_blk_watch crash + +the G_IO_HUP is watched in tcp_chr_connect, and the callback +vhost_user_blk_watch is not needed, because tcp_chr_hup is registered as +callback. And it will close the tcp link. + +Signed-off-by: Li Feng +Message-Id: <20200323052924.29286-1-fengli@smartx.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Peng Liang +--- + hw/block/vhost-user-blk.c | 19 ------------------- + include/hw/virtio/vhost-user-blk.h | 1 - + 2 files changed, 20 deletions(-) + +diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c +index 85bc4017e7e9..dc66f8a5febd 100644 +--- a/hw/block/vhost-user-blk.c ++++ b/hw/block/vhost-user-blk.c +@@ -346,18 +346,6 @@ static void vhost_user_blk_disconnect(DeviceState *dev) + vhost_dev_cleanup(&s->dev); + } + +-static gboolean vhost_user_blk_watch(GIOChannel *chan, GIOCondition cond, +- void *opaque) +-{ +- DeviceState *dev = opaque; +- VirtIODevice *vdev = VIRTIO_DEVICE(dev); +- VHostUserBlk *s = VHOST_USER_BLK(vdev); +- +- qemu_chr_fe_disconnect(&s->chardev); +- +- return true; +-} +- + static void vhost_user_blk_event(void *opaque, int event) + { + DeviceState *dev = opaque; +@@ -370,15 +358,9 @@ static void vhost_user_blk_event(void *opaque, int event) + qemu_chr_fe_disconnect(&s->chardev); + return; + } +- s->watch = qemu_chr_fe_add_watch(&s->chardev, G_IO_HUP, +- vhost_user_blk_watch, dev); + break; + case CHR_EVENT_CLOSED: + vhost_user_blk_disconnect(dev); +- if (s->watch) { +- g_source_remove(s->watch); +- s->watch = 0; +- } + break; + } + } +@@ -419,7 +401,6 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) + + s->inflight = g_new0(struct vhost_inflight, 1); + s->vqs = g_new(struct vhost_virtqueue, s->num_queues); +- s->watch = 0; + s->connected = false; + + qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, vhost_user_blk_event, +diff --git a/include/hw/virtio/vhost-user-blk.h b/include/hw/virtio/vhost-user-blk.h +index 8dbf11c6f071..ad9b742a644c 100644 +--- a/include/hw/virtio/vhost-user-blk.h ++++ b/include/hw/virtio/vhost-user-blk.h +@@ -38,7 +38,6 @@ typedef struct VHostUserBlk { + struct vhost_inflight *inflight; + VhostUserState vhost_user; + struct vhost_virtqueue *vqs; +- guint watch; + bool connected; + } VHostUserBlk; + +-- +2.26.2 + diff --git a/hmp-vnc-Fix-info-vnc-list-leak.patch b/hmp-vnc-Fix-info-vnc-list-leak.patch new file mode 100644 index 0000000000000000000000000000000000000000..ccc4e1db511a18c5da864a1d8b2732e9a4cd8a1f --- /dev/null +++ b/hmp-vnc-Fix-info-vnc-list-leak.patch @@ -0,0 +1,48 @@ +From 6cb599f75b7844aefd7823ad97fc3bae70eff11f Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Mon, 23 Mar 2020 12:08:22 +0000 +Subject: [PATCH 06/14] hmp/vnc: Fix info vnc list leak + +We're iterating the list, and then freeing the iteration pointer rather +than the list head. + +Fixes: 0a9667ecdb6d ("hmp: Update info vnc") +Reported-by: Coverity (CID 1421932) +Signed-off-by: Dr. David Alan Gilbert +Message-Id: <20200323120822.51266-1-dgilbert@redhat.com> +Reviewed-by: Peter Maydell +Signed-off-by: Dr. David Alan Gilbert +Signed-off-by: Peng Liang +--- + monitor/hmp-cmds.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c +index 5ca3ebe94272..fc5d6b92c4b6 100644 +--- a/monitor/hmp-cmds.c ++++ b/monitor/hmp-cmds.c +@@ -745,10 +745,11 @@ static void hmp_info_vnc_servers(Monitor *mon, VncServerInfo2List *server) + + void hmp_info_vnc(Monitor *mon, const QDict *qdict) + { +- VncInfo2List *info2l; ++ VncInfo2List *info2l, *info2l_head; + Error *err = NULL; + + info2l = qmp_query_vnc_servers(&err); ++ info2l_head = info2l; + if (err) { + hmp_handle_error(mon, &err); + return; +@@ -777,7 +778,7 @@ void hmp_info_vnc(Monitor *mon, const QDict *qdict) + info2l = info2l->next; + } + +- qapi_free_VncInfo2List(info2l); ++ qapi_free_VncInfo2List(info2l_head); + + } + #endif +-- +2.26.2 + diff --git a/hppa-fix-leak-from-g_strdup_printf.patch b/hppa-fix-leak-from-g_strdup_printf.patch new file mode 100644 index 0000000000000000000000000000000000000000..b04193e380fe58ef14e91cb56d162abc264dce9b --- /dev/null +++ b/hppa-fix-leak-from-g_strdup_printf.patch @@ -0,0 +1,54 @@ +From b7ef7e6fb5a2b08268f4b19c07c07abd4fbb2064 Mon Sep 17 00:00:00 2001 +From: lizhengui +Date: Wed, 9 Sep 2020 14:48:49 +0800 +Subject: [PATCH] hppa: fix leak from g_strdup_printf +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +memory_region_init_* takes care of copying the name into memory it owns. +Free it in the caller. + +Signed-off-by: Paolo Bonzini +Reviewed-by: Philippe Mathieu-Daudé +--- + hw/hppa/dino.c | 1 + + hw/hppa/machine.c | 4 +++- + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c +index e94614ab..ef923b49 100644 +--- a/hw/hppa/dino.c ++++ b/hw/hppa/dino.c +@@ -485,6 +485,7 @@ PCIBus *dino_init(MemoryRegion *addr_space, + 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. */ +diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c +index 662838d8..9e25660e 100644 +--- a/hw/hppa/machine.c ++++ b/hw/hppa/machine.c +@@ -78,13 +78,15 @@ static void machine_hppa_init(MachineState *machine) + + /* Create CPUs. */ + for (i = 0; i < smp_cpus; i++) { ++ char *name = g_strdup_printf("cpu%ld-io-eir", i); + cpu[i] = HPPA_CPU(cpu_create(machine->cpu_type)); + + cpu_region = g_new(MemoryRegion, 1); + memory_region_init_io(cpu_region, OBJECT(cpu[i]), &hppa_io_eir_ops, +- cpu[i], g_strdup_printf("cpu%ld-io-eir", i), 4); ++ cpu[i], name, 4); + memory_region_add_subregion(addr_space, CPU_HPA + i * 0x1000, + cpu_region); ++ g_free(name); + } + + /* Limit main memory. */ +-- +2.19.1 + diff --git a/hw-arm-virt-Init-PMU-for-hotplugged-vCPU.patch b/hw-arm-virt-Init-PMU-for-hotplugged-vCPU.patch new file mode 100644 index 0000000000000000000000000000000000000000..c124df5394121fdb0415b3b85d04fc3417a747aa --- /dev/null +++ b/hw-arm-virt-Init-PMU-for-hotplugged-vCPU.patch @@ -0,0 +1,73 @@ +From acc5162f1d1591ee4830f9b67934fc6d8a9ebbc1 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Tue, 8 Sep 2020 22:09:44 +0800 +Subject: [PATCH] hw/arm/virt: Init PMU for hotplugged vCPU + +Factor out PMU init code from fdt_add_pmu_nodes and +do PMU init for hotplugged vCPU. + +Signed-off-by: Keqian Zhu +--- + hw/arm/virt.c | 29 +++++++++++++++++++++-------- + 1 file changed, 21 insertions(+), 8 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 7afc6c5e..7506d0ff 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -605,6 +605,23 @@ static void fdt_add_gic_node(VirtMachineState *vms) + g_free(nodename); + } + ++static bool virt_cpu_init_pmu(const VirtMachineState *vms, CPUState *cpu) ++{ ++ ARMCPU *armcpu = ARM_CPU(cpu); ++ ++ if (!arm_feature(&armcpu->env, ARM_FEATURE_PMU)) { ++ return false; ++ } ++ if (kvm_enabled()) { ++ if (kvm_irqchip_in_kernel()) { ++ kvm_arm_pmu_set_irq(cpu, PPI(VIRTUAL_PMU_IRQ)); ++ } ++ kvm_arm_pmu_init(cpu); ++ } ++ ++ return true; ++} ++ + static void fdt_add_pmu_nodes(const VirtMachineState *vms) + { + CPUState *cpu; +@@ -612,16 +629,9 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms) + uint32_t irqflags = GIC_FDT_IRQ_FLAGS_LEVEL_HI; + + CPU_FOREACH(cpu) { +- armcpu = ARM_CPU(cpu); +- if (!arm_feature(&armcpu->env, ARM_FEATURE_PMU)) { ++ if (!virt_cpu_init_pmu(vms, cpu)) { + return; + } +- if (kvm_enabled()) { +- if (kvm_irqchip_in_kernel()) { +- kvm_arm_pmu_set_irq(cpu, PPI(VIRTUAL_PMU_IRQ)); +- } +- kvm_arm_pmu_init(cpu); +- } + } + + if (vms->gic_version == 2) { +@@ -2248,6 +2258,9 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, + agcc->cpu_hotplug_realize(gicv3, ncpu); + connect_gic_cpu_irqs(vms, ncpu); + ++ /* Init PMU part */ ++ virt_cpu_init_pmu(vms, cs); ++ + /* Register CPU reset and trigger it manually */ + cpu_synchronize_state(cs); + cpu_hotplug_register_reset(ncpu); +-- +2.23.0 + + diff --git a/hw-arm-virt-vTPM-support.patch b/hw-arm-virt-vTPM-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..cbdc68e62f88981b10ebd459ce101caaf10dba6d --- /dev/null +++ b/hw-arm-virt-vTPM-support.patch @@ -0,0 +1,141 @@ +From 443ebab9c299b04f020a6873454facb078723141 Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Thu, 13 Aug 2020 20:01:10 +0800 +Subject: [PATCH 15/19] hw/arm/virt: vTPM support + +Let the TPM TIS SYSBUS device be dynamically instantiable +in ARM virt. A device tree node is dynamically created +(TPM via MMIO). + +The TPM Physical Presence interface (PPI) is not supported. + +To run with the swtmp TPM emulator, the qemu command line must +be augmented with: + + -chardev socket,id=chrtpm,path=swtpm-sock + -tpmdev emulator,id=tpm0,chardev=chrtpm + -device tpm-tis-device,tpmdev=tpm0 + +swtpm/libtpms command line example: + +swtpm socket --tpm2 -t -d --tpmstate dir=/tmp/tpm +--ctrl type=unixio,path=swtpm-sock + +Signed-off-by: Eric Auger +Reviewed-by: Stefan Berger +Tested-by: Ard Biesheuvel +Acked-by: Ard Biesheuvel +Message-id: 20200305165149.618-7-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + hw/arm/Kconfig | 1 + + hw/arm/sysbus-fdt.c | 33 +++++++++++++++++++++++++++++++++ + hw/arm/virt.c | 7 +++++++ + 3 files changed, 41 insertions(+) + +diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig +index 15e18b0a..06e49f26 100644 +--- a/hw/arm/Kconfig ++++ b/hw/arm/Kconfig +@@ -5,6 +5,7 @@ config ARM_VIRT + imply VFIO_AMD_XGBE + imply VFIO_PLATFORM + imply VFIO_XGMAC ++ imply TPM_TIS_SYSBUS + select A15MPCORE + select ACPI + select ARM_SMMUV3 +diff --git a/hw/arm/sysbus-fdt.c b/hw/arm/sysbus-fdt.c +index 57f94e65..c725d325 100644 +--- a/hw/arm/sysbus-fdt.c ++++ b/hw/arm/sysbus-fdt.c +@@ -30,6 +30,7 @@ + #include "hw/arm/sysbus-fdt.h" + #include "qemu/error-report.h" + #include "sysemu/device_tree.h" ++#include "sysemu/tpm.h" + #include "hw/platform-bus.h" + #include "sysemu/sysemu.h" + #include "hw/vfio/vfio-platform.h" +@@ -437,6 +438,37 @@ static bool vfio_platform_match(SysBusDevice *sbdev, + + #endif /* CONFIG_LINUX */ + ++/* ++ * add_tpm_tis_fdt_node: Create a DT node for TPM TIS ++ * ++ * See kernel documentation: ++ * Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt ++ * Optional interrupt for command completion is not exposed ++ */ ++static int add_tpm_tis_fdt_node(SysBusDevice *sbdev, void *opaque) ++{ ++ PlatformBusFDTData *data = opaque; ++ PlatformBusDevice *pbus = data->pbus; ++ void *fdt = data->fdt; ++ const char *parent_node = data->pbus_node_name; ++ char *nodename; ++ uint32_t reg_attr[2]; ++ uint64_t mmio_base; ++ ++ mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0); ++ nodename = g_strdup_printf("%s/tpm_tis@%" PRIx64, parent_node, mmio_base); ++ qemu_fdt_add_subnode(fdt, nodename); ++ ++ qemu_fdt_setprop_string(fdt, nodename, "compatible", "tcg,tpm-tis-mmio"); ++ ++ reg_attr[0] = cpu_to_be32(mmio_base); ++ reg_attr[1] = cpu_to_be32(0x5000); ++ qemu_fdt_setprop(fdt, nodename, "reg", reg_attr, 2 * sizeof(uint32_t)); ++ ++ g_free(nodename); ++ return 0; ++} ++ + static int no_fdt_node(SysBusDevice *sbdev, void *opaque) + { + return 0; +@@ -457,6 +489,7 @@ static const BindingEntry bindings[] = { + TYPE_BINDING(TYPE_VFIO_AMD_XGBE, add_amd_xgbe_fdt_node), + VFIO_PLATFORM_BINDING("amd,xgbe-seattle-v1a", add_amd_xgbe_fdt_node), + #endif ++ TYPE_BINDING(TYPE_TPM_TIS_SYSBUS, add_tpm_tis_fdt_node), + TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node), + TYPE_BINDING("", NULL), /* last element */ + }; +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 133d36a4..7afc6c5e 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -47,6 +47,7 @@ + #include "sysemu/numa.h" + #include "sysemu/cpus.h" + #include "sysemu/sysemu.h" ++#include "sysemu/tpm.h" + #include "sysemu/kvm.h" + #include "sysemu/cpus.h" + #include "sysemu/hw_accel.h" +@@ -2368,6 +2369,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_AMD_XGBE); + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE); + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_PLATFORM); ++ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS); + mc->block_default_type = IF_VIRTIO; + mc->no_cdrom = 1; + mc->pci_allow_0_address = true; +@@ -2481,6 +2483,11 @@ type_init(machvirt_machine_init); + + static void virt_machine_4_1_options(MachineClass *mc) + { ++ static GlobalProperty compat[] = { ++ { TYPE_TPM_TIS_SYSBUS, "ppi", "false" }, ++ }; ++ ++ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); + } + DEFINE_VIRT_MACHINE_AS_LATEST(4, 1) + +-- +2.23.0 + diff --git a/hw-block-nvme-fix-pci-doorbell-size-calculation.patch b/hw-block-nvme-fix-pci-doorbell-size-calculation.patch new file mode 100644 index 0000000000000000000000000000000000000000..f0aa09670e471a344c220ae38b8f5ba43b263eaf --- /dev/null +++ b/hw-block-nvme-fix-pci-doorbell-size-calculation.patch @@ -0,0 +1,62 @@ +From 1aa42c9269c762ad1b7efa41e92f734b093dce1c Mon Sep 17 00:00:00 2001 +From: Klaus Jensen +Date: Tue, 9 Jun 2020 21:03:12 +0200 +Subject: [PATCH 10/11] hw/block/nvme: fix pci doorbell size calculation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The size of the BAR is 0x1000 (main registers) + 8 bytes for each +queue. Currently, the size of the BAR is calculated like so: + + n->reg_size = pow2ceil(0x1004 + 2 * (n->num_queues + 1) * 4); + +Since the 'num_queues' parameter already accounts for the admin queue, +this should in any case not need to be incremented by one. Also, the +size should be initialized to (0x1000). + + n->reg_size = pow2ceil(0x1000 + 2 * n->num_queues * 4); + +This, with the default value of num_queues (64), we will set aside room +for 1 admin queue and 63 I/O queues (4 bytes per doorbell, 2 doorbells +per queue). + +Signed-off-by: Klaus Jensen +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Maxim Levitsky +Reviewed-by: Keith Busch +Message-Id: <20200609190333.59390-2-its@irrelevant.dk> +Signed-off-by: Kevin Wolf +Signed-off-by: BiaoXiang Ye +--- + hw/block/nvme.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/hw/block/nvme.c b/hw/block/nvme.c +index 417068d8..edac2f1d 100644 +--- a/hw/block/nvme.c ++++ b/hw/block/nvme.c +@@ -42,6 +42,9 @@ + #include "trace.h" + #include "nvme.h" + ++#define NVME_REG_SIZE 0x1000 ++#define NVME_DB_SIZE 4 ++ + #define NVME_GUEST_ERR(trace, fmt, ...) \ + do { \ + (trace_##trace)(__VA_ARGS__); \ +@@ -1348,7 +1351,9 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) + pcie_endpoint_cap_init(pci_dev, 0x80); + + n->num_namespaces = 1; +- n->reg_size = pow2ceil(0x1004 + 2 * (n->num_queues + 1) * 4); ++ ++ /* num_queues is really number of pairs, so each has two doorbells */ ++ n->reg_size = pow2ceil(NVME_REG_SIZE + 2 * n->num_queues * NVME_DB_SIZE); + n->ns_size = bs_size / (uint64_t)n->num_namespaces; + + n->namespaces = g_new0(NvmeNamespace, n->num_namespaces); +-- +2.27.0.dirty + diff --git a/hw-block-nvme-fix-pin-based-interrupt-behavior.patch b/hw-block-nvme-fix-pin-based-interrupt-behavior.patch new file mode 100644 index 0000000000000000000000000000000000000000..1fe1213d998869c0f87eabd5d75fc62c3750f06b --- /dev/null +++ b/hw-block-nvme-fix-pin-based-interrupt-behavior.patch @@ -0,0 +1,87 @@ +From 74ef18c90684f0ae18aef071b9e11a5e8796177b Mon Sep 17 00:00:00 2001 +From: alexchen +Date: Tue, 8 Sep 2020 11:17:20 +0000 +Subject: [PATCH] hw/block/nvme: fix pin-based interrupt behavior + +First, since the device only supports MSI-X or pin-based interrupt, if +MSI-X is not enabled, it should not accept interrupt vectors different +from 0 when creating completion queues. + +Secondly, the irq_status NvmeCtrl member is meant to be compared to the +INTMS register, so it should only be 32 bits wide. And it is really only +useful when used with multi-message MSI. + +Third, since we do not force a 1-to-1 correspondence between cqid and +interrupt vector, the irq_status register should not have bits set +according to cqid, but according to the associated interrupt vector. + +Fix these issues, but keep irq_status available so we can easily support +multi-message MSI down the line. + +Fixes: 5e9aa92eb1a5 ("hw/block: Fix pin-based interrupt behaviour of NVMe") +Cc: "Michael S. Tsirkin" +Cc: Marcel Apfelbaum +Signed-off-by: Klaus Jensen +Reviewed-by: Keith Busch +Message-Id: <20200609190333.59390-8-its@irrelevant.dk> +Signed-off-by: Kevin Wolf +Signed-off-by: BiaoXiang Ye +Signed-off-by: Zhenyu Ye +--- + hw/block/nvme.c | 12 ++++++++---- + hw/block/nvme.h | 2 +- + 2 files changed, 9 insertions(+), 5 deletions(-) + +diff --git a/hw/block/nvme.c b/hw/block/nvme.c +index 36d6a8bb..e35c2e10 100644 +--- a/hw/block/nvme.c ++++ b/hw/block/nvme.c +@@ -115,8 +115,8 @@ static void nvme_irq_assert(NvmeCtrl *n, NvmeCQueue *cq) + msix_notify(&(n->parent_obj), cq->vector); + } else { + trace_nvme_irq_pin(); +- assert(cq->cqid < 64); +- n->irq_status |= 1 << cq->cqid; ++ assert(cq->vector < 32); ++ n->irq_status |= 1 << cq->vector; + nvme_irq_check(n); + } + } else { +@@ -130,8 +130,8 @@ static void nvme_irq_deassert(NvmeCtrl *n, NvmeCQueue *cq) + if (msix_enabled(&(n->parent_obj))) { + return; + } else { +- assert(cq->cqid < 64); +- n->irq_status &= ~(1 << cq->cqid); ++ assert(cq->vector < 32); ++ n->irq_status &= ~(1 << cq->vector); + nvme_irq_check(n); + } + } +@@ -630,6 +630,10 @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd) + trace_nvme_err_invalid_create_cq_addr(prp1); + return NVME_INVALID_FIELD | NVME_DNR; + } ++ if (unlikely(!msix_enabled(&n->parent_obj) && vector)) { ++ trace_nvme_err_invalid_create_cq_vector(vector); ++ return NVME_INVALID_IRQ_VECTOR | NVME_DNR; ++ } + if (unlikely(vector > n->num_queues)) { + trace_nvme_err_invalid_create_cq_vector(vector); + return NVME_INVALID_IRQ_VECTOR | NVME_DNR; +diff --git a/hw/block/nvme.h b/hw/block/nvme.h +index 557194ee..f4c1ff91 100644 +--- a/hw/block/nvme.h ++++ b/hw/block/nvme.h +@@ -78,7 +78,7 @@ typedef struct NvmeCtrl { + uint32_t cmbsz; + uint32_t cmbloc; + uint8_t *cmbuf; +- uint64_t irq_status; ++ uint32_t irq_status; + uint64_t host_timestamp; /* Timestamp sent by the host */ + uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */ + +-- +2.23.0 + diff --git a/hw-pci-pci_bridge-Correct-pci_bridge_io-memory-regio.patch b/hw-pci-pci_bridge-Correct-pci_bridge_io-memory-regio.patch new file mode 100644 index 0000000000000000000000000000000000000000..76497d9ef4f4e111baba53cdd84ac7b7dbecb112 --- /dev/null +++ b/hw-pci-pci_bridge-Correct-pci_bridge_io-memory-regio.patch @@ -0,0 +1,67 @@ +From 595a0d0a0f21cd73863ea3b78ecccb6e0ea8b7a8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Mon, 1 Jun 2020 16:29:25 +0200 +Subject: [PATCH 2/5] hw/pci/pci_bridge: Correct pci_bridge_io memory region + size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +memory_region_set_size() handle the 16 Exabytes limit by +special-casing the UINT64_MAX value. This is not a problem +for the 32-bit maximum, 4 GiB. +By using the UINT32_MAX value, the pci_bridge_io MemoryRegion +ends up missing 1 byte: + + (qemu) info mtree + memory-region: pci_bridge_io + 0000000000000000-00000000fffffffe (prio 0, i/o): pci_bridge_io + 0000000000000060-0000000000000060 (prio 0, i/o): i8042-data + 0000000000000064-0000000000000064 (prio 0, i/o): i8042-cmd + 00000000000001ce-00000000000001d1 (prio 0, i/o): vbe + 0000000000000378-000000000000037f (prio 0, i/o): parallel + 00000000000003b4-00000000000003b5 (prio 0, i/o): vga + ... + +Fix by using the correct value. We now have: + + memory-region: pci_bridge_io + 0000000000000000-00000000ffffffff (prio 0, i/o): pci_bridge_io + 0000000000000060-0000000000000060 (prio 0, i/o): i8042-data + 0000000000000064-0000000000000064 (prio 0, i/o): i8042-cmd + ... + +Reviewed-by: Peter Maydell +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20200601142930.29408-4-f4bug@amsat.org> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Richard Henderson +--- + hw/pci/pci_bridge.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c +index 715b9a4f..d67c691d 100644 +--- a/hw/pci/pci_bridge.c ++++ b/hw/pci/pci_bridge.c +@@ -30,6 +30,7 @@ + */ + + #include "qemu/osdep.h" ++#include "qemu/units.h" + #include "hw/pci/pci_bridge.h" + #include "hw/pci/pci_bus.h" + #include "qemu/module.h" +@@ -381,7 +382,7 @@ void pci_bridge_initfn(PCIDevice *dev, const char *typename) + memory_region_init(&br->address_space_mem, OBJECT(br), "pci_bridge_pci", UINT64_MAX); + sec_bus->address_space_io = &br->address_space_io; + memory_region_init(&br->address_space_io, OBJECT(br), "pci_bridge_io", +- UINT32_MAX); ++ 4 * GiB); + br->windows = pci_bridge_region_init(br); + QLIST_INIT(&sec_bus->child); + QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling); +-- +2.23.0 + diff --git a/hw-ppc-Kconfig-Enable-TPM_SPAPR-as-part-of-PSERIES-c.patch b/hw-ppc-Kconfig-Enable-TPM_SPAPR-as-part-of-PSERIES-c.patch new file mode 100644 index 0000000000000000000000000000000000000000..ad3fc3a8356d20d28805db548c12b2b3745e8054 --- /dev/null +++ b/hw-ppc-Kconfig-Enable-TPM_SPAPR-as-part-of-PSERIES-c.patch @@ -0,0 +1,36 @@ +From 95cbe18c649a20f98562a993537a67e0ad78bf36 Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Tue, 21 Jan 2020 10:29:34 -0500 +Subject: [PATCH 08/19] hw/ppc/Kconfig: Enable TPM_SPAPR as part of PSERIES + config +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Stefan Berger +Reviewed-by: Marc-André Lureau +Reviewed-by: David Gibson +Message-Id: <20200121152935.649898-6-stefanb@linux.ibm.com> +[dwg: Use default in Kconfig rather than select to avoid breaking + Windows host build] +Signed-off-by: David Gibson +Signed-off-by: jiangfangjie +--- + hw/tpm/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig +index 4d4ab085..9e67d990 100644 +--- a/hw/tpm/Kconfig ++++ b/hw/tpm/Kconfig +@@ -25,6 +25,6 @@ config TPM_EMULATOR + + config TPM_SPAPR + bool +- default n ++ default y + depends on TPM && PSERIES + select TPMDEV +-- +2.23.0 + diff --git a/hw-tpm-rename-Error-parameter-to-more-common-errp.patch b/hw-tpm-rename-Error-parameter-to-more-common-errp.patch new file mode 100644 index 0000000000000000000000000000000000000000..a47a1ae68da792d7811b9d85cb5cbd5f5d5ac0cd --- /dev/null +++ b/hw-tpm-rename-Error-parameter-to-more-common-errp.patch @@ -0,0 +1,58 @@ +From f2dceb3cde537210896a2cadb8958cfd310113a3 Mon Sep 17 00:00:00 2001 +From: Vladimir Sementsov-Ogievskiy +Date: Thu, 5 Dec 2019 20:46:30 +0300 +Subject: [PATCH 01/19] hw/tpm: rename Error ** parameter to more common errp +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Stefan Berger +Message-Id: <20191205174635.18758-17-vsementsov@virtuozzo.com> +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Markus Armbruster +Signed-off-by: jiangfangjie +--- + hw/tpm/tpm_emulator.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c +index fc0b512f..38bf5fd6 100644 +--- a/hw/tpm/tpm_emulator.c ++++ b/hw/tpm/tpm_emulator.c +@@ -155,7 +155,7 @@ static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu, + const uint8_t *in, uint32_t in_len, + uint8_t *out, uint32_t out_len, + bool *selftest_done, +- Error **err) ++ Error **errp) + { + ssize_t ret; + bool is_selftest = false; +@@ -165,20 +165,20 @@ static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu, + is_selftest = tpm_util_is_selftest(in, in_len); + } + +- ret = qio_channel_write_all(tpm_emu->data_ioc, (char *)in, in_len, err); ++ ret = qio_channel_write_all(tpm_emu->data_ioc, (char *)in, in_len, errp); + if (ret != 0) { + return -1; + } + + ret = qio_channel_read_all(tpm_emu->data_ioc, (char *)out, +- sizeof(struct tpm_resp_hdr), err); ++ sizeof(struct tpm_resp_hdr), errp); + if (ret != 0) { + return -1; + } + + ret = qio_channel_read_all(tpm_emu->data_ioc, + (char *)out + sizeof(struct tpm_resp_hdr), +- tpm_cmd_get_size(out) - sizeof(struct tpm_resp_hdr), err); ++ tpm_cmd_get_size(out) - sizeof(struct tpm_resp_hdr), errp); + if (ret != 0) { + return -1; + } +-- +2.23.0 + diff --git a/ide-fix-leak-from-qemu_allocate_irqs.patch b/ide-fix-leak-from-qemu_allocate_irqs.patch new file mode 100644 index 0000000000000000000000000000000000000000..dce6e906ce92e7e303d2198d7a612905ca0632c1 --- /dev/null +++ b/ide-fix-leak-from-qemu_allocate_irqs.patch @@ -0,0 +1,28 @@ +From df35f8fe2687df32cb65f6a03b8dd80314cc4c53 Mon Sep 17 00:00:00 2001 +From: lizhengui +Date: Wed, 9 Sep 2020 15:00:08 +0800 +Subject: [PATCH] ide: fix leak from qemu_allocate_irqs + +The array returned by qemu_allocate_irqs is malloced, free it. + +Signed-off-by: Paolo Bonzini +Reviewed-by: Thomas Huth +--- + hw/ide/cmd646.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c +index ed23aabf..a149cd6c 100644 +--- a/hw/ide/cmd646.c ++++ b/hw/ide/cmd646.c +@@ -299,6 +299,7 @@ static void pci_cmd646_ide_realize(PCIDevice *dev, Error **errp) + d->bmdma[i].bus = &d->bus[i]; + ide_register_restart_cb(&d->bus[i]); + } ++ g_free(irq); + + vmstate_register(DEVICE(dev), 0, &vmstate_ide_pci, d); + qemu_register_reset(cmd646_reset, d); +-- +2.19.1 + diff --git a/linux-user-mmap.c-fix-integer-underflow-in-target_mr.patch b/linux-user-mmap.c-fix-integer-underflow-in-target_mr.patch new file mode 100644 index 0000000000000000000000000000000000000000..2d0c6abf3d233a0694cec23a2097011c39d4fd1f --- /dev/null +++ b/linux-user-mmap.c-fix-integer-underflow-in-target_mr.patch @@ -0,0 +1,34 @@ +From 7b4aded3f772ef43e2b600594f755eadd5da5958 Mon Sep 17 00:00:00 2001 +From: Jonathan Marler +Date: Sat, 2 May 2020 10:12:25 -0600 +Subject: [PATCH 3/5] linux-user/mmap.c: fix integer underflow in target_mremap + +Fixes: https://bugs.launchpad.net/bugs/1876373 + +This code path in mmap occurs when a page size is decreased with mremap. When a section of pages is shrunk, qemu calls mmap_reserve on the pages that were released. However, it has the diff operation reversed, subtracting the larger old_size from the smaller new_size. Instead, it should be subtracting the smaller new_size from the larger old_size. You can also see in the previous line of the change that this mmap_reserve call only occurs when old_size > new_size. + +Bug: https://bugs.launchpad.net/qemu/+bug/1876373 +Signed-off-by: Jonathan Marler +Reviewded-by: Laurent Vivier +Message-Id: <20200502161225.14346-1-johnnymarler@gmail.com> +Signed-off-by: Laurent Vivier +--- + linux-user/mmap.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/linux-user/mmap.c b/linux-user/mmap.c +index 46a6e3a7..2a9ca0c3 100644 +--- a/linux-user/mmap.c ++++ b/linux-user/mmap.c +@@ -740,7 +740,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, + if (prot == 0) { + host_addr = mremap(g2h(old_addr), old_size, new_size, flags); + if (host_addr != MAP_FAILED && reserved_va && old_size > new_size) { +- mmap_reserve(old_addr + old_size, new_size - old_size); ++ mmap_reserve(old_addr + old_size, old_size - new_size); + } + } else { + errno = ENOMEM; +-- +2.23.0 + diff --git a/lm32-do-not-leak-memory-on-object_new-object_unref.patch b/lm32-do-not-leak-memory-on-object_new-object_unref.patch new file mode 100644 index 0000000000000000000000000000000000000000..7ccc53684bb3d3224757209a4c1710883214fcc8 --- /dev/null +++ b/lm32-do-not-leak-memory-on-object_new-object_unref.patch @@ -0,0 +1,77 @@ +From d50be5295c49be1b6024f5902948b52e683b4c23 Mon Sep 17 00:00:00 2001 +From: lizhengui +Date: Wed, 9 Sep 2020 14:18:35 +0800 +Subject: [PATCH] lm32: do not leak memory on object_new/object_unref +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Bottom halves and ptimers are malloced, but nothing in these +files is freeing memory allocated by instance_init. Since +these are sysctl devices that are never unrealized, just moving +the allocations to realize is enough to avoid the leak in +practice (and also to avoid upsetting asan when running +device-introspect-test). + +Signed-off-by: Paolo Bonzini +Reviewed-by: Philippe Mathieu-Daudé +--- + hw/timer/lm32_timer.c | 6 +++--- + hw/timer/milkymist-sysctl.c | 10 +++++----- + 2 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/hw/timer/lm32_timer.c b/hw/timer/lm32_timer.c +index 6ce876c6..13f15825 100644 +--- a/hw/timer/lm32_timer.c ++++ b/hw/timer/lm32_timer.c +@@ -184,9 +184,6 @@ static void lm32_timer_init(Object *obj) + + sysbus_init_irq(dev, &s->irq); + +- s->bh = qemu_bh_new(timer_hit, s); +- s->ptimer = ptimer_init(s->bh, PTIMER_POLICY_DEFAULT); +- + memory_region_init_io(&s->iomem, obj, &timer_ops, s, + "timer", R_MAX * 4); + sysbus_init_mmio(dev, &s->iomem); +@@ -196,6 +193,9 @@ static void lm32_timer_realize(DeviceState *dev, Error **errp) + { + LM32TimerState *s = LM32_TIMER(dev); + ++ s->bh = qemu_bh_new(timer_hit, s); ++ s->ptimer = ptimer_init(s->bh, PTIMER_POLICY_DEFAULT); ++ + ptimer_set_freq(s->ptimer, s->freq_hz); + } + +diff --git a/hw/timer/milkymist-sysctl.c b/hw/timer/milkymist-sysctl.c +index a9d25087..2f1ecc6d 100644 +--- a/hw/timer/milkymist-sysctl.c ++++ b/hw/timer/milkymist-sysctl.c +@@ -280,11 +280,6 @@ static void milkymist_sysctl_init(Object *obj) + sysbus_init_irq(dev, &s->timer0_irq); + sysbus_init_irq(dev, &s->timer1_irq); + +- s->bh0 = qemu_bh_new(timer0_hit, s); +- s->bh1 = qemu_bh_new(timer1_hit, s); +- s->ptimer0 = ptimer_init(s->bh0, PTIMER_POLICY_DEFAULT); +- s->ptimer1 = ptimer_init(s->bh1, PTIMER_POLICY_DEFAULT); +- + memory_region_init_io(&s->regs_region, obj, &sysctl_mmio_ops, s, + "milkymist-sysctl", R_MAX * 4); + sysbus_init_mmio(dev, &s->regs_region); +@@ -294,6 +289,11 @@ static void milkymist_sysctl_realize(DeviceState *dev, Error **errp) + { + MilkymistSysctlState *s = MILKYMIST_SYSCTL(dev); + ++ s->bh0 = qemu_bh_new(timer0_hit, s); ++ s->bh1 = qemu_bh_new(timer1_hit, s); ++ s->ptimer0 = ptimer_init(s->bh0, PTIMER_POLICY_DEFAULT); ++ s->ptimer1 = ptimer_init(s->bh1, PTIMER_POLICY_DEFAULT); ++ + ptimer_set_freq(s->ptimer0, s->freq_hz); + ptimer_set_freq(s->ptimer1, s->freq_hz); + } +-- +2.19.1 + diff --git a/make-check-unit-use-after-free-in-test-opts-visitor.patch b/make-check-unit-use-after-free-in-test-opts-visitor.patch new file mode 100644 index 0000000000000000000000000000000000000000..590970004769b464b68977639a0e5e823bb9b9ac --- /dev/null +++ b/make-check-unit-use-after-free-in-test-opts-visitor.patch @@ -0,0 +1,102 @@ +From e3dfb5d2848975e9e947cb894afac87ce386a2bc Mon Sep 17 00:00:00 2001 +From: lizhengui +Date: Wed, 9 Sep 2020 15:18:52 +0800 +Subject: [PATCH] make check-unit: use after free in test-opts-visitor + +In the struct OptsVisitor, the 'repeated_opts' member points to a list +in the 'unprocessed_opts' hash table after the list has been destroyed. +A subsequent call to visit_type_int() references the deleted list. +It results in use-after-free issue reproduced by running the test case +under the Valgrind: valgrind tests/test-opts-visitor. +A new mode ListMode::LM_TRAVERSED is declared to mark the list +traversal completed. + +Suggested-by: Markus Armbruster +Signed-off-by: Andrey Shinkevich +Message-Id: <1565024586-387112-1-git-send-email-andrey.shinkevich@virtuozzo.com> +--- + qapi/opts-visitor.c | 26 ++++++++++++++++++++++---- + 1 file changed, 22 insertions(+), 4 deletions(-) + +diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c +index 324b1974..42d87df6 100644 +--- a/qapi/opts-visitor.c ++++ b/qapi/opts-visitor.c +@@ -24,7 +24,8 @@ enum ListMode + { + LM_NONE, /* not traversing a list of repeated options */ + +- LM_IN_PROGRESS, /* opts_next_list() ready to be called. ++ LM_IN_PROGRESS, /* ++ * opts_next_list() ready to be called. + * + * Generating the next list link will consume the most + * recently parsed QemuOpt instance of the repeated +@@ -36,7 +37,8 @@ enum ListMode + * LM_UNSIGNED_INTERVAL. + */ + +- LM_SIGNED_INTERVAL, /* opts_next_list() has been called. ++ LM_SIGNED_INTERVAL, /* ++ * opts_next_list() has been called. + * + * Generating the next list link will consume the most + * recently stored element from the signed interval, +@@ -48,7 +50,14 @@ enum ListMode + * next element of the signed interval. + */ + +- LM_UNSIGNED_INTERVAL /* Same as above, only for an unsigned interval. */ ++ LM_UNSIGNED_INTERVAL, /* Same as above, only for an unsigned interval. */ ++ ++ LM_TRAVERSED /* ++ * opts_next_list() has been called. ++ * ++ * No more QemuOpt instance in the list. ++ * The traversal has been completed. ++ */ + }; + + typedef enum ListMode ListMode; +@@ -238,6 +247,8 @@ opts_next_list(Visitor *v, GenericList *tail, size_t size) + OptsVisitor *ov = to_ov(v); + + switch (ov->list_mode) { ++ case LM_TRAVERSED: ++ return NULL; + case LM_SIGNED_INTERVAL: + case LM_UNSIGNED_INTERVAL: + if (ov->list_mode == LM_SIGNED_INTERVAL) { +@@ -258,6 +269,8 @@ opts_next_list(Visitor *v, GenericList *tail, size_t size) + opt = g_queue_pop_head(ov->repeated_opts); + if (g_queue_is_empty(ov->repeated_opts)) { + g_hash_table_remove(ov->unprocessed_opts, opt->name); ++ ov->repeated_opts = NULL; ++ ov->list_mode = LM_TRAVERSED; + return NULL; + } + break; +@@ -289,7 +302,8 @@ opts_end_list(Visitor *v, void **obj) + + assert(ov->list_mode == LM_IN_PROGRESS || + ov->list_mode == LM_SIGNED_INTERVAL || +- ov->list_mode == LM_UNSIGNED_INTERVAL); ++ ov->list_mode == LM_UNSIGNED_INTERVAL || ++ ov->list_mode == LM_TRAVERSED); + ov->repeated_opts = NULL; + ov->list_mode = LM_NONE; + } +@@ -306,6 +320,10 @@ lookup_scalar(const OptsVisitor *ov, const char *name, Error **errp) + list = lookup_distinct(ov, name, errp); + return list ? g_queue_peek_tail(list) : NULL; + } ++ if (ov->list_mode == LM_TRAVERSED) { ++ error_setg(errp, "Fewer list elements than expected"); ++ return NULL; ++ } + assert(ov->list_mode == LM_IN_PROGRESS); + return g_queue_peek_head(ov->repeated_opts); + } +-- +2.19.1 + diff --git a/mcf5208-fix-leak-from-qemu_allocate_irqs.patch b/mcf5208-fix-leak-from-qemu_allocate_irqs.patch new file mode 100644 index 0000000000000000000000000000000000000000..7e254f577e4f08bc332bb94dda769ce9a584c623 --- /dev/null +++ b/mcf5208-fix-leak-from-qemu_allocate_irqs.patch @@ -0,0 +1,29 @@ +From 07b7cdb648124748c34be299fbfdfe3b6e38a521 Mon Sep 17 00:00:00 2001 +From: lizhengui +Date: Wed, 9 Sep 2020 14:53:00 +0800 +Subject: [PATCH] mcf5208: fix leak from qemu_allocate_irqs + +The array returned by qemu_allocate_irqs is malloced, free it. + +Signed-off-by: Paolo Bonzini +Reviewed-by: Thomas Huth +--- + hw/m68k/mcf5208.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c +index 6f6efae9..cc765eac 100644 +--- a/hw/m68k/mcf5208.c ++++ b/hw/m68k/mcf5208.c +@@ -270,6 +270,8 @@ static void mcf5208evb_init(MachineState *machine) + 0xfc030000, pic + 36); + } + ++ g_free(pic); ++ + /* 0xfc000000 SCM. */ + /* 0xfc004000 XBS. */ + /* 0xfc008000 FlexBus CS. */ +-- +2.19.1 + diff --git a/microblaze-fix-leak-of-fdevice-tree-blob.patch b/microblaze-fix-leak-of-fdevice-tree-blob.patch new file mode 100644 index 0000000000000000000000000000000000000000..dd845e80cef5f3315e44417f3b7eeaa60ce6b8bb --- /dev/null +++ b/microblaze-fix-leak-of-fdevice-tree-blob.patch @@ -0,0 +1,32 @@ +From 2ff9c28e2b72cd359a0c4e931412e355baee8e1e Mon Sep 17 00:00:00 2001 +From: lizhengui +Date: Wed, 9 Sep 2020 14:55:11 +0800 +Subject: [PATCH] microblaze: fix leak of fdevice tree blob +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The device tree blob returned by load_device_tree is malloced. +Free it before returning. + +Signed-off-by: Paolo Bonzini +Reviewed-by: Philippe Mathieu-Daudé +--- + hw/microblaze/boot.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/microblaze/boot.c b/hw/microblaze/boot.c +index a7af4c07..0fcc4e9d 100644 +--- a/hw/microblaze/boot.c ++++ b/hw/microblaze/boot.c +@@ -99,6 +99,7 @@ static int microblaze_load_dtb(hwaddr addr, + } + + cpu_physical_memory_write(addr, fdt, fdt_size); ++ g_free(fdt); + return fdt_size; + } + +-- +2.19.1 + diff --git a/migration-Count-new_dirty-instead-of-real_dirty.patch b/migration-Count-new_dirty-instead-of-real_dirty.patch new file mode 100644 index 0000000000000000000000000000000000000000..a9ff297ffac9fb42ce63ef8a256e648adf1166dd --- /dev/null +++ b/migration-Count-new_dirty-instead-of-real_dirty.patch @@ -0,0 +1,74 @@ +From 63320ae36834e4ff2f0d139f205c464caa3887b4 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Mon, 22 Jun 2020 11:20:37 +0800 +Subject: [PATCH 04/11] migration: Count new_dirty instead of real_dirty + +real_dirty_pages becomes equal to total ram size after dirty log sync +in ram_init_bitmaps, the reason is that the bitmap of ramblock is +initialized to be all set, so old path counts them as "real dirty" at +beginning. + +This causes wrong dirty rate and false positive throttling. + +Signed-off-by: Keqian Zhu +Message-Id: <20200622032037.31112-1-zhukeqian1@huawei.com> +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Dr. David Alan Gilbert +Signed-off-by: BiaoXiang Ye +--- + include/exec/ram_addr.h | 5 +---- + migration/ram.c | 8 +++++--- + 2 files changed, 6 insertions(+), 7 deletions(-) + +diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h +index b7b2e60f..52344066 100644 +--- a/include/exec/ram_addr.h ++++ b/include/exec/ram_addr.h +@@ -485,8 +485,7 @@ static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start, + static inline + uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb, + ram_addr_t start, +- ram_addr_t length, +- uint64_t *real_dirty_pages) ++ ram_addr_t length) + { + ram_addr_t addr; + unsigned long word = BIT_WORD((start + rb->offset) >> TARGET_PAGE_BITS); +@@ -512,7 +511,6 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb, + if (src[idx][offset]) { + unsigned long bits = atomic_xchg(&src[idx][offset], 0); + unsigned long new_dirty; +- *real_dirty_pages += ctpopl(bits); + new_dirty = ~dest[k]; + dest[k] |= bits; + new_dirty &= bits; +@@ -545,7 +543,6 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb, + start + addr + offset, + TARGET_PAGE_SIZE, + DIRTY_MEMORY_MIGRATION)) { +- *real_dirty_pages += 1; + long k = (start + addr) >> TARGET_PAGE_BITS; + if (!test_and_set_bit(k, dest)) { + num_dirty++; +diff --git a/migration/ram.c b/migration/ram.c +index 840e3548..83cabec6 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1765,9 +1765,11 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs, + static void migration_bitmap_sync_range(RAMState *rs, RAMBlock *rb, + ram_addr_t length) + { +- rs->migration_dirty_pages += +- cpu_physical_memory_sync_dirty_bitmap(rb, 0, length, +- &rs->num_dirty_pages_period); ++ uint64_t new_dirty_pages = ++ cpu_physical_memory_sync_dirty_bitmap(rb, 0, rb->used_length); ++ ++ rs->migration_dirty_pages += new_dirty_pages; ++ rs->num_dirty_pages_period += new_dirty_pages; + } + + /** +-- +2.27.0.dirty + diff --git a/migration-colo-fix-use-after-free-of-local_err.patch b/migration-colo-fix-use-after-free-of-local_err.patch new file mode 100644 index 0000000000000000000000000000000000000000..c03ceb5120bc3069ac123cc9c2702653c4d2da17 --- /dev/null +++ b/migration-colo-fix-use-after-free-of-local_err.patch @@ -0,0 +1,33 @@ +From 663e9b5f25d22834260a0686f77a27c957cd7b2f Mon Sep 17 00:00:00 2001 +From: Vladimir Sementsov-Ogievskiy +Date: Tue, 24 Mar 2020 18:36:28 +0300 +Subject: [PATCH 07/14] migration/colo: fix use after free of local_err + +local_err is used again in secondary_vm_do_failover() after +replication_stop_all(), so we must zero it. Otherwise try to set +non-NULL local_err will crash. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20200324153630.11882-5-vsementsov@virtuozzo.com> +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Dr. David Alan Gilbert +Signed-off-by: Peng Liang +--- + migration/colo.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/migration/colo.c b/migration/colo.c +index 9f84b1fa3c0f..761b3544d472 100644 +--- a/migration/colo.c ++++ b/migration/colo.c +@@ -89,6 +89,7 @@ static void secondary_vm_do_failover(void) + replication_stop_all(true, &local_err); + if (local_err) { + error_report_err(local_err); ++ local_err = NULL; + } + + /* Notify all filters of all NIC to do checkpoint */ +-- +2.26.2 + diff --git a/migration-fix-cleanup_bh-leak-on-resume.patch b/migration-fix-cleanup_bh-leak-on-resume.patch new file mode 100644 index 0000000000000000000000000000000000000000..6b75ed01b8faa4c3d5b9d1e17e6d3d205daa2396 --- /dev/null +++ b/migration-fix-cleanup_bh-leak-on-resume.patch @@ -0,0 +1,64 @@ +From 1d7c227bbb24665cea03f96a984ad6be223ac40c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 25 Mar 2020 19:47:21 +0100 +Subject: [PATCH 2/5] migration: fix cleanup_bh leak on resume +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since commit 8c6b0356b53977bcfdea5299db07884915425b0c ("util/async: +make bh_aio_poll() O(1)"), migration-test reveals a leak: + +QTEST_QEMU_BINARY=x86_64-softmmu/qemu-system-x86_64 +tests/qtest/migration-test -p /x86_64/migration/postcopy/recovery +tests/qtest/libqtest.c:140: kill_qemu() tried to terminate QEMU +process but encountered exit status 1 (expected 0) + +================================================================= +==2082571==ERROR: LeakSanitizer: detected memory leaks + +Direct leak of 40 byte(s) in 1 object(s) allocated from: + #0 0x7f25971dfc58 in __interceptor_malloc (/lib64/libasan.so.5+0x10dc58) + #1 0x7f2596d08358 in g_malloc (/lib64/libglib-2.0.so.0+0x57358) + #2 0x560970d006f8 in qemu_bh_new /home/elmarco/src/qemu/util/main-loop.c:532 + #3 0x5609704afa02 in migrate_fd_connect +/home/elmarco/src/qemu/migration/migration.c:3407 + #4 0x5609704b6b6f in migration_channel_connect +/home/elmarco/src/qemu/migration/channel.c:92 + #5 0x5609704b2bfb in socket_outgoing_migration +/home/elmarco/src/qemu/migration/socket.c:108 + #6 0x560970b9bd6c in qio_task_complete /home/elmarco/src/qemu/io/task.c:196 + #7 0x560970b9aa97 in qio_task_thread_result +/home/elmarco/src/qemu/io/task.c:111 + #8 0x7f2596cfee3a (/lib64/libglib-2.0.so.0+0x4de3a) + +Signed-off-by: Marc-André Lureau +Message-Id: <20200325184723.2029630-2-marcandre.lureau@redhat.com> +Reviewed-by: Juan Quintela +Signed-off-by: Paolo Bonzini +Signed-off-by: Zhenyu Ye +--- + migration/migration.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/migration/migration.c b/migration/migration.c +index 8f2fc2b4..7949f2a4 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -3313,7 +3313,12 @@ void migrate_fd_connect(MigrationState *s, Error *error_in) + bool resume = s->state == MIGRATION_STATUS_POSTCOPY_PAUSED; + + s->expected_downtime = s->parameters.downtime_limit; +- s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup_bh, s); ++ if (resume) { ++ assert(s->cleanup_bh); ++ } else { ++ assert(!s->cleanup_bh); ++ s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup_bh, s); ++ } + if (error_in) { + migrate_fd_error(s, error_in); + migrate_fd_cleanup(s); +-- +2.22.0.windows.1 + diff --git a/migration-fix-multifd_send_pages-next-channel.patch b/migration-fix-multifd_send_pages-next-channel.patch new file mode 100644 index 0000000000000000000000000000000000000000..4bb113c644c4175386636e02a5d7188e8c2e408c --- /dev/null +++ b/migration-fix-multifd_send_pages-next-channel.patch @@ -0,0 +1,50 @@ +From c11a23b92334ae86eddfdc2b155d404293891985 Mon Sep 17 00:00:00 2001 +From: alexchen +Date: Tue, 8 Sep 2020 11:18:50 +0000 +Subject: [PATCH 08/11] migration: fix multifd_send_pages() next channel + +multifd_send_pages() loops around the available channels, +the next channel to use between two calls to multifd_send_pages() is stored +inside a local static variable, next_channel. + +It works well, except if the number of channels decreases between two calls +to multifd_send_pages(). In this case, the loop can try to access the +data of a channel that doesn't exist anymore. + +The problem can be triggered if we start a migration with a given number of +channels and then we cancel the migration to restart it with a lower number. +This ends generally with an error like: +qemu-system-ppc64: .../util/qemu-thread-posix.c:77: qemu_mutex_lock_impl: Assertion `mutex->initialized' failed. + +This patch fixes the error by capping next_channel with the current number +of channels before using it. + +Signed-off-by: Laurent Vivier +Message-Id: <20200617113154.593233-1-lvivier@redhat.com> +Reviewed-by: Juan Quintela +Signed-off-by: Dr. David Alan Gilbert +Signed-off-by: BiaoXiang Ye +--- + migration/ram.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/migration/ram.c b/migration/ram.c +index 83cabec6..ac033f22 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -931,6 +931,12 @@ static int multifd_send_pages(RAMState *rs) + uint64_t transferred; + + qemu_sem_wait(&multifd_send_state->channels_ready); ++ /* ++ * next_channel can remain from a previous migration that was ++ * using more channels, so ensure it doesn't overflow if the ++ * limit is lower now. ++ */ ++ next_channel %= migrate_multifd_channels(); + for (i = next_channel;; i = (i + 1) % migrate_multifd_channels()) { + p = &multifd_send_state->params[i]; + +-- +2.27.0.dirty + diff --git a/migration-ram-fix-use-after-free-of-local_err.patch b/migration-ram-fix-use-after-free-of-local_err.patch new file mode 100644 index 0000000000000000000000000000000000000000..f74e3b18df98ae0e5a88ff9224fa06c8ea24197a --- /dev/null +++ b/migration-ram-fix-use-after-free-of-local_err.patch @@ -0,0 +1,33 @@ +From 019526f7f7b42a7d1b8a74e1db6a8050adf9e1fb Mon Sep 17 00:00:00 2001 +From: Vladimir Sementsov-Ogievskiy +Date: Tue, 24 Mar 2020 18:36:29 +0300 +Subject: [PATCH 08/14] migration/ram: fix use after free of local_err + +local_err is used again in migration_bitmap_sync_precopy() after +precopy_notify(), so we must zero it. Otherwise try to set +non-NULL local_err will crash. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20200324153630.11882-6-vsementsov@virtuozzo.com> +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Dr. David Alan Gilbert +Signed-off-by: Peng Liang +--- + migration/ram.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/migration/ram.c b/migration/ram.c +index 840e35480b04..5d1ae7570018 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1912,6 +1912,7 @@ static void migration_bitmap_sync_precopy(RAMState *rs) + */ + if (precopy_notify(PRECOPY_NOTIFY_BEFORE_BITMAP_SYNC, &local_err)) { + error_report_err(local_err); ++ local_err = NULL; + } + + migration_bitmap_sync(rs); +-- +2.26.2 + diff --git a/migration-rdma-cleanup-rdma-context-before-g_free-to.patch b/migration-rdma-cleanup-rdma-context-before-g_free-to.patch new file mode 100644 index 0000000000000000000000000000000000000000..a39894ada540a713645b0735b719eb4d5a3edbff --- /dev/null +++ b/migration-rdma-cleanup-rdma-context-before-g_free-to.patch @@ -0,0 +1,58 @@ +From 9867dc6fc3f131324b73664b9617376270d8d013 Mon Sep 17 00:00:00 2001 +From: Pan Nengyuan +Date: Fri, 8 May 2020 06:07:55 -0400 +Subject: [PATCH 4/5] migration/rdma: cleanup rdma context before g_free to + avoid memleaks + +When error happen in initializing 'rdma_return_path', we should cleanup rdma context +before g_free(rdma) to avoid some memleaks. This patch fix that. + +Reported-by: Euler Robot +Signed-off-by: Pan Nengyuan +Message-Id: <20200508100755.7875-3-pannengyuan@huawei.com> +Reviewed-by: Juan Quintela +Signed-off-by: Dr. David Alan Gilbert +--- + migration/rdma.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/migration/rdma.c b/migration/rdma.c +index 3036221e..bb24dac5 100644 +--- a/migration/rdma.c ++++ b/migration/rdma.c +@@ -4103,20 +4103,20 @@ void rdma_start_outgoing_migration(void *opaque, + rdma_return_path = qemu_rdma_data_init(host_port, errp); + + if (rdma_return_path == NULL) { +- goto err; ++ goto return_path_err; + } + + ret = qemu_rdma_source_init(rdma_return_path, + s->enabled_capabilities[MIGRATION_CAPABILITY_RDMA_PIN_ALL], errp); + + if (ret) { +- goto err; ++ goto return_path_err; + } + + ret = qemu_rdma_connect(rdma_return_path, errp); + + if (ret) { +- goto err; ++ goto return_path_err; + } + + rdma->return_path = rdma_return_path; +@@ -4129,6 +4129,8 @@ void rdma_start_outgoing_migration(void *opaque, + s->to_dst_file = qemu_fopen_rdma(rdma, "wb"); + migrate_fd_connect(s, NULL); + return; ++return_path_err: ++ qemu_rdma_cleanup(rdma); + err: + g_free(rdma); + g_free(rdma_return_path); +-- +2.23.0 + diff --git a/object-return-self-in-object_ref.patch b/object-return-self-in-object_ref.patch new file mode 100644 index 0000000000000000000000000000000000000000..e851fb30d20a4c56b65bb7ce1c6ddb9109c643aa --- /dev/null +++ b/object-return-self-in-object_ref.patch @@ -0,0 +1,58 @@ +From b77ade9bb37b2e9813a42008cb21d0c743aa50a1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Fri, 10 Jan 2020 19:30:31 +0400 +Subject: [PATCH] object: return self in object_ref() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allow for simpler assignment with ref: foo = object_ref(bar) + +Signed-off-by: Marc-André Lureau +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20200110153039.1379601-19-marcandre.lureau@redhat.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Zhenyu Ye +--- + include/qom/object.h | 3 ++- + qom/object.c | 5 +++-- + 2 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/include/qom/object.h b/include/qom/object.h +index 5e2f60d4b0..18660fde1c 100644 +--- a/include/qom/object.h ++++ b/include/qom/object.h +@@ -1005,8 +1005,9 @@ GSList *object_class_get_list_sorted(const char *implements_type, + * + * Increase the reference count of a object. A object cannot be freed as long + * as its reference count is greater than zero. ++ * Returns: @obj + */ +-void object_ref(Object *obj); ++Object *object_ref(Object *obj); + + /** + * object_unref: +diff --git a/qom/object.c b/qom/object.c +index 66c4a5f1cb..555c8b9d07 100644 +--- a/qom/object.c ++++ b/qom/object.c +@@ -1107,12 +1107,13 @@ GSList *object_class_get_list_sorted(const char *implements_type, + object_class_cmp); + } + +-void object_ref(Object *obj) ++Object *object_ref(Object *obj) + { + if (!obj) { +- return; ++ return NULL; + } + atomic_inc(&obj->ref); ++ return obj; + } + + void object_unref(Object *obj) +-- +2.22.0.windows.1 + diff --git a/pc-bios-s390-ccw-net-fix-a-possible-memory-leak-in-g.patch b/pc-bios-s390-ccw-net-fix-a-possible-memory-leak-in-g.patch new file mode 100644 index 0000000000000000000000000000000000000000..6e29f08d69c56a2907892008c9c4ce177778c097 --- /dev/null +++ b/pc-bios-s390-ccw-net-fix-a-possible-memory-leak-in-g.patch @@ -0,0 +1,34 @@ +From d2bb5b4c4ed3b1dbc0096deb195b6df33f813f23 Mon Sep 17 00:00:00 2001 +From: Yifan Luo +Date: Wed, 14 Aug 2019 14:14:26 +0800 +Subject: [PATCH 5/5] pc-bios/s390-ccw/net: fix a possible memory leak in + get_uuid() + +There is a possible memory leak in get_uuid(). Should free allocated mem +before +return NULL. + +Signed-off-by: Yifan Luo +Message-Id: <02cf01d55267$86cf2850$946d78f0$@cmss.chinamobile.com> +Reviewed-by: Thomas Huth +Reviewed-by: Cornelia Huck +Signed-off-by: Thomas Huth +--- + pc-bios/s390-ccw/netmain.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c +index f3542cb2..f2dcc01e 100644 +--- a/pc-bios/s390-ccw/netmain.c ++++ b/pc-bios/s390-ccw/netmain.c +@@ -269,6 +269,7 @@ static const char *get_uuid(void) + : "d" (r0), "d" (r1), [addr] "a" (buf) + : "cc", "memory"); + if (cc) { ++ free(mem); + return NULL; + } + +-- +2.23.0 + diff --git a/qemu-img-free-memory-before-re-assign.patch b/qemu-img-free-memory-before-re-assign.patch new file mode 100644 index 0000000000000000000000000000000000000000..2d46d64b1b9664b66efc76ea6490a1bc22663137 --- /dev/null +++ b/qemu-img-free-memory-before-re-assign.patch @@ -0,0 +1,33 @@ +From d22af5cb41c16829dbf3ed3c611ef56ceeb840ff Mon Sep 17 00:00:00 2001 +From: Pan Nengyuan +Date: Thu, 27 Feb 2020 09:29:50 +0800 +Subject: [PATCH 02/14] qemu-img: free memory before re-assign + +collect_image_check() is called twice in img_check(), the filename/format will be alloced without free the original memory. +It is not a big deal since the process will exit anyway, but seems like a clean code and it will remove the warning spotted by asan. + +Reported-by: Euler Robot +Signed-off-by: Pan Nengyuan +Message-Id: <20200227012950.12256-3-pannengyuan@huawei.com> +Signed-off-by: Max Reitz +Signed-off-by: Peng Liang +--- + qemu-img.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/qemu-img.c b/qemu-img.c +index 79983772de39..2e9cc5db7c4c 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -808,6 +808,8 @@ static int img_check(int argc, char **argv) + check->corruptions_fixed); + } + ++ qapi_free_ImageCheck(check); ++ check = g_new0(ImageCheck, 1); + ret = collect_image_check(bs, check, filename, fmt, 0); + + check->leaks_fixed = leaks_fixed; +-- +2.26.2 + diff --git a/qemu.spec b/qemu.spec index 115f3f6d189d39bddf6ebf9030cb8296ea1f14b8..430ece86b3abe7dbf32412e171867b750849a260 100644 --- a/qemu.spec +++ b/qemu.spec @@ -1,6 +1,6 @@ Name: qemu Version: 4.1.0 -Release: 18 +Release: 19 Epoch: 2 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY @@ -184,6 +184,7 @@ Patch0171: megasas-use-unsigned-type-for-positive-numeric-field.patch Patch0172: hw-scsi-megasas-Fix-possible-out-of-bounds-array-acc.patch Patch0173: hw-arm-acpi-enable-SHPC-native-hot-plug.patch PATCH0174: hw-usb-core-fix-buffer-overflow.patch +Patch0175: slirp-networking-fix-out-of-bounds-read-information.patch BuildRequires: flex BuildRequires: bison @@ -326,6 +327,7 @@ buildldflags="VL_LDFLAGS=-Wl,--build-id" --enable-linux-aio \ --enable-cap-ng \ --enable-vhost-user \ + --enable-tpm \ %ifarch aarch64 --enable-fdt \ --enable-virglrenderer \ @@ -529,6 +531,9 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Thu Sep 10 2020 Huawei Technologies Co., LTD +- slirp/src/ip6_input.c: fix out-of-bounds read information + * Thu Aug 27 2020 Huawei Technologies Co., Ltd - hw/usb/core.c: fix buffer overflow in do_token_setup function diff --git a/qga-Plug-unlikely-memory-leak-in-guest-set-memory-bl.patch b/qga-Plug-unlikely-memory-leak-in-guest-set-memory-bl.patch new file mode 100644 index 0000000000000000000000000000000000000000..a901a500181bb9a36f9bd307d8bdee5929b6144f --- /dev/null +++ b/qga-Plug-unlikely-memory-leak-in-guest-set-memory-bl.patch @@ -0,0 +1,40 @@ +From 1580682eafb489eaf417456778267662629cf696 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Tue, 30 Jun 2020 11:03:33 +0200 +Subject: [PATCH 05/11] qga: Plug unlikely memory leak in + guest-set-memory-blocks + +transfer_memory_block() leaks an Error object when reading file +/sys/devices/system/memory/memory/state fails with errno other +than ENOENT, and @sys2memblk is false, i.e. when the state file exists +but cannot be read (seems quite unlikely), and this is +guest-set-memory-blocks, not guest-get-memory-blocks. + +Plug the leak. + +Fixes: bd240fca42d5f072fb758a71720d9de9990ac553 +Cc: Michael Roth +Cc: Hailiang Zhang +Signed-off-by: Markus Armbruster +Reviewed-by: zhanghailiang +Message-Id: <20200630090351.1247703-9-armbru@redhat.com> +Signed-off-by: BiaoXiang Ye +--- + qga/commands-posix.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/qga/commands-posix.c b/qga/commands-posix.c +index dfc05f5b..c318cee7 100644 +--- a/qga/commands-posix.c ++++ b/qga/commands-posix.c +@@ -2420,6 +2420,7 @@ static void transfer_memory_block(GuestMemoryBlock *mem_blk, bool sys2memblk, + if (sys2memblk) { + error_propagate(errp, local_err); + } else { ++ error_free(local_err); + result->response = + GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED; + } +-- +2.27.0.dirty + diff --git a/qga-commands-posix-fix-use-after-free-of-local_err.patch b/qga-commands-posix-fix-use-after-free-of-local_err.patch new file mode 100644 index 0000000000000000000000000000000000000000..9628d0c59445c9d29ddaa39e6fb271fe73a5c274 --- /dev/null +++ b/qga-commands-posix-fix-use-after-free-of-local_err.patch @@ -0,0 +1,49 @@ +From 15847279f29b0bd67b95daefff395cab8fad80d3 Mon Sep 17 00:00:00 2001 +From: Vladimir Sementsov-Ogievskiy +Date: Tue, 24 Mar 2020 18:36:30 +0300 +Subject: [PATCH 4/5] qga/commands-posix: fix use after free of local_err + +local_err is used several times in guest_suspend(). Setting non-NULL +local_err will crash, so let's zero it after freeing. Also fix possible +leak of local_err in final if(). + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20200324153630.11882-7-vsementsov@virtuozzo.com> +Reviewed-by: Richard Henderson +Signed-off-by: Markus Armbruster +Signed-off-by: Zhenyu Ye +--- + qga/commands-posix.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/qga/commands-posix.c b/qga/commands-posix.c +index dfc05f5b..66164e6c 100644 +--- a/qga/commands-posix.c ++++ b/qga/commands-posix.c +@@ -1760,6 +1760,7 @@ static void guest_suspend(SuspendMode mode, Error **errp) + } + + error_free(local_err); ++ local_err = NULL; + + if (pmutils_supports_mode(mode, &local_err)) { + mode_supported = true; +@@ -1771,6 +1772,7 @@ static void guest_suspend(SuspendMode mode, Error **errp) + } + + error_free(local_err); ++ local_err = NULL; + + if (linux_sys_state_supports_mode(mode, &local_err)) { + mode_supported = true; +@@ -1778,6 +1780,7 @@ static void guest_suspend(SuspendMode mode, Error **errp) + } + + if (!mode_supported) { ++ error_free(local_err); + error_setg(errp, + "the requested suspend mode is not supported by the guest"); + } else { +-- +2.22.0.windows.1 + diff --git a/qga-fix-assert-regression-on-guest-shutdown.patch b/qga-fix-assert-regression-on-guest-shutdown.patch new file mode 100644 index 0000000000000000000000000000000000000000..c5f1e1069b5097ff1adf2328bea6a25e9483cda1 --- /dev/null +++ b/qga-fix-assert-regression-on-guest-shutdown.patch @@ -0,0 +1,47 @@ +From aeccff89333c565c7a894f99c17c0044d7d43be2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Thu, 4 Jun 2020 11:44:25 +0200 +Subject: [PATCH 02/11] qga: fix assert regression on guest-shutdown +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since commit 781f2b3d1e ("qga: process_event() simplification"), +send_response() is called unconditionally, but will assert when "rsp" is +NULL. This may happen with QCO_NO_SUCCESS_RESP commands, such as +"guest-shutdown". + +Fixes: 781f2b3d1e5ef389b44016a897fd55e7a780bf35 +Cc: Michael Roth +Reported-by: Christian Ehrhardt +Signed-off-by: Marc-André Lureau +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Christian Ehrhardt +Tested-by: Christian Ehrhardt +Cc: qemu-stable@nongnu.org +Signed-off-by: Michael Roth +Signed-off-by: BiaoXiang Ye +--- + qga/main.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/qga/main.c b/qga/main.c +index c35c2a21..12fa463f 100644 +--- a/qga/main.c ++++ b/qga/main.c +@@ -529,7 +529,11 @@ static int send_response(GAState *s, const QDict *rsp) + QString *payload_qstr, *response_qstr; + GIOStatus status; + +- g_assert(rsp && s->channel); ++ g_assert(s->channel); ++ ++ if (!rsp) { ++ return 0; ++ } + + payload_qstr = qobject_to_json(QOBJECT(rsp)); + if (!payload_qstr) { +-- +2.27.0.dirty + diff --git a/qmp-fix-leak-on-callbacks-that-return-both-value-and.patch b/qmp-fix-leak-on-callbacks-that-return-both-value-and.patch new file mode 100644 index 0000000000000000000000000000000000000000..1ceb1e70b84f1e1a9a3f785ff2d4d55b697a7cb4 --- /dev/null +++ b/qmp-fix-leak-on-callbacks-that-return-both-value-and.patch @@ -0,0 +1,47 @@ +From 1f1949368d4ac7a18973aa83a074daf01daf97ad Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 25 Mar 2020 19:47:22 +0100 +Subject: [PATCH 3/5] qmp: fix leak on callbacks that return both value and + error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Direct leak of 4120 byte(s) in 1 object(s) allocated from: + #0 0x7fa114931887 in __interceptor_calloc (/lib64/libasan.so.6+0xb0887) + #1 0x7fa1144ad8f0 in g_malloc0 (/lib64/libglib-2.0.so.0+0x588f0) + #2 0x561e3c9c8897 in qmp_object_add /home/elmarco/src/qemu/qom/qom-qmp-cmds.c:291 + #3 0x561e3cf48736 in qmp_dispatch /home/elmarco/src/qemu/qapi/qmp-dispatch.c:155 + #4 0x561e3c8efb36 in monitor_qmp_dispatch /home/elmarco/src/qemu/monitor/qmp.c:145 + #5 0x561e3c8f09ed in monitor_qmp_bh_dispatcher /home/elmarco/src/qemu/monitor/qmp.c:234 + #6 0x561e3d08c993 in aio_bh_call /home/elmarco/src/qemu/util/async.c:136 + #7 0x561e3d08d0a5 in aio_bh_poll /home/elmarco/src/qemu/util/async.c:164 + #8 0x561e3d0a535a in aio_dispatch /home/elmarco/src/qemu/util/aio-posix.c:380 + #9 0x561e3d08e3ca in aio_ctx_dispatch /home/elmarco/src/qemu/util/async.c:298 + #10 0x7fa1144a776e in g_main_context_dispatch (/lib64/libglib-2.0.so.0+0x5276e) + +Signed-off-by: Marc-André Lureau +Message-Id: <20200325184723.2029630-3-marcandre.lureau@redhat.com> +Reviewed-by: Markus Armbruster +Signed-off-by: Paolo Bonzini +Signed-off-by: Zhenyu Ye +--- + qapi/qmp-dispatch.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c +index 6dfdad57..a635abb9 100644 +--- a/qapi/qmp-dispatch.c ++++ b/qapi/qmp-dispatch.c +@@ -189,6 +189,8 @@ QDict *qmp_dispatch(QmpCommandList *cmds, QObject *request, + + ret = do_qmp_dispatch(cmds, request, allow_oob, &err); + if (err) { ++ /* or assert(!ret) after reviewing all handlers: */ ++ qobject_unref(ret); + rsp = qmp_error_response(err); + } else if (ret) { + rsp = qdict_new(); +-- +2.22.0.windows.1 + diff --git a/slirp-networking-fix-out-of-bounds-read-information.patch b/slirp-networking-fix-out-of-bounds-read-information.patch new file mode 100644 index 0000000000000000000000000000000000000000..b6205b9c6a767914b481df76de989678bbe547e0 --- /dev/null +++ b/slirp-networking-fix-out-of-bounds-read-information.patch @@ -0,0 +1,30 @@ +From: Jiajie Li +Date: Thu, 10 Sep 2020 11:10:00 +0800 +Subject: [PATCH]slirp-networking-fix-out-of-bounds-read-information + +Drop IPv6 message shorter than what's mentioned in the payload +length header (+ the size of IPv6 header). They're invalid an could +lead to data leakage in icmp6_send_echoreply(). + + + + + +diff --git a/qemu-4.0.0/slirp/src/ip6_input.c b/qemu-4.0.0/slirp/src/ip6_input.c +index d9d2b7e..c2dce52 100644 +--- a/qemu-4.0.0/slirp/src/ip6_input.c ++++ b/qemu-4.0.0/slirp/src/ip6_input.c +@@ -49,6 +49,13 @@ void ip6_input(struct mbuf *m) + goto bad; + } + ++ // Check if the message size is big enough to hold what's ++ // set in the payload length header. If not this is an invalid ++ // packet ++ if (m->m_len < ntohs(ip6->ip_pl) + sizeof(struct ip6)) { ++ goto bad; ++ } ++ + /* check ip_ttl for a correct ICMP reply */ + if (ip6->ip_hl == 0) { + icmp6_send_error(m, ICMP6_TIMXCEED, ICMP6_TIMXCEED_INTRANS); diff --git a/spapr-Implement-get_dt_compatible-callback.patch b/spapr-Implement-get_dt_compatible-callback.patch new file mode 100644 index 0000000000000000000000000000000000000000..e64a8746f498a68085824f6cace1bb2e958ce7c7 --- /dev/null +++ b/spapr-Implement-get_dt_compatible-callback.patch @@ -0,0 +1,68 @@ +From c520d8e823431be94268daa2a911e224cab81521 Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Tue, 21 Jan 2020 10:29:31 -0500 +Subject: [PATCH 04/19] spapr: Implement get_dt_compatible() callback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +For devices that cannot be statically initialized, implement a +get_dt_compatible() callback that allows us to ask the device for +the 'compatible' value. + +Signed-off-by: Stefan Berger +Reviewed-by: Marc-André Lureau +Reviewed-by: David Gibson +Message-Id: <20200121152935.649898-3-stefanb@linux.ibm.com> +Signed-off-by: David Gibson +Signed-off-by: jiangfangjie +--- + hw/ppc/spapr_vio.c | 11 +++++++++-- + include/hw/ppc/spapr_vio.h | 1 + + 2 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c +index 583c13de..4e50916f 100644 +--- a/hw/ppc/spapr_vio.c ++++ b/hw/ppc/spapr_vio.c +@@ -89,6 +89,7 @@ static int vio_make_devnode(SpaprVioDevice *dev, + SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); + int vdevice_off, node_off, ret; + char *dt_name; ++ const char *dt_compatible; + + vdevice_off = fdt_path_offset(fdt, "/vdevice"); + if (vdevice_off < 0) { +@@ -115,9 +116,15 @@ static int vio_make_devnode(SpaprVioDevice *dev, + } + } + +- if (pc->dt_compatible) { ++ if (pc->get_dt_compatible) { ++ dt_compatible = pc->get_dt_compatible(dev); ++ } else { ++ dt_compatible = pc->dt_compatible; ++ } ++ ++ if (dt_compatible) { + ret = fdt_setprop_string(fdt, node_off, "compatible", +- pc->dt_compatible); ++ dt_compatible); + if (ret < 0) { + return ret; + } +diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h +index 04609f21..97951fc6 100644 +--- a/include/hw/ppc/spapr_vio.h ++++ b/include/hw/ppc/spapr_vio.h +@@ -56,6 +56,7 @@ typedef struct SpaprVioDeviceClass { + void (*realize)(SpaprVioDevice *dev, Error **errp); + void (*reset)(SpaprVioDevice *dev); + int (*devnode)(SpaprVioDevice *dev, void *fdt, int node_off); ++ const char *(*get_dt_compatible)(SpaprVioDevice *dev); + } SpaprVioDeviceClass; + + struct SpaprVioDevice { +-- +2.23.0 + diff --git a/target-arm-Add-CPU-features-to-query-cpu-model-expan.patch b/target-arm-Add-CPU-features-to-query-cpu-model-expan.patch new file mode 100644 index 0000000000000000000000000000000000000000..4047145033d7010acfb3cfb002feb920fb303f0d --- /dev/null +++ b/target-arm-Add-CPU-features-to-query-cpu-model-expan.patch @@ -0,0 +1,89 @@ +From 274d25bdb2df13a26ad6d2a8a06fcc281a22f642 Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Thu, 6 Aug 2020 16:14:58 +0800 +Subject: [PATCH 7/9] target/arm: Add CPU features to query-cpu-model-expansion + +Add CPU features to the result of query-cpu-model-expansion so that +other applications (such as libvirt) can know the supported CPU +features. + +Signed-off-by: zhanghailiang +Signed-off-by: Peng Liang +--- + target/arm/cpu.c | 27 +++++++++++++++++++++++++++ + target/arm/cpu.h | 2 ++ + target/arm/monitor.c | 2 ++ + 3 files changed, 31 insertions(+) + +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index db46afba..dcf9f49e 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -25,6 +25,8 @@ + #include "qemu/module.h" + #include "qapi/error.h" + #include "qapi/visitor.h" ++#include "qapi/qmp/qdict.h" ++#include "qom/qom-qobject.h" + #include "cpu.h" + #include "internals.h" + #include "exec/exec-all.h" +@@ -1403,6 +1405,31 @@ static const CPUFeatureDep feature_dependencies[] = { + }, + }; + ++void arm_cpu_features_to_dict(ARMCPU *cpu, QDict *features) ++{ ++ Object *obj = OBJECT(cpu); ++ const char *name; ++ ObjectProperty *prop; ++ bool is_32bit = !arm_feature(&cpu->env, ARM_FEATURE_AARCH64); ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(cpu_features); ++i) { ++ if (is_32bit != cpu_features[i].is_32bit) { ++ continue; ++ } ++ ++ name = cpu_features[i].name; ++ prop = object_property_find(obj, name, NULL); ++ if (prop) { ++ QObject *value; ++ ++ assert(prop->get); ++ value = object_property_get_qobject(obj, name, &error_abort); ++ qdict_put_obj(features, name, value); ++ } ++ } ++} ++ + static void arm_cpu_get_bit_prop(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) + { +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 7bb481fb..068c3fa2 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -3692,4 +3692,6 @@ static inline bool isar_feature_any_pmu_8_1(const ARMISARegisters *id) + #define cpu_isar_feature(name, cpu) \ + ({ ARMCPU *cpu_ = (cpu); isar_feature_##name(&cpu_->isar); }) + ++void arm_cpu_features_to_dict(ARMCPU *cpu, QDict *features); ++ + #endif +diff --git a/target/arm/monitor.c b/target/arm/monitor.c +index e2b1d117..7c2ff3c0 100644 +--- a/target/arm/monitor.c ++++ b/target/arm/monitor.c +@@ -219,6 +219,8 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, + } + } + ++ arm_cpu_features_to_dict(ARM_CPU(obj), qdict_out); ++ + if (!qdict_size(qdict_out)) { + qobject_unref(qdict_out); + } else { +-- +2.25.1 + diff --git a/target-arm-Add-ID_AA64MMFR2_EL1.patch b/target-arm-Add-ID_AA64MMFR2_EL1.patch new file mode 100644 index 0000000000000000000000000000000000000000..eee33ae241bde2333d5308c7ca39297782598ccc --- /dev/null +++ b/target-arm-Add-ID_AA64MMFR2_EL1.patch @@ -0,0 +1,87 @@ +From 3451fb922aa7b0fe532e508ca13d4ab4b3ec75bf Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Sat, 8 Feb 2020 12:58:13 +0000 +Subject: [PATCH 02/13] target/arm: Add ID_AA64MMFR2_EL1 + +Add definitions for all of the fields, up to ARMv8.5. +Convert the existing RESERVED register to a full register. +Query KVM for the value of the register for the host. + +Reviewed-by: Peter Maydell +Signed-off-by: Richard Henderson +Message-id: 20200208125816.14954-18-richard.henderson@linaro.org +Signed-off-by: Peter Maydell +--- + target/arm/cpu.h | 17 +++++++++++++++++ + target/arm/helper.c | 4 ++-- + target/arm/kvm64.c | 2 ++ + 3 files changed, 21 insertions(+), 2 deletions(-) + +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index fe310828..3e65bc50 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -866,6 +866,7 @@ struct ARMCPU { + uint64_t id_aa64pfr1; + uint64_t id_aa64mmfr0; + uint64_t id_aa64mmfr1; ++ uint64_t id_aa64mmfr2; + } isar; + uint32_t midr; + uint32_t revidr; +@@ -1762,6 +1763,22 @@ FIELD(ID_AA64MMFR1, PAN, 20, 4) + FIELD(ID_AA64MMFR1, SPECSEI, 24, 4) + FIELD(ID_AA64MMFR1, XNX, 28, 4) + ++FIELD(ID_AA64MMFR2, CNP, 0, 4) ++FIELD(ID_AA64MMFR2, UAO, 4, 4) ++FIELD(ID_AA64MMFR2, LSM, 8, 4) ++FIELD(ID_AA64MMFR2, IESB, 12, 4) ++FIELD(ID_AA64MMFR2, VARANGE, 16, 4) ++FIELD(ID_AA64MMFR2, CCIDX, 20, 4) ++FIELD(ID_AA64MMFR2, NV, 24, 4) ++FIELD(ID_AA64MMFR2, ST, 28, 4) ++FIELD(ID_AA64MMFR2, AT, 32, 4) ++FIELD(ID_AA64MMFR2, IDS, 36, 4) ++FIELD(ID_AA64MMFR2, FWB, 40, 4) ++FIELD(ID_AA64MMFR2, TTL, 48, 4) ++FIELD(ID_AA64MMFR2, BBM, 52, 4) ++FIELD(ID_AA64MMFR2, EVT, 56, 4) ++FIELD(ID_AA64MMFR2, E0PD, 60, 4) ++ + FIELD(ID_DFR0, COPDBG, 0, 4) + FIELD(ID_DFR0, COPSDBG, 4, 4) + FIELD(ID_DFR0, MMAPDBG, 8, 4) +diff --git a/target/arm/helper.c b/target/arm/helper.c +index b74c23a9..c50b1ba1 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -6182,10 +6182,10 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 1, + .access = PL1_R, .type = ARM_CP_CONST, + .resetvalue = cpu->isar.id_aa64mmfr1 }, +- { .name = "ID_AA64MMFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64, ++ { .name = "ID_AA64MMFR2_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 2, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = 0 }, ++ .resetvalue = cpu->isar.id_aa64mmfr2 }, + { .name = "ID_AA64MMFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 3, + .access = PL1_R, .type = ARM_CP_CONST, +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 4f0bf000..b794108a 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -541,6 +541,8 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + ARM64_SYS_REG(3, 0, 0, 7, 0)); + err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr1, + ARM64_SYS_REG(3, 0, 0, 7, 1)); ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr2, ++ ARM64_SYS_REG(3, 0, 0, 7, 2)); + + /* + * Note that if AArch32 support is not present in the host, +-- +2.25.1 + diff --git a/target-arm-Add-_aa64_-and-_any_-versions-of-pmu_8_1-.patch b/target-arm-Add-_aa64_-and-_any_-versions-of-pmu_8_1-.patch new file mode 100644 index 0000000000000000000000000000000000000000..7516ed8108de271970e600dbd03c964611b3b0ba --- /dev/null +++ b/target-arm-Add-_aa64_-and-_any_-versions-of-pmu_8_1-.patch @@ -0,0 +1,166 @@ +From 515975da851ca9567053bcf0487fde4447dfdc4f Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 14 Feb 2020 17:51:04 +0000 +Subject: [PATCH 06/13] target/arm: Add _aa64_ and _any_ versions of pmu_8_1 + isar checks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add the 64-bit version of the "is this a v8.1 PMUv3?" +ID register check function, and the _any_ version that +checks for either AArch32 or AArch64 support. We'll use +this in a later commit. + +We don't (yet) do any isar_feature checks on ID_AA64DFR1_EL1, +but we move id_aa64dfr1 into the ARMISARegisters struct with +id_aa64dfr0, for consistency. + +Reviewed-by: Richard Henderson +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Peter Maydell +Message-id: 20200214175116.9164-10-peter.maydell@linaro.org +--- + target/arm/cpu.c | 3 ++- + target/arm/cpu.h | 15 +++++++++++++-- + target/arm/cpu64.c | 8 ++++---- + target/arm/helper.c | 12 +++++++----- + 4 files changed, 26 insertions(+), 12 deletions(-) + +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 7e9b85a2..bb2edf4e 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1522,7 +1522,8 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + cpu); + #endif + } else { +- cpu->id_aa64dfr0 = FIELD_DP64(cpu->id_aa64dfr0, ID_AA64DFR0, PMUVER, 0); ++ cpu->isar.id_aa64dfr0 = ++ FIELD_DP64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, PMUVER, 0); + cpu->isar.id_dfr0 = FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, PERFMON, 0); + cpu->pmceid0 = 0; + cpu->pmceid1 = 0; +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 2d8d27e8..230130be 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -868,6 +868,8 @@ struct ARMCPU { + uint64_t id_aa64mmfr0; + uint64_t id_aa64mmfr1; + uint64_t id_aa64mmfr2; ++ uint64_t id_aa64dfr0; ++ uint64_t id_aa64dfr1; + } isar; + uint32_t midr; + uint32_t revidr; +@@ -884,8 +886,6 @@ struct ARMCPU { + uint32_t id_mmfr2; + uint32_t id_mmfr3; + uint32_t id_mmfr4; +- uint64_t id_aa64dfr0; +- uint64_t id_aa64dfr1; + uint64_t id_aa64afr0; + uint64_t id_aa64afr1; + uint32_t dbgdidr; +@@ -3657,6 +3657,17 @@ static inline bool isar_feature_aa64_bti(const ARMISARegisters *id) + return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0; + } + ++static inline bool isar_feature_aa64_pmu_8_1(const ARMISARegisters *id) ++{ ++ return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 && ++ FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf; ++} ++ ++static inline bool isar_feature_any_pmu_8_1(const ARMISARegisters *id) ++{ ++ return isar_feature_aa64_pmu_8_1(id) || isar_feature_aa32_pmu_8_1(id); ++} ++ + /* + * Forward to the above feature tests given an ARMCPU pointer. + */ +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index afdabbeb..aa96548f 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -137,7 +137,7 @@ static void aarch64_a57_initfn(Object *obj) + cpu->isar.id_isar5 = 0x00011121; + cpu->isar.id_isar6 = 0; + cpu->isar.id_aa64pfr0 = 0x00002222; +- cpu->id_aa64dfr0 = 0x10305106; ++ cpu->isar.id_aa64dfr0 = 0x10305106; + cpu->isar.id_aa64isar0 = 0x00011120; + cpu->isar.id_aa64mmfr0 = 0x00001124; + cpu->dbgdidr = 0x3516d000; +@@ -191,7 +191,7 @@ static void aarch64_a53_initfn(Object *obj) + cpu->isar.id_isar5 = 0x00011121; + cpu->isar.id_isar6 = 0; + cpu->isar.id_aa64pfr0 = 0x00002222; +- cpu->id_aa64dfr0 = 0x10305106; ++ cpu->isar.id_aa64dfr0 = 0x10305106; + cpu->isar.id_aa64isar0 = 0x00011120; + cpu->isar.id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */ + cpu->dbgdidr = 0x3516d000; +@@ -244,7 +244,7 @@ static void aarch64_a72_initfn(Object *obj) + cpu->isar.id_isar4 = 0x00011142; + cpu->isar.id_isar5 = 0x00011121; + cpu->isar.id_aa64pfr0 = 0x00002222; +- cpu->id_aa64dfr0 = 0x10305106; ++ cpu->isar.id_aa64dfr0 = 0x10305106; + cpu->isar.id_aa64isar0 = 0x00011120; + cpu->isar.id_aa64mmfr0 = 0x00001124; + cpu->dbgdidr = 0x3516d000; +@@ -276,7 +276,7 @@ static void aarch64_kunpeng_920_initfn(Object *obj) + cpu->midr = 0x480fd010; + cpu->ctr = 0x84448004; + cpu->isar.id_aa64pfr0 = 0x11001111; +- cpu->id_aa64dfr0 = 0x110305408; ++ cpu->isar.id_aa64dfr0 = 0x110305408; + cpu->isar.id_aa64isar0 = 0x10211120; + cpu->isar.id_aa64mmfr0 = 0x101125; + } +diff --git a/target/arm/helper.c b/target/arm/helper.c +index 3f06ca19..a71f4ef6 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -23,6 +23,7 @@ + #include "hw/semihosting/semihost.h" + #include "sysemu/cpus.h" + #include "sysemu/kvm.h" ++#include "sysemu/tcg.h" + #include "qemu/range.h" + #include "qapi/qapi-commands-machine-target.h" + #include "qapi/error.h" +@@ -5611,9 +5612,10 @@ static void define_debug_regs(ARMCPU *cpu) + * check that if they both exist then they agree. + */ + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { +- assert(FIELD_EX64(cpu->id_aa64dfr0, ID_AA64DFR0, BRPS) == brps); +- assert(FIELD_EX64(cpu->id_aa64dfr0, ID_AA64DFR0, WRPS) == wrps); +- assert(FIELD_EX64(cpu->id_aa64dfr0, ID_AA64DFR0, CTX_CMPS) == ctx_cmps); ++ assert(FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, BRPS) == brps); ++ assert(FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, WRPS) == wrps); ++ assert(FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS) ++ == ctx_cmps); + } + + define_one_arm_cp_reg(cpu, &dbgdidr); +@@ -6112,11 +6114,11 @@ void register_cp_regs_for_features(ARMCPU *cpu) + { .name = "ID_AA64DFR0_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->id_aa64dfr0 }, ++ .resetvalue = cpu->isar.id_aa64dfr0 }, + { .name = "ID_AA64DFR1_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 1, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->id_aa64dfr1 }, ++ .resetvalue = cpu->isar.id_aa64dfr1 }, + { .name = "ID_AA64DFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 2, + .access = PL1_R, .type = ARM_CP_CONST, +-- +2.25.1 + diff --git a/target-arm-Add-and-use-FIELD-definitions-for-ID_AA64.patch b/target-arm-Add-and-use-FIELD-definitions-for-ID_AA64.patch new file mode 100644 index 0000000000000000000000000000000000000000..66e4ec4ad078aacdd4e7cb9a76244e1460487551 --- /dev/null +++ b/target-arm-Add-and-use-FIELD-definitions-for-ID_AA64.patch @@ -0,0 +1,76 @@ +From 4001f3040937094660eab44dbb49b86817317ea9 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 14 Feb 2020 17:51:01 +0000 +Subject: [PATCH 03/13] target/arm: Add and use FIELD definitions for + ID_AA64DFR0_EL1 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add FIELD() definitions for the ID_AA64DFR0_EL1 and use them +where we currently have hard-coded bit values. + +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Richard Henderson +Signed-off-by: Peter Maydell +Message-id: 20200214175116.9164-7-peter.maydell@linaro.org +--- + target/arm/cpu.c | 2 +- + target/arm/cpu.h | 10 ++++++++++ + target/arm/helper.c | 6 +++--- + 3 files changed, 14 insertions(+), 4 deletions(-) + +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 811e5c63..dbd05e01 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1522,7 +1522,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + cpu); + #endif + } else { +- cpu->id_aa64dfr0 &= ~0xf00; ++ cpu->id_aa64dfr0 = FIELD_DP64(cpu->id_aa64dfr0, ID_AA64DFR0, PMUVER, 0); + cpu->id_dfr0 &= ~(0xf << 24); + cpu->pmceid0 = 0; + cpu->pmceid1 = 0; +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 3e65bc50..91cc02b4 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -1779,6 +1779,16 @@ FIELD(ID_AA64MMFR2, BBM, 52, 4) + FIELD(ID_AA64MMFR2, EVT, 56, 4) + FIELD(ID_AA64MMFR2, E0PD, 60, 4) + ++FIELD(ID_AA64DFR0, DEBUGVER, 0, 4) ++FIELD(ID_AA64DFR0, TRACEVER, 4, 4) ++FIELD(ID_AA64DFR0, PMUVER, 8, 4) ++FIELD(ID_AA64DFR0, BRPS, 12, 4) ++FIELD(ID_AA64DFR0, WRPS, 20, 4) ++FIELD(ID_AA64DFR0, CTX_CMPS, 28, 4) ++FIELD(ID_AA64DFR0, PMSVER, 32, 4) ++FIELD(ID_AA64DFR0, DOUBLELOCK, 36, 4) ++FIELD(ID_AA64DFR0, TRACEFILT, 40, 4) ++ + FIELD(ID_DFR0, COPDBG, 0, 4) + FIELD(ID_DFR0, COPSDBG, 4, 4) + FIELD(ID_DFR0, MMAPDBG, 8, 4) +diff --git a/target/arm/helper.c b/target/arm/helper.c +index c50b1ba1..419be640 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -5611,9 +5611,9 @@ static void define_debug_regs(ARMCPU *cpu) + * check that if they both exist then they agree. + */ + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { +- assert(extract32(cpu->id_aa64dfr0, 12, 4) == brps); +- assert(extract32(cpu->id_aa64dfr0, 20, 4) == wrps); +- assert(extract32(cpu->id_aa64dfr0, 28, 4) == ctx_cmps); ++ assert(FIELD_EX64(cpu->id_aa64dfr0, ID_AA64DFR0, BRPS) == brps); ++ assert(FIELD_EX64(cpu->id_aa64dfr0, ID_AA64DFR0, WRPS) == wrps); ++ assert(FIELD_EX64(cpu->id_aa64dfr0, ID_AA64DFR0, CTX_CMPS) == ctx_cmps); + } + + define_one_arm_cp_reg(cpu, &dbgdidr); +-- +2.25.1 + diff --git a/target-arm-Add-isar_feature-tests-for-PAN-ATS1E1.patch b/target-arm-Add-isar_feature-tests-for-PAN-ATS1E1.patch new file mode 100644 index 0000000000000000000000000000000000000000..d6e29be12e1bbf6ef55d43bf35960e2168fc51e8 --- /dev/null +++ b/target-arm-Add-isar_feature-tests-for-PAN-ATS1E1.patch @@ -0,0 +1,77 @@ +From 6f18e959eabf9c752659eb3851f193bf343346c5 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Sat, 8 Feb 2020 12:57:59 +0000 +Subject: [PATCH 01/13] target/arm: Add isar_feature tests for PAN + ATS1E1 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Include definitions for all of the bits in ID_MMFR3. +We already have a definition for ID_AA64MMFR1.PAN. + +Reviewed-by: Alex Bennée +Reviewed-by: Peter Maydell +Signed-off-by: Richard Henderson +Message-id: 20200208125816.14954-4-richard.henderson@linaro.org +Signed-off-by: Peter Maydell +--- + target/arm/cpu.h | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 86eb79cd..fe310828 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -1680,6 +1680,15 @@ FIELD(ID_ISAR6, FHM, 8, 4) + FIELD(ID_ISAR6, SB, 12, 4) + FIELD(ID_ISAR6, SPECRES, 16, 4) + ++FIELD(ID_MMFR3, CMAINTVA, 0, 4) ++FIELD(ID_MMFR3, CMAINTSW, 4, 4) ++FIELD(ID_MMFR3, BPMAINT, 8, 4) ++FIELD(ID_MMFR3, MAINTBCST, 12, 4) ++FIELD(ID_MMFR3, PAN, 16, 4) ++FIELD(ID_MMFR3, COHWALK, 20, 4) ++FIELD(ID_MMFR3, CMEMSZ, 24, 4) ++FIELD(ID_MMFR3, SUPERSEC, 28, 4) ++ + FIELD(ID_MMFR4, SPECSEI, 0, 4) + FIELD(ID_MMFR4, AC2, 4, 4) + FIELD(ID_MMFR4, XNX, 8, 4) +@@ -3445,6 +3454,16 @@ static inline bool isar_feature_aa32_vminmaxnm(const ARMISARegisters *id) + return FIELD_EX64(id->mvfr2, MVFR2, FPMISC) >= 4; + } + ++static inline bool isar_feature_aa32_pan(const ARMISARegisters *id) ++{ ++ return FIELD_EX64(id->mvfr0, ID_MMFR3, PAN) != 0; ++} ++ ++static inline bool isar_feature_aa32_ats1e1(const ARMISARegisters *id) ++{ ++ return FIELD_EX64(id->mvfr0, ID_MMFR3, PAN) >= 2; ++} ++ + /* + * 64-bit feature tests via id registers. + */ +@@ -3589,6 +3608,16 @@ static inline bool isar_feature_aa64_lor(const ARMISARegisters *id) + return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, LO) != 0; + } + ++static inline bool isar_feature_aa64_pan(const ARMISARegisters *id) ++{ ++ return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) != 0; ++} ++ ++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_bti(const ARMISARegisters *id) + { + return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0; +-- +2.25.1 + diff --git a/target-arm-Add-more-CPU-features.patch b/target-arm-Add-more-CPU-features.patch new file mode 100644 index 0000000000000000000000000000000000000000..a22e5177300d305df8c0430ee21e29c587bd5399 --- /dev/null +++ b/target-arm-Add-more-CPU-features.patch @@ -0,0 +1,30 @@ +From 3eee1e4ff1ca342e760f759c727abc41780d0afa Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Tue, 11 Aug 2020 10:28:10 +0800 +Subject: [PATCH 9/9] target/arm: Add more CPU features + +Add i8mm, bf16, and dgh CPU features for AArch64. + +Signed-off-by: zhanghailiang +Signed-off-by: Peng Liang +--- + target/arm/cpu.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index dcf9f49e..7ae2d3da 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1132,6 +1132,9 @@ static struct CPUFeatureInfo cpu_features[] = { + FIELD_INFO("fhm", ID_ISAR6, FHM, false, 1, 0, true), + FIELD_INFO("sb", ID_ISAR6, SB, false, 1, 0, true), + FIELD_INFO("specres", ID_ISAR6, SPECRES, false, 1, 0, true), ++ FIELD_INFO("i8mm", ID_AA64ISAR1, I8MM, false, 1, 0, false), ++ FIELD_INFO("bf16", ID_AA64ISAR1, BF16, false, 1, 0, false), ++ FIELD_INFO("dgh", ID_AA64ISAR1, DGH, false, 1, 0, false), + + FIELD_INFO("cmaintva", ID_MMFR3, CMAINTVA, false, 1, 0, true), + FIELD_INFO("cmaintsw", ID_MMFR3, CMAINTSW, false, 1, 0, true), +-- +2.25.1 + diff --git a/target-arm-Allow-ID-registers-to-synchronize-to-KVM.patch b/target-arm-Allow-ID-registers-to-synchronize-to-KVM.patch new file mode 100644 index 0000000000000000000000000000000000000000..81ad2961b00130a741079e0f38c56b7dffdcf803 --- /dev/null +++ b/target-arm-Allow-ID-registers-to-synchronize-to-KVM.patch @@ -0,0 +1,160 @@ +From 79a60f0eeb56faf5d162ca566d1cd9988c3e4d60 Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Thu, 6 Aug 2020 16:14:40 +0800 +Subject: [PATCH 4/9] target/arm: Allow ID registers to synchronize to KVM + +There are 2 steps to synchronize the values of system registers from +CPU state to KVM: +1. write to the values of system registers from CPU state to + (index,value) list by write_cpustate_to_list; +2. write the values in (index,value) list to KVM by + write_list_to_kvmstate; + +In step 1, the values of constant system registers are not allowed to +write to (index,value) list. However, a constant system register is +CONSTANT for guest but not for QEMU, which means, QEMU can set/modify +the value of constant system registers that is different from phsical +registers when startup. But if KVM is enabled, guest can not read the +values of the system registers which QEMU set unless they can be written +to (index,value) list. And why not try to write to KVM if kvm_sync is +true? + +At the moment we call write_cpustate_to_list, all ID registers are +contant, including ID_PFR1_EL1 and ID_AA64PFR0_EL1 because GIC has been +initialized. Hence, let's give all ID registers a chance to write to +KVM. If the write is successful, then write to (index,value) list. + +Signed-off-by: zhanghailiang +Signed-off-by: Peng Liang +--- + target/arm/helper.c | 31 ++++++++++++++++++++----------- + target/arm/kvm.c | 38 ++++++++++++++++++++++++++++++++++++++ + target/arm/kvm_arm.h | 3 +++ + 3 files changed, 61 insertions(+), 11 deletions(-) + +diff --git a/target/arm/helper.c b/target/arm/helper.c +index 459af431..97b6b861 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -32,6 +32,7 @@ + #include "arm_ldst.h" + #include "exec/cpu_ldst.h" + #endif ++#include "kvm_arm.h" + + #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */ + +@@ -267,30 +268,38 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync) + ok = false; + continue; + } +- if (ri->type & ARM_CP_NO_RAW) { ++ /* ++ * (Op0, Op1, CRn, CRm, Op2) of ID registers is (3, 0, 0, crm, op2), ++ * where 1<=crm<8, 0<=op2<8. Let's give ID registers a chance to ++ * synchronize to kvm. ++ */ ++ if ((ri->type & ARM_CP_NO_RAW) && !(kvm_sync && ++ ri->opc0 == 3 && ri->opc1 == 0 && ri->crn == 0 && ri->crm > 0)) { + continue; + } + + newval = read_raw_cp_reg(&cpu->env, ri); + if (kvm_sync) { +- /* +- * Only sync if the previous list->cpustate sync succeeded. +- * Rather than tracking the success/failure state for every +- * item in the list, we just recheck "does the raw write we must +- * have made in write_list_to_cpustate() read back OK" here. +- */ +- uint64_t oldval = cpu->cpreg_values[i]; ++ /* Only sync if we can sync to KVM successfully. */ ++ uint64_t oldval; ++ uint64_t kvmval; + ++ if (kvm_arm_get_one_reg(cpu, cpu->cpreg_indexes[i], &oldval)) { ++ continue; ++ } + if (oldval == newval) { + continue; + } + +- write_raw_cp_reg(&cpu->env, ri, oldval); +- if (read_raw_cp_reg(&cpu->env, ri) != oldval) { ++ if (kvm_arm_set_one_reg(cpu, cpu->cpreg_indexes[i], &newval)) { ++ continue; ++ } ++ if (kvm_arm_get_one_reg(cpu, cpu->cpreg_indexes[i], &kvmval) || ++ kvmval != newval) { + continue; + } + +- write_raw_cp_reg(&cpu->env, ri, newval); ++ kvm_arm_set_one_reg(cpu, cpu->cpreg_indexes[i], &oldval); + } + cpu->cpreg_values[i] = newval; + } +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index 4f131f68..229b17ce 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -457,6 +457,44 @@ out: + return ret; + } + ++int kvm_arm_get_one_reg(ARMCPU *cpu, uint64_t regidx, uint64_t *target) ++{ ++ uint32_t v32; ++ int ret; ++ ++ switch (regidx & KVM_REG_SIZE_MASK) { ++ case KVM_REG_SIZE_U32: ++ ret = kvm_get_one_reg(CPU(cpu), regidx, &v32); ++ if (ret == 0) { ++ *target = v32; ++ } ++ return ret; ++ case KVM_REG_SIZE_U64: ++ return kvm_get_one_reg(CPU(cpu), regidx, target); ++ default: ++ return -1; ++ } ++} ++ ++int kvm_arm_set_one_reg(ARMCPU *cpu, uint64_t regidx, uint64_t *source) ++{ ++ uint32_t v32; ++ ++ switch (regidx & KVM_REG_SIZE_MASK) { ++ case KVM_REG_SIZE_U32: ++ v32 = *source; ++ if (v32 != *source) { ++ error_report("the value of source is too large"); ++ return -1; ++ } ++ return kvm_set_one_reg(CPU(cpu), regidx, &v32); ++ case KVM_REG_SIZE_U64: ++ return kvm_set_one_reg(CPU(cpu), regidx, source); ++ default: ++ return -1; ++ } ++} ++ + bool write_kvmstate_to_list(ARMCPU *cpu) + { + CPUState *cs = CPU(cpu); +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index 0de5f83e..9b7104d6 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -400,4 +400,7 @@ static inline const char *its_class_name(void) + } + } + ++int kvm_arm_get_one_reg(ARMCPU *cpu, uint64_t regidx, uint64_t *target); ++int kvm_arm_set_one_reg(ARMCPU *cpu, uint64_t regidx, uint64_t *source); ++ + #endif +-- +2.25.1 + diff --git a/target-arm-Define-an-aa32_pmu_8_1-isar-feature-test-.patch b/target-arm-Define-an-aa32_pmu_8_1-isar-feature-test-.patch new file mode 100644 index 0000000000000000000000000000000000000000..bfcce54936d4cb8c8ca1de997a6d0d469dab3bc1 --- /dev/null +++ b/target-arm-Define-an-aa32_pmu_8_1-isar-feature-test-.patch @@ -0,0 +1,248 @@ +From 2eded1a4deeb5dd8d28414e54948bcf773f6b540 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 14 Feb 2020 17:51:03 +0000 +Subject: [PATCH 05/13] target/arm: Define an aa32_pmu_8_1 isar feature test + function + +Instead of open-coding a check on the ID_DFR0 PerfMon ID register +field, create a standardly-named isar_feature for "does AArch32 have +a v8.1 PMUv3" and use it. + +This entails moving the id_dfr0 field into the ARMISARegisters struct. + +Reviewed-by: Richard Henderson +Signed-off-by: Peter Maydell +Message-id: 20200214175116.9164-9-peter.maydell@linaro.org +--- + hw/intc/armv7m_nvic.c | 2 +- + target/arm/cpu.c | 26 +++++++++++++------------- + target/arm/cpu.h | 9 ++++++++- + target/arm/cpu64.c | 6 +++--- + target/arm/helper.c | 5 ++--- + 5 files changed, 27 insertions(+), 21 deletions(-) + +diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c +index 9f8f0d3f..0741db7b 100644 +--- a/hw/intc/armv7m_nvic.c ++++ b/hw/intc/armv7m_nvic.c +@@ -1223,7 +1223,7 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) + case 0xd44: /* PFR1. */ + return cpu->id_pfr1; + case 0xd48: /* DFR0. */ +- return cpu->id_dfr0; ++ return cpu->isar.id_dfr0; + case 0xd4c: /* AFR0. */ + return cpu->id_afr0; + case 0xd50: /* MMFR0. */ +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 6ad211b1..7e9b85a2 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1523,7 +1523,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + #endif + } else { + cpu->id_aa64dfr0 = FIELD_DP64(cpu->id_aa64dfr0, ID_AA64DFR0, PMUVER, 0); +- cpu->id_dfr0 = FIELD_DP32(cpu->id_dfr0, ID_DFR0, PERFMON, 0); ++ cpu->isar.id_dfr0 = FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, PERFMON, 0); + cpu->pmceid0 = 0; + cpu->pmceid1 = 0; + } +@@ -1761,7 +1761,7 @@ static void arm1136_r2_initfn(Object *obj) + cpu->reset_sctlr = 0x00050078; + cpu->id_pfr0 = 0x111; + cpu->id_pfr1 = 0x1; +- cpu->id_dfr0 = 0x2; ++ cpu->isar.id_dfr0 = 0x2; + cpu->id_afr0 = 0x3; + cpu->id_mmfr0 = 0x01130003; + cpu->id_mmfr1 = 0x10030302; +@@ -1793,7 +1793,7 @@ static void arm1136_initfn(Object *obj) + cpu->reset_sctlr = 0x00050078; + cpu->id_pfr0 = 0x111; + cpu->id_pfr1 = 0x1; +- cpu->id_dfr0 = 0x2; ++ cpu->isar.id_dfr0 = 0x2; + cpu->id_afr0 = 0x3; + cpu->id_mmfr0 = 0x01130003; + cpu->id_mmfr1 = 0x10030302; +@@ -1826,7 +1826,7 @@ static void arm1176_initfn(Object *obj) + cpu->reset_sctlr = 0x00050078; + cpu->id_pfr0 = 0x111; + cpu->id_pfr1 = 0x11; +- cpu->id_dfr0 = 0x33; ++ cpu->isar.id_dfr0 = 0x33; + cpu->id_afr0 = 0; + cpu->id_mmfr0 = 0x01130003; + cpu->id_mmfr1 = 0x10030302; +@@ -1856,7 +1856,7 @@ static void arm11mpcore_initfn(Object *obj) + cpu->ctr = 0x1d192992; /* 32K icache 32K dcache */ + cpu->id_pfr0 = 0x111; + cpu->id_pfr1 = 0x1; +- cpu->id_dfr0 = 0; ++ cpu->isar.id_dfr0 = 0; + cpu->id_afr0 = 0x2; + cpu->id_mmfr0 = 0x01100103; + cpu->id_mmfr1 = 0x10020302; +@@ -1888,7 +1888,7 @@ static void cortex_m3_initfn(Object *obj) + cpu->pmsav7_dregion = 8; + cpu->id_pfr0 = 0x00000030; + cpu->id_pfr1 = 0x00000200; +- cpu->id_dfr0 = 0x00100000; ++ cpu->isar.id_dfr0 = 0x00100000; + cpu->id_afr0 = 0x00000000; + cpu->id_mmfr0 = 0x00000030; + cpu->id_mmfr1 = 0x00000000; +@@ -1919,7 +1919,7 @@ static void cortex_m4_initfn(Object *obj) + cpu->isar.mvfr2 = 0x00000000; + cpu->id_pfr0 = 0x00000030; + cpu->id_pfr1 = 0x00000200; +- cpu->id_dfr0 = 0x00100000; ++ cpu->isar.id_dfr0 = 0x00100000; + cpu->id_afr0 = 0x00000000; + cpu->id_mmfr0 = 0x00000030; + cpu->id_mmfr1 = 0x00000000; +@@ -1952,7 +1952,7 @@ static void cortex_m33_initfn(Object *obj) + cpu->isar.mvfr2 = 0x00000040; + cpu->id_pfr0 = 0x00000030; + cpu->id_pfr1 = 0x00000210; +- cpu->id_dfr0 = 0x00200000; ++ cpu->isar.id_dfr0 = 0x00200000; + cpu->id_afr0 = 0x00000000; + cpu->id_mmfr0 = 0x00101F40; + cpu->id_mmfr1 = 0x00000000; +@@ -2003,7 +2003,7 @@ static void cortex_r5_initfn(Object *obj) + cpu->midr = 0x411fc153; /* r1p3 */ + cpu->id_pfr0 = 0x0131; + cpu->id_pfr1 = 0x001; +- cpu->id_dfr0 = 0x010400; ++ cpu->isar.id_dfr0 = 0x010400; + cpu->id_afr0 = 0x0; + cpu->id_mmfr0 = 0x0210030; + cpu->id_mmfr1 = 0x00000000; +@@ -2058,7 +2058,7 @@ static void cortex_a8_initfn(Object *obj) + cpu->reset_sctlr = 0x00c50078; + cpu->id_pfr0 = 0x1031; + cpu->id_pfr1 = 0x11; +- cpu->id_dfr0 = 0x400; ++ cpu->isar.id_dfr0 = 0x400; + cpu->id_afr0 = 0; + cpu->id_mmfr0 = 0x31100003; + cpu->id_mmfr1 = 0x20000000; +@@ -2131,7 +2131,7 @@ static void cortex_a9_initfn(Object *obj) + cpu->reset_sctlr = 0x00c50078; + cpu->id_pfr0 = 0x1031; + cpu->id_pfr1 = 0x11; +- cpu->id_dfr0 = 0x000; ++ cpu->isar.id_dfr0 = 0x000; + cpu->id_afr0 = 0; + cpu->id_mmfr0 = 0x00100103; + cpu->id_mmfr1 = 0x20000000; +@@ -2196,7 +2196,7 @@ static void cortex_a7_initfn(Object *obj) + cpu->reset_sctlr = 0x00c50078; + cpu->id_pfr0 = 0x00001131; + cpu->id_pfr1 = 0x00011011; +- cpu->id_dfr0 = 0x02010555; ++ cpu->isar.id_dfr0 = 0x02010555; + cpu->id_afr0 = 0x00000000; + cpu->id_mmfr0 = 0x10101105; + cpu->id_mmfr1 = 0x40000000; +@@ -2242,7 +2242,7 @@ static void cortex_a15_initfn(Object *obj) + cpu->reset_sctlr = 0x00c50078; + cpu->id_pfr0 = 0x00001131; + cpu->id_pfr1 = 0x00011011; +- cpu->id_dfr0 = 0x02010555; ++ cpu->isar.id_dfr0 = 0x02010555; + cpu->id_afr0 = 0x00000000; + cpu->id_mmfr0 = 0x10201105; + cpu->id_mmfr1 = 0x20000000; +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 91cc02b4..2d8d27e8 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -860,6 +860,7 @@ struct ARMCPU { + uint32_t mvfr0; + uint32_t mvfr1; + uint32_t mvfr2; ++ uint32_t id_dfr0; + uint64_t id_aa64isar0; + uint64_t id_aa64isar1; + uint64_t id_aa64pfr0; +@@ -875,7 +876,6 @@ struct ARMCPU { + uint32_t reset_sctlr; + uint32_t id_pfr0; + uint32_t id_pfr1; +- uint32_t id_dfr0; + uint64_t pmceid0; + uint64_t pmceid1; + uint32_t id_afr0; +@@ -3491,6 +3491,13 @@ static inline bool isar_feature_aa32_ats1e1(const ARMISARegisters *id) + return FIELD_EX64(id->mvfr0, ID_MMFR3, PAN) >= 2; + } + ++static inline bool isar_feature_aa32_pmu_8_1(const ARMISARegisters *id) ++{ ++ /* 0xf means "non-standard IMPDEF PMU" */ ++ return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 4 && ++ FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf; ++} ++ + /* + * 64-bit feature tests via id registers. + */ +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 15f4ee92..afdabbeb 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -123,7 +123,7 @@ static void aarch64_a57_initfn(Object *obj) + cpu->reset_sctlr = 0x00c50838; + cpu->id_pfr0 = 0x00000131; + cpu->id_pfr1 = 0x00011011; +- cpu->id_dfr0 = 0x03010066; ++ cpu->isar.id_dfr0 = 0x03010066; + cpu->id_afr0 = 0x00000000; + cpu->id_mmfr0 = 0x10101105; + cpu->id_mmfr1 = 0x40000000; +@@ -177,7 +177,7 @@ static void aarch64_a53_initfn(Object *obj) + cpu->reset_sctlr = 0x00c50838; + cpu->id_pfr0 = 0x00000131; + cpu->id_pfr1 = 0x00011011; +- cpu->id_dfr0 = 0x03010066; ++ cpu->isar.id_dfr0 = 0x03010066; + cpu->id_afr0 = 0x00000000; + cpu->id_mmfr0 = 0x10101105; + cpu->id_mmfr1 = 0x40000000; +@@ -231,7 +231,7 @@ static void aarch64_a72_initfn(Object *obj) + cpu->reset_sctlr = 0x00c50838; + cpu->id_pfr0 = 0x00000131; + cpu->id_pfr1 = 0x00011011; +- cpu->id_dfr0 = 0x03010066; ++ cpu->isar.id_dfr0 = 0x03010066; + cpu->id_afr0 = 0x00000000; + cpu->id_mmfr0 = 0x10201105; + cpu->id_mmfr1 = 0x40000000; +diff --git a/target/arm/helper.c b/target/arm/helper.c +index 419be640..3f06ca19 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -5907,7 +5907,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + { .name = "ID_DFR0", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 2, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->id_dfr0 }, ++ .resetvalue = cpu->isar.id_dfr0 }, + { .name = "ID_AFR0", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 3, + .access = PL1_R, .type = ARM_CP_CONST, +@@ -6050,8 +6050,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + } else { + define_arm_cp_regs(cpu, not_v7_cp_reginfo); + } +- if (FIELD_EX32(cpu->id_dfr0, ID_DFR0, PERFMON) >= 4 && +- FIELD_EX32(cpu->id_dfr0, ID_DFR0, PERFMON) != 0xf) { ++ if (cpu_isar_feature(aa32_pmu_8_1, cpu)) { + ARMCPRegInfo v81_pmu_regs[] = { + { .name = "PMCEID2", .state = ARM_CP_STATE_AA32, + .cp = 15, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 4, +-- +2.25.1 + diff --git a/target-arm-Enable-ARMv8.2-ATS1E1-in-cpu-max.patch b/target-arm-Enable-ARMv8.2-ATS1E1-in-cpu-max.patch new file mode 100644 index 0000000000000000000000000000000000000000..d6e82fae2dc02954d37eb723f930bccd28b70618 --- /dev/null +++ b/target-arm-Enable-ARMv8.2-ATS1E1-in-cpu-max.patch @@ -0,0 +1,57 @@ +From 69eedbfc873ded9bf35439b813e9f6a7431dc727 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Sat, 8 Feb 2020 12:58:12 +0000 +Subject: [PATCH 09/13] target/arm: Enable ARMv8.2-ATS1E1 in -cpu max + +This includes enablement of ARMv8.1-PAN. + +Reviewed-by: Peter Maydell +Signed-off-by: Richard Henderson +Message-id: 20200208125816.14954-17-richard.henderson@linaro.org +Signed-off-by: Peter Maydell +--- + target/arm/cpu.c | 4 ++++ + target/arm/cpu64.c | 5 +++++ + 2 files changed, 9 insertions(+) + +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index a23c71db..119bd275 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -2484,6 +2484,10 @@ static void arm_max_initfn(Object *obj) + t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ + cpu->isar.mvfr2 = t; + ++ t = cpu->id_mmfr3; ++ t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */ ++ cpu->id_mmfr3 = t; ++ + t = cpu->id_mmfr4; + t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ + cpu->id_mmfr4 = t; +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 7ad8b5e2..a0d07fd7 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -362,6 +362,7 @@ static void aarch64_max_initfn(Object *obj) + 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, PAN, 2); /* ATS1E1 */ + cpu->isar.id_aa64mmfr1 = t; + + /* Replicate the same data to the 32-bit id registers. */ +@@ -382,6 +383,10 @@ static void aarch64_max_initfn(Object *obj) + u = FIELD_DP32(u, ID_ISAR6, SPECRES, 1); + cpu->isar.id_isar6 = u; + ++ u = cpu->id_mmfr3; ++ u = FIELD_DP32(u, ID_MMFR3, PAN, 2); /* ATS1E1 */ ++ cpu->id_mmfr3 = u; ++ + /* + * FIXME: We do not yet support ARMv8.2-fp16 for AArch32 yet, + * so do not set MVFR1.FPHP. Strictly speaking this is not legal, +-- +2.25.1 + diff --git a/target-arm-Move-DBGDIDR-into-ARMISARegisters.patch b/target-arm-Move-DBGDIDR-into-ARMISARegisters.patch new file mode 100644 index 0000000000000000000000000000000000000000..e7f2833ee889363902a3e063bffbbff4b4e2c6af --- /dev/null +++ b/target-arm-Move-DBGDIDR-into-ARMISARegisters.patch @@ -0,0 +1,158 @@ +From df641941e6fd7fef78e5c77c9a809a7a8e148589 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 14 Feb 2020 17:51:06 +0000 +Subject: [PATCH 08/13] target/arm: Move DBGDIDR into ARMISARegisters + +We're going to want to read the DBGDIDR register from KVM in +a subsequent commit, which means it needs to be in the +ARMISARegisters sub-struct. Move it. + +Signed-off-by: Peter Maydell +Reviewed-by: Richard Henderson +Message-id: 20200214175116.9164-12-peter.maydell@linaro.org +--- + target/arm/cpu.c | 8 ++++---- + target/arm/cpu.h | 2 +- + target/arm/cpu64.c | 6 +++--- + target/arm/helper.c | 2 +- + target/arm/internals.h | 6 +++--- + 5 files changed, 12 insertions(+), 12 deletions(-) + +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index bb2edf4e..a23c71db 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -2070,7 +2070,7 @@ static void cortex_a8_initfn(Object *obj) + cpu->isar.id_isar2 = 0x21232031; + cpu->isar.id_isar3 = 0x11112131; + cpu->isar.id_isar4 = 0x00111142; +- cpu->dbgdidr = 0x15141000; ++ cpu->isar.dbgdidr = 0x15141000; + cpu->clidr = (1 << 27) | (2 << 24) | 3; + cpu->ccsidr[0] = 0xe007e01a; /* 16k L1 dcache. */ + cpu->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */ +@@ -2143,7 +2143,7 @@ static void cortex_a9_initfn(Object *obj) + cpu->isar.id_isar2 = 0x21232041; + cpu->isar.id_isar3 = 0x11112131; + cpu->isar.id_isar4 = 0x00111142; +- cpu->dbgdidr = 0x35141000; ++ cpu->isar.dbgdidr = 0x35141000; + cpu->clidr = (1 << 27) | (1 << 24) | 3; + cpu->ccsidr[0] = 0xe00fe019; /* 16k L1 dcache. */ + cpu->ccsidr[1] = 0x200fe019; /* 16k L1 icache. */ +@@ -2211,7 +2211,7 @@ static void cortex_a7_initfn(Object *obj) + cpu->isar.id_isar2 = 0x21232041; + cpu->isar.id_isar3 = 0x11112131; + cpu->isar.id_isar4 = 0x10011142; +- cpu->dbgdidr = 0x3515f005; ++ cpu->isar.dbgdidr = 0x3515f005; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ + cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ +@@ -2254,7 +2254,7 @@ static void cortex_a15_initfn(Object *obj) + cpu->isar.id_isar2 = 0x21232041; + cpu->isar.id_isar3 = 0x11112131; + cpu->isar.id_isar4 = 0x10011142; +- cpu->dbgdidr = 0x3515f021; ++ cpu->isar.dbgdidr = 0x3515f021; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ + cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 4b1ae32b..3040aa40 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -861,6 +861,7 @@ struct ARMCPU { + uint32_t mvfr1; + uint32_t mvfr2; + uint32_t id_dfr0; ++ uint32_t dbgdidr; + uint64_t id_aa64isar0; + uint64_t id_aa64isar1; + uint64_t id_aa64pfr0; +@@ -888,7 +889,6 @@ struct ARMCPU { + uint32_t id_mmfr4; + uint64_t id_aa64afr0; + uint64_t id_aa64afr1; +- uint32_t dbgdidr; + uint32_t clidr; + uint64_t mp_affinity; /* MP ID without feature bits */ + /* The elements of this array are the CCSIDR values for each cache, +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index aa96548f..7ad8b5e2 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -140,7 +140,7 @@ static void aarch64_a57_initfn(Object *obj) + cpu->isar.id_aa64dfr0 = 0x10305106; + cpu->isar.id_aa64isar0 = 0x00011120; + cpu->isar.id_aa64mmfr0 = 0x00001124; +- cpu->dbgdidr = 0x3516d000; ++ cpu->isar.dbgdidr = 0x3516d000; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ +@@ -194,7 +194,7 @@ static void aarch64_a53_initfn(Object *obj) + cpu->isar.id_aa64dfr0 = 0x10305106; + cpu->isar.id_aa64isar0 = 0x00011120; + cpu->isar.id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */ +- cpu->dbgdidr = 0x3516d000; ++ cpu->isar.dbgdidr = 0x3516d000; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */ +@@ -247,7 +247,7 @@ static void aarch64_a72_initfn(Object *obj) + cpu->isar.id_aa64dfr0 = 0x10305106; + cpu->isar.id_aa64isar0 = 0x00011120; + cpu->isar.id_aa64mmfr0 = 0x00001124; +- cpu->dbgdidr = 0x3516d000; ++ cpu->isar.dbgdidr = 0x3516d000; + 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 c1ff4b6b..60ff7c0f 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -5597,7 +5597,7 @@ static void define_debug_regs(ARMCPU *cpu) + ARMCPRegInfo dbgdidr = { + .name = "DBGDIDR", .cp = 14, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL0_R, .accessfn = access_tda, +- .type = ARM_CP_CONST, .resetvalue = cpu->dbgdidr, ++ .type = ARM_CP_CONST, .resetvalue = cpu->isar.dbgdidr, + }; + + /* Note that all these register fields hold "number of Xs minus 1". */ +diff --git a/target/arm/internals.h b/target/arm/internals.h +index a72d0a6c..1d01ecc4 100644 +--- a/target/arm/internals.h ++++ b/target/arm/internals.h +@@ -867,7 +867,7 @@ static inline int arm_num_brps(ARMCPU *cpu) + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { + return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, BRPS) + 1; + } else { +- return FIELD_EX32(cpu->dbgdidr, DBGDIDR, BRPS) + 1; ++ return FIELD_EX32(cpu->isar.dbgdidr, DBGDIDR, BRPS) + 1; + } + } + +@@ -881,7 +881,7 @@ static inline int arm_num_wrps(ARMCPU *cpu) + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { + return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, WRPS) + 1; + } else { +- return FIELD_EX32(cpu->dbgdidr, DBGDIDR, WRPS) + 1; ++ return FIELD_EX32(cpu->isar.dbgdidr, DBGDIDR, WRPS) + 1; + } + } + +@@ -895,7 +895,7 @@ static inline int arm_num_ctx_cmps(ARMCPU *cpu) + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { + return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS) + 1; + } else { +- return FIELD_EX32(cpu->dbgdidr, DBGDIDR, CTX_CMPS) + 1; ++ return FIELD_EX32(cpu->isar.dbgdidr, DBGDIDR, CTX_CMPS) + 1; + } + } + +-- +2.25.1 + diff --git a/target-arm-Read-debug-related-ID-registers-from-KVM.patch b/target-arm-Read-debug-related-ID-registers-from-KVM.patch new file mode 100644 index 0000000000000000000000000000000000000000..1be7cd1713a456204efcb412c1d76398991ef77d --- /dev/null +++ b/target-arm-Read-debug-related-ID-registers-from-KVM.patch @@ -0,0 +1,131 @@ +From 9cda8af5af9e95e7b0ff683d0fb661c1ffcba8d8 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 14 Feb 2020 17:51:07 +0000 +Subject: [PATCH 11/13] target/arm: Read debug-related ID registers from KVM + +Now we have isar_feature test functions that look at fields in the +ID_AA64DFR0_EL1 and ID_DFR0 ID registers, add the code that reads +these register values from KVM so that the checks behave correctly +when we're using KVM. + +No isar_feature function tests ID_AA64DFR1_EL1 or DBGDIDR yet, but we +add it to maintain the invariant that every field in the +ARMISARegisters struct is populated for a KVM CPU and can be relied +on. This requirement isn't actually written down yet, so add a note +to the relevant comment. + +Signed-off-by: Peter Maydell +Reviewed-by: Richard Henderson +Message-id: 20200214175116.9164-13-peter.maydell@linaro.org +--- + target/arm/cpu.h | 5 +++++ + target/arm/kvm32.c | 8 ++++++++ + target/arm/kvm64.c | 36 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 49 insertions(+) + +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index a78c30c3..56d8cd8c 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -848,6 +848,11 @@ struct ARMCPU { + * prefix means a constant register. + * Some of these registers are split out into a substructure that + * is shared with the translators to control the ISA. ++ * ++ * Note that if you add an ID register to the ARMISARegisters struct ++ * you need to also update the 32-bit and 64-bit versions of the ++ * kvm_arm_get_host_cpu_features() function to correctly populate the ++ * field by reading the value from the KVM vCPU. + */ + struct ARMISARegisters { + uint32_t id_isar0; +diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c +index 2247148e..e984d52d 100644 +--- a/target/arm/kvm32.c ++++ b/target/arm/kvm32.c +@@ -93,6 +93,9 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + ahcf->isar.id_isar6 = 0; + } + ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr0, ++ ARM_CP15_REG32(0, 0, 1, 2)); ++ + err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr0, + KVM_REG_ARM | KVM_REG_SIZE_U32 | + KVM_REG_ARM_VFP | KVM_REG_ARM_VFP_MVFR0); +@@ -121,6 +124,11 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + ahcf->isar.id_mmfr4 = 0; + } + ++ /* ++ * There is no way to read DBGDIDR, because currently 32-bit KVM ++ * doesn't implement debug at all. Leave it at zero. ++ */ ++ + kvm_arm_destroy_scratch_host_vcpu(fdarray); + + if (err < 0) { +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 276d1466..2a88b8df 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -533,6 +533,10 @@ 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_aa64dfr0, ++ ARM64_SYS_REG(3, 0, 0, 5, 0)); ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr1, ++ ARM64_SYS_REG(3, 0, 0, 5, 1)); + err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar0, + ARM64_SYS_REG(3, 0, 0, 6, 0)); + err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar1, +@@ -551,6 +555,8 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + * than skipping the reads and leaving 0, as we must avoid + * considering the values in every case. + */ ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr0, ++ ARM64_SYS_REG(3, 0, 0, 1, 2)); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr0, + ARM64_SYS_REG(3, 0, 0, 1, 4)); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr1, +@@ -582,6 +588,36 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + ARM64_SYS_REG(3, 0, 0, 3, 1)); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr2, + ARM64_SYS_REG(3, 0, 0, 3, 2)); ++ ++ /* ++ * DBGDIDR is a bit complicated because the kernel doesn't ++ * provide an accessor for it in 64-bit mode, which is what this ++ * scratch VM is in, and there's no architected "64-bit sysreg ++ * which reads the same as the 32-bit register" the way there is ++ * for other ID registers. Instead we synthesize a value from the ++ * AArch64 ID_AA64DFR0, the same way the kernel code in ++ * arch/arm64/kvm/sys_regs.c:trap_dbgidr() does. ++ * We only do this if the CPU supports AArch32 at EL1. ++ */ ++ if (FIELD_EX32(ahcf->isar.id_aa64pfr0, ID_AA64PFR0, EL1) >= 2) { ++ int wrps = FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, WRPS); ++ int brps = FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, BRPS); ++ int ctx_cmps = ++ FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS); ++ int version = 6; /* ARMv8 debug architecture */ ++ bool has_el3 = ++ !!FIELD_EX32(ahcf->isar.id_aa64pfr0, ID_AA64PFR0, EL3); ++ uint32_t dbgdidr = 0; ++ ++ dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, WRPS, wrps); ++ dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, BRPS, brps); ++ dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, CTX_CMPS, ctx_cmps); ++ dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, VERSION, version); ++ dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, NSUHD_IMP, has_el3); ++ dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, SE_IMP, has_el3); ++ dbgdidr |= (1 << 15); /* RES1 bit */ ++ ahcf->isar.dbgdidr = dbgdidr; ++ } + } + + kvm_arm_destroy_scratch_host_vcpu(fdarray); +-- +2.25.1 + diff --git a/target-arm-Stop-assuming-DBGDIDR-always-exists.patch b/target-arm-Stop-assuming-DBGDIDR-always-exists.patch new file mode 100644 index 0000000000000000000000000000000000000000..c7648c5430ebd61b2267a184ad16828dd8d25015 --- /dev/null +++ b/target-arm-Stop-assuming-DBGDIDR-always-exists.patch @@ -0,0 +1,186 @@ +From 1d4d4cda9637ec09f8cf30785f68b58cd46815c8 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 14 Feb 2020 17:51:05 +0000 +Subject: [PATCH 07/13] target/arm: Stop assuming DBGDIDR always exists + +The AArch32 DBGDIDR defines properties like the number of +breakpoints, watchpoints and context-matching comparators. On an +AArch64 CPU, the register may not even exist if AArch32 is not +supported at EL1. + +Currently we hard-code use of DBGDIDR to identify the number of +breakpoints etc; this works for all our TCG CPUs, but will break if +we ever add an AArch64-only CPU. We also have an assert() that the +AArch32 and AArch64 registers match, which currently works only by +luck for KVM because we don't populate either of these ID registers +from the KVM vCPU and so they are both zero. + +Clean this up so we have functions for finding the number +of breakpoints, watchpoints and context comparators which look +in the appropriate ID register. + +This allows us to drop the "check that AArch64 and AArch32 agree +on the number of breakpoints etc" asserts: + * we no longer look at the AArch32 versions unless that's the + right place to be looking + * it's valid to have a CPU (eg AArch64-only) where they don't match + * we shouldn't have been asserting the validity of ID registers + in a codepath used with KVM anyway + +Signed-off-by: Peter Maydell +Reviewed-by: Richard Henderson +Message-id: 20200214175116.9164-11-peter.maydell@linaro.org +--- + target/arm/cpu.h | 7 +++++++ + target/arm/debug_helper.c | 6 +++--- + target/arm/helper.c | 21 +++++--------------- + target/arm/internals.h | 42 +++++++++++++++++++++++++++++++++++++++ + 4 files changed, 57 insertions(+), 19 deletions(-) + +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 230130be..4b1ae32b 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -1798,6 +1798,13 @@ FIELD(ID_DFR0, MPROFDBG, 20, 4) + FIELD(ID_DFR0, PERFMON, 24, 4) + FIELD(ID_DFR0, TRACEFILT, 28, 4) + ++FIELD(DBGDIDR, SE_IMP, 12, 1) ++FIELD(DBGDIDR, NSUHD_IMP, 14, 1) ++FIELD(DBGDIDR, VERSION, 16, 4) ++FIELD(DBGDIDR, CTX_CMPS, 20, 4) ++FIELD(DBGDIDR, BRPS, 24, 4) ++FIELD(DBGDIDR, WRPS, 28, 4) ++ + FIELD(MVFR0, SIMDREG, 0, 4) + FIELD(MVFR0, FPSP, 4, 4) + FIELD(MVFR0, FPDP, 8, 4) +diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c +index dde80273..3f8f667d 100644 +--- a/target/arm/debug_helper.c ++++ b/target/arm/debug_helper.c +@@ -16,8 +16,8 @@ static bool linked_bp_matches(ARMCPU *cpu, int lbn) + { + CPUARMState *env = &cpu->env; + uint64_t bcr = env->cp15.dbgbcr[lbn]; +- int brps = extract32(cpu->dbgdidr, 24, 4); +- int ctx_cmps = extract32(cpu->dbgdidr, 20, 4); ++ int brps = arm_num_brps(cpu); ++ int ctx_cmps = arm_num_ctx_cmps(cpu); + int bt; + uint32_t contextidr; + +@@ -28,7 +28,7 @@ static bool linked_bp_matches(ARMCPU *cpu, int lbn) + * case DBGWCR_EL1.LBN must indicate that breakpoint). + * We choose the former. + */ +- if (lbn > brps || lbn < (brps - ctx_cmps)) { ++ if (lbn >= brps || lbn < (brps - ctx_cmps)) { + return false; + } + +diff --git a/target/arm/helper.c b/target/arm/helper.c +index a71f4ef6..c1ff4b6b 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -5601,23 +5601,12 @@ static void define_debug_regs(ARMCPU *cpu) + }; + + /* Note that all these register fields hold "number of Xs minus 1". */ +- brps = extract32(cpu->dbgdidr, 24, 4); +- wrps = extract32(cpu->dbgdidr, 28, 4); +- ctx_cmps = extract32(cpu->dbgdidr, 20, 4); ++ brps = arm_num_brps(cpu); ++ wrps = arm_num_wrps(cpu); ++ ctx_cmps = arm_num_ctx_cmps(cpu); + + assert(ctx_cmps <= brps); + +- /* The DBGDIDR and ID_AA64DFR0_EL1 define various properties +- * of the debug registers such as number of breakpoints; +- * check that if they both exist then they agree. +- */ +- if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { +- assert(FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, BRPS) == brps); +- assert(FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, WRPS) == wrps); +- assert(FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS) +- == ctx_cmps); +- } +- + define_one_arm_cp_reg(cpu, &dbgdidr); + define_arm_cp_regs(cpu, debug_cp_reginfo); + +@@ -5625,7 +5614,7 @@ static void define_debug_regs(ARMCPU *cpu) + define_arm_cp_regs(cpu, debug_lpae_cp_reginfo); + } + +- for (i = 0; i < brps + 1; i++) { ++ for (i = 0; i < brps; i++) { + ARMCPRegInfo dbgregs[] = { + { .name = "DBGBVR", .state = ARM_CP_STATE_BOTH, + .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 4, +@@ -5644,7 +5633,7 @@ static void define_debug_regs(ARMCPU *cpu) + define_arm_cp_regs(cpu, dbgregs); + } + +- for (i = 0; i < wrps + 1; i++) { ++ for (i = 0; i < wrps; i++) { + ARMCPRegInfo dbgregs[] = { + { .name = "DBGWVR", .state = ARM_CP_STATE_BOTH, + .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 6, +diff --git a/target/arm/internals.h b/target/arm/internals.h +index 232d9638..a72d0a6c 100644 +--- a/target/arm/internals.h ++++ b/target/arm/internals.h +@@ -857,6 +857,48 @@ static inline uint32_t arm_debug_exception_fsr(CPUARMState *env) + } + } + ++/** ++ * arm_num_brps: Return number of implemented breakpoints. ++ * Note that the ID register BRPS field is "number of bps - 1", ++ * and we return the actual number of breakpoints. ++ */ ++static inline int arm_num_brps(ARMCPU *cpu) ++{ ++ if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { ++ return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, BRPS) + 1; ++ } else { ++ return FIELD_EX32(cpu->dbgdidr, DBGDIDR, BRPS) + 1; ++ } ++} ++ ++/** ++ * arm_num_wrps: Return number of implemented watchpoints. ++ * Note that the ID register WRPS field is "number of wps - 1", ++ * and we return the actual number of watchpoints. ++ */ ++static inline int arm_num_wrps(ARMCPU *cpu) ++{ ++ if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { ++ return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, WRPS) + 1; ++ } else { ++ return FIELD_EX32(cpu->dbgdidr, DBGDIDR, WRPS) + 1; ++ } ++} ++ ++/** ++ * arm_num_ctx_cmps: Return number of implemented context comparators. ++ * Note that the ID register CTX_CMPS field is "number of cmps - 1", ++ * and we return the actual number of comparators. ++ */ ++static inline int arm_num_ctx_cmps(ARMCPU *cpu) ++{ ++ if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { ++ return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS) + 1; ++ } else { ++ return FIELD_EX32(cpu->dbgdidr, DBGDIDR, CTX_CMPS) + 1; ++ } ++} ++ + /* Note make_memop_idx reserves 4 bits for mmu_idx, and MO_BSWAP is bit 3. + * Thus a TCGMemOpIdx, without any MO_ALIGN bits, fits in 8 bits. + */ +-- +2.25.1 + diff --git a/target-arm-Test-correct-register-in-aa32_pan-and-aa3.patch b/target-arm-Test-correct-register-in-aa32_pan-and-aa3.patch new file mode 100644 index 0000000000000000000000000000000000000000..ecbaf7750c42aab1efade6d50e53fd7e92762883 --- /dev/null +++ b/target-arm-Test-correct-register-in-aa32_pan-and-aa3.patch @@ -0,0 +1,453 @@ +From 2bc630dc858bd0c010b7c375ebf1e8f4b4e0e346 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 14 Feb 2020 17:51:13 +0000 +Subject: [PATCH 10/13] target/arm: Test correct register in aa32_pan and + aa32_ats1e1 checks + +The isar_feature_aa32_pan and isar_feature_aa32_ats1e1 functions +are supposed to be testing fields in ID_MMFR3; but a cut-and-paste +error meant we were looking at MVFR0 instead. + +Fix the functions to look at the right register; this requires +us to move at least id_mmfr3 to the ARMISARegisters struct; we +choose to move all the ID_MMFRn registers for consistency. + +Fixes: 3d6ad6bb466f +Signed-off-by: Peter Maydell +Reviewed-by: Richard Henderson +Message-id: 20200214175116.9164-19-peter.maydell@linaro.org +--- + hw/intc/armv7m_nvic.c | 8 ++-- + target/arm/cpu.c | 96 +++++++++++++++++++++---------------------- + target/arm/cpu.h | 14 +++---- + target/arm/cpu64.c | 28 ++++++------- + target/arm/helper.c | 12 +++--- + target/arm/kvm32.c | 17 ++++++++ + target/arm/kvm64.c | 10 +++++ + 7 files changed, 106 insertions(+), 79 deletions(-) + +diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c +index 0741db7b..f7ef6ad1 100644 +--- a/hw/intc/armv7m_nvic.c ++++ b/hw/intc/armv7m_nvic.c +@@ -1227,13 +1227,13 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) + case 0xd4c: /* AFR0. */ + return cpu->id_afr0; + case 0xd50: /* MMFR0. */ +- return cpu->id_mmfr0; ++ return cpu->isar.id_mmfr0; + case 0xd54: /* MMFR1. */ +- return cpu->id_mmfr1; ++ return cpu->isar.id_mmfr1; + case 0xd58: /* MMFR2. */ +- return cpu->id_mmfr2; ++ return cpu->isar.id_mmfr2; + case 0xd5c: /* MMFR3. */ +- return cpu->id_mmfr3; ++ return cpu->isar.id_mmfr3; + case 0xd60: /* ISAR0. */ + return cpu->isar.id_isar0; + case 0xd64: /* ISAR1. */ +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 119bd275..c3728e3d 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1764,9 +1764,9 @@ static void arm1136_r2_initfn(Object *obj) + cpu->id_pfr1 = 0x1; + cpu->isar.id_dfr0 = 0x2; + cpu->id_afr0 = 0x3; +- cpu->id_mmfr0 = 0x01130003; +- cpu->id_mmfr1 = 0x10030302; +- cpu->id_mmfr2 = 0x01222110; ++ cpu->isar.id_mmfr0 = 0x01130003; ++ cpu->isar.id_mmfr1 = 0x10030302; ++ cpu->isar.id_mmfr2 = 0x01222110; + cpu->isar.id_isar0 = 0x00140011; + cpu->isar.id_isar1 = 0x12002111; + cpu->isar.id_isar2 = 0x11231111; +@@ -1796,9 +1796,9 @@ static void arm1136_initfn(Object *obj) + cpu->id_pfr1 = 0x1; + cpu->isar.id_dfr0 = 0x2; + cpu->id_afr0 = 0x3; +- cpu->id_mmfr0 = 0x01130003; +- cpu->id_mmfr1 = 0x10030302; +- cpu->id_mmfr2 = 0x01222110; ++ cpu->isar.id_mmfr0 = 0x01130003; ++ cpu->isar.id_mmfr1 = 0x10030302; ++ cpu->isar.id_mmfr2 = 0x01222110; + cpu->isar.id_isar0 = 0x00140011; + cpu->isar.id_isar1 = 0x12002111; + cpu->isar.id_isar2 = 0x11231111; +@@ -1829,9 +1829,9 @@ static void arm1176_initfn(Object *obj) + cpu->id_pfr1 = 0x11; + cpu->isar.id_dfr0 = 0x33; + cpu->id_afr0 = 0; +- cpu->id_mmfr0 = 0x01130003; +- cpu->id_mmfr1 = 0x10030302; +- cpu->id_mmfr2 = 0x01222100; ++ cpu->isar.id_mmfr0 = 0x01130003; ++ cpu->isar.id_mmfr1 = 0x10030302; ++ cpu->isar.id_mmfr2 = 0x01222100; + cpu->isar.id_isar0 = 0x0140011; + cpu->isar.id_isar1 = 0x12002111; + cpu->isar.id_isar2 = 0x11231121; +@@ -1859,9 +1859,9 @@ static void arm11mpcore_initfn(Object *obj) + cpu->id_pfr1 = 0x1; + cpu->isar.id_dfr0 = 0; + cpu->id_afr0 = 0x2; +- cpu->id_mmfr0 = 0x01100103; +- cpu->id_mmfr1 = 0x10020302; +- cpu->id_mmfr2 = 0x01222000; ++ cpu->isar.id_mmfr0 = 0x01100103; ++ cpu->isar.id_mmfr1 = 0x10020302; ++ cpu->isar.id_mmfr2 = 0x01222000; + cpu->isar.id_isar0 = 0x00100011; + cpu->isar.id_isar1 = 0x12002111; + cpu->isar.id_isar2 = 0x11221011; +@@ -1891,10 +1891,10 @@ static void cortex_m3_initfn(Object *obj) + cpu->id_pfr1 = 0x00000200; + cpu->isar.id_dfr0 = 0x00100000; + cpu->id_afr0 = 0x00000000; +- cpu->id_mmfr0 = 0x00000030; +- cpu->id_mmfr1 = 0x00000000; +- cpu->id_mmfr2 = 0x00000000; +- cpu->id_mmfr3 = 0x00000000; ++ cpu->isar.id_mmfr0 = 0x00000030; ++ cpu->isar.id_mmfr1 = 0x00000000; ++ cpu->isar.id_mmfr2 = 0x00000000; ++ cpu->isar.id_mmfr3 = 0x00000000; + cpu->isar.id_isar0 = 0x01141110; + cpu->isar.id_isar1 = 0x02111000; + cpu->isar.id_isar2 = 0x21112231; +@@ -1922,10 +1922,10 @@ static void cortex_m4_initfn(Object *obj) + cpu->id_pfr1 = 0x00000200; + cpu->isar.id_dfr0 = 0x00100000; + cpu->id_afr0 = 0x00000000; +- cpu->id_mmfr0 = 0x00000030; +- cpu->id_mmfr1 = 0x00000000; +- cpu->id_mmfr2 = 0x00000000; +- cpu->id_mmfr3 = 0x00000000; ++ cpu->isar.id_mmfr0 = 0x00000030; ++ cpu->isar.id_mmfr1 = 0x00000000; ++ cpu->isar.id_mmfr2 = 0x00000000; ++ cpu->isar.id_mmfr3 = 0x00000000; + cpu->isar.id_isar0 = 0x01141110; + cpu->isar.id_isar1 = 0x02111000; + cpu->isar.id_isar2 = 0x21112231; +@@ -1955,10 +1955,10 @@ static void cortex_m33_initfn(Object *obj) + cpu->id_pfr1 = 0x00000210; + cpu->isar.id_dfr0 = 0x00200000; + cpu->id_afr0 = 0x00000000; +- cpu->id_mmfr0 = 0x00101F40; +- cpu->id_mmfr1 = 0x00000000; +- cpu->id_mmfr2 = 0x01000000; +- cpu->id_mmfr3 = 0x00000000; ++ cpu->isar.id_mmfr0 = 0x00101F40; ++ cpu->isar.id_mmfr1 = 0x00000000; ++ cpu->isar.id_mmfr2 = 0x01000000; ++ cpu->isar.id_mmfr3 = 0x00000000; + cpu->isar.id_isar0 = 0x01101110; + cpu->isar.id_isar1 = 0x02212000; + cpu->isar.id_isar2 = 0x20232232; +@@ -2006,10 +2006,10 @@ static void cortex_r5_initfn(Object *obj) + cpu->id_pfr1 = 0x001; + cpu->isar.id_dfr0 = 0x010400; + cpu->id_afr0 = 0x0; +- cpu->id_mmfr0 = 0x0210030; +- cpu->id_mmfr1 = 0x00000000; +- cpu->id_mmfr2 = 0x01200000; +- cpu->id_mmfr3 = 0x0211; ++ cpu->isar.id_mmfr0 = 0x0210030; ++ cpu->isar.id_mmfr1 = 0x00000000; ++ cpu->isar.id_mmfr2 = 0x01200000; ++ cpu->isar.id_mmfr3 = 0x0211; + cpu->isar.id_isar0 = 0x02101111; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232141; +@@ -2061,10 +2061,10 @@ static void cortex_a8_initfn(Object *obj) + cpu->id_pfr1 = 0x11; + cpu->isar.id_dfr0 = 0x400; + cpu->id_afr0 = 0; +- cpu->id_mmfr0 = 0x31100003; +- cpu->id_mmfr1 = 0x20000000; +- cpu->id_mmfr2 = 0x01202000; +- cpu->id_mmfr3 = 0x11; ++ cpu->isar.id_mmfr0 = 0x31100003; ++ cpu->isar.id_mmfr1 = 0x20000000; ++ cpu->isar.id_mmfr2 = 0x01202000; ++ cpu->isar.id_mmfr3 = 0x11; + cpu->isar.id_isar0 = 0x00101111; + cpu->isar.id_isar1 = 0x12112111; + cpu->isar.id_isar2 = 0x21232031; +@@ -2134,10 +2134,10 @@ static void cortex_a9_initfn(Object *obj) + cpu->id_pfr1 = 0x11; + cpu->isar.id_dfr0 = 0x000; + cpu->id_afr0 = 0; +- cpu->id_mmfr0 = 0x00100103; +- cpu->id_mmfr1 = 0x20000000; +- cpu->id_mmfr2 = 0x01230000; +- cpu->id_mmfr3 = 0x00002111; ++ cpu->isar.id_mmfr0 = 0x00100103; ++ cpu->isar.id_mmfr1 = 0x20000000; ++ cpu->isar.id_mmfr2 = 0x01230000; ++ cpu->isar.id_mmfr3 = 0x00002111; + cpu->isar.id_isar0 = 0x00101111; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232041; +@@ -2199,10 +2199,10 @@ static void cortex_a7_initfn(Object *obj) + cpu->id_pfr1 = 0x00011011; + cpu->isar.id_dfr0 = 0x02010555; + cpu->id_afr0 = 0x00000000; +- cpu->id_mmfr0 = 0x10101105; +- cpu->id_mmfr1 = 0x40000000; +- cpu->id_mmfr2 = 0x01240000; +- cpu->id_mmfr3 = 0x02102211; ++ cpu->isar.id_mmfr0 = 0x10101105; ++ cpu->isar.id_mmfr1 = 0x40000000; ++ cpu->isar.id_mmfr2 = 0x01240000; ++ cpu->isar.id_mmfr3 = 0x02102211; + /* a7_mpcore_r0p5_trm, page 4-4 gives 0x01101110; but + * table 4-41 gives 0x02101110, which includes the arm div insns. + */ +@@ -2245,10 +2245,10 @@ static void cortex_a15_initfn(Object *obj) + cpu->id_pfr1 = 0x00011011; + cpu->isar.id_dfr0 = 0x02010555; + cpu->id_afr0 = 0x00000000; +- cpu->id_mmfr0 = 0x10201105; +- cpu->id_mmfr1 = 0x20000000; +- cpu->id_mmfr2 = 0x01240000; +- cpu->id_mmfr3 = 0x02102211; ++ cpu->isar.id_mmfr0 = 0x10201105; ++ cpu->isar.id_mmfr1 = 0x20000000; ++ cpu->isar.id_mmfr2 = 0x01240000; ++ cpu->isar.id_mmfr3 = 0x02102211; + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232041; +@@ -2484,13 +2484,13 @@ static void arm_max_initfn(Object *obj) + t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ + cpu->isar.mvfr2 = t; + +- t = cpu->id_mmfr3; ++ t = cpu->isar.id_mmfr3; + t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */ +- cpu->id_mmfr3 = t; ++ cpu->isar.id_mmfr3 = t; + +- t = cpu->id_mmfr4; ++ t = cpu->isar.id_mmfr4; + t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ +- cpu->id_mmfr4 = t; ++ cpu->isar.id_mmfr4 = t; + } + #endif + } +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 3040aa40..a78c30c3 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -857,6 +857,11 @@ struct ARMCPU { + uint32_t id_isar4; + uint32_t id_isar5; + uint32_t id_isar6; ++ uint32_t id_mmfr0; ++ uint32_t id_mmfr1; ++ uint32_t id_mmfr2; ++ uint32_t id_mmfr3; ++ uint32_t id_mmfr4; + uint32_t mvfr0; + uint32_t mvfr1; + uint32_t mvfr2; +@@ -882,11 +887,6 @@ struct ARMCPU { + uint64_t pmceid0; + uint64_t pmceid1; + uint32_t id_afr0; +- uint32_t id_mmfr0; +- uint32_t id_mmfr1; +- uint32_t id_mmfr2; +- uint32_t id_mmfr3; +- uint32_t id_mmfr4; + uint64_t id_aa64afr0; + uint64_t id_aa64afr1; + uint32_t clidr; +@@ -3490,12 +3490,12 @@ static inline bool isar_feature_aa32_vminmaxnm(const ARMISARegisters *id) + + static inline bool isar_feature_aa32_pan(const ARMISARegisters *id) + { +- return FIELD_EX64(id->mvfr0, ID_MMFR3, PAN) != 0; ++ return FIELD_EX32(id->id_mmfr3, ID_MMFR3, PAN) != 0; + } + + static inline bool isar_feature_aa32_ats1e1(const ARMISARegisters *id) + { +- return FIELD_EX64(id->mvfr0, ID_MMFR3, PAN) >= 2; ++ return FIELD_EX32(id->id_mmfr3, ID_MMFR3, PAN) >= 2; + } + + static inline bool isar_feature_aa32_pmu_8_1(const ARMISARegisters *id) +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index a0d07fd7..d450b8c8 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -125,10 +125,10 @@ static void aarch64_a57_initfn(Object *obj) + cpu->id_pfr1 = 0x00011011; + cpu->isar.id_dfr0 = 0x03010066; + cpu->id_afr0 = 0x00000000; +- cpu->id_mmfr0 = 0x10101105; +- cpu->id_mmfr1 = 0x40000000; +- cpu->id_mmfr2 = 0x01260000; +- cpu->id_mmfr3 = 0x02102211; ++ 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; +@@ -179,10 +179,10 @@ static void aarch64_a53_initfn(Object *obj) + cpu->id_pfr1 = 0x00011011; + cpu->isar.id_dfr0 = 0x03010066; + cpu->id_afr0 = 0x00000000; +- cpu->id_mmfr0 = 0x10101105; +- cpu->id_mmfr1 = 0x40000000; +- cpu->id_mmfr2 = 0x01260000; +- cpu->id_mmfr3 = 0x02102211; ++ 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; +@@ -233,10 +233,10 @@ static void aarch64_a72_initfn(Object *obj) + cpu->id_pfr1 = 0x00011011; + cpu->isar.id_dfr0 = 0x03010066; + cpu->id_afr0 = 0x00000000; +- cpu->id_mmfr0 = 0x10201105; +- cpu->id_mmfr1 = 0x40000000; +- cpu->id_mmfr2 = 0x01260000; +- cpu->id_mmfr3 = 0x02102211; ++ cpu->isar.id_mmfr0 = 0x10201105; ++ 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; +@@ -383,9 +383,9 @@ static void aarch64_max_initfn(Object *obj) + u = FIELD_DP32(u, ID_ISAR6, SPECRES, 1); + cpu->isar.id_isar6 = u; + +- u = cpu->id_mmfr3; ++ u = cpu->isar.id_mmfr3; + u = FIELD_DP32(u, ID_MMFR3, PAN, 2); /* ATS1E1 */ +- cpu->id_mmfr3 = u; ++ cpu->isar.id_mmfr3 = u; + + /* + * FIXME: We do not yet support ARMv8.2-fp16 for AArch32 yet, +diff --git a/target/arm/helper.c b/target/arm/helper.c +index 60ff7c0f..49cd7a7e 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -5906,19 +5906,19 @@ void register_cp_regs_for_features(ARMCPU *cpu) + { .name = "ID_MMFR0", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 4, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->id_mmfr0 }, ++ .resetvalue = cpu->isar.id_mmfr0 }, + { .name = "ID_MMFR1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 5, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->id_mmfr1 }, ++ .resetvalue = cpu->isar.id_mmfr1 }, + { .name = "ID_MMFR2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 6, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->id_mmfr2 }, ++ .resetvalue = cpu->isar.id_mmfr2 }, + { .name = "ID_MMFR3", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 7, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->id_mmfr3 }, ++ .resetvalue = cpu->isar.id_mmfr3 }, + { .name = "ID_ISAR0", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, +@@ -5946,7 +5946,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + { .name = "ID_MMFR4", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 6, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->id_mmfr4 }, ++ .resetvalue = cpu->isar.id_mmfr4 }, + { .name = "ID_ISAR6", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 7, + .access = PL1_R, .type = ARM_CP_CONST, +@@ -6426,7 +6426,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + define_arm_cp_regs(cpu, vmsa_pmsa_cp_reginfo); + define_arm_cp_regs(cpu, vmsa_cp_reginfo); + /* TTCBR2 is introduced with ARMv8.2-A32HPD. */ +- if (FIELD_EX32(cpu->id_mmfr4, ID_MMFR4, HPDS) != 0) { ++ if (FIELD_EX32(cpu->isar.id_mmfr4, ID_MMFR4, HPDS) != 0) { + define_one_arm_cp_reg(cpu, &ttbcr2_reginfo); + } + } +diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c +index ee158830..2247148e 100644 +--- a/target/arm/kvm32.c ++++ b/target/arm/kvm32.c +@@ -104,6 +104,23 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + * Fortunately there is not yet anything in there that affects migration. + */ + ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr0, ++ ARM_CP15_REG32(0, 0, 1, 4)); ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr1, ++ ARM_CP15_REG32(0, 0, 1, 5)); ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr2, ++ ARM_CP15_REG32(0, 0, 1, 6)); ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr3, ++ ARM_CP15_REG32(0, 0, 1, 7)); ++ if (read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr4, ++ ARM_CP15_REG32(0, 0, 2, 6))) { ++ /* ++ * Older kernels don't support reading ID_MMFR4 (a new in v8 ++ * register); assume it's zero. ++ */ ++ ahcf->isar.id_mmfr4 = 0; ++ } ++ + kvm_arm_destroy_scratch_host_vcpu(fdarray); + + if (err < 0) { +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index b794108a..276d1466 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -551,6 +551,14 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + * than skipping the reads and leaving 0, as we must avoid + * considering the values in every case. + */ ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr0, ++ ARM64_SYS_REG(3, 0, 0, 1, 4)); ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr1, ++ ARM64_SYS_REG(3, 0, 0, 1, 5)); ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr2, ++ ARM64_SYS_REG(3, 0, 0, 1, 6)); ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr3, ++ ARM64_SYS_REG(3, 0, 0, 1, 7)); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar0, + ARM64_SYS_REG(3, 0, 0, 2, 0)); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar1, +@@ -563,6 +571,8 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + ARM64_SYS_REG(3, 0, 0, 2, 4)); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar5, + ARM64_SYS_REG(3, 0, 0, 2, 5)); ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr4, ++ ARM64_SYS_REG(3, 0, 0, 2, 6)); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar6, + ARM64_SYS_REG(3, 0, 0, 2, 7)); + +-- +2.25.1 + diff --git a/target-arm-Update-ID-fields.patch b/target-arm-Update-ID-fields.patch new file mode 100644 index 0000000000000000000000000000000000000000..94ed8027c9e238f384e767bc88c209749eee234e --- /dev/null +++ b/target-arm-Update-ID-fields.patch @@ -0,0 +1,84 @@ +From 47c76d73a435884b66ce6417cb853893099be5eb Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Tue, 11 Aug 2020 10:18:57 +0800 +Subject: [PATCH 8/9] target/arm: Update ID fields + +Update definitions for ID fields, up to ARMv8.6. + +Signed-off-by: zhanghailiang +Signed-off-by: Peng Liang +--- + target/arm/cpu.h | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 068c3fa2..eb875e11 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -1691,6 +1691,8 @@ FIELD(ID_ISAR6, DP, 4, 4) + FIELD(ID_ISAR6, FHM, 8, 4) + FIELD(ID_ISAR6, SB, 12, 4) + FIELD(ID_ISAR6, SPECRES, 16, 4) ++FIELD(ID_ISAR6, BF16, 20, 4) ++FIELD(ID_ISAR6, I8MM, 24, 4) + + FIELD(ID_MMFR3, CMAINTVA, 0, 4) + FIELD(ID_MMFR3, CMAINTSW, 4, 4) +@@ -1736,6 +1738,9 @@ FIELD(ID_AA64ISAR1, GPI, 28, 4) + FIELD(ID_AA64ISAR1, FRINTTS, 32, 4) + FIELD(ID_AA64ISAR1, SB, 36, 4) + FIELD(ID_AA64ISAR1, SPECRES, 40, 4) ++FIELD(ID_AA64ISAR1, BF16, 44, 4) ++FIELD(ID_AA64ISAR1, DGH, 48, 4) ++FIELD(ID_AA64ISAR1, I8MM, 52, 4) + + FIELD(ID_AA64PFR0, EL0, 0, 4) + FIELD(ID_AA64PFR0, EL1, 4, 4) +@@ -1746,11 +1751,18 @@ FIELD(ID_AA64PFR0, ADVSIMD, 20, 4) + FIELD(ID_AA64PFR0, GIC, 24, 4) + FIELD(ID_AA64PFR0, RAS, 28, 4) + FIELD(ID_AA64PFR0, SVE, 32, 4) ++FIELD(ID_AA64PFR0, SEL2, 36, 4) ++FIELD(ID_AA64PFR0, MPAM, 40, 4) ++FIELD(ID_AA64PFR0, AMU, 44, 4) ++FIELD(ID_AA64PFR0, DIT, 44, 4) ++FIELD(ID_AA64PFR0, CSV2, 56, 4) ++FIELD(ID_AA64PFR0, CSV3, 60, 4) + + FIELD(ID_AA64PFR1, BT, 0, 4) + FIELD(ID_AA64PFR1, SBSS, 4, 4) + FIELD(ID_AA64PFR1, MTE, 8, 4) + FIELD(ID_AA64PFR1, RAS_FRAC, 12, 4) ++FIELD(ID_AA64PFR1, MPAM_FRAC, 16, 4) + + FIELD(ID_AA64MMFR0, PARANGE, 0, 4) + FIELD(ID_AA64MMFR0, ASIDBITS, 4, 4) +@@ -1764,6 +1776,8 @@ FIELD(ID_AA64MMFR0, TGRAN16_2, 32, 4) + FIELD(ID_AA64MMFR0, TGRAN64_2, 36, 4) + FIELD(ID_AA64MMFR0, TGRAN4_2, 40, 4) + FIELD(ID_AA64MMFR0, EXS, 44, 4) ++FIELD(ID_AA64MMFR0, FGT, 56, 4) ++FIELD(ID_AA64MMFR0, ECV, 60, 4) + + FIELD(ID_AA64MMFR1, HAFDBS, 0, 4) + FIELD(ID_AA64MMFR1, VMIDBITS, 4, 4) +@@ -1773,6 +1787,8 @@ FIELD(ID_AA64MMFR1, LO, 16, 4) + FIELD(ID_AA64MMFR1, PAN, 20, 4) + FIELD(ID_AA64MMFR1, SPECSEI, 24, 4) + FIELD(ID_AA64MMFR1, XNX, 28, 4) ++FIELD(ID_AA64MMFR1, TWED, 32, 4) ++FIELD(ID_AA64MMFR1, ETS, 36, 4) + + FIELD(ID_AA64MMFR2, CNP, 0, 4) + FIELD(ID_AA64MMFR2, UAO, 4, 4) +@@ -1799,6 +1815,7 @@ FIELD(ID_AA64DFR0, CTX_CMPS, 28, 4) + FIELD(ID_AA64DFR0, PMSVER, 32, 4) + FIELD(ID_AA64DFR0, DOUBLELOCK, 36, 4) + FIELD(ID_AA64DFR0, TRACEFILT, 40, 4) ++FIELD(ID_AA64DFR0, MUPMU, 48, 4) + + FIELD(ID_DFR0, COPDBG, 0, 4) + FIELD(ID_DFR0, COPSDBG, 4, 4) +-- +2.25.1 + diff --git a/target-arm-Use-FIELD-macros-for-clearing-ID_DFR0-PER.patch b/target-arm-Use-FIELD-macros-for-clearing-ID_DFR0-PER.patch new file mode 100644 index 0000000000000000000000000000000000000000..0e32f85104cb492dba2d0e72aa6138342ef960db --- /dev/null +++ b/target-arm-Use-FIELD-macros-for-clearing-ID_DFR0-PER.patch @@ -0,0 +1,36 @@ +From f54cdca97bf86f5ca1df8471bc229b89797b287e Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 14 Feb 2020 17:51:02 +0000 +Subject: [PATCH 04/13] target/arm: Use FIELD macros for clearing ID_DFR0 + PERFMON field +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We already define FIELD macros for ID_DFR0, so use them in the +one place where we're doing direct bit value manipulation. + +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Richard Henderson +Signed-off-by: Peter Maydell +Message-id: 20200214175116.9164-8-peter.maydell@linaro.org +--- + target/arm/cpu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index dbd05e01..6ad211b1 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1523,7 +1523,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + #endif + } else { + cpu->id_aa64dfr0 = FIELD_DP64(cpu->id_aa64dfr0, ID_AA64DFR0, PMUVER, 0); +- cpu->id_dfr0 &= ~(0xf << 24); ++ cpu->id_dfr0 = FIELD_DP32(cpu->id_dfr0, ID_DFR0, PERFMON, 0); + cpu->pmceid0 = 0; + cpu->pmceid1 = 0; + } +-- +2.25.1 + diff --git a/target-arm-convert-isar-regs-to-array.patch b/target-arm-convert-isar-regs-to-array.patch new file mode 100644 index 0000000000000000000000000000000000000000..528371212aad42f034db62858b1a2da2cdcba79d --- /dev/null +++ b/target-arm-convert-isar-regs-to-array.patch @@ -0,0 +1,1908 @@ +From ac92f0f7bbf7cf063ba45fbfaf7e7970dd76544a Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Thu, 6 Aug 2020 16:14:25 +0800 +Subject: [PATCH 1/9] target/arm: convert isar regs to array + +The isar in ARMCPU is a struct, each field of which represents an ID +register. It's not convenient for us to support CPU feature in AArch64. +So let's change it to an array first and add an enum as the index of the +array for convenience. Since we will never access high 32-bits of ID +registers in AArch32, it's harmless to change the ID registers in +AArch32 to 64-bits. + +Signed-off-by: zhanghailiang +Signed-off-by: Peng Liang +--- + hw/intc/armv7m_nvic.c | 28 +-- + target/arm/cpu.c | 440 +++++++++++++++++++++-------------------- + target/arm/cpu.h | 178 +++++++++-------- + target/arm/cpu64.c | 158 +++++++-------- + target/arm/helper.c | 54 ++--- + target/arm/internals.h | 15 +- + target/arm/kvm64.c | 68 +++---- + 7 files changed, 478 insertions(+), 463 deletions(-) + +diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c +index f7ef6ad1..5013ec97 100644 +--- a/hw/intc/armv7m_nvic.c ++++ b/hw/intc/armv7m_nvic.c +@@ -1223,29 +1223,29 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) + case 0xd44: /* PFR1. */ + return cpu->id_pfr1; + case 0xd48: /* DFR0. */ +- return cpu->isar.id_dfr0; ++ return cpu->isar.regs[ID_DFR0]; + case 0xd4c: /* AFR0. */ + return cpu->id_afr0; + case 0xd50: /* MMFR0. */ +- return cpu->isar.id_mmfr0; ++ return cpu->isar.regs[ID_MMFR0]; + case 0xd54: /* MMFR1. */ +- return cpu->isar.id_mmfr1; ++ return cpu->isar.regs[ID_MMFR1]; + case 0xd58: /* MMFR2. */ +- return cpu->isar.id_mmfr2; ++ return cpu->isar.regs[ID_MMFR2]; + case 0xd5c: /* MMFR3. */ +- return cpu->isar.id_mmfr3; ++ return cpu->isar.regs[ID_MMFR3]; + case 0xd60: /* ISAR0. */ +- return cpu->isar.id_isar0; ++ return cpu->isar.regs[ID_ISAR0]; + case 0xd64: /* ISAR1. */ +- return cpu->isar.id_isar1; ++ return cpu->isar.regs[ID_ISAR1]; + case 0xd68: /* ISAR2. */ +- return cpu->isar.id_isar2; ++ return cpu->isar.regs[ID_ISAR2]; + case 0xd6c: /* ISAR3. */ +- return cpu->isar.id_isar3; ++ return cpu->isar.regs[ID_ISAR3]; + case 0xd70: /* ISAR4. */ +- return cpu->isar.id_isar4; ++ return cpu->isar.regs[ID_ISAR4]; + case 0xd74: /* ISAR5. */ +- return cpu->isar.id_isar5; ++ return cpu->isar.regs[ID_ISAR5]; + case 0xd78: /* CLIDR */ + return cpu->clidr; + case 0xd7c: /* CTR */ +@@ -1450,11 +1450,11 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) + } + return cpu->env.v7m.fpdscr[attrs.secure]; + case 0xf40: /* MVFR0 */ +- return cpu->isar.mvfr0; ++ return cpu->isar.regs[MVFR0]; + case 0xf44: /* MVFR1 */ +- return cpu->isar.mvfr1; ++ return cpu->isar.regs[MVFR1]; + case 0xf48: /* MVFR2 */ +- return cpu->isar.mvfr2; ++ return cpu->isar.regs[MVFR2]; + default: + bad_offset: + qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset); +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index c3728e3d..5bcdad0c 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -170,9 +170,9 @@ static void arm_cpu_reset(CPUState *s) + g_hash_table_foreach(cpu->cp_regs, cp_reg_check_reset, cpu); + + env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid; +- env->vfp.xregs[ARM_VFP_MVFR0] = cpu->isar.mvfr0; +- env->vfp.xregs[ARM_VFP_MVFR1] = cpu->isar.mvfr1; +- env->vfp.xregs[ARM_VFP_MVFR2] = cpu->isar.mvfr2; ++ env->vfp.xregs[ARM_VFP_MVFR0] = cpu->isar.regs[MVFR0]; ++ env->vfp.xregs[ARM_VFP_MVFR1] = cpu->isar.regs[MVFR1]; ++ env->vfp.xregs[ARM_VFP_MVFR2] = cpu->isar.regs[MVFR2]; + + cpu->power_state = cpu->start_powered_off ? PSCI_OFF : PSCI_ON; + s->halted = cpu->start_powered_off; +@@ -1251,19 +1251,19 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + unset_feature(env, ARM_FEATURE_VFP3); + unset_feature(env, ARM_FEATURE_VFP4); + +- t = cpu->isar.id_aa64isar1; ++ t = cpu->isar.regs[ID_AA64ISAR1]; + t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 0); +- cpu->isar.id_aa64isar1 = t; ++ cpu->isar.regs[ID_AA64ISAR1] = t; + +- t = cpu->isar.id_aa64pfr0; ++ t = cpu->isar.regs[ID_AA64PFR0]; + t = FIELD_DP64(t, ID_AA64PFR0, FP, 0xf); +- cpu->isar.id_aa64pfr0 = t; ++ cpu->isar.regs[ID_AA64PFR0] = t; + +- u = cpu->isar.id_isar6; ++ u = cpu->isar.regs[ID_ISAR6]; + u = FIELD_DP32(u, ID_ISAR6, JSCVT, 0); +- cpu->isar.id_isar6 = u; ++ cpu->isar.regs[ID_ISAR6] = u; + +- u = cpu->isar.mvfr0; ++ u = cpu->isar.regs[MVFR0]; + u = FIELD_DP32(u, MVFR0, FPSP, 0); + u = FIELD_DP32(u, MVFR0, FPDP, 0); + u = FIELD_DP32(u, MVFR0, FPTRAP, 0); +@@ -1271,17 +1271,17 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + u = FIELD_DP32(u, MVFR0, FPSQRT, 0); + u = FIELD_DP32(u, MVFR0, FPSHVEC, 0); + u = FIELD_DP32(u, MVFR0, FPROUND, 0); +- cpu->isar.mvfr0 = u; ++ cpu->isar.regs[MVFR0] = u; + +- u = cpu->isar.mvfr1; ++ u = cpu->isar.regs[MVFR1]; + u = FIELD_DP32(u, MVFR1, FPFTZ, 0); + u = FIELD_DP32(u, MVFR1, FPDNAN, 0); + u = FIELD_DP32(u, MVFR1, FPHP, 0); +- cpu->isar.mvfr1 = u; ++ cpu->isar.regs[MVFR1] = u; + +- u = cpu->isar.mvfr2; ++ u = cpu->isar.regs[MVFR2]; + u = FIELD_DP32(u, MVFR2, FPMISC, 0); +- cpu->isar.mvfr2 = u; ++ cpu->isar.regs[MVFR2] = u; + } + + if (!cpu->has_neon) { +@@ -1290,56 +1290,56 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + + unset_feature(env, ARM_FEATURE_NEON); + +- t = cpu->isar.id_aa64isar0; ++ t = cpu->isar.regs[ID_AA64ISAR0]; + t = FIELD_DP64(t, ID_AA64ISAR0, DP, 0); +- cpu->isar.id_aa64isar0 = t; ++ cpu->isar.regs[ID_AA64ISAR0] = t; + +- t = cpu->isar.id_aa64isar1; ++ t = cpu->isar.regs[ID_AA64ISAR1]; + t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 0); +- cpu->isar.id_aa64isar1 = t; ++ cpu->isar.regs[ID_AA64ISAR1] = t; + +- t = cpu->isar.id_aa64pfr0; ++ t = cpu->isar.regs[ID_AA64PFR0]; + t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 0xf); +- cpu->isar.id_aa64pfr0 = t; ++ cpu->isar.regs[ID_AA64PFR0] = t; + +- u = cpu->isar.id_isar5; ++ u = cpu->isar.regs[ID_ISAR5]; + u = FIELD_DP32(u, ID_ISAR5, RDM, 0); + u = FIELD_DP32(u, ID_ISAR5, VCMA, 0); +- cpu->isar.id_isar5 = u; ++ cpu->isar.regs[ID_ISAR5] = u; + +- u = cpu->isar.id_isar6; ++ u = cpu->isar.regs[ID_ISAR6]; + u = FIELD_DP32(u, ID_ISAR6, DP, 0); + u = FIELD_DP32(u, ID_ISAR6, FHM, 0); +- cpu->isar.id_isar6 = u; ++ cpu->isar.regs[ID_ISAR6] = u; + +- u = cpu->isar.mvfr1; ++ u = cpu->isar.regs[MVFR1]; + u = FIELD_DP32(u, MVFR1, SIMDLS, 0); + u = FIELD_DP32(u, MVFR1, SIMDINT, 0); + u = FIELD_DP32(u, MVFR1, SIMDSP, 0); + u = FIELD_DP32(u, MVFR1, SIMDHP, 0); + u = FIELD_DP32(u, MVFR1, SIMDFMAC, 0); +- cpu->isar.mvfr1 = u; ++ cpu->isar.regs[MVFR1] = u; + +- u = cpu->isar.mvfr2; ++ u = cpu->isar.regs[MVFR2]; + u = FIELD_DP32(u, MVFR2, SIMDMISC, 0); +- cpu->isar.mvfr2 = u; ++ cpu->isar.regs[MVFR2] = u; + } + + if (!cpu->has_neon && !cpu->has_vfp) { + uint64_t t; + uint32_t u; + +- t = cpu->isar.id_aa64isar0; ++ t = cpu->isar.regs[ID_AA64ISAR0]; + t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 0); +- cpu->isar.id_aa64isar0 = t; ++ cpu->isar.regs[ID_AA64ISAR0] = t; + +- t = cpu->isar.id_aa64isar1; ++ t = cpu->isar.regs[ID_AA64ISAR1]; + t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 0); +- cpu->isar.id_aa64isar1 = t; ++ cpu->isar.regs[ID_AA64ISAR1] = t; + +- u = cpu->isar.mvfr0; ++ u = cpu->isar.regs[MVFR0]; + u = FIELD_DP32(u, MVFR0, SIMDREG, 0); +- cpu->isar.mvfr0 = u; ++ cpu->isar.regs[MVFR0] = u; + } + + if (arm_feature(env, ARM_FEATURE_M) && !cpu->has_dsp) { +@@ -1347,19 +1347,19 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + + unset_feature(env, ARM_FEATURE_THUMB_DSP); + +- u = cpu->isar.id_isar1; ++ u = cpu->isar.regs[ID_ISAR1]; + u = FIELD_DP32(u, ID_ISAR1, EXTEND, 1); +- cpu->isar.id_isar1 = u; ++ cpu->isar.regs[ID_ISAR1] = u; + +- u = cpu->isar.id_isar2; ++ u = cpu->isar.regs[ID_ISAR2]; + u = FIELD_DP32(u, ID_ISAR2, MULTU, 1); + u = FIELD_DP32(u, ID_ISAR2, MULTS, 1); +- cpu->isar.id_isar2 = u; ++ cpu->isar.regs[ID_ISAR2] = u; + +- u = cpu->isar.id_isar3; ++ u = cpu->isar.regs[ID_ISAR3]; + u = FIELD_DP32(u, ID_ISAR3, SIMD, 1); + u = FIELD_DP32(u, ID_ISAR3, SATURATE, 0); +- cpu->isar.id_isar3 = u; ++ cpu->isar.regs[ID_ISAR3] = u; + } + + /* Some features automatically imply others: */ +@@ -1499,7 +1499,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + * registers as well. These are id_pfr1[7:4] and id_aa64pfr0[15:12]. + */ + cpu->id_pfr1 &= ~0xf0; +- cpu->isar.id_aa64pfr0 &= ~0xf000; ++ cpu->isar.regs[ID_AA64PFR0] &= ~0xf000; + } + + if (!cpu->has_el2) { +@@ -1522,9 +1522,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + cpu); + #endif + } else { +- cpu->isar.id_aa64dfr0 = +- FIELD_DP64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, PMUVER, 0); +- cpu->isar.id_dfr0 = FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, PERFMON, 0); ++ cpu->isar.regs[ID_AA64DFR0] = ++ FIELD_DP64(cpu->isar.regs[ID_AA64DFR0], ID_AA64DFR0, PMUVER, 0); ++ cpu->isar.regs[ID_DFR0] = FIELD_DP32(cpu->isar.regs[ID_DFR0], ID_DFR0, ++ PERFMON, 0); + cpu->pmceid0 = 0; + cpu->pmceid1 = 0; + } +@@ -1534,7 +1535,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + * registers if we don't have EL2. These are id_pfr1[15:12] and + * id_aa64pfr0_el1[11:8]. + */ +- cpu->isar.id_aa64pfr0 &= ~0xf00; ++ cpu->isar.regs[ID_AA64PFR0] &= ~0xf00; + cpu->id_pfr1 &= ~0xf000; + } + +@@ -1675,13 +1676,15 @@ static void arm926_initfn(Object *obj) + * ARMv5 does not have the ID_ISAR registers, but we can still + * set the field to indicate Jazelle support within QEMU. + */ +- cpu->isar.id_isar1 = FIELD_DP32(cpu->isar.id_isar1, ID_ISAR1, JAZELLE, 1); ++ cpu->isar.regs[ID_ISAR1] = FIELD_DP32(cpu->isar.regs[ID_ISAR1], ID_ISAR1, ++ JAZELLE, 1); + /* + * Similarly, we need to set MVFR0 fields to enable double precision + * and short vector support even though ARMv5 doesn't have this register. + */ +- cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); +- cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPDP, 1); ++ cpu->isar.regs[MVFR0] = FIELD_DP32(cpu->isar.regs[MVFR0], MVFR0, ++ FPSHVEC, 1); ++ cpu->isar.regs[MVFR0] = FIELD_DP32(cpu->isar.regs[MVFR0], MVFR0, FPDP, 1); + } + + static void arm946_initfn(Object *obj) +@@ -1717,13 +1720,15 @@ static void arm1026_initfn(Object *obj) + * ARMv5 does not have the ID_ISAR registers, but we can still + * set the field to indicate Jazelle support within QEMU. + */ +- cpu->isar.id_isar1 = FIELD_DP32(cpu->isar.id_isar1, ID_ISAR1, JAZELLE, 1); ++ cpu->isar.regs[ID_ISAR1] = FIELD_DP32(cpu->isar.regs[ID_ISAR1], ID_ISAR1, ++ JAZELLE, 1); + /* + * Similarly, we need to set MVFR0 fields to enable double precision + * and short vector support even though ARMv5 doesn't have this register. + */ +- cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); +- cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPDP, 1); ++ cpu->isar.regs[MVFR0] = FIELD_DP32(cpu->isar.regs[MVFR0], MVFR0, ++ FPSHVEC, 1); ++ cpu->isar.regs[MVFR0] = FIELD_DP32(cpu->isar.regs[MVFR0], MVFR0, FPDP, 1); + + { + /* The 1026 had an IFAR at c6,c0,0,1 rather than the ARMv6 c6,c0,0,2 */ +@@ -1756,22 +1761,22 @@ static void arm1136_r2_initfn(Object *obj) + set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); + cpu->midr = 0x4107b362; + cpu->reset_fpsid = 0x410120b4; +- cpu->isar.mvfr0 = 0x11111111; +- cpu->isar.mvfr1 = 0x00000000; ++ cpu->isar.regs[MVFR0] = 0x11111111; ++ cpu->isar.regs[MVFR1] = 0x00000000; + cpu->ctr = 0x1dd20d2; + cpu->reset_sctlr = 0x00050078; + cpu->id_pfr0 = 0x111; + cpu->id_pfr1 = 0x1; +- cpu->isar.id_dfr0 = 0x2; ++ cpu->isar.regs[ID_DFR0] = 0x2; + cpu->id_afr0 = 0x3; +- cpu->isar.id_mmfr0 = 0x01130003; +- cpu->isar.id_mmfr1 = 0x10030302; +- cpu->isar.id_mmfr2 = 0x01222110; +- cpu->isar.id_isar0 = 0x00140011; +- cpu->isar.id_isar1 = 0x12002111; +- cpu->isar.id_isar2 = 0x11231111; +- cpu->isar.id_isar3 = 0x01102131; +- cpu->isar.id_isar4 = 0x141; ++ cpu->isar.regs[ID_MMFR0] = 0x01130003; ++ cpu->isar.regs[ID_MMFR1] = 0x10030302; ++ cpu->isar.regs[ID_MMFR2] = 0x01222110; ++ cpu->isar.regs[ID_ISAR0] = 0x00140011; ++ cpu->isar.regs[ID_ISAR1] = 0x12002111; ++ cpu->isar.regs[ID_ISAR2] = 0x11231111; ++ cpu->isar.regs[ID_ISAR3] = 0x01102131; ++ cpu->isar.regs[ID_ISAR4] = 0x141; + cpu->reset_auxcr = 7; + } + +@@ -1788,22 +1793,22 @@ static void arm1136_initfn(Object *obj) + set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); + cpu->midr = 0x4117b363; + cpu->reset_fpsid = 0x410120b4; +- cpu->isar.mvfr0 = 0x11111111; +- cpu->isar.mvfr1 = 0x00000000; ++ cpu->isar.regs[MVFR0] = 0x11111111; ++ cpu->isar.regs[MVFR1] = 0x00000000; + cpu->ctr = 0x1dd20d2; + cpu->reset_sctlr = 0x00050078; + cpu->id_pfr0 = 0x111; + cpu->id_pfr1 = 0x1; +- cpu->isar.id_dfr0 = 0x2; ++ cpu->isar.regs[ID_DFR0] = 0x2; + cpu->id_afr0 = 0x3; +- cpu->isar.id_mmfr0 = 0x01130003; +- cpu->isar.id_mmfr1 = 0x10030302; +- cpu->isar.id_mmfr2 = 0x01222110; +- cpu->isar.id_isar0 = 0x00140011; +- cpu->isar.id_isar1 = 0x12002111; +- cpu->isar.id_isar2 = 0x11231111; +- cpu->isar.id_isar3 = 0x01102131; +- cpu->isar.id_isar4 = 0x141; ++ cpu->isar.regs[ID_MMFR0] = 0x01130003; ++ cpu->isar.regs[ID_MMFR1] = 0x10030302; ++ cpu->isar.regs[ID_MMFR2] = 0x01222110; ++ cpu->isar.regs[ID_ISAR0] = 0x00140011; ++ cpu->isar.regs[ID_ISAR1] = 0x12002111; ++ cpu->isar.regs[ID_ISAR2] = 0x11231111; ++ cpu->isar.regs[ID_ISAR3] = 0x01102131; ++ cpu->isar.regs[ID_ISAR4] = 0x141; + cpu->reset_auxcr = 7; + } + +@@ -1821,22 +1826,22 @@ static void arm1176_initfn(Object *obj) + set_feature(&cpu->env, ARM_FEATURE_EL3); + cpu->midr = 0x410fb767; + cpu->reset_fpsid = 0x410120b5; +- cpu->isar.mvfr0 = 0x11111111; +- cpu->isar.mvfr1 = 0x00000000; ++ cpu->isar.regs[MVFR0] = 0x11111111; ++ cpu->isar.regs[MVFR1] = 0x00000000; + cpu->ctr = 0x1dd20d2; + cpu->reset_sctlr = 0x00050078; + cpu->id_pfr0 = 0x111; + cpu->id_pfr1 = 0x11; +- cpu->isar.id_dfr0 = 0x33; ++ cpu->isar.regs[ID_DFR0] = 0x33; + cpu->id_afr0 = 0; +- cpu->isar.id_mmfr0 = 0x01130003; +- cpu->isar.id_mmfr1 = 0x10030302; +- cpu->isar.id_mmfr2 = 0x01222100; +- cpu->isar.id_isar0 = 0x0140011; +- cpu->isar.id_isar1 = 0x12002111; +- cpu->isar.id_isar2 = 0x11231121; +- cpu->isar.id_isar3 = 0x01102131; +- cpu->isar.id_isar4 = 0x01141; ++ cpu->isar.regs[ID_MMFR0] = 0x01130003; ++ cpu->isar.regs[ID_MMFR1] = 0x10030302; ++ cpu->isar.regs[ID_MMFR2] = 0x01222100; ++ cpu->isar.regs[ID_ISAR0] = 0x0140011; ++ cpu->isar.regs[ID_ISAR1] = 0x12002111; ++ cpu->isar.regs[ID_ISAR2] = 0x11231121; ++ cpu->isar.regs[ID_ISAR3] = 0x01102131; ++ cpu->isar.regs[ID_ISAR4] = 0x01141; + cpu->reset_auxcr = 7; + } + +@@ -1852,21 +1857,21 @@ static void arm11mpcore_initfn(Object *obj) + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + cpu->midr = 0x410fb022; + cpu->reset_fpsid = 0x410120b4; +- cpu->isar.mvfr0 = 0x11111111; +- cpu->isar.mvfr1 = 0x00000000; ++ cpu->isar.regs[MVFR0] = 0x11111111; ++ cpu->isar.regs[MVFR1] = 0x00000000; + cpu->ctr = 0x1d192992; /* 32K icache 32K dcache */ + cpu->id_pfr0 = 0x111; + cpu->id_pfr1 = 0x1; +- cpu->isar.id_dfr0 = 0; ++ cpu->isar.regs[ID_DFR0] = 0; + cpu->id_afr0 = 0x2; +- cpu->isar.id_mmfr0 = 0x01100103; +- cpu->isar.id_mmfr1 = 0x10020302; +- cpu->isar.id_mmfr2 = 0x01222000; +- cpu->isar.id_isar0 = 0x00100011; +- cpu->isar.id_isar1 = 0x12002111; +- cpu->isar.id_isar2 = 0x11221011; +- cpu->isar.id_isar3 = 0x01102131; +- cpu->isar.id_isar4 = 0x141; ++ cpu->isar.regs[ID_MMFR0] = 0x01100103; ++ cpu->isar.regs[ID_MMFR1] = 0x10020302; ++ cpu->isar.regs[ID_MMFR2] = 0x01222000; ++ cpu->isar.regs[ID_ISAR0] = 0x00100011; ++ cpu->isar.regs[ID_ISAR1] = 0x12002111; ++ cpu->isar.regs[ID_ISAR2] = 0x11221011; ++ cpu->isar.regs[ID_ISAR3] = 0x01102131; ++ cpu->isar.regs[ID_ISAR4] = 0x141; + cpu->reset_auxcr = 1; + } + +@@ -1889,19 +1894,19 @@ static void cortex_m3_initfn(Object *obj) + cpu->pmsav7_dregion = 8; + cpu->id_pfr0 = 0x00000030; + cpu->id_pfr1 = 0x00000200; +- cpu->isar.id_dfr0 = 0x00100000; ++ cpu->isar.regs[ID_DFR0] = 0x00100000; + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x00000030; +- cpu->isar.id_mmfr1 = 0x00000000; +- cpu->isar.id_mmfr2 = 0x00000000; +- cpu->isar.id_mmfr3 = 0x00000000; +- cpu->isar.id_isar0 = 0x01141110; +- cpu->isar.id_isar1 = 0x02111000; +- cpu->isar.id_isar2 = 0x21112231; +- cpu->isar.id_isar3 = 0x01111110; +- cpu->isar.id_isar4 = 0x01310102; +- cpu->isar.id_isar5 = 0x00000000; +- cpu->isar.id_isar6 = 0x00000000; ++ cpu->isar.regs[ID_MMFR0] = 0x00000030; ++ cpu->isar.regs[ID_MMFR1] = 0x00000000; ++ cpu->isar.regs[ID_MMFR2] = 0x00000000; ++ cpu->isar.regs[ID_MMFR3] = 0x00000000; ++ cpu->isar.regs[ID_ISAR0] = 0x01141110; ++ cpu->isar.regs[ID_ISAR1] = 0x02111000; ++ cpu->isar.regs[ID_ISAR2] = 0x21112231; ++ cpu->isar.regs[ID_ISAR3] = 0x01111110; ++ cpu->isar.regs[ID_ISAR4] = 0x01310102; ++ cpu->isar.regs[ID_ISAR5] = 0x00000000; ++ cpu->isar.regs[ID_ISAR6] = 0x00000000; + } + + static void cortex_m4_initfn(Object *obj) +@@ -1915,24 +1920,24 @@ static void cortex_m4_initfn(Object *obj) + set_feature(&cpu->env, ARM_FEATURE_VFP4); + cpu->midr = 0x410fc240; /* r0p0 */ + cpu->pmsav7_dregion = 8; +- cpu->isar.mvfr0 = 0x10110021; +- cpu->isar.mvfr1 = 0x11000011; +- cpu->isar.mvfr2 = 0x00000000; ++ cpu->isar.regs[MVFR0] = 0x10110021; ++ cpu->isar.regs[MVFR1] = 0x11000011; ++ cpu->isar.regs[MVFR2] = 0x00000000; + cpu->id_pfr0 = 0x00000030; + cpu->id_pfr1 = 0x00000200; +- cpu->isar.id_dfr0 = 0x00100000; ++ cpu->isar.regs[ID_DFR0] = 0x00100000; + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x00000030; +- cpu->isar.id_mmfr1 = 0x00000000; +- cpu->isar.id_mmfr2 = 0x00000000; +- cpu->isar.id_mmfr3 = 0x00000000; +- cpu->isar.id_isar0 = 0x01141110; +- cpu->isar.id_isar1 = 0x02111000; +- cpu->isar.id_isar2 = 0x21112231; +- cpu->isar.id_isar3 = 0x01111110; +- cpu->isar.id_isar4 = 0x01310102; +- cpu->isar.id_isar5 = 0x00000000; +- cpu->isar.id_isar6 = 0x00000000; ++ cpu->isar.regs[ID_MMFR0] = 0x00000030; ++ cpu->isar.regs[ID_MMFR1] = 0x00000000; ++ cpu->isar.regs[ID_MMFR2] = 0x00000000; ++ cpu->isar.regs[ID_MMFR3] = 0x00000000; ++ cpu->isar.regs[ID_ISAR0] = 0x01141110; ++ cpu->isar.regs[ID_ISAR1] = 0x02111000; ++ cpu->isar.regs[ID_ISAR2] = 0x21112231; ++ cpu->isar.regs[ID_ISAR3] = 0x01111110; ++ cpu->isar.regs[ID_ISAR4] = 0x01310102; ++ cpu->isar.regs[ID_ISAR5] = 0x00000000; ++ cpu->isar.regs[ID_ISAR6] = 0x00000000; + } + + static void cortex_m33_initfn(Object *obj) +@@ -1948,24 +1953,24 @@ static void cortex_m33_initfn(Object *obj) + cpu->midr = 0x410fd213; /* r0p3 */ + cpu->pmsav7_dregion = 16; + cpu->sau_sregion = 8; +- cpu->isar.mvfr0 = 0x10110021; +- cpu->isar.mvfr1 = 0x11000011; +- cpu->isar.mvfr2 = 0x00000040; ++ cpu->isar.regs[MVFR0] = 0x10110021; ++ cpu->isar.regs[MVFR1] = 0x11000011; ++ cpu->isar.regs[MVFR2] = 0x00000040; + cpu->id_pfr0 = 0x00000030; + cpu->id_pfr1 = 0x00000210; +- cpu->isar.id_dfr0 = 0x00200000; ++ cpu->isar.regs[ID_DFR0] = 0x00200000; + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x00101F40; +- cpu->isar.id_mmfr1 = 0x00000000; +- cpu->isar.id_mmfr2 = 0x01000000; +- cpu->isar.id_mmfr3 = 0x00000000; +- cpu->isar.id_isar0 = 0x01101110; +- cpu->isar.id_isar1 = 0x02212000; +- cpu->isar.id_isar2 = 0x20232232; +- cpu->isar.id_isar3 = 0x01111131; +- cpu->isar.id_isar4 = 0x01310132; +- cpu->isar.id_isar5 = 0x00000000; +- cpu->isar.id_isar6 = 0x00000000; ++ cpu->isar.regs[ID_MMFR0] = 0x00101F40; ++ cpu->isar.regs[ID_MMFR1] = 0x00000000; ++ cpu->isar.regs[ID_MMFR2] = 0x01000000; ++ cpu->isar.regs[ID_MMFR3] = 0x00000000; ++ cpu->isar.regs[ID_ISAR0] = 0x01101110; ++ cpu->isar.regs[ID_ISAR1] = 0x02212000; ++ cpu->isar.regs[ID_ISAR2] = 0x20232232; ++ cpu->isar.regs[ID_ISAR3] = 0x01111131; ++ cpu->isar.regs[ID_ISAR4] = 0x01310132; ++ cpu->isar.regs[ID_ISAR5] = 0x00000000; ++ cpu->isar.regs[ID_ISAR6] = 0x00000000; + cpu->clidr = 0x00000000; + cpu->ctr = 0x8000c000; + } +@@ -2004,19 +2009,19 @@ static void cortex_r5_initfn(Object *obj) + cpu->midr = 0x411fc153; /* r1p3 */ + cpu->id_pfr0 = 0x0131; + cpu->id_pfr1 = 0x001; +- cpu->isar.id_dfr0 = 0x010400; ++ cpu->isar.regs[ID_DFR0] = 0x010400; + cpu->id_afr0 = 0x0; +- cpu->isar.id_mmfr0 = 0x0210030; +- cpu->isar.id_mmfr1 = 0x00000000; +- cpu->isar.id_mmfr2 = 0x01200000; +- cpu->isar.id_mmfr3 = 0x0211; +- cpu->isar.id_isar0 = 0x02101111; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232141; +- cpu->isar.id_isar3 = 0x01112131; +- cpu->isar.id_isar4 = 0x0010142; +- cpu->isar.id_isar5 = 0x0; +- cpu->isar.id_isar6 = 0x0; ++ cpu->isar.regs[ID_MMFR0] = 0x0210030; ++ cpu->isar.regs[ID_MMFR1] = 0x00000000; ++ cpu->isar.regs[ID_MMFR2] = 0x01200000; ++ cpu->isar.regs[ID_MMFR3] = 0x0211; ++ cpu->isar.regs[ID_ISAR0] = 0x02101111; ++ cpu->isar.regs[ID_ISAR1] = 0x13112111; ++ cpu->isar.regs[ID_ISAR2] = 0x21232141; ++ cpu->isar.regs[ID_ISAR3] = 0x01112131; ++ cpu->isar.regs[ID_ISAR4] = 0x0010142; ++ cpu->isar.regs[ID_ISAR5] = 0x0; ++ cpu->isar.regs[ID_ISAR6] = 0x0; + cpu->mp_is_up = true; + cpu->pmsav7_dregion = 16; + define_arm_cp_regs(cpu, cortexr5_cp_reginfo); +@@ -2028,8 +2033,8 @@ static void cortex_r5f_initfn(Object *obj) + + cortex_r5_initfn(obj); + set_feature(&cpu->env, ARM_FEATURE_VFP3); +- cpu->isar.mvfr0 = 0x10110221; +- cpu->isar.mvfr1 = 0x00000011; ++ cpu->isar.regs[MVFR0] = 0x10110221; ++ cpu->isar.regs[MVFR1] = 0x00000011; + } + + static const ARMCPRegInfo cortexa8_cp_reginfo[] = { +@@ -2053,24 +2058,24 @@ static void cortex_a8_initfn(Object *obj) + set_feature(&cpu->env, ARM_FEATURE_EL3); + cpu->midr = 0x410fc080; + cpu->reset_fpsid = 0x410330c0; +- cpu->isar.mvfr0 = 0x11110222; +- cpu->isar.mvfr1 = 0x00011111; ++ cpu->isar.regs[MVFR0] = 0x11110222; ++ cpu->isar.regs[MVFR1] = 0x00011111; + cpu->ctr = 0x82048004; + cpu->reset_sctlr = 0x00c50078; + cpu->id_pfr0 = 0x1031; + cpu->id_pfr1 = 0x11; +- cpu->isar.id_dfr0 = 0x400; ++ cpu->isar.regs[ID_DFR0] = 0x400; + cpu->id_afr0 = 0; +- cpu->isar.id_mmfr0 = 0x31100003; +- cpu->isar.id_mmfr1 = 0x20000000; +- cpu->isar.id_mmfr2 = 0x01202000; +- cpu->isar.id_mmfr3 = 0x11; +- cpu->isar.id_isar0 = 0x00101111; +- cpu->isar.id_isar1 = 0x12112111; +- cpu->isar.id_isar2 = 0x21232031; +- cpu->isar.id_isar3 = 0x11112131; +- cpu->isar.id_isar4 = 0x00111142; +- cpu->isar.dbgdidr = 0x15141000; ++ cpu->isar.regs[ID_MMFR0] = 0x31100003; ++ cpu->isar.regs[ID_MMFR1] = 0x20000000; ++ cpu->isar.regs[ID_MMFR2] = 0x01202000; ++ cpu->isar.regs[ID_MMFR3] = 0x11; ++ cpu->isar.regs[ID_ISAR0] = 0x00101111; ++ cpu->isar.regs[ID_ISAR1] = 0x12112111; ++ cpu->isar.regs[ID_ISAR2] = 0x21232031; ++ cpu->isar.regs[ID_ISAR3] = 0x11112131; ++ cpu->isar.regs[ID_ISAR4] = 0x00111142; ++ cpu->isar.regs[DBGDIDR] = 0x15141000; + cpu->clidr = (1 << 27) | (2 << 24) | 3; + cpu->ccsidr[0] = 0xe007e01a; /* 16k L1 dcache. */ + cpu->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */ +@@ -2126,24 +2131,24 @@ static void cortex_a9_initfn(Object *obj) + set_feature(&cpu->env, ARM_FEATURE_CBAR); + cpu->midr = 0x410fc090; + cpu->reset_fpsid = 0x41033090; +- cpu->isar.mvfr0 = 0x11110222; +- cpu->isar.mvfr1 = 0x01111111; ++ cpu->isar.regs[MVFR0] = 0x11110222; ++ cpu->isar.regs[MVFR1] = 0x01111111; + cpu->ctr = 0x80038003; + cpu->reset_sctlr = 0x00c50078; + cpu->id_pfr0 = 0x1031; + cpu->id_pfr1 = 0x11; +- cpu->isar.id_dfr0 = 0x000; ++ cpu->isar.regs[ID_DFR0] = 0x000; + cpu->id_afr0 = 0; +- cpu->isar.id_mmfr0 = 0x00100103; +- cpu->isar.id_mmfr1 = 0x20000000; +- cpu->isar.id_mmfr2 = 0x01230000; +- cpu->isar.id_mmfr3 = 0x00002111; +- cpu->isar.id_isar0 = 0x00101111; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232041; +- cpu->isar.id_isar3 = 0x11112131; +- cpu->isar.id_isar4 = 0x00111142; +- cpu->isar.dbgdidr = 0x35141000; ++ cpu->isar.regs[ID_MMFR0] = 0x00100103; ++ cpu->isar.regs[ID_MMFR1] = 0x20000000; ++ cpu->isar.regs[ID_MMFR2] = 0x01230000; ++ cpu->isar.regs[ID_MMFR3] = 0x00002111; ++ cpu->isar.regs[ID_ISAR0] = 0x00101111; ++ cpu->isar.regs[ID_ISAR1] = 0x13112111; ++ cpu->isar.regs[ID_ISAR2] = 0x21232041; ++ cpu->isar.regs[ID_ISAR3] = 0x11112131; ++ cpu->isar.regs[ID_ISAR4] = 0x00111142; ++ cpu->isar.regs[DBGDIDR] = 0x35141000; + cpu->clidr = (1 << 27) | (1 << 24) | 3; + cpu->ccsidr[0] = 0xe00fe019; /* 16k L1 dcache. */ + cpu->ccsidr[1] = 0x200fe019; /* 16k L1 icache. */ +@@ -2191,27 +2196,27 @@ static void cortex_a7_initfn(Object *obj) + cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A7; + cpu->midr = 0x410fc075; + cpu->reset_fpsid = 0x41023075; +- cpu->isar.mvfr0 = 0x10110222; +- cpu->isar.mvfr1 = 0x11111111; ++ cpu->isar.regs[MVFR0] = 0x10110222; ++ cpu->isar.regs[MVFR1] = 0x11111111; + cpu->ctr = 0x84448003; + cpu->reset_sctlr = 0x00c50078; + cpu->id_pfr0 = 0x00001131; + cpu->id_pfr1 = 0x00011011; +- cpu->isar.id_dfr0 = 0x02010555; ++ cpu->isar.regs[ID_DFR0] = 0x02010555; + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x10101105; +- cpu->isar.id_mmfr1 = 0x40000000; +- cpu->isar.id_mmfr2 = 0x01240000; +- cpu->isar.id_mmfr3 = 0x02102211; ++ cpu->isar.regs[ID_MMFR0] = 0x10101105; ++ cpu->isar.regs[ID_MMFR1] = 0x40000000; ++ cpu->isar.regs[ID_MMFR2] = 0x01240000; ++ cpu->isar.regs[ID_MMFR3] = 0x02102211; + /* a7_mpcore_r0p5_trm, page 4-4 gives 0x01101110; but + * table 4-41 gives 0x02101110, which includes the arm div insns. + */ +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232041; +- cpu->isar.id_isar3 = 0x11112131; +- cpu->isar.id_isar4 = 0x10011142; +- cpu->isar.dbgdidr = 0x3515f005; ++ cpu->isar.regs[ID_ISAR0] = 0x02101110; ++ cpu->isar.regs[ID_ISAR1] = 0x13112111; ++ cpu->isar.regs[ID_ISAR2] = 0x21232041; ++ cpu->isar.regs[ID_ISAR3] = 0x11112131; ++ cpu->isar.regs[ID_ISAR4] = 0x10011142; ++ cpu->isar.regs[DBGDIDR] = 0x3515f005; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ + cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ +@@ -2237,24 +2242,24 @@ static void cortex_a15_initfn(Object *obj) + cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15; + cpu->midr = 0x412fc0f1; + cpu->reset_fpsid = 0x410430f0; +- cpu->isar.mvfr0 = 0x10110222; +- cpu->isar.mvfr1 = 0x11111111; ++ cpu->isar.regs[MVFR0] = 0x10110222; ++ cpu->isar.regs[MVFR1] = 0x11111111; + cpu->ctr = 0x8444c004; + cpu->reset_sctlr = 0x00c50078; + cpu->id_pfr0 = 0x00001131; + cpu->id_pfr1 = 0x00011011; +- cpu->isar.id_dfr0 = 0x02010555; ++ cpu->isar.regs[ID_DFR0] = 0x02010555; + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x10201105; +- cpu->isar.id_mmfr1 = 0x20000000; +- cpu->isar.id_mmfr2 = 0x01240000; +- cpu->isar.id_mmfr3 = 0x02102211; +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232041; +- cpu->isar.id_isar3 = 0x11112131; +- cpu->isar.id_isar4 = 0x10011142; +- cpu->isar.dbgdidr = 0x3515f021; ++ cpu->isar.regs[ID_MMFR0] = 0x10201105; ++ cpu->isar.regs[ID_MMFR1] = 0x20000000; ++ cpu->isar.regs[ID_MMFR2] = 0x01240000; ++ cpu->isar.regs[ID_MMFR3] = 0x02102211; ++ cpu->isar.regs[ID_ISAR0] = 0x02101110; ++ cpu->isar.regs[ID_ISAR1] = 0x13112111; ++ cpu->isar.regs[ID_ISAR2] = 0x21232041; ++ cpu->isar.regs[ID_ISAR3] = 0x11112131; ++ cpu->isar.regs[ID_ISAR4] = 0x10011142; ++ cpu->isar.regs[DBGDIDR] = 0x3515f021; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ + cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ +@@ -2447,7 +2452,8 @@ static void arm_max_initfn(Object *obj) + cortex_a15_initfn(obj); + + /* old-style VFP short-vector support */ +- cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); ++ cpu->isar.regs[MVFR0] = FIELD_DP32(cpu->isar.regs[MVFR0], MVFR0, ++ FPSHVEC, 1); + + #ifdef CONFIG_USER_ONLY + /* We don't set these in system emulation mode for the moment, +@@ -2458,39 +2464,39 @@ static void arm_max_initfn(Object *obj) + { + uint32_t t; + +- t = cpu->isar.id_isar5; ++ t = cpu->isar.regs[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; ++ cpu->isar.regs[ID_ISAR5] = t; + +- t = cpu->isar.id_isar6; ++ t = cpu->isar.regs[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); +- cpu->isar.id_isar6 = t; ++ cpu->isar.regs[ID_ISAR6] = t; + +- t = cpu->isar.mvfr1; ++ t = cpu->isar.regs[MVFR1]; + t = FIELD_DP32(t, MVFR1, FPHP, 2); /* v8.0 FP support */ +- cpu->isar.mvfr1 = t; ++ cpu->isar.regs[MVFR1] = t; + +- t = cpu->isar.mvfr2; ++ t = cpu->isar.regs[MVFR2]; + t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ + t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ +- cpu->isar.mvfr2 = t; ++ cpu->isar.regs[MVFR2] = t; + +- t = cpu->isar.id_mmfr3; ++ t = cpu->isar.regs[ID_MMFR3]; + t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */ +- cpu->isar.id_mmfr3 = t; ++ cpu->isar.regs[ID_MMFR3] = t; + +- t = cpu->isar.id_mmfr4; ++ t = cpu->isar.regs[ID_MMFR4]; + t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ +- cpu->isar.id_mmfr4 = t; ++ cpu->isar.regs[ID_MMFR4] = t; + } + #endif + } +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 56d8cd8c..7bb481fb 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -63,6 +63,37 @@ + #define ARMV7M_EXCP_PENDSV 14 + #define ARMV7M_EXCP_SYSTICK 15 + ++typedef enum CPUIDReg { ++ MIDR_EL1, ++ ID_ISAR0, ++ ID_ISAR1, ++ ID_ISAR2, ++ ID_ISAR3, ++ ID_ISAR4, ++ ID_ISAR5, ++ ID_ISAR6, ++ ID_MMFR0, ++ ID_MMFR1, ++ ID_MMFR2, ++ ID_MMFR3, ++ ID_MMFR4, ++ ID_AA64ISAR0, ++ ID_AA64ISAR1, ++ ID_AA64PFR0, ++ ID_AA64PFR1, ++ ID_AA64MMFR0, ++ ID_AA64MMFR1, ++ ID_AA64MMFR2, ++ ID_AA64DFR0, ++ ID_AA64DFR1, ++ ID_DFR0, ++ MVFR0, ++ MVFR1, ++ MVFR2, ++ DBGDIDR, ++ ID_MAX, ++} CPUIDReg; ++ + /* For M profile, some registers are banked secure vs non-secure; + * these are represented as a 2-element array where the first element + * is the non-secure copy and the second is the secure copy. +@@ -855,32 +886,7 @@ struct ARMCPU { + * field by reading the value from the KVM vCPU. + */ + struct ARMISARegisters { +- uint32_t id_isar0; +- uint32_t id_isar1; +- uint32_t id_isar2; +- uint32_t id_isar3; +- uint32_t id_isar4; +- uint32_t id_isar5; +- uint32_t id_isar6; +- uint32_t id_mmfr0; +- uint32_t id_mmfr1; +- uint32_t id_mmfr2; +- uint32_t id_mmfr3; +- uint32_t id_mmfr4; +- uint32_t mvfr0; +- uint32_t mvfr1; +- uint32_t mvfr2; +- uint32_t id_dfr0; +- uint32_t dbgdidr; +- uint64_t id_aa64isar0; +- uint64_t id_aa64isar1; +- uint64_t id_aa64pfr0; +- uint64_t id_aa64pfr1; +- uint64_t id_aa64mmfr0; +- uint64_t id_aa64mmfr1; +- uint64_t id_aa64mmfr2; +- uint64_t id_aa64dfr0; +- uint64_t id_aa64dfr1; ++ uint64_t regs[ID_MAX]; + } isar; + uint32_t midr; + uint32_t revidr; +@@ -3358,77 +3364,77 @@ extern const uint64_t pred_esz_masks[4]; + */ + static inline bool isar_feature_thumb_div(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar0, ID_ISAR0, DIVIDE) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR0], ID_ISAR0, DIVIDE) != 0; + } + + static inline bool isar_feature_arm_div(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar0, ID_ISAR0, DIVIDE) > 1; ++ return FIELD_EX32(id->regs[ID_ISAR0], ID_ISAR0, DIVIDE) > 1; + } + + static inline bool isar_feature_jazelle(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar1, ID_ISAR1, JAZELLE) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR1], ID_ISAR1, JAZELLE) != 0; + } + + static inline bool isar_feature_aa32_aes(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, AES) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, AES) != 0; + } + + static inline bool isar_feature_aa32_pmull(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, AES) > 1; ++ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, AES) > 1; + } + + static inline bool isar_feature_aa32_sha1(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, SHA1) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, SHA1) != 0; + } + + static inline bool isar_feature_aa32_sha2(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, SHA2) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, SHA2) != 0; + } + + static inline bool isar_feature_aa32_crc32(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, CRC32) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, CRC32) != 0; + } + + static inline bool isar_feature_aa32_rdm(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, RDM) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, RDM) != 0; + } + + static inline bool isar_feature_aa32_vcma(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, VCMA) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR5], ID_ISAR5, VCMA) != 0; + } + + static inline bool isar_feature_aa32_jscvt(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar6, ID_ISAR6, JSCVT) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR6], ID_ISAR6, JSCVT) != 0; + } + + static inline bool isar_feature_aa32_dp(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar6, ID_ISAR6, DP) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR6], ID_ISAR6, DP) != 0; + } + + static inline bool isar_feature_aa32_fhm(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar6, ID_ISAR6, FHM) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR6], ID_ISAR6, FHM) != 0; + } + + static inline bool isar_feature_aa32_sb(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar6, ID_ISAR6, SB) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR6], ID_ISAR6, SB) != 0; + } + + static inline bool isar_feature_aa32_predinv(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar6, ID_ISAR6, SPECRES) != 0; ++ return FIELD_EX32(id->regs[ID_ISAR6], ID_ISAR6, SPECRES) != 0; + } + + static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id) +@@ -3438,24 +3444,24 @@ static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id) + * the ARMv8.2-FP16 extension is implemented for aa32 mode. + * At which point we can properly set and check MVFR1.FPHP. + */ +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) == 1; ++ return FIELD_EX64(id->regs[ID_AA64PFR0], ID_AA64PFR0, FP) == 1; + } + + static inline bool isar_feature_aa32_fp_d32(const ARMISARegisters *id) + { + /* Return true if D16-D31 are implemented */ +- return FIELD_EX64(id->mvfr0, MVFR0, SIMDREG) >= 2; ++ return FIELD_EX64(id->regs[MVFR0], MVFR0, SIMDREG) >= 2; + } + + static inline bool isar_feature_aa32_fpshvec(const ARMISARegisters *id) + { +- return FIELD_EX64(id->mvfr0, MVFR0, FPSHVEC) > 0; ++ return FIELD_EX64(id->regs[MVFR0], MVFR0, FPSHVEC) > 0; + } + + static inline bool isar_feature_aa32_fpdp(const ARMISARegisters *id) + { + /* Return true if CPU supports double precision floating point */ +- return FIELD_EX64(id->mvfr0, MVFR0, FPDP) > 0; ++ return FIELD_EX64(id->regs[MVFR0], MVFR0, FPDP) > 0; + } + + /* +@@ -3465,49 +3471,49 @@ static inline bool isar_feature_aa32_fpdp(const ARMISARegisters *id) + */ + static inline bool isar_feature_aa32_fp16_spconv(const ARMISARegisters *id) + { +- return FIELD_EX64(id->mvfr1, MVFR1, FPHP) > 0; ++ return FIELD_EX64(id->regs[MVFR1], MVFR1, FPHP) > 0; + } + + static inline bool isar_feature_aa32_fp16_dpconv(const ARMISARegisters *id) + { +- return FIELD_EX64(id->mvfr1, MVFR1, FPHP) > 1; ++ return FIELD_EX64(id->regs[MVFR1], MVFR1, FPHP) > 1; + } + + static inline bool isar_feature_aa32_vsel(const ARMISARegisters *id) + { +- return FIELD_EX64(id->mvfr2, MVFR2, FPMISC) >= 1; ++ return FIELD_EX64(id->regs[MVFR2], MVFR2, FPMISC) >= 1; + } + + static inline bool isar_feature_aa32_vcvt_dr(const ARMISARegisters *id) + { +- return FIELD_EX64(id->mvfr2, MVFR2, FPMISC) >= 2; ++ return FIELD_EX64(id->regs[MVFR2], MVFR2, FPMISC) >= 2; + } + + static inline bool isar_feature_aa32_vrint(const ARMISARegisters *id) + { +- return FIELD_EX64(id->mvfr2, MVFR2, FPMISC) >= 3; ++ return FIELD_EX64(id->regs[MVFR2], MVFR2, FPMISC) >= 3; + } + + static inline bool isar_feature_aa32_vminmaxnm(const ARMISARegisters *id) + { +- return FIELD_EX64(id->mvfr2, MVFR2, FPMISC) >= 4; ++ return FIELD_EX64(id->regs[MVFR2], MVFR2, FPMISC) >= 4; + } + + static inline bool isar_feature_aa32_pan(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_mmfr3, ID_MMFR3, PAN) != 0; ++ return FIELD_EX32(id->regs[ID_MMFR3], ID_MMFR3, PAN) != 0; + } + + static inline bool isar_feature_aa32_ats1e1(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_mmfr3, ID_MMFR3, PAN) >= 2; ++ return FIELD_EX32(id->regs[ID_MMFR3], ID_MMFR3, PAN) >= 2; + } + + static inline bool isar_feature_aa32_pmu_8_1(const ARMISARegisters *id) + { + /* 0xf means "non-standard IMPDEF PMU" */ +- return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 4 && +- FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf; ++ return FIELD_EX32(id->regs[ID_DFR0], ID_DFR0, PERFMON) >= 4 && ++ FIELD_EX32(id->regs[ID_DFR0], ID_DFR0, PERFMON) != 0xf; + } + + /* +@@ -3515,92 +3521,92 @@ static inline bool isar_feature_aa32_pmu_8_1(const ARMISARegisters *id) + */ + static inline bool isar_feature_aa64_aes(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, AES) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, AES) != 0; + } + + static inline bool isar_feature_aa64_pmull(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, AES) > 1; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, AES) > 1; + } + + static inline bool isar_feature_aa64_sha1(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA1) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, SHA1) != 0; + } + + static inline bool isar_feature_aa64_sha256(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA2) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, SHA2) != 0; + } + + static inline bool isar_feature_aa64_sha512(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA2) > 1; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, SHA2) > 1; + } + + static inline bool isar_feature_aa64_crc32(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, CRC32) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, CRC32) != 0; + } + + static inline bool isar_feature_aa64_atomics(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, ATOMIC) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, ATOMIC) != 0; + } + + static inline bool isar_feature_aa64_rdm(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, RDM) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, RDM) != 0; + } + + static inline bool isar_feature_aa64_sha3(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA3) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, SHA3) != 0; + } + + static inline bool isar_feature_aa64_sm3(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SM3) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, SM3) != 0; + } + + static inline bool isar_feature_aa64_sm4(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SM4) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, SM4) != 0; + } + + static inline bool isar_feature_aa64_dp(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, DP) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, DP) != 0; + } + + static inline bool isar_feature_aa64_fhm(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, FHM) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, FHM) != 0; + } + + static inline bool isar_feature_aa64_condm_4(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TS) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, TS) != 0; + } + + static inline bool isar_feature_aa64_condm_5(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TS) >= 2; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, TS) >= 2; + } + + static inline bool isar_feature_aa64_rndr(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, RNDR) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR0], ID_AA64ISAR0, RNDR) != 0; + } + + static inline bool isar_feature_aa64_jscvt(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, JSCVT) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, JSCVT) != 0; + } + + static inline bool isar_feature_aa64_fcma(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FCMA) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, FCMA) != 0; + } + + static inline bool isar_feature_aa64_pauth(const ARMISARegisters *id) +@@ -3611,7 +3617,7 @@ static inline bool isar_feature_aa64_pauth(const ARMISARegisters *id) + * defined algorithms, and thus API+GPI, and this predicate controls + * migration of the 128-bit keys. + */ +- return (id->id_aa64isar1 & ++ return (id->regs[ID_AA64ISAR1] & + (FIELD_DP64(0, ID_AA64ISAR1, APA, 0xf) | + FIELD_DP64(0, ID_AA64ISAR1, API, 0xf) | + FIELD_DP64(0, ID_AA64ISAR1, GPA, 0xf) | +@@ -3620,59 +3626,59 @@ static inline bool isar_feature_aa64_pauth(const ARMISARegisters *id) + + static inline bool isar_feature_aa64_sb(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, SB) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, SB) != 0; + } + + static inline bool isar_feature_aa64_predinv(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, SPECRES) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, SPECRES) != 0; + } + + static inline bool isar_feature_aa64_frint(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FRINTTS) != 0; ++ return FIELD_EX64(id->regs[ID_AA64ISAR1], ID_AA64ISAR1, FRINTTS) != 0; + } + + static inline bool isar_feature_aa64_fp16(const ARMISARegisters *id) + { + /* We always set the AdvSIMD and FP fields identically wrt FP16. */ +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) == 1; ++ return FIELD_EX64(id->regs[ID_AA64PFR0], ID_AA64PFR0, FP) == 1; + } + + static inline bool isar_feature_aa64_aa32(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, EL0) >= 2; ++ return FIELD_EX64(id->regs[ID_AA64PFR0], ID_AA64PFR0, EL0) >= 2; + } + + static inline bool isar_feature_aa64_sve(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SVE) != 0; ++ return FIELD_EX64(id->regs[ID_AA64PFR0], ID_AA64PFR0, SVE) != 0; + } + + static inline bool isar_feature_aa64_lor(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, LO) != 0; ++ return FIELD_EX64(id->regs[ID_AA64MMFR1], ID_AA64MMFR1, LO) != 0; + } + + static inline bool isar_feature_aa64_pan(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) != 0; ++ return FIELD_EX64(id->regs[ID_AA64MMFR1], ID_AA64MMFR1, PAN) != 0; + } + + static inline bool isar_feature_aa64_ats1e1(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) >= 2; ++ return FIELD_EX64(id->regs[ID_AA64MMFR1], ID_AA64MMFR1, PAN) >= 2; + } + + static inline bool isar_feature_aa64_bti(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0; ++ return FIELD_EX64(id->regs[ID_AA64PFR1], ID_AA64PFR1, BT) != 0; + } + + static inline bool isar_feature_aa64_pmu_8_1(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 && +- FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf; ++ return FIELD_EX64(id->regs[ID_AA64DFR0], ID_AA64DFR0, PMUVER) >= 4 && ++ FIELD_EX64(id->regs[ID_AA64DFR0], ID_AA64DFR0, PMUVER) != 0xf; + } + + static inline bool isar_feature_any_pmu_8_1(const ARMISARegisters *id) +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index d450b8c8..fe648752 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -116,31 +116,31 @@ static void aarch64_a57_initfn(Object *obj) + cpu->midr = 0x411fd070; + cpu->revidr = 0x00000000; + cpu->reset_fpsid = 0x41034070; +- cpu->isar.mvfr0 = 0x10110222; +- cpu->isar.mvfr1 = 0x12111111; +- cpu->isar.mvfr2 = 0x00000043; ++ cpu->isar.regs[MVFR0] = 0x10110222; ++ cpu->isar.regs[MVFR1] = 0x12111111; ++ cpu->isar.regs[MVFR2] = 0x00000043; + cpu->ctr = 0x8444c004; + cpu->reset_sctlr = 0x00c50838; + cpu->id_pfr0 = 0x00000131; + cpu->id_pfr1 = 0x00011011; +- cpu->isar.id_dfr0 = 0x03010066; ++ cpu->isar.regs[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.id_aa64pfr0 = 0x00002222; +- cpu->isar.id_aa64dfr0 = 0x10305106; +- cpu->isar.id_aa64isar0 = 0x00011120; +- cpu->isar.id_aa64mmfr0 = 0x00001124; +- cpu->isar.dbgdidr = 0x3516d000; ++ cpu->isar.regs[ID_MMFR0] = 0x10101105; ++ cpu->isar.regs[ID_MMFR1] = 0x40000000; ++ cpu->isar.regs[ID_MMFR2] = 0x01260000; ++ cpu->isar.regs[ID_MMFR3] = 0x02102211; ++ cpu->isar.regs[ID_ISAR0] = 0x02101110; ++ cpu->isar.regs[ID_ISAR1] = 0x13112111; ++ cpu->isar.regs[ID_ISAR2] = 0x21232042; ++ cpu->isar.regs[ID_ISAR3] = 0x01112131; ++ cpu->isar.regs[ID_ISAR4] = 0x00011142; ++ cpu->isar.regs[ID_ISAR5] = 0x00011121; ++ cpu->isar.regs[ID_ISAR6] = 0; ++ cpu->isar.regs[ID_AA64PFR0] = 0x00002222; ++ cpu->isar.regs[ID_AA64DFR0] = 0x10305106; ++ cpu->isar.regs[ID_AA64ISAR0] = 0x00011120; ++ cpu->isar.regs[ID_AA64MMFR0] = 0x00001124; ++ cpu->isar.regs[DBGDIDR] = 0x3516d000; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ +@@ -170,31 +170,31 @@ static void aarch64_a53_initfn(Object *obj) + cpu->midr = 0x410fd034; + cpu->revidr = 0x00000000; + cpu->reset_fpsid = 0x41034070; +- cpu->isar.mvfr0 = 0x10110222; +- cpu->isar.mvfr1 = 0x12111111; +- cpu->isar.mvfr2 = 0x00000043; ++ cpu->isar.regs[MVFR0] = 0x10110222; ++ cpu->isar.regs[MVFR1] = 0x12111111; ++ cpu->isar.regs[MVFR2] = 0x00000043; + cpu->ctr = 0x84448004; /* L1Ip = VIPT */ + cpu->reset_sctlr = 0x00c50838; + cpu->id_pfr0 = 0x00000131; + cpu->id_pfr1 = 0x00011011; +- cpu->isar.id_dfr0 = 0x03010066; ++ cpu->isar.regs[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.id_aa64pfr0 = 0x00002222; +- cpu->isar.id_aa64dfr0 = 0x10305106; +- cpu->isar.id_aa64isar0 = 0x00011120; +- cpu->isar.id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */ +- cpu->isar.dbgdidr = 0x3516d000; ++ cpu->isar.regs[ID_MMFR0] = 0x10101105; ++ cpu->isar.regs[ID_MMFR1] = 0x40000000; ++ cpu->isar.regs[ID_MMFR2] = 0x01260000; ++ cpu->isar.regs[ID_MMFR3] = 0x02102211; ++ cpu->isar.regs[ID_ISAR0] = 0x02101110; ++ cpu->isar.regs[ID_ISAR1] = 0x13112111; ++ cpu->isar.regs[ID_ISAR2] = 0x21232042; ++ cpu->isar.regs[ID_ISAR3] = 0x01112131; ++ cpu->isar.regs[ID_ISAR4] = 0x00011142; ++ cpu->isar.regs[ID_ISAR5] = 0x00011121; ++ cpu->isar.regs[ID_ISAR6] = 0; ++ cpu->isar.regs[ID_AA64PFR0] = 0x00002222; ++ cpu->isar.regs[ID_AA64DFR0] = 0x10305106; ++ cpu->isar.regs[ID_AA64ISAR0] = 0x00011120; ++ cpu->isar.regs[ID_AA64MMFR0] = 0x00001122; /* 40 bit physical addr */ ++ cpu->isar.regs[DBGDIDR] = 0x3516d000; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */ +@@ -224,30 +224,30 @@ static void aarch64_a72_initfn(Object *obj) + cpu->midr = 0x410fd083; + cpu->revidr = 0x00000000; + cpu->reset_fpsid = 0x41034080; +- cpu->isar.mvfr0 = 0x10110222; +- cpu->isar.mvfr1 = 0x12111111; +- cpu->isar.mvfr2 = 0x00000043; ++ cpu->isar.regs[MVFR0] = 0x10110222; ++ cpu->isar.regs[MVFR1] = 0x12111111; ++ cpu->isar.regs[MVFR2] = 0x00000043; + cpu->ctr = 0x8444c004; + cpu->reset_sctlr = 0x00c50838; + cpu->id_pfr0 = 0x00000131; + cpu->id_pfr1 = 0x00011011; +- cpu->isar.id_dfr0 = 0x03010066; ++ cpu->isar.regs[ID_DFR0] = 0x03010066; + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x10201105; +- 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_aa64pfr0 = 0x00002222; +- cpu->isar.id_aa64dfr0 = 0x10305106; +- cpu->isar.id_aa64isar0 = 0x00011120; +- cpu->isar.id_aa64mmfr0 = 0x00001124; +- cpu->isar.dbgdidr = 0x3516d000; ++ cpu->isar.regs[ID_MMFR0] = 0x10201105; ++ cpu->isar.regs[ID_MMFR1] = 0x40000000; ++ cpu->isar.regs[ID_MMFR2] = 0x01260000; ++ cpu->isar.regs[ID_MMFR3] = 0x02102211; ++ cpu->isar.regs[ID_ISAR0] = 0x02101110; ++ cpu->isar.regs[ID_ISAR1] = 0x13112111; ++ cpu->isar.regs[ID_ISAR2] = 0x21232042; ++ cpu->isar.regs[ID_ISAR3] = 0x01112131; ++ cpu->isar.regs[ID_ISAR4] = 0x00011142; ++ cpu->isar.regs[ID_ISAR5] = 0x00011121; ++ cpu->isar.regs[ID_AA64PFR0] = 0x00002222; ++ cpu->isar.regs[ID_AA64DFR0] = 0x10305106; ++ cpu->isar.regs[ID_AA64ISAR0] = 0x00011120; ++ cpu->isar.regs[ID_AA64MMFR0] = 0x00001124; ++ cpu->isar.regs[DBGDIDR] = 0x3516d000; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ +@@ -275,10 +275,10 @@ static void aarch64_kunpeng_920_initfn(Object *obj) + + cpu->midr = 0x480fd010; + cpu->ctr = 0x84448004; +- cpu->isar.id_aa64pfr0 = 0x11001111; +- cpu->isar.id_aa64dfr0 = 0x110305408; +- cpu->isar.id_aa64isar0 = 0x10211120; +- cpu->isar.id_aa64mmfr0 = 0x101125; ++ cpu->isar.regs[ID_AA64PFR0] = 0x11001111; ++ cpu->isar.regs[ID_AA64DFR0] = 0x110305408; ++ cpu->isar.regs[ID_AA64ISAR0] = 0x10211120; ++ cpu->isar.regs[ID_AA64MMFR0] = 0x101125; + } + + static void cpu_max_get_sve_vq(Object *obj, Visitor *v, const char *name, +@@ -321,7 +321,7 @@ static void aarch64_max_initfn(Object *obj) + uint32_t u; + aarch64_a57_initfn(obj); + +- t = cpu->isar.id_aa64isar0; ++ t = cpu->isar.regs[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 */ +@@ -335,9 +335,9 @@ static void aarch64_max_initfn(Object *obj) + 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, RNDR, 1); +- cpu->isar.id_aa64isar0 = t; ++ cpu->isar.regs[ID_AA64ISAR0] = t; + +- t = cpu->isar.id_aa64isar1; ++ t = cpu->isar.regs[ID_AA64ISAR1]; + t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1); + t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1); + t = FIELD_DP64(t, ID_AA64ISAR1, APA, 1); /* PAuth, architected only */ +@@ -347,45 +347,45 @@ static void aarch64_max_initfn(Object *obj) + t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1); + t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1); + t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1); +- cpu->isar.id_aa64isar1 = t; ++ cpu->isar.regs[ID_AA64ISAR1] = t; + +- t = cpu->isar.id_aa64pfr0; ++ t = cpu->isar.regs[ID_AA64PFR0]; + t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); + t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); + t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); +- cpu->isar.id_aa64pfr0 = t; ++ cpu->isar.regs[ID_AA64PFR0] = t; + +- t = cpu->isar.id_aa64pfr1; ++ t = cpu->isar.regs[ID_AA64PFR1]; + t = FIELD_DP64(t, ID_AA64PFR1, BT, 1); +- cpu->isar.id_aa64pfr1 = t; ++ cpu->isar.regs[ID_AA64PFR1] = t; + +- t = cpu->isar.id_aa64mmfr1; ++ t = cpu->isar.regs[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, PAN, 2); /* ATS1E1 */ +- cpu->isar.id_aa64mmfr1 = t; ++ cpu->isar.regs[ID_AA64MMFR1] = t; + + /* Replicate the same data to the 32-bit id registers. */ +- u = cpu->isar.id_isar5; ++ u = cpu->isar.regs[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; ++ cpu->isar.regs[ID_ISAR5] = u; + +- u = cpu->isar.id_isar6; ++ u = cpu->isar.regs[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); +- cpu->isar.id_isar6 = u; ++ cpu->isar.regs[ID_ISAR6] = u; + +- u = cpu->isar.id_mmfr3; ++ u = cpu->isar.regs[ID_MMFR3]; + u = FIELD_DP32(u, ID_MMFR3, PAN, 2); /* ATS1E1 */ +- cpu->isar.id_mmfr3 = u; ++ cpu->isar.regs[ID_MMFR3] = u; + + /* + * FIXME: We do not yet support ARMv8.2-fp16 for AArch32 yet, +diff --git a/target/arm/helper.c b/target/arm/helper.c +index 49cd7a7e..459af431 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -5597,7 +5597,7 @@ static void define_debug_regs(ARMCPU *cpu) + ARMCPRegInfo dbgdidr = { + .name = "DBGDIDR", .cp = 14, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL0_R, .accessfn = access_tda, +- .type = ARM_CP_CONST, .resetvalue = cpu->isar.dbgdidr, ++ .type = ARM_CP_CONST, .resetvalue = cpu->isar.regs[DBGDIDR], + }; + + /* Note that all these register fields hold "number of Xs minus 1". */ +@@ -5672,7 +5672,7 @@ static uint64_t id_pfr1_read(CPUARMState *env, const ARMCPRegInfo *ri) + static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri) + { + ARMCPU *cpu = env_archcpu(env); +- uint64_t pfr0 = cpu->isar.id_aa64pfr0; ++ uint64_t pfr0 = cpu->isar.regs[ID_AA64PFR0]; + + if (env->gicv3state) { + pfr0 |= 1 << 24; +@@ -5898,7 +5898,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + { .name = "ID_DFR0", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 2, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_dfr0 }, ++ .resetvalue = cpu->isar.regs[ID_DFR0] }, + { .name = "ID_AFR0", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 3, + .access = PL1_R, .type = ARM_CP_CONST, +@@ -5906,51 +5906,51 @@ void register_cp_regs_for_features(ARMCPU *cpu) + { .name = "ID_MMFR0", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 4, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_mmfr0 }, ++ .resetvalue = cpu->isar.regs[ID_MMFR0] }, + { .name = "ID_MMFR1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 5, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_mmfr1 }, ++ .resetvalue = cpu->isar.regs[ID_MMFR1] }, + { .name = "ID_MMFR2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 6, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_mmfr2 }, ++ .resetvalue = cpu->isar.regs[ID_MMFR2] }, + { .name = "ID_MMFR3", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 7, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_mmfr3 }, ++ .resetvalue = cpu->isar.regs[ID_MMFR3] }, + { .name = "ID_ISAR0", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_isar0 }, ++ .resetvalue = cpu->isar.regs[ID_ISAR0] }, + { .name = "ID_ISAR1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 1, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_isar1 }, ++ .resetvalue = cpu->isar.regs[ID_ISAR1] }, + { .name = "ID_ISAR2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_isar2 }, ++ .resetvalue = cpu->isar.regs[ID_ISAR2] }, + { .name = "ID_ISAR3", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 3, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_isar3 }, ++ .resetvalue = cpu->isar.regs[ID_ISAR3] }, + { .name = "ID_ISAR4", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 4, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_isar4 }, ++ .resetvalue = cpu->isar.regs[ID_ISAR4] }, + { .name = "ID_ISAR5", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 5, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_isar5 }, ++ .resetvalue = cpu->isar.regs[ID_ISAR5] }, + { .name = "ID_MMFR4", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 6, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_mmfr4 }, ++ .resetvalue = cpu->isar.regs[ID_MMFR4] }, + { .name = "ID_ISAR6", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 7, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_isar6 }, ++ .resetvalue = cpu->isar.regs[ID_ISAR6] }, + REGINFO_SENTINEL + }; + define_arm_cp_regs(cpu, v6_idregs); +@@ -6074,7 +6074,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + { .name = "ID_AA64PFR1_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 1, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_aa64pfr1}, ++ .resetvalue = cpu->isar.regs[ID_AA64PFR1]}, + { .name = "ID_AA64PFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 2, + .access = PL1_R, .type = ARM_CP_CONST, +@@ -6103,11 +6103,11 @@ void register_cp_regs_for_features(ARMCPU *cpu) + { .name = "ID_AA64DFR0_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_aa64dfr0 }, ++ .resetvalue = cpu->isar.regs[ID_AA64DFR0] }, + { .name = "ID_AA64DFR1_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 1, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_aa64dfr1 }, ++ .resetvalue = cpu->isar.regs[ID_AA64DFR1] }, + { .name = "ID_AA64DFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 2, + .access = PL1_R, .type = ARM_CP_CONST, +@@ -6135,11 +6135,11 @@ void register_cp_regs_for_features(ARMCPU *cpu) + { .name = "ID_AA64ISAR0_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_aa64isar0 }, ++ .resetvalue = cpu->isar.regs[ID_AA64ISAR0] }, + { .name = "ID_AA64ISAR1_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 1, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_aa64isar1 }, ++ .resetvalue = cpu->isar.regs[ID_AA64ISAR1] }, + { .name = "ID_AA64ISAR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 2, + .access = PL1_R, .type = ARM_CP_CONST, +@@ -6167,15 +6167,15 @@ void register_cp_regs_for_features(ARMCPU *cpu) + { .name = "ID_AA64MMFR0_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_aa64mmfr0 }, ++ .resetvalue = cpu->isar.regs[ID_AA64MMFR0] }, + { .name = "ID_AA64MMFR1_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 1, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_aa64mmfr1 }, ++ .resetvalue = cpu->isar.regs[ID_AA64MMFR1] }, + { .name = "ID_AA64MMFR2_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 2, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_aa64mmfr2 }, ++ .resetvalue = cpu->isar.regs[ID_AA64MMFR2] }, + { .name = "ID_AA64MMFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 3, + .access = PL1_R, .type = ARM_CP_CONST, +@@ -6199,15 +6199,15 @@ void register_cp_regs_for_features(ARMCPU *cpu) + { .name = "MVFR0_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.mvfr0 }, ++ .resetvalue = cpu->isar.regs[MVFR0] }, + { .name = "MVFR1_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 1, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.mvfr1 }, ++ .resetvalue = cpu->isar.regs[MVFR1] }, + { .name = "MVFR2_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 2, + .access = PL1_R, .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.mvfr2 }, ++ .resetvalue = cpu->isar.regs[MVFR2] }, + { .name = "MVFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 3, + .access = PL1_R, .type = ARM_CP_CONST, +@@ -6426,7 +6426,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + define_arm_cp_regs(cpu, vmsa_pmsa_cp_reginfo); + define_arm_cp_regs(cpu, vmsa_cp_reginfo); + /* TTCBR2 is introduced with ARMv8.2-A32HPD. */ +- if (FIELD_EX32(cpu->isar.id_mmfr4, ID_MMFR4, HPDS) != 0) { ++ if (FIELD_EX32(cpu->isar.regs[ID_MMFR4], ID_MMFR4, HPDS) != 0) { + define_one_arm_cp_reg(cpu, &ttbcr2_reginfo); + } + } +diff --git a/target/arm/internals.h b/target/arm/internals.h +index 1d01ecc4..2da13ba8 100644 +--- a/target/arm/internals.h ++++ b/target/arm/internals.h +@@ -237,7 +237,7 @@ static inline unsigned int arm_pamax(ARMCPU *cpu) + [5] = 48, + }; + unsigned int parange = +- FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE); ++ FIELD_EX64(cpu->isar.regs[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. */ +@@ -865,9 +865,9 @@ static inline uint32_t arm_debug_exception_fsr(CPUARMState *env) + static inline int arm_num_brps(ARMCPU *cpu) + { + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { +- return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, BRPS) + 1; ++ return FIELD_EX64(cpu->isar.regs[ID_AA64DFR0], ID_AA64DFR0, BRPS) + 1; + } else { +- return FIELD_EX32(cpu->isar.dbgdidr, DBGDIDR, BRPS) + 1; ++ return FIELD_EX32(cpu->isar.regs[DBGDIDR], DBGDIDR, BRPS) + 1; + } + } + +@@ -879,9 +879,9 @@ static inline int arm_num_brps(ARMCPU *cpu) + static inline int arm_num_wrps(ARMCPU *cpu) + { + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { +- return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, WRPS) + 1; ++ return FIELD_EX64(cpu->isar.regs[ID_AA64DFR0], ID_AA64DFR0, WRPS) + 1; + } else { +- return FIELD_EX32(cpu->isar.dbgdidr, DBGDIDR, WRPS) + 1; ++ return FIELD_EX32(cpu->isar.regs[DBGDIDR], DBGDIDR, WRPS) + 1; + } + } + +@@ -893,9 +893,10 @@ static inline int arm_num_wrps(ARMCPU *cpu) + static inline int arm_num_ctx_cmps(ARMCPU *cpu) + { + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { +- return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS) + 1; ++ return FIELD_EX64(cpu->isar.regs[ID_AA64DFR0], ID_AA64DFR0, ++ CTX_CMPS) + 1; + } else { +- return FIELD_EX32(cpu->isar.dbgdidr, DBGDIDR, CTX_CMPS) + 1; ++ return FIELD_EX32(cpu->isar.regs[DBGDIDR], DBGDIDR, CTX_CMPS) + 1; + } + } + +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 2a88b8df..06cf31e8 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -455,7 +455,7 @@ static inline void unset_feature(uint64_t *features, int feature) + *features &= ~(1ULL << feature); + } + +-static int read_sys_reg32(int fd, uint32_t *pret, uint64_t id) ++static int read_sys_reg32(int fd, uint64_t *pret, uint64_t id) + { + uint64_t ret; + struct kvm_one_reg idreg = { .id = id, .addr = (uintptr_t)&ret }; +@@ -509,7 +509,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + ahcf->target = init.target; + ahcf->dtb_compatible = "arm,arm-v8"; + +- err = read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr0, ++ err = read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64PFR0], + ARM64_SYS_REG(3, 0, 0, 4, 0)); + if (unlikely(err < 0)) { + /* +@@ -528,24 +528,24 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + * ??? Either of these sounds like too much effort just + * to work around running a modern host kernel. + */ +- ahcf->isar.id_aa64pfr0 = 0x00000011; /* EL1&0, AArch64 only */ ++ ahcf->isar.regs[ID_AA64PFR0] = 0x00000011; /* EL1&0, AArch64 only */ + err = 0; + } else { +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr1, ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64PFR1], + ARM64_SYS_REG(3, 0, 0, 4, 1)); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr0, ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64DFR0], + ARM64_SYS_REG(3, 0, 0, 5, 0)); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr1, ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64DFR1], + ARM64_SYS_REG(3, 0, 0, 5, 1)); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar0, ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64ISAR0], + ARM64_SYS_REG(3, 0, 0, 6, 0)); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar1, ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64ISAR1], + ARM64_SYS_REG(3, 0, 0, 6, 1)); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr0, ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64MMFR0], + ARM64_SYS_REG(3, 0, 0, 7, 0)); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr1, ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64MMFR1], + ARM64_SYS_REG(3, 0, 0, 7, 1)); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr2, ++ err |= read_sys_reg64(fdarray[2], &ahcf->isar.regs[ID_AA64MMFR2], + ARM64_SYS_REG(3, 0, 0, 7, 2)); + + /* +@@ -555,38 +555,38 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + * than skipping the reads and leaving 0, as we must avoid + * considering the values in every case. + */ +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr0, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_DFR0], + ARM64_SYS_REG(3, 0, 0, 1, 2)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr0, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_MMFR0], + ARM64_SYS_REG(3, 0, 0, 1, 4)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr1, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_MMFR1], + ARM64_SYS_REG(3, 0, 0, 1, 5)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr2, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_MMFR2], + ARM64_SYS_REG(3, 0, 0, 1, 6)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr3, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_MMFR3], + ARM64_SYS_REG(3, 0, 0, 1, 7)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar0, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_ISAR0], + ARM64_SYS_REG(3, 0, 0, 2, 0)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar1, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_ISAR1], + ARM64_SYS_REG(3, 0, 0, 2, 1)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar2, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_ISAR2], + ARM64_SYS_REG(3, 0, 0, 2, 2)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar3, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_ISAR3], + ARM64_SYS_REG(3, 0, 0, 2, 3)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar4, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_ISAR4], + ARM64_SYS_REG(3, 0, 0, 2, 4)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar5, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_ISAR5], + ARM64_SYS_REG(3, 0, 0, 2, 5)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr4, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_MMFR4], + ARM64_SYS_REG(3, 0, 0, 2, 6)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar6, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[ID_ISAR6], + ARM64_SYS_REG(3, 0, 0, 2, 7)); + +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr0, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[MVFR0], + ARM64_SYS_REG(3, 0, 0, 3, 0)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr1, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[MVFR1], + ARM64_SYS_REG(3, 0, 0, 3, 1)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr2, ++ err |= read_sys_reg32(fdarray[2], &ahcf->isar.regs[MVFR2], + ARM64_SYS_REG(3, 0, 0, 3, 2)); + + /* +@@ -599,14 +599,16 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + * arch/arm64/kvm/sys_regs.c:trap_dbgidr() does. + * We only do this if the CPU supports AArch32 at EL1. + */ +- if (FIELD_EX32(ahcf->isar.id_aa64pfr0, ID_AA64PFR0, EL1) >= 2) { +- int wrps = FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, WRPS); +- int brps = FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, BRPS); ++ if (FIELD_EX32(ahcf->isar.regs[ID_AA64PFR0], ID_AA64PFR0, EL1) >= 2) { ++ int wrps = FIELD_EX64(ahcf->isar.regs[ID_AA64DFR0], ++ ID_AA64DFR0, WRPS); ++ int brps = FIELD_EX64(ahcf->isar.regs[ID_AA64DFR0], ++ ID_AA64DFR0, BRPS); + int ctx_cmps = +- FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS); ++ FIELD_EX64(ahcf->isar.regs[ID_AA64DFR0], ID_AA64DFR0, CTX_CMPS); + int version = 6; /* ARMv8 debug architecture */ + bool has_el3 = +- !!FIELD_EX32(ahcf->isar.id_aa64pfr0, ID_AA64PFR0, EL3); ++ !!FIELD_EX32(ahcf->isar.regs[ID_AA64PFR0], ID_AA64PFR0, EL3); + uint32_t dbgdidr = 0; + + dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, WRPS, wrps); +@@ -616,7 +618,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, NSUHD_IMP, has_el3); + dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, SE_IMP, has_el3); + dbgdidr |= (1 << 15); /* RES1 bit */ +- ahcf->isar.dbgdidr = dbgdidr; ++ ahcf->isar.regs[DBGDIDR] = dbgdidr; + } + } + +-- +2.25.1 + diff --git a/target-arm-ignore-evtstrm-and-cpuid-CPU-features.patch b/target-arm-ignore-evtstrm-and-cpuid-CPU-features.patch new file mode 100644 index 0000000000000000000000000000000000000000..cf9bb73b8f5bf63c5e073042ca137266fd28e894 --- /dev/null +++ b/target-arm-ignore-evtstrm-and-cpuid-CPU-features.patch @@ -0,0 +1,66 @@ +From dfedc889fafd35efd4f8382b7672bf0e556f9f45 Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Mon, 7 Sep 2020 14:07:07 +0800 +Subject: [PATCH] target/arm: ignore evtstrm and cpuid CPU features + +evtstrm and cpuid cann't be controlled by VMM: +1. evtstrm: The generic timer is configured to generate events at a + frequency of approximately 100KHz. It's controlled by the linux + kernel config CONFIG_ARM_ARCH_TIMER_EVTSTREAM. +2. cpuid: EL0 access to certain ID registers is available. It's always + set by linux kernel after 77c97b4ee2129 ("arm64: cpufeature: Expose + CPUID registers by emulation"). +However, they are exposed by getauxval() and /proc/cpuinfo. Hence, +let's report and ignore the CPU features if someone set them. + +Signed-off-by: Peng Liang +--- + target/arm/cpu64.c | 29 ++++++++++++++++++++++++++++- + 1 file changed, 28 insertions(+), 1 deletion(-) + +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 7de20848..726d123d 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -506,10 +506,37 @@ static void arm_cpu_parse_featurestr(const char *typename, char *features, + } + } + ++static const char *unconfigurable_feats[] = { ++ "evtstrm", ++ "cpuid", ++ NULL ++}; ++ ++static bool is_configurable_feat(const char *name) ++{ ++ int i; ++ ++ for (i = 0; unconfigurable_feats[i]; ++i) { ++ if (g_strcmp0(unconfigurable_feats[i], name) == 0) { ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + static void + cpu_add_feat_as_prop(const char *typename, const char *name, const char *val) + { +- GlobalProperty *prop = g_new0(typeof(*prop), 1); ++ GlobalProperty *prop; ++ ++ if (!is_configurable_feat(name)) { ++ info_report("CPU feature '%s' is not configurable by QEMU. Ignore it.", ++ name); ++ return; ++ } ++ ++ prop = g_new0(typeof(*prop), 1); + prop->driver = typename; + prop->property = g_strdup(name); + prop->value = g_strdup(val); +-- +2.28.0 + diff --git a/target-arm-introduce-CPU-feature-dependency-mechanis.patch b/target-arm-introduce-CPU-feature-dependency-mechanis.patch new file mode 100644 index 0000000000000000000000000000000000000000..8c47cba243d4890cfc205c6c9b5b04b37705664f --- /dev/null +++ b/target-arm-introduce-CPU-feature-dependency-mechanis.patch @@ -0,0 +1,184 @@ +From da538bb9d1acc22543a2b7b07ae35a62386bf226 Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Thu, 6 Aug 2020 16:14:46 +0800 +Subject: [PATCH 5/9] target/arm: introduce CPU feature dependency mechanism + +Some CPU features are dependent on other CPU features. For example, +ID_AA64PFR0_EL1.FP field and ID_AA64PFR0_EL1.AdvSIMD must have the same +value, which means FP and ADVSIMD are dependent on each other, FPHP and +ADVSIMDHP are dependent on each other. + +This commit introduces a mechanism for CPU feature dependency in +AArch64. We build a directed graph from the CPU feature dependency +relationship, each edge from->to means the `to` CPU feature is dependent +on the `from` CPU feature. And we will automatically enable/disable CPU +feature according to the directed graph. + +For example, a, b, and c CPU features are in relationship a->b->c, which +means c is dependent on b and b is dependent on a. If c is enabled by +user, then a and b is enabled automatically. And if a is disabled by +user, then b and c is disabled automatically. + +Signed-off-by: zhanghailiang +Signed-off-by: Peng Liang +--- + target/arm/cpu.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 129 insertions(+) + +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 3f63312c..d5576538 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1306,6 +1306,103 @@ static struct CPUFeatureInfo cpu_features[] = { + }, + }; + ++typedef struct CPUFeatureDep { ++ CPUFeatureInfo from, to; ++} CPUFeatureDep; ++ ++static const CPUFeatureDep feature_dependencies[] = { ++ { ++ .from = FIELD_INFO("fp", ID_AA64PFR0, FP, true, 0, 0xf, false), ++ .to = FIELD_INFO("asimd", ID_AA64PFR0, ADVSIMD, true, 0, 0xf, false), ++ }, ++ { ++ .from = FIELD_INFO("asimd", ID_AA64PFR0, ADVSIMD, true, 0, 0xf, false), ++ .to = FIELD_INFO("fp", ID_AA64PFR0, FP, true, 0, 0xf, false), ++ }, ++ { ++ .from = { ++ .reg = ID_AA64PFR0, .length = R_ID_AA64PFR0_FP_LENGTH, ++ .shift = R_ID_AA64PFR0_FP_SHIFT, .sign = true, .min_value = 1, ++ .ni_value = 0, .name = "fphp", .is_32bit = false, ++ }, ++ .to = { ++ .reg = ID_AA64PFR0, .length = R_ID_AA64PFR0_ADVSIMD_LENGTH, ++ .shift = R_ID_AA64PFR0_ADVSIMD_SHIFT, .sign = true, .min_value = 1, ++ .ni_value = 0, .name = "asimdhp", .is_32bit = false, ++ }, ++ }, ++ { ++ .from = { ++ .reg = ID_AA64PFR0, .length = R_ID_AA64PFR0_ADVSIMD_LENGTH, ++ .shift = R_ID_AA64PFR0_ADVSIMD_SHIFT, .sign = true, .min_value = 1, ++ .ni_value = 0, .name = "asimdhp", .is_32bit = false, ++ }, ++ .to = { ++ .reg = ID_AA64PFR0, .length = R_ID_AA64PFR0_FP_LENGTH, ++ .shift = R_ID_AA64PFR0_FP_SHIFT, .sign = true, .min_value = 1, ++ .ni_value = 0, .name = "fphp", .is_32bit = false, ++ }, ++ }, ++ { ++ ++ .from = FIELD_INFO("aes", ID_AA64ISAR0, AES, false, 1, 0, false), ++ .to = { ++ .reg = ID_AA64ISAR0, .length = R_ID_AA64ISAR0_AES_LENGTH, ++ .shift = R_ID_AA64ISAR0_AES_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "pmull", .is_32bit = false, ++ }, ++ }, ++ { ++ ++ .from = FIELD_INFO("sha2", ID_AA64ISAR0, SHA2, false, 1, 0, false), ++ .to = { ++ .reg = ID_AA64ISAR0, .length = R_ID_AA64ISAR0_SHA2_LENGTH, ++ .shift = R_ID_AA64ISAR0_SHA2_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "sha512", .is_32bit = false, ++ }, ++ }, ++ { ++ .from = FIELD_INFO("lrcpc", ID_AA64ISAR1, LRCPC, false, 1, 0, false), ++ .to = { ++ .reg = ID_AA64ISAR1, .length = R_ID_AA64ISAR1_LRCPC_LENGTH, ++ .shift = R_ID_AA64ISAR1_LRCPC_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "ilrcpc", .is_32bit = false, ++ }, ++ }, ++ { ++ .from = FIELD_INFO("sm3", ID_AA64ISAR0, SM3, false, 1, 0, false), ++ .to = FIELD_INFO("sm4", ID_AA64ISAR0, SM4, false, 1, 0, false), ++ }, ++ { ++ .from = FIELD_INFO("sm4", ID_AA64ISAR0, SM4, false, 1, 0, false), ++ .to = FIELD_INFO("sm3", ID_AA64ISAR0, SM3, false, 1, 0, false), ++ }, ++ { ++ .from = FIELD_INFO("sha1", ID_AA64ISAR0, SHA1, false, 1, 0, false), ++ .to = FIELD_INFO("sha2", ID_AA64ISAR0, SHA2, false, 1, 0, false), ++ }, ++ { ++ .from = FIELD_INFO("sha1", ID_AA64ISAR0, SHA1, false, 1, 0, false), ++ .to = FIELD_INFO("sha3", ID_AA64ISAR0, SHA3, false, 1, 0, false), ++ }, ++ { ++ .from = FIELD_INFO("sha3", ID_AA64ISAR0, SHA3, false, 1, 0, false), ++ .to = { ++ .reg = ID_AA64ISAR0, .length = R_ID_AA64ISAR0_SHA2_LENGTH, ++ .shift = R_ID_AA64ISAR0_SHA2_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "sha512", .is_32bit = false, ++ }, ++ }, ++ { ++ .from = { ++ .reg = ID_AA64ISAR0, .length = R_ID_AA64ISAR0_SHA2_LENGTH, ++ .shift = R_ID_AA64ISAR0_SHA2_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "sha512", .is_32bit = false, ++ }, ++ .to = FIELD_INFO("sha3", ID_AA64ISAR0, SHA3, false, 1, 0, false), ++ }, ++}; ++ + static void arm_cpu_get_bit_prop(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) + { +@@ -1342,13 +1439,45 @@ static void arm_cpu_set_bit_prop(Object *obj, Visitor *v, const char *name, + } + + if (value) { ++ if (object_property_get_bool(obj, feat->name, NULL)) { ++ return; ++ } + isar->regs[feat->reg] = deposit64(isar->regs[feat->reg], + feat->shift, feat->length, + feat->min_value); ++ /* Auto enable the features which current feature is dependent on. */ ++ for (int i = 0; i < ARRAY_SIZE(feature_dependencies); ++i) { ++ const CPUFeatureDep *d = &feature_dependencies[i]; ++ if (strcmp(d->to.name, feat->name) != 0) { ++ continue; ++ } ++ ++ object_property_set_bool(obj, true, d->from.name, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; ++ } ++ } + } else { ++ if (!object_property_get_bool(obj, feat->name, NULL)) { ++ return; ++ } + isar->regs[feat->reg] = deposit64(isar->regs[feat->reg], + feat->shift, feat->length, + feat->ni_value); ++ /* Auto disable the features which are dependent on current feature. */ ++ for (int i = 0; i < ARRAY_SIZE(feature_dependencies); ++i) { ++ const CPUFeatureDep *d = &feature_dependencies[i]; ++ if (strcmp(d->from.name, feat->name) != 0) { ++ continue; ++ } ++ ++ object_property_set_bool(obj, false, d->to.name, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; ++ } ++ } + } + } + +-- +2.25.1 + diff --git a/target-arm-introduce-KVM_CAP_ARM_CPU_FEATURE.patch b/target-arm-introduce-KVM_CAP_ARM_CPU_FEATURE.patch new file mode 100644 index 0000000000000000000000000000000000000000..0477419196061a5e452363845ffd4591bfc5ef21 --- /dev/null +++ b/target-arm-introduce-KVM_CAP_ARM_CPU_FEATURE.patch @@ -0,0 +1,92 @@ +From 7ed595242f52d0654982d41a9c2a63be2bc3378e Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Thu, 6 Aug 2020 16:14:55 +0800 +Subject: [PATCH 6/9] target/arm: introduce KVM_CAP_ARM_CPU_FEATURE + +Introduce KVM_CAP_ARM_CPU_FEATURE to check whether KVM supports to set +CPU features in ARM. + +Signed-off-by: zhanghailiang +Signed-off-by: Peng Liang +--- + linux-headers/linux/kvm.h | 2 ++ + target/arm/cpu.c | 5 +++++ + target/arm/kvm64.c | 14 ++++++++++++++ + target/arm/kvm_arm.h | 7 +++++++ + 4 files changed, 28 insertions(+) + +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index 744e888e..4844edc3 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -995,6 +995,8 @@ struct kvm_ppc_resize_hpt { + #define KVM_CAP_ARM_PTRAUTH_ADDRESS 171 + #define KVM_CAP_ARM_PTRAUTH_GENERIC 172 + ++#define KVM_CAP_ARM_CPU_FEATURE 555 ++ + #ifdef KVM_CAP_IRQ_ROUTING + + struct kvm_irq_routing_irqchip { +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index d5576538..db46afba 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1427,6 +1427,11 @@ static void arm_cpu_set_bit_prop(Object *obj, Visitor *v, const char *name, + Error *local_err = NULL; + bool value; + ++ if (!kvm_arm_cpu_feature_supported()) { ++ warn_report("KVM doesn't support to set CPU feature in arm. " ++ "Setting to `%s` is ignored.", name); ++ return; ++ } + if (dev->realized) { + qdev_prop_set_after_realize(dev, name, errp); + return; +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 06cf31e8..05345556 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -644,6 +644,20 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + return true; + } + ++bool kvm_arm_cpu_feature_supported(void) ++{ ++ static bool cpu_feature_initialized; ++ static bool cpu_feature_supported; ++ ++ if (!cpu_feature_initialized) { ++ cpu_feature_supported = kvm_check_extension(kvm_state, ++ KVM_CAP_ARM_CPU_FEATURE); ++ cpu_feature_initialized = true; ++ } ++ ++ return cpu_feature_supported; ++} ++ + #define ARM_CPU_ID_MPIDR 3, 0, 0, 0, 5 + + int kvm_arch_init_vcpu(CPUState *cs) +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index 9b7104d6..49e80878 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -239,6 +239,13 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu); + */ + void kvm_arm_add_vcpu_properties(Object *obj); + ++/** ++ * kvm_arm_cpu_feature_supported: ++ * ++ * Returns true if KVM can set CPU features and false otherwise. ++ */ ++bool kvm_arm_cpu_feature_supported(void); ++ + /** + * kvm_arm_get_max_vm_ipa_size: + * @ms: Machine state handle +-- +2.25.1 + diff --git a/target-arm-monitor-Introduce-qmp_query_cpu_model_exp.patch b/target-arm-monitor-Introduce-qmp_query_cpu_model_exp.patch new file mode 100644 index 0000000000000000000000000000000000000000..30f14bafcc5b70310e462e9b4f5ca5cb91708cef --- /dev/null +++ b/target-arm-monitor-Introduce-qmp_query_cpu_model_exp.patch @@ -0,0 +1,373 @@ +From c527fa45dd0bb03c7f35b79ff53f127297f96314 Mon Sep 17 00:00:00 2001 +From: Andrew Jones +Date: Thu, 31 Oct 2019 15:27:26 +0100 +Subject: [PATCH 12/13] target/arm/monitor: Introduce + qmp_query_cpu_model_expansion + +Add support for the query-cpu-model-expansion QMP command to Arm. We +do this selectively, only exposing CPU properties which represent +optional CPU features which the user may want to enable/disable. +Additionally we restrict the list of queryable cpu models to 'max', +'host', or the current type when KVM is in use. And, finally, we only +implement expansion type 'full', as Arm does not yet have a "base" +CPU type. More details and example queries are described in a new +document (docs/arm-cpu-features.rst). + +Note, certainly more features may be added to the list of advertised +features, e.g. 'vfp' and 'neon'. The only requirement is that we can +detect invalid configurations and emit failures at QMP query time. +For 'vfp' and 'neon' this will require some refactoring to share a +validation function between the QMP query and the CPU realize +functions. + +Signed-off-by: Andrew Jones +Reviewed-by: Richard Henderson +Reviewed-by: Eric Auger +Reviewed-by: Beata Michalska +Message-id: 20191031142734.8590-2-drjones@redhat.com +Signed-off-by: Peter Maydell +--- + docs/arm-cpu-features.rst | 137 +++++++++++++++++++++++++++++++++++ + qapi/machine-target.json | 6 +- + target/arm/monitor.c | 145 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 285 insertions(+), 3 deletions(-) + create mode 100644 docs/arm-cpu-features.rst + +diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst +new file mode 100644 +index 00000000..c79dcffb +--- /dev/null ++++ b/docs/arm-cpu-features.rst +@@ -0,0 +1,137 @@ ++================ ++ARM CPU Features ++================ ++ ++Examples of probing and using ARM CPU features ++ ++Introduction ++============ ++ ++CPU features are optional features that a CPU of supporting type may ++choose to implement or not. In QEMU, optional CPU features have ++corresponding boolean CPU proprieties that, when enabled, indicate ++that the feature is implemented, and, conversely, when disabled, ++indicate that it is not implemented. An example of an ARM CPU feature ++is the Performance Monitoring Unit (PMU). CPU types such as the ++Cortex-A15 and the Cortex-A57, which respectively implement ARM ++architecture reference manuals ARMv7-A and ARMv8-A, may both optionally ++implement PMUs. For example, if a user wants to use a Cortex-A15 without ++a PMU, then the `-cpu` parameter should contain `pmu=off` on the QEMU ++command line, i.e. `-cpu cortex-a15,pmu=off`. ++ ++As not all CPU types support all optional CPU features, then whether or ++not a CPU property exists depends on the CPU type. For example, CPUs ++that implement the ARMv8-A architecture reference manual may optionally ++support the AArch32 CPU feature, which may be enabled by disabling the ++`aarch64` CPU property. A CPU type such as the Cortex-A15, which does ++not implement ARMv8-A, will not have the `aarch64` CPU property. ++ ++QEMU's support may be limited for some CPU features, only partially ++supporting the feature or only supporting the feature under certain ++configurations. For example, the `aarch64` CPU feature, which, when ++disabled, enables the optional AArch32 CPU feature, is only supported ++when using the KVM accelerator and when running on a host CPU type that ++supports the feature. ++ ++CPU Feature Probing ++=================== ++ ++Determining which CPU features are available and functional for a given ++CPU type is possible with the `query-cpu-model-expansion` QMP command. ++Below are some examples where `scripts/qmp/qmp-shell` (see the top comment ++block in the script for usage) is used to issue the QMP commands. ++ ++(1) Determine which CPU features are available for the `max` CPU type ++ (Note, we started QEMU with qemu-system-aarch64, so `max` is ++ implementing the ARMv8-A reference manual in this case):: ++ ++ (QEMU) query-cpu-model-expansion type=full model={"name":"max"} ++ { "return": { ++ "model": { "name": "max", "props": { ++ "pmu": true, "aarch64": true ++ }}}} ++ ++We see that the `max` CPU type has the `pmu` and `aarch64` CPU features. ++We also see that the CPU features are enabled, as they are all `true`. ++ ++(2) Let's try to disable the PMU:: ++ ++ (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"pmu":false}} ++ { "return": { ++ "model": { "name": "max", "props": { ++ "pmu": false, "aarch64": true ++ }}}} ++ ++We see it worked, as `pmu` is now `false`. ++ ++(3) Let's try to disable `aarch64`, which enables the AArch32 CPU feature:: ++ ++ (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"aarch64":false}} ++ {"error": { ++ "class": "GenericError", "desc": ++ "'aarch64' feature cannot be disabled unless KVM is enabled and 32-bit EL1 is supported" ++ }} ++ ++It looks like this feature is limited to a configuration we do not ++currently have. ++ ++(4) Let's try probing CPU features for the Cortex-A15 CPU type:: ++ ++ (QEMU) query-cpu-model-expansion type=full model={"name":"cortex-a15"} ++ {"return": {"model": {"name": "cortex-a15", "props": {"pmu": true}}}} ++ ++Only the `pmu` CPU feature is available. ++ ++A note about CPU feature dependencies ++------------------------------------- ++ ++It's possible for features to have dependencies on other features. I.e. ++it may be possible to change one feature at a time without error, but ++when attempting to change all features at once an error could occur ++depending on the order they are processed. It's also possible changing ++all at once doesn't generate an error, because a feature's dependencies ++are satisfied with other features, but the same feature cannot be changed ++independently without error. For these reasons callers should always ++attempt to make their desired changes all at once in order to ensure the ++collection is valid. ++ ++A note about CPU models and KVM ++------------------------------- ++ ++Named CPU models generally do not work with KVM. There are a few cases ++that do work, e.g. using the named CPU model `cortex-a57` with KVM on a ++seattle host, but mostly if KVM is enabled the `host` CPU type must be ++used. This means the guest is provided all the same CPU features as the ++host CPU type has. And, for this reason, the `host` CPU type should ++enable all CPU features that the host has by default. Indeed it's even ++a bit strange to allow disabling CPU features that the host has when using ++the `host` CPU type, but in the absence of CPU models it's the best we can ++do if we want to launch guests without all the host's CPU features enabled. ++ ++Enabling KVM also affects the `query-cpu-model-expansion` QMP command. The ++affect is not only limited to specific features, as pointed out in example ++(3) of "CPU Feature Probing", but also to which CPU types may be expanded. ++When KVM is enabled, only the `max`, `host`, and current CPU type may be ++expanded. This restriction is necessary as it's not possible to know all ++CPU types that may work with KVM, but it does impose a small risk of users ++experiencing unexpected errors. For example on a seattle, as mentioned ++above, the `cortex-a57` CPU type is also valid when KVM is enabled. ++Therefore a user could use the `host` CPU type for the current type, but ++then attempt to query `cortex-a57`, however that query will fail with our ++restrictions. This shouldn't be an issue though as management layers and ++users have been preferring the `host` CPU type for use with KVM for quite ++some time. Additionally, if the KVM-enabled QEMU instance running on a ++seattle host is using the `cortex-a57` CPU type, then querying `cortex-a57` ++will work. ++ ++Using CPU Features ++================== ++ ++After determining which CPU features are available and supported for a ++given CPU type, then they may be selectively enabled or disabled on the ++QEMU command line with that CPU type:: ++ ++ $ qemu-system-aarch64 -M virt -cpu max,pmu=off ++ ++The example above disables the PMU for the `max` CPU type. ++ +diff --git a/qapi/machine-target.json b/qapi/machine-target.json +index 55310a6a..04623224 100644 +--- a/qapi/machine-target.json ++++ b/qapi/machine-target.json +@@ -212,7 +212,7 @@ + ## + { 'struct': 'CpuModelExpansionInfo', + 'data': { 'model': 'CpuModelInfo' }, +- 'if': 'defined(TARGET_S390X) || defined(TARGET_I386)' } ++ 'if': 'defined(TARGET_S390X) || defined(TARGET_I386) || defined(TARGET_ARM)' } + + ## + # @query-cpu-model-expansion: +@@ -237,7 +237,7 @@ + # query-cpu-model-expansion while using these is not advised. + # + # Some architectures may not support all expansion types. s390x supports +-# "full" and "static". ++# "full" and "static". Arm only supports "full". + # + # Returns: a CpuModelExpansionInfo. Returns an error if expanding CPU models is + # not supported, if the model cannot be expanded, if the model contains +@@ -251,7 +251,7 @@ + 'data': { 'type': 'CpuModelExpansionType', + 'model': 'CpuModelInfo' }, + 'returns': 'CpuModelExpansionInfo', +- 'if': 'defined(TARGET_S390X) || defined(TARGET_I386)' } ++ 'if': 'defined(TARGET_S390X) || defined(TARGET_I386) || defined(TARGET_ARM)' } + + ## + # @CpuDefinitionInfo: +diff --git a/target/arm/monitor.c b/target/arm/monitor.c +index 6ec6dd04..560970de 100644 +--- a/target/arm/monitor.c ++++ b/target/arm/monitor.c +@@ -23,7 +23,14 @@ + #include "qemu/osdep.h" + #include "hw/boards.h" + #include "kvm_arm.h" ++#include "qapi/error.h" ++#include "qapi/visitor.h" ++#include "qapi/qobject-input-visitor.h" ++#include "qapi/qapi-commands-machine-target.h" + #include "qapi/qapi-commands-misc-target.h" ++#include "qapi/qmp/qerror.h" ++#include "qapi/qmp/qdict.h" ++#include "qom/qom-qobject.h" + + static GICCapability *gic_cap_new(int version) + { +@@ -82,3 +89,141 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp) + + return head; + } ++ ++/* ++ * These are cpu model features we want to advertise. The order here ++ * matters as this is the order in which qmp_query_cpu_model_expansion ++ * will attempt to set them. If there are dependencies between features, ++ * then the order that considers those dependencies must be used. ++ */ ++static const char *cpu_model_advertised_features[] = { ++ "aarch64", "pmu", ++ NULL ++}; ++ ++CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, ++ CpuModelInfo *model, ++ Error **errp) ++{ ++ CpuModelExpansionInfo *expansion_info; ++ const QDict *qdict_in = NULL; ++ QDict *qdict_out; ++ ObjectClass *oc; ++ Object *obj; ++ const char *name; ++ int i; ++ ++ if (type != CPU_MODEL_EXPANSION_TYPE_FULL) { ++ error_setg(errp, "The requested expansion type is not supported"); ++ return NULL; ++ } ++ ++ if (!kvm_enabled() && !strcmp(model->name, "host")) { ++ error_setg(errp, "The CPU type '%s' requires KVM", model->name); ++ return NULL; ++ } ++ ++ oc = cpu_class_by_name(TYPE_ARM_CPU, model->name); ++ if (!oc) { ++ error_setg(errp, "The CPU type '%s' is not a recognized ARM CPU type", ++ model->name); ++ return NULL; ++ } ++ ++ if (kvm_enabled()) { ++ const char *cpu_type = current_machine->cpu_type; ++ int len = strlen(cpu_type) - strlen(ARM_CPU_TYPE_SUFFIX); ++ bool supported = false; ++ ++ if (!strcmp(model->name, "host") || !strcmp(model->name, "max")) { ++ /* These are kvmarm's recommended cpu types */ ++ supported = true; ++ } else if (strlen(model->name) == len && ++ !strncmp(model->name, cpu_type, len)) { ++ /* KVM is enabled and we're using this type, so it works. */ ++ supported = true; ++ } ++ if (!supported) { ++ error_setg(errp, "We cannot guarantee the CPU type '%s' works " ++ "with KVM on this host", model->name); ++ return NULL; ++ } ++ } ++ ++ if (model->props) { ++ qdict_in = qobject_to(QDict, model->props); ++ if (!qdict_in) { ++ error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict"); ++ return NULL; ++ } ++ } ++ ++ obj = object_new(object_class_get_name(oc)); ++ ++ if (qdict_in) { ++ Visitor *visitor; ++ Error *err = NULL; ++ ++ visitor = qobject_input_visitor_new(model->props); ++ visit_start_struct(visitor, NULL, NULL, 0, &err); ++ if (err) { ++ visit_free(visitor); ++ object_unref(obj); ++ error_propagate(errp, err); ++ return NULL; ++ } ++ ++ i = 0; ++ while ((name = cpu_model_advertised_features[i++]) != NULL) { ++ if (qdict_get(qdict_in, name)) { ++ object_property_set(obj, visitor, name, &err); ++ if (err) { ++ break; ++ } ++ } ++ } ++ ++ if (!err) { ++ visit_check_struct(visitor, &err); ++ } ++ visit_end_struct(visitor, NULL); ++ visit_free(visitor); ++ if (err) { ++ object_unref(obj); ++ error_propagate(errp, err); ++ return NULL; ++ } ++ } ++ ++ expansion_info = g_new0(CpuModelExpansionInfo, 1); ++ expansion_info->model = g_malloc0(sizeof(*expansion_info->model)); ++ expansion_info->model->name = g_strdup(model->name); ++ ++ qdict_out = qdict_new(); ++ ++ i = 0; ++ while ((name = cpu_model_advertised_features[i++]) != NULL) { ++ ObjectProperty *prop = object_property_find(obj, name, NULL); ++ if (prop) { ++ Error *err = NULL; ++ QObject *value; ++ ++ assert(prop->get); ++ value = object_property_get_qobject(obj, name, &err); ++ assert(!err); ++ ++ qdict_put_obj(qdict_out, name, value); ++ } ++ } ++ ++ if (!qdict_size(qdict_out)) { ++ qobject_unref(qdict_out); ++ } else { ++ expansion_info->model->props = QOBJECT(qdict_out); ++ expansion_info->model->has_props = true; ++ } ++ ++ object_unref(obj); ++ ++ return expansion_info; ++} +-- +2.25.1 + diff --git a/target-arm-monitor-query-cpu-model-expansion-crashed.patch b/target-arm-monitor-query-cpu-model-expansion-crashed.patch new file mode 100644 index 0000000000000000000000000000000000000000..60973a7c2233a8e57f23d89c69a0c3a972835e8b --- /dev/null +++ b/target-arm-monitor-query-cpu-model-expansion-crashed.patch @@ -0,0 +1,59 @@ +From 5d75b922480f3fbefe83b5bb5e241e56a16e1e3e Mon Sep 17 00:00:00 2001 +From: Liang Yan +Date: Fri, 7 Feb 2020 14:04:21 +0000 +Subject: [PATCH 13/13] target/arm/monitor: query-cpu-model-expansion crashed + qemu when using machine type none + +Commit e19afd566781 mentioned that target-arm only supports queryable +cpu models 'max', 'host', and the current type when KVM is in use. +The logic works well until using machine type none. + +For machine type none, cpu_type will be null if cpu option is not +set by command line, strlen(cpu_type) will terminate process. +So We add a check above it. + +This won't affect i386 and s390x since they do not use current_cpu. + +Signed-off-by: Liang Yan +Message-id: 20200203134251.12986-1-lyan@suse.com +Reviewed-by: Andrew Jones +Tested-by: Andrew Jones +Signed-off-by: Peter Maydell +--- + target/arm/monitor.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/target/arm/monitor.c b/target/arm/monitor.c +index 560970de..e2b1d117 100644 +--- a/target/arm/monitor.c ++++ b/target/arm/monitor.c +@@ -131,17 +131,20 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, + } + + if (kvm_enabled()) { +- const char *cpu_type = current_machine->cpu_type; +- int len = strlen(cpu_type) - strlen(ARM_CPU_TYPE_SUFFIX); + bool supported = false; + + if (!strcmp(model->name, "host") || !strcmp(model->name, "max")) { + /* These are kvmarm's recommended cpu types */ + supported = true; +- } else if (strlen(model->name) == len && +- !strncmp(model->name, cpu_type, len)) { +- /* KVM is enabled and we're using this type, so it works. */ +- supported = true; ++ } else if (current_machine->cpu_type) { ++ const char *cpu_type = current_machine->cpu_type; ++ int len = strlen(cpu_type) - strlen(ARM_CPU_TYPE_SUFFIX); ++ ++ if (strlen(model->name) == len && ++ !strncmp(model->name, cpu_type, len)) { ++ /* KVM is enabled and we're using this type, so it works. */ ++ supported = true; ++ } + } + if (!supported) { + error_setg(errp, "We cannot guarantee the CPU type '%s' works " +-- +2.25.1 + diff --git a/target-arm-parse-cpu-feature-related-options.patch b/target-arm-parse-cpu-feature-related-options.patch new file mode 100644 index 0000000000000000000000000000000000000000..066e231af6266d21eecaf5d0c519b8a6aa4069d6 --- /dev/null +++ b/target-arm-parse-cpu-feature-related-options.patch @@ -0,0 +1,124 @@ +From dca1df05ce3d6b17d03203fc6fd94e23548216c7 Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Thu, 6 Aug 2020 16:14:35 +0800 +Subject: [PATCH 2/9] target/arm: parse cpu feature related options + +The implementation of CPUClass::parse_features only supports CPU +features in "feature=value" format. However, libvirt maybe send us a +CPU feature string in "+feature/-feature" format. Hence, we need to +override CPUClass::parse_features to support CPU feature string in both +"feature=value" and "+feature/-feature" format. + +The logic of AArch64CPUClass::parse_features is similar to that of +X86CPUClass::parse_features. + +Signed-off-by: zhanghailiang +Signed-off-by: Peng Liang +--- + target/arm/cpu64.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 83 insertions(+) + +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index fe648752..7de20848 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -506,6 +506,88 @@ static void arm_cpu_parse_featurestr(const char *typename, char *features, + } + } + ++static void ++cpu_add_feat_as_prop(const char *typename, const char *name, const char *val) ++{ ++ GlobalProperty *prop = g_new0(typeof(*prop), 1); ++ prop->driver = typename; ++ prop->property = g_strdup(name); ++ prop->value = g_strdup(val); ++ qdev_prop_register_global(prop); ++} ++ ++static gint compare_string(gconstpointer a, gconstpointer b) ++{ ++ return g_strcmp0(a, b); ++} ++ ++static GList *plus_features, *minus_features; ++ ++static void aarch64_cpu_parse_features(const char *typename, char *features, ++ Error **errp) ++{ ++ GList *l; ++ char *featurestr; /* Single 'key=value" string being parsed */ ++ static bool cpu_globals_initialized; ++ ++ if (cpu_globals_initialized) { ++ return; ++ } ++ cpu_globals_initialized = true; ++ ++ if (!features) { ++ return; ++ } ++ for (featurestr = strtok(features, ","); ++ featurestr; ++ featurestr = strtok(NULL, ",")) { ++ const char *name; ++ const char *val = NULL; ++ char *eq = NULL; ++ ++ /* Compatibility syntax: */ ++ if (featurestr[0] == '+') { ++ plus_features = g_list_append(plus_features, ++ g_strdup(featurestr + 1)); ++ continue; ++ } else if (featurestr[0] == '-') { ++ minus_features = g_list_append(minus_features, ++ g_strdup(featurestr + 1)); ++ continue; ++ } ++ ++ eq = strchr(featurestr, '='); ++ name = featurestr; ++ if (eq) { ++ *eq++ = 0; ++ val = eq; ++ } else { ++ error_setg(errp, "Unsupported property format: %s", name); ++ return; ++ } ++ ++ if (g_list_find_custom(plus_features, name, compare_string)) { ++ warn_report("Ambiguous CPU model string. " ++ "Don't mix both \"+%s\" and \"%s=%s\"", ++ name, name, val); ++ } ++ if (g_list_find_custom(minus_features, name, compare_string)) { ++ warn_report("Ambiguous CPU model string. " ++ "Don't mix both \"-%s\" and \"%s=%s\"", ++ name, name, val); ++ } ++ cpu_add_feat_as_prop(typename, name, val); ++ } ++ ++ for (l = plus_features; l; l = l->next) { ++ cpu_add_feat_as_prop(typename, l->data, "on"); ++ } ++ ++ for (l = minus_features; l; l = l->next) { ++ cpu_add_feat_as_prop(typename, l->data, "off"); ++ } ++} ++ + static void aarch64_cpu_class_init(ObjectClass *oc, void *data) + { + CPUClass *cc = CPU_CLASS(oc); +@@ -517,6 +599,7 @@ static void aarch64_cpu_class_init(ObjectClass *oc, void *data) + cc->gdb_num_core_regs = 34; + cc->gdb_core_xml_file = "aarch64-core.xml"; + cc->gdb_arch_name = aarch64_gdb_arch_name; ++ cc->parse_features = aarch64_cpu_parse_features; + } + + static void aarch64_cpu_instance_init(Object *obj) +-- +2.25.1 + diff --git a/target-arm-register-CPU-features-for-property.patch b/target-arm-register-CPU-features-for-property.patch new file mode 100644 index 0000000000000000000000000000000000000000..ea42a63ea7620fc790d01ae94590fb4336e12c32 --- /dev/null +++ b/target-arm-register-CPU-features-for-property.patch @@ -0,0 +1,398 @@ +From f169b1f76cad9f727c701df853b05ad5e8d7f927 Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Thu, 6 Aug 2020 16:14:37 +0800 +Subject: [PATCH 3/9] target/arm: register CPU features for property + +The Arm architecture specifies a number of ID registers that are +characterized as comprising a set of 4-bit ID fields. Each ID field +identifies the presence, and possibly the level of support for, a +particular feature in an implementation of the architecture. [1] + +For most of the ID fields, there is a minimum presence value, equal to +or higher than which means the corresponding CPU feature is implemented. +Hence, we can use the minimum presence value to determine whether a CPU +feature is enabled and enable a CPU feature. + +To disable a CPU feature, setting the corresponding ID field to 0x0/0xf +(for unsigned/signed field) seems as a good idea. However, it maybe +lead to some problems. For example, ID_AA64PFR0_EL1.FP is a signed ID +field. ID_AA64PFR0_EL1.FP == 0x0 represents the implementation of FP +(floating-point) and ID_AA64PFR0_EL1.FP == 0x1 represents the +implementation of FPHP (half-precision floating-point). If +ID_AA64PFR0_EL1.FP is set to 0xf when FPHP is disabled (which is also +disable FP), guest kernel maybe stuck. Hence, we add a ni_value (means +not-implemented value) to disable a CPU feature safely. + +[1] D13.1.3 Principles of the ID scheme for fields in ID registers in + DDI.0487 + +Signed-off-by: zhanghailiang +Signed-off-by: Peng Liang +--- + target/arm/cpu.c | 343 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 343 insertions(+) + +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 5bcdad0c..3f63312c 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1034,6 +1034,347 @@ static void arm_set_init_svtor(Object *obj, Visitor *v, const char *name, + visit_type_uint32(v, name, &cpu->init_svtor, errp); + } + ++/** ++ * CPUFeatureInfo: ++ * @reg: The ID register where the ID field is in. ++ * @name: The name of the CPU feature. ++ * @length: The bit length of the ID field. ++ * @shift: The bit shift of the ID field in the ID register. ++ * @min_value: The minimum value equal to or larger than which means the CPU ++ * feature is implemented. ++ * @ni_value: Not-implemented value. It will be set to the ID field when ++ * disabling the CPU feature. Usually, it's min_value - 1. ++ * @sign: Whether the ID field is signed. ++ * @is_32bit: Whether the CPU feature is for 32-bit. ++ * ++ * In ARM, a CPU feature is described by an ID field, which is a 4-bit field in ++ * an ID register. ++ */ ++typedef struct CPUFeatureInfo { ++ CPUIDReg reg; ++ const char *name; ++ int length; ++ int shift; ++ int min_value; ++ int ni_value; ++ bool sign; ++ bool is_32bit; ++} CPUFeatureInfo; ++ ++#define FIELD_INFO(feature_name, id_reg, field, s, min_val, ni_val, is32bit) { \ ++ .reg = id_reg, \ ++ .length = R_ ## id_reg ## _ ## field ## _LENGTH, \ ++ .shift = R_ ## id_reg ## _ ## field ## _SHIFT, \ ++ .sign = s, \ ++ .min_value = min_val, \ ++ .ni_value = ni_val, \ ++ .name = feature_name, \ ++ .is_32bit = is32bit, \ ++} ++ ++static struct CPUFeatureInfo cpu_features[] = { ++ FIELD_INFO("swap", ID_ISAR0, SWAP, false, 1, 0, true), ++ FIELD_INFO("bitcount", ID_ISAR0, BITCOUNT, false, 1, 0, true), ++ FIELD_INFO("bitfield", ID_ISAR0, BITFIELD, false, 1, 0, true), ++ FIELD_INFO("cmpbranch", ID_ISAR0, CMPBRANCH, false, 1, 0, true), ++ FIELD_INFO("coproc", ID_ISAR0, COPROC, false, 1, 0, true), ++ FIELD_INFO("debug", ID_ISAR0, DEBUG, false, 1, 0, true), ++ FIELD_INFO("device", ID_ISAR0, DIVIDE, false, 1, 0, true), ++ ++ FIELD_INFO("endian", ID_ISAR1, ENDIAN, false, 1, 0, true), ++ FIELD_INFO("except", ID_ISAR1, EXCEPT, false, 1, 0, true), ++ FIELD_INFO("except_ar", ID_ISAR1, EXCEPT_AR, false, 1, 0, true), ++ FIELD_INFO("extend", ID_ISAR1, EXTEND, false, 1, 0, true), ++ FIELD_INFO("ifthen", ID_ISAR1, IFTHEN, false, 1, 0, true), ++ FIELD_INFO("immediate", ID_ISAR1, IMMEDIATE, false, 1, 0, true), ++ FIELD_INFO("interwork", ID_ISAR1, INTERWORK, false, 1, 0, true), ++ FIELD_INFO("jazelle", ID_ISAR1, JAZELLE, false, 1, 0, true), ++ ++ FIELD_INFO("loadstore", ID_ISAR2, LOADSTORE, false, 1, 0, true), ++ FIELD_INFO("memhint", ID_ISAR2, MEMHINT, false, 1, 0, true), ++ FIELD_INFO("multiaccessint", ID_ISAR2, MULTIACCESSINT, false, 1, 0, true), ++ FIELD_INFO("mult", ID_ISAR2, MULT, false, 1, 0, true), ++ FIELD_INFO("mults", ID_ISAR2, MULTS, false, 1, 0, true), ++ FIELD_INFO("multu", ID_ISAR2, MULTU, false, 1, 0, true), ++ FIELD_INFO("psr_ar", ID_ISAR2, PSR_AR, false, 1, 0, true), ++ FIELD_INFO("reversal", ID_ISAR2, REVERSAL, false, 1, 0, true), ++ ++ FIELD_INFO("saturate", ID_ISAR3, SATURATE, false, 1, 0, true), ++ FIELD_INFO("simd", ID_ISAR3, SIMD, false, 1, 0, true), ++ FIELD_INFO("svc", ID_ISAR3, SVC, false, 1, 0, true), ++ FIELD_INFO("synchprim", ID_ISAR3, SYNCHPRIM, false, 1, 0, true), ++ FIELD_INFO("tabbranch", ID_ISAR3, TABBRANCH, false, 1, 0, true), ++ FIELD_INFO("t32copy", ID_ISAR3, T32COPY, false, 1, 0, true), ++ FIELD_INFO("truenop", ID_ISAR3, TRUENOP, false, 1, 0, true), ++ FIELD_INFO("t32ee", ID_ISAR3, T32EE, false, 1, 0, true), ++ ++ FIELD_INFO("unpriv", ID_ISAR4, UNPRIV, false, 1, 0, true), ++ FIELD_INFO("withshifts", ID_ISAR4, WITHSHIFTS, false, 1, 0, true), ++ FIELD_INFO("writeback", ID_ISAR4, WRITEBACK, false, 1, 0, true), ++ FIELD_INFO("smc", ID_ISAR4, SMC, false, 1, 0, true), ++ FIELD_INFO("barrier", ID_ISAR4, BARRIER, false, 1, 0, true), ++ FIELD_INFO("synchprim_frac", ID_ISAR4, SYNCHPRIM_FRAC, false, 1, 0, true), ++ FIELD_INFO("psr_m", ID_ISAR4, PSR_M, false, 1, 0, true), ++ FIELD_INFO("swp_frac", ID_ISAR4, SWP_FRAC, false, 1, 0, true), ++ ++ FIELD_INFO("sevl", ID_ISAR5, SEVL, false, 1, 0, true), ++ FIELD_INFO("aes", ID_ISAR5, AES, false, 1, 0, true), ++ FIELD_INFO("sha1", ID_ISAR5, SHA1, false, 1, 0, true), ++ FIELD_INFO("sha2", ID_ISAR5, SHA2, false, 1, 0, true), ++ FIELD_INFO("crc32", ID_ISAR5, CRC32, false, 1, 0, true), ++ FIELD_INFO("rdm", ID_ISAR5, RDM, false, 1, 0, true), ++ FIELD_INFO("vcma", ID_ISAR5, VCMA, false, 1, 0, true), ++ ++ FIELD_INFO("jscvt", ID_ISAR6, JSCVT, false, 1, 0, true), ++ FIELD_INFO("dp", ID_ISAR6, DP, false, 1, 0, true), ++ FIELD_INFO("fhm", ID_ISAR6, FHM, false, 1, 0, true), ++ FIELD_INFO("sb", ID_ISAR6, SB, false, 1, 0, true), ++ FIELD_INFO("specres", ID_ISAR6, SPECRES, false, 1, 0, true), ++ ++ FIELD_INFO("cmaintva", ID_MMFR3, CMAINTVA, false, 1, 0, true), ++ FIELD_INFO("cmaintsw", ID_MMFR3, CMAINTSW, false, 1, 0, true), ++ FIELD_INFO("bpmaint", ID_MMFR3, BPMAINT, false, 1, 0, true), ++ FIELD_INFO("maintbcst", ID_MMFR3, MAINTBCST, false, 1, 0, true), ++ FIELD_INFO("pan", ID_MMFR3, PAN, false, 1, 0, true), ++ FIELD_INFO("cohwalk", ID_MMFR3, COHWALK, false, 1, 0, true), ++ FIELD_INFO("cmemsz", ID_MMFR3, CMEMSZ, false, 1, 0, true), ++ FIELD_INFO("supersec", ID_MMFR3, SUPERSEC, false, 1, 0, true), ++ ++ FIELD_INFO("specsei", ID_MMFR4, SPECSEI, false, 1, 0, true), ++ FIELD_INFO("ac2", ID_MMFR4, AC2, false, 1, 0, true), ++ FIELD_INFO("xnx", ID_MMFR4, XNX, false, 1, 0, true), ++ FIELD_INFO("cnp", ID_MMFR4, CNP, false, 1, 0, true), ++ FIELD_INFO("hpds", ID_MMFR4, HPDS, false, 1, 0, true), ++ FIELD_INFO("lsm", ID_MMFR4, LSM, false, 1, 0, true), ++ FIELD_INFO("ccidx", ID_MMFR4, CCIDX, false, 1, 0, true), ++ FIELD_INFO("evt", ID_MMFR4, EVT, false, 1, 0, true), ++ ++ FIELD_INFO("simdreg", MVFR0, SIMDREG, false, 1, 0, true), ++ FIELD_INFO("fpsp", MVFR0, FPSP, false, 1, 0, true), ++ FIELD_INFO("fpdp", MVFR0, FPDP, false, 1, 0, true), ++ FIELD_INFO("fptrap", MVFR0, FPTRAP, false, 1, 0, true), ++ FIELD_INFO("fpdivide", MVFR0, FPDIVIDE, false, 1, 0, true), ++ FIELD_INFO("fpsqrt", MVFR0, FPSQRT, false, 1, 0, true), ++ FIELD_INFO("fpshvec", MVFR0, FPSHVEC, false, 1, 0, true), ++ FIELD_INFO("fpround", MVFR0, FPROUND, false, 1, 0, true), ++ ++ FIELD_INFO("fpftz", MVFR1, FPFTZ, false, 1, 0, true), ++ FIELD_INFO("fpdnan", MVFR1, FPDNAN, false, 1, 0, true), ++ FIELD_INFO("simdls", MVFR1, SIMDLS, false, 1, 0, true), ++ FIELD_INFO("simdint", MVFR1, SIMDINT, false, 1, 0, true), ++ FIELD_INFO("simdsp", MVFR1, SIMDSP, false, 1, 0, true), ++ FIELD_INFO("simdhp", MVFR1, SIMDHP, false, 1, 0, true), ++ FIELD_INFO("fphp", MVFR1, FPHP, false, 1, 0, true), ++ FIELD_INFO("simdfmac", MVFR1, SIMDFMAC, false, 1, 0, true), ++ ++ FIELD_INFO("simdmisc", MVFR2, SIMDMISC, false, 1, 0, true), ++ FIELD_INFO("fpmisc", MVFR2, FPMISC, false, 1, 0, true), ++ ++ FIELD_INFO("debugver", ID_AA64DFR0, DEBUGVER, false, 1, 0, false), ++ FIELD_INFO("tracever", ID_AA64DFR0, TRACEVER, false, 1, 0, false), ++ FIELD_INFO("pmuver", ID_AA64DFR0, PMUVER, false, 1, 0, false), ++ FIELD_INFO("brps", ID_AA64DFR0, BRPS, false, 1, 0, false), ++ FIELD_INFO("wrps", ID_AA64DFR0, WRPS, false, 1, 0, false), ++ FIELD_INFO("ctx_cmps", ID_AA64DFR0, CTX_CMPS, false, 1, 0, false), ++ FIELD_INFO("pmsver", ID_AA64DFR0, PMSVER, false, 1, 0, false), ++ FIELD_INFO("doublelock", ID_AA64DFR0, DOUBLELOCK, false, 1, 0, false), ++ FIELD_INFO("tracefilt", ID_AA64DFR0, TRACEFILT, false, 1, 0, false), ++ ++ FIELD_INFO("aes", ID_AA64ISAR0, AES, false, 1, 0, false), ++ FIELD_INFO("sha1", ID_AA64ISAR0, SHA1, false, 1, 0, false), ++ FIELD_INFO("sha2", ID_AA64ISAR0, SHA2, false, 1, 0, false), ++ FIELD_INFO("crc32", ID_AA64ISAR0, CRC32, false, 1, 0, false), ++ FIELD_INFO("atomics", ID_AA64ISAR0, ATOMIC, false, 1, 0, false), ++ FIELD_INFO("asimdrdm", ID_AA64ISAR0, RDM, false, 1, 0, false), ++ FIELD_INFO("sha3", ID_AA64ISAR0, SHA3, false, 1, 0, false), ++ FIELD_INFO("sm3", ID_AA64ISAR0, SM3, false, 1, 0, false), ++ FIELD_INFO("sm4", ID_AA64ISAR0, SM4, false, 1, 0, false), ++ FIELD_INFO("asimddp", ID_AA64ISAR0, DP, false, 1, 0, false), ++ FIELD_INFO("asimdfhm", ID_AA64ISAR0, FHM, false, 1, 0, false), ++ FIELD_INFO("flagm", ID_AA64ISAR0, TS, false, 1, 0, false), ++ FIELD_INFO("tlb", ID_AA64ISAR0, TLB, false, 1, 0, false), ++ FIELD_INFO("rng", ID_AA64ISAR0, RNDR, false, 1, 0, false), ++ ++ FIELD_INFO("dcpop", ID_AA64ISAR1, DPB, false, 1, 0, false), ++ FIELD_INFO("papa", ID_AA64ISAR1, APA, false, 1, 0, false), ++ FIELD_INFO("api", ID_AA64ISAR1, API, false, 1, 0, false), ++ FIELD_INFO("jscvt", ID_AA64ISAR1, JSCVT, false, 1, 0, false), ++ FIELD_INFO("fcma", ID_AA64ISAR1, FCMA, false, 1, 0, false), ++ FIELD_INFO("lrcpc", ID_AA64ISAR1, LRCPC, false, 1, 0, false), ++ FIELD_INFO("pacg", ID_AA64ISAR1, GPA, false, 1, 0, false), ++ FIELD_INFO("gpi", ID_AA64ISAR1, GPI, false, 1, 0, false), ++ FIELD_INFO("frint", ID_AA64ISAR1, FRINTTS, false, 1, 0, false), ++ FIELD_INFO("sb", ID_AA64ISAR1, SB, false, 1, 0, false), ++ FIELD_INFO("specres", ID_AA64ISAR1, SPECRES, false, 1, 0, false), ++ ++ FIELD_INFO("el0", ID_AA64PFR0, EL0, false, 1, 0, false), ++ FIELD_INFO("el1", ID_AA64PFR0, EL1, false, 1, 0, false), ++ FIELD_INFO("el2", ID_AA64PFR0, EL2, false, 1, 0, false), ++ FIELD_INFO("el3", ID_AA64PFR0, EL3, false, 1, 0, false), ++ FIELD_INFO("fp", ID_AA64PFR0, FP, true, 0, 0xf, false), ++ FIELD_INFO("asimd", ID_AA64PFR0, ADVSIMD, true, 0, 0xf, false), ++ FIELD_INFO("gic", ID_AA64PFR0, GIC, false, 1, 0, false), ++ FIELD_INFO("ras", ID_AA64PFR0, RAS, false, 1, 0, false), ++ FIELD_INFO("sve", ID_AA64PFR0, SVE, false, 1, 0, false), ++ ++ FIELD_INFO("bti", ID_AA64PFR1, BT, false, 1, 0, false), ++ FIELD_INFO("sbss", ID_AA64PFR1, SBSS, false, 1, 0, false), ++ FIELD_INFO("mte", ID_AA64PFR1, MTE, false, 1, 0, false), ++ FIELD_INFO("ras_frac", ID_AA64PFR1, RAS_FRAC, false, 1, 0, false), ++ ++ FIELD_INFO("parange", ID_AA64MMFR0, PARANGE, false, 1, 0, false), ++ FIELD_INFO("asidbits", ID_AA64MMFR0, ASIDBITS, false, 1, 0, false), ++ FIELD_INFO("bigend", ID_AA64MMFR0, BIGEND, false, 1, 0, false), ++ FIELD_INFO("snsmem", ID_AA64MMFR0, SNSMEM, false, 1, 0, false), ++ FIELD_INFO("bigendel0", ID_AA64MMFR0, BIGENDEL0, false, 1, 0, false), ++ FIELD_INFO("tgran16", ID_AA64MMFR0, TGRAN16, false, 1, 0, false), ++ FIELD_INFO("tgran64", ID_AA64MMFR0, TGRAN64, false, 1, 0, false), ++ FIELD_INFO("tgran4", ID_AA64MMFR0, TGRAN4, false, 1, 0, false), ++ FIELD_INFO("tgran16_2", ID_AA64MMFR0, TGRAN16_2, false, 1, 0, false), ++ FIELD_INFO("tgran64_2", ID_AA64MMFR0, TGRAN64_2, false, 1, 0, false), ++ FIELD_INFO("tgran4_2", ID_AA64MMFR0, TGRAN4_2, false, 1, 0, false), ++ FIELD_INFO("exs", ID_AA64MMFR0, EXS, false, 1, 0, false), ++ ++ FIELD_INFO("hafdbs", ID_AA64MMFR1, HAFDBS, false, 1, 0, false), ++ FIELD_INFO("vmidbits", ID_AA64MMFR1, VMIDBITS, false, 1, 0, false), ++ FIELD_INFO("vh", ID_AA64MMFR1, VH, false, 1, 0, false), ++ FIELD_INFO("hpds", ID_AA64MMFR1, HPDS, false, 1, 0, false), ++ FIELD_INFO("lo", ID_AA64MMFR1, LO, false, 1, 0, false), ++ FIELD_INFO("pan", ID_AA64MMFR1, PAN, false, 1, 0, false), ++ FIELD_INFO("specsei", ID_AA64MMFR1, SPECSEI, false, 1, 0, false), ++ FIELD_INFO("xnx", ID_AA64MMFR1, XNX, false, 1, 0, false), ++ ++ FIELD_INFO("cnp", ID_AA64MMFR2, CNP, false, 1, 0, false), ++ FIELD_INFO("uao", ID_AA64MMFR2, UAO, false, 1, 0, false), ++ FIELD_INFO("lsm", ID_AA64MMFR2, LSM, false, 1, 0, false), ++ FIELD_INFO("iesb", ID_AA64MMFR2, IESB, false, 1, 0, false), ++ FIELD_INFO("varange", ID_AA64MMFR2, VARANGE, false, 1, 0, false), ++ FIELD_INFO("ccidx", ID_AA64MMFR2, CCIDX, false, 1, 0, false), ++ FIELD_INFO("nv", ID_AA64MMFR2, NV, false, 1, 0, false), ++ FIELD_INFO("st", ID_AA64MMFR2, ST, false, 1, 0, false), ++ FIELD_INFO("uscat", ID_AA64MMFR2, AT, false, 1, 0, false), ++ FIELD_INFO("ids", ID_AA64MMFR2, IDS, false, 1, 0, false), ++ FIELD_INFO("fwb", ID_AA64MMFR2, FWB, false, 1, 0, false), ++ FIELD_INFO("ttl", ID_AA64MMFR2, TTL, false, 1, 0, false), ++ FIELD_INFO("bbm", ID_AA64MMFR2, BBM, false, 1, 0, false), ++ FIELD_INFO("evt", ID_AA64MMFR2, EVT, false, 1, 0, false), ++ FIELD_INFO("e0pd", ID_AA64MMFR2, E0PD, false, 1, 0, false), ++ ++ FIELD_INFO("copdbg", ID_DFR0, COPDBG, false, 1, 0, false), ++ FIELD_INFO("copsdbg", ID_DFR0, COPSDBG, false, 1, 0, false), ++ FIELD_INFO("mmapdbg", ID_DFR0, MMAPDBG, false, 1, 0, false), ++ FIELD_INFO("coptrc", ID_DFR0, COPTRC, false, 1, 0, false), ++ FIELD_INFO("mmaptrc", ID_DFR0, MMAPTRC, false, 1, 0, false), ++ FIELD_INFO("mprofdbg", ID_DFR0, MPROFDBG, false, 1, 0, false), ++ FIELD_INFO("perfmon", ID_DFR0, PERFMON, false, 1, 0, false), ++ FIELD_INFO("tracefilt", ID_DFR0, TRACEFILT, false, 1, 0, false), ++ ++ { ++ .reg = ID_AA64PFR0, .length = R_ID_AA64PFR0_FP_LENGTH, ++ .shift = R_ID_AA64PFR0_FP_SHIFT, .sign = true, .min_value = 1, ++ .ni_value = 0, .name = "fphp", .is_32bit = false, ++ }, ++ { ++ .reg = ID_AA64PFR0, .length = R_ID_AA64PFR0_ADVSIMD_LENGTH, ++ .shift = R_ID_AA64PFR0_ADVSIMD_SHIFT, .sign = true, .min_value = 1, ++ .ni_value = 0, .name = "asimdhp", .is_32bit = false, ++ }, ++ { ++ .reg = ID_AA64ISAR0, .length = R_ID_AA64ISAR0_AES_LENGTH, ++ .shift = R_ID_AA64ISAR0_AES_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "pmull", .is_32bit = false, ++ }, ++ { ++ .reg = ID_AA64ISAR0, .length = R_ID_AA64ISAR0_SHA2_LENGTH, ++ .shift = R_ID_AA64ISAR0_SHA2_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "sha512", .is_32bit = false, ++ }, ++ { ++ .reg = ID_AA64ISAR0, .length = R_ID_AA64ISAR0_TS_LENGTH, ++ .shift = R_ID_AA64ISAR0_TS_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "flagm2", .is_32bit = false, ++ }, ++ { ++ .reg = ID_AA64ISAR1, .length = R_ID_AA64ISAR1_DPB_LENGTH, ++ .shift = R_ID_AA64ISAR1_DPB_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "dcpodp", .is_32bit = false, ++ }, ++ { ++ .reg = ID_AA64ISAR1, .length = R_ID_AA64ISAR1_LRCPC_LENGTH, ++ .shift = R_ID_AA64ISAR1_LRCPC_SHIFT, .sign = false, .min_value = 2, ++ .ni_value = 1, .name = "ilrcpc", .is_32bit = false, ++ }, ++}; ++ ++static void arm_cpu_get_bit_prop(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ ARMCPU *cpu = ARM_CPU(obj); ++ CPUFeatureInfo *feat = opaque; ++ int field_value = feat->sign ? sextract64(cpu->isar.regs[feat->reg], ++ feat->shift, feat->length) : ++ extract64(cpu->isar.regs[feat->reg], ++ feat->shift, feat->length); ++ bool value = field_value >= feat->min_value; ++ ++ visit_type_bool(v, name, &value, errp); ++} ++ ++static void arm_cpu_set_bit_prop(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ DeviceState *dev = DEVICE(obj); ++ ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; ++ CPUFeatureInfo *feat = opaque; ++ Error *local_err = NULL; ++ bool value; ++ ++ if (dev->realized) { ++ qdev_prop_set_after_realize(dev, name, errp); ++ return; ++ } ++ ++ visit_type_bool(v, name, &value, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; ++ } ++ ++ if (value) { ++ isar->regs[feat->reg] = deposit64(isar->regs[feat->reg], ++ feat->shift, feat->length, ++ feat->min_value); ++ } else { ++ isar->regs[feat->reg] = deposit64(isar->regs[feat->reg], ++ feat->shift, feat->length, ++ feat->ni_value); ++ } ++} ++ ++static void arm_cpu_register_feature_props(ARMCPU *cpu) ++{ ++ int i; ++ int num = ARRAY_SIZE(cpu_features); ++ ObjectProperty *op; ++ CPUARMState *env = &cpu->env; ++ ++ for (i = 0; i < num; i++) { ++ if ((arm_feature(env, ARM_FEATURE_AARCH64) && cpu_features[i].is_32bit) ++ || (!arm_feature(env, ARM_FEATURE_AARCH64) && ++ cpu_features[i].is_32bit)) { ++ continue; ++ } ++ op = object_property_find(OBJECT(cpu), cpu_features[i].name, NULL); ++ if (!op) { ++ object_property_add(OBJECT(cpu), cpu_features[i].name, "bool", ++ arm_cpu_get_bit_prop, ++ arm_cpu_set_bit_prop, ++ NULL, &cpu_features[i], &error_abort); ++ } ++ } ++} ++ + void arm_cpu_post_init(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); +@@ -1150,6 +1491,8 @@ void arm_cpu_post_init(Object *obj) + + qdev_property_add_static(DEVICE(obj), &arm_cpu_cfgend_property, + &error_abort); ++ ++ arm_cpu_register_feature_props(cpu); + } + + static void arm_cpu_finalizefn(Object *obj) +-- +2.25.1 + diff --git a/test-tpm-pass-optional-machine-options-to-swtpm-test.patch b/test-tpm-pass-optional-machine-options-to-swtpm-test.patch new file mode 100644 index 0000000000000000000000000000000000000000..fe7fd4ac907813d676cdf0c2a713e31279c29685 --- /dev/null +++ b/test-tpm-pass-optional-machine-options-to-swtpm-test.patch @@ -0,0 +1,187 @@ +From c06a3ceacc1793bc1cfe5c2a6ed510c9aea8253d Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Thu, 13 Aug 2020 20:28:25 +0800 +Subject: [PATCH 17/19] test: tpm: pass optional machine options to swtpm test + functions + +We plan to use swtpm test functions on ARM for testing the +sysbus TPM-TIS device. However on ARM there is no default machine +type. So we need to explictly pass some machine options on startup. +Let's allow this by adding a new parameter to both swtpm test +functions and update all call sites. + +Signed-off-by: Eric Auger +Reviewed-by: Stefan Berger +Message-id: 20200305165149.618-9-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + tests/tpm-crb-swtpm-test.c | 5 +++-- + tests/tpm-tests.c | 10 ++++++---- + tests/tpm-tests.h | 5 +++-- + tests/tpm-tis-swtpm-test.c | 5 +++-- + tests/tpm-util.c | 8 ++++++-- + tests/tpm-util.h | 3 ++- + 6 files changed, 23 insertions(+), 13 deletions(-) + +diff --git a/tests/tpm-crb-swtpm-test.c b/tests/tpm-crb-swtpm-test.c +index 2c4fb8ae..5228cb7a 100644 +--- a/tests/tpm-crb-swtpm-test.c ++++ b/tests/tpm-crb-swtpm-test.c +@@ -29,7 +29,8 @@ static void tpm_crb_swtpm_test(const void *data) + { + const TestState *ts = data; + +- tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_crb_transfer, "tpm-crb"); ++ tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_crb_transfer, ++ "tpm-crb", NULL); + } + + static void tpm_crb_swtpm_migration_test(const void *data) +@@ -37,7 +38,7 @@ static void tpm_crb_swtpm_migration_test(const void *data) + const TestState *ts = data; + + tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri, +- tpm_util_crb_transfer, "tpm-crb"); ++ tpm_util_crb_transfer, "tpm-crb", NULL); + } + + int main(int argc, char **argv) +diff --git a/tests/tpm-tests.c b/tests/tpm-tests.c +index e640777a..d823bda8 100644 +--- a/tests/tpm-tests.c ++++ b/tests/tpm-tests.c +@@ -30,7 +30,7 @@ tpm_test_swtpm_skip(void) + } + + void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx, +- const char *ifmodel) ++ const char *ifmodel, const char *machine_options) + { + char *args = NULL; + QTestState *s; +@@ -47,10 +47,11 @@ void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx, + g_assert_true(succ); + + args = g_strdup_printf( ++ "%s " + "-chardev socket,id=chr,path=%s " + "-tpmdev emulator,id=dev,chardev=chr " + "-device %s,tpmdev=dev", +- addr->u.q_unix.path, ifmodel); ++ machine_options ? : "", addr->u.q_unix.path, ifmodel); + + s = qtest_start(args); + g_free(args); +@@ -78,7 +79,8 @@ void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx, + void tpm_test_swtpm_migration_test(const char *src_tpm_path, + const char *dst_tpm_path, + const char *uri, tx_func *tx, +- const char *ifmodel) ++ const char *ifmodel, ++ const char *machine_options) + { + gboolean succ; + GPid src_tpm_pid, dst_tpm_pid; +@@ -100,7 +102,7 @@ void tpm_test_swtpm_migration_test(const char *src_tpm_path, + + tpm_util_migration_start_qemu(&src_qemu, &dst_qemu, + src_tpm_addr, dst_tpm_addr, uri, +- ifmodel); ++ ifmodel, machine_options); + + tpm_util_startup(src_qemu, tx); + tpm_util_pcrextend(src_qemu, tx); +diff --git a/tests/tpm-tests.h b/tests/tpm-tests.h +index b97688fe..a5df35ab 100644 +--- a/tests/tpm-tests.h ++++ b/tests/tpm-tests.h +@@ -16,11 +16,12 @@ + #include "tpm-util.h" + + void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx, +- const char *ifmodel); ++ const char *ifmodel, const char *machine_options); + + void tpm_test_swtpm_migration_test(const char *src_tpm_path, + const char *dst_tpm_path, + const char *uri, tx_func *tx, +- const char *ifmodel); ++ const char *ifmodel, ++ const char *machine_options); + + #endif /* TESTS_TPM_TESTS_H */ +diff --git a/tests/tpm-tis-swtpm-test.c b/tests/tpm-tis-swtpm-test.c +index 9f58a3a9..9470f157 100644 +--- a/tests/tpm-tis-swtpm-test.c ++++ b/tests/tpm-tis-swtpm-test.c +@@ -29,7 +29,8 @@ static void tpm_tis_swtpm_test(const void *data) + { + const TestState *ts = data; + +- tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_tis_transfer, "tpm-tis"); ++ tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_tis_transfer, ++ "tpm-tis", NULL); + } + + static void tpm_tis_swtpm_migration_test(const void *data) +@@ -37,7 +38,7 @@ static void tpm_tis_swtpm_migration_test(const void *data) + const TestState *ts = data; + + tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri, +- tpm_util_tis_transfer, "tpm-tis"); ++ tpm_util_tis_transfer, "tpm-tis", NULL); + } + + int main(int argc, char **argv) +diff --git a/tests/tpm-util.c b/tests/tpm-util.c +index e08b1376..7ecdae2f 100644 +--- a/tests/tpm-util.c ++++ b/tests/tpm-util.c +@@ -258,23 +258,27 @@ void tpm_util_migration_start_qemu(QTestState **src_qemu, + SocketAddress *src_tpm_addr, + SocketAddress *dst_tpm_addr, + const char *miguri, +- const char *ifmodel) ++ const char *ifmodel, ++ const char *machine_options) + { + char *src_qemu_args, *dst_qemu_args; + + src_qemu_args = g_strdup_printf( ++ "%s " + "-chardev socket,id=chr,path=%s " + "-tpmdev emulator,id=dev,chardev=chr " + "-device %s,tpmdev=dev ", +- src_tpm_addr->u.q_unix.path, ifmodel); ++ machine_options ? : "", src_tpm_addr->u.q_unix.path, ifmodel); + + *src_qemu = qtest_init(src_qemu_args); + + dst_qemu_args = g_strdup_printf( ++ "%s " + "-chardev socket,id=chr,path=%s " + "-tpmdev emulator,id=dev,chardev=chr " + "-device %s,tpmdev=dev " + "-incoming %s", ++ machine_options ? : "", + dst_tpm_addr->u.q_unix.path, + ifmodel, miguri); + +diff --git a/tests/tpm-util.h b/tests/tpm-util.h +index 5755698a..15e39249 100644 +--- a/tests/tpm-util.h ++++ b/tests/tpm-util.h +@@ -44,7 +44,8 @@ void tpm_util_migration_start_qemu(QTestState **src_qemu, + SocketAddress *src_tpm_addr, + SocketAddress *dst_tpm_addr, + const char *miguri, +- const char *ifmodel); ++ const char *ifmodel, ++ const char *machine_options); + + void tpm_util_wait_for_migration_complete(QTestState *who); + +-- +2.23.0 + diff --git a/test-tpm-tis-Add-Sysbus-TPM-TIS-device-test.patch b/test-tpm-tis-Add-Sysbus-TPM-TIS-device-test.patch new file mode 100644 index 0000000000000000000000000000000000000000..fe33c8f4bd99eba304dc696d70a5126c559cd052 --- /dev/null +++ b/test-tpm-tis-Add-Sysbus-TPM-TIS-device-test.patch @@ -0,0 +1,226 @@ +From 2d28c0edddeaee5e4aa6e8c6b109776cddc1c4e4 Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Thu, 13 Aug 2020 21:37:23 +0800 +Subject: [PATCH 19/19] test: tpm-tis: Add Sysbus TPM-TIS device test + +The tests themselves are the same as the ISA device ones. +Only the main() changes as the tpm-tis-device device gets +instantiated. Also the base address of the device is not +0xFED40000 anymore but matches the base address of the +ARM virt platform bus. + +Signed-off-by: Eric Auger +Reviewed-by: Stefan Berger +Message-id: 20200305165149.618-11-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + tests/Makefile.include | 5 ++ + tests/tpm-tis-device-swtpm-test.c | 76 +++++++++++++++++++++++++++ + tests/tpm-tis-device-test.c | 87 +++++++++++++++++++++++++++++++ + 3 files changed, 168 insertions(+) + create mode 100644 tests/tpm-tis-device-swtpm-test.c + create mode 100644 tests/tpm-tis-device-test.c + +diff --git a/tests/Makefile.include b/tests/Makefile.include +index 950b32a2..d6de4e10 100644 +--- a/tests/Makefile.include ++++ b/tests/Makefile.include +@@ -263,6 +263,8 @@ check-qtest-arm-y += tests/boot-serial-test$(EXESUF) + check-qtest-arm-y += tests/hexloader-test$(EXESUF) + check-qtest-arm-$(CONFIG_PFLASH_CFI02) += tests/pflash-cfi02-test$(EXESUF) + ++check-qtest-aarch64-$(CONFIG_TPM_TIS_SYSBUS) += tpm-tis-device-test ++check-qtest-aarch64-$(CONFIG_TPM_TIS_SYSBUS) += tpm-tis-device-swtpm-test + check-qtest-aarch64-y = tests/numa-test$(EXESUF) + check-qtest-aarch64-y += tests/boot-serial-test$(EXESUF) + check-qtest-aarch64-y += tests/migration-test$(EXESUF) +@@ -667,7 +669,10 @@ tests/tpm-crb-swtpm-test$(EXESUF): tests/tpm-crb-swtpm-test.o tests/tpm-emu.o \ + tests/tpm-crb-test$(EXESUF): tests/tpm-crb-test.o tests/tpm-emu.o $(test-io-obj-y) + tests/tpm-tis-swtpm-test$(EXESUF): tests/tpm-tis-swtpm-test.o tests/tpm-emu.o \ + tests/tpm-util.o tests/tpm-tests.o $(test-io-obj-y) ++tests/tpm-tis-device-swtpm-test$(EXESUF): tests/tpm-tis-device-swtpm-test.o tests/tpm-emu.o \ ++ tests/tpm-util.o tests/tpm-tests.o $(test-io-obj-y) + tests/tpm-tis-test$(EXESUF): tests/tpm-tis-test.o tests/tpm-tis-util.o tests/tpm-emu.o $(test-io-obj-y) ++tests/tpm-tis-device-test$(EXESUF): tests/tpm-tis-device-test.o tests/tpm-tis-util.o tests/tpm-emu.o $(test-io-obj-y) + tests/test-io-channel-file$(EXESUF): tests/test-io-channel-file.o \ + tests/io-channel-helpers.o $(test-io-obj-y) + tests/test-io-channel-tls$(EXESUF): tests/test-io-channel-tls.o \ +diff --git a/tests/tpm-tis-device-swtpm-test.c b/tests/tpm-tis-device-swtpm-test.c +new file mode 100644 +index 00000000..7b200351 +--- /dev/null ++++ b/tests/tpm-tis-device-swtpm-test.c +@@ -0,0 +1,76 @@ ++/* ++ * QTest testcase for Sysbus TPM TIS talking to external swtpm and swtpm ++ * migration ++ * ++ * Copyright (c) 2018 IBM Corporation ++ * with parts borrowed from migration-test.c that is: ++ * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates ++ * ++ * Authors: ++ * Stefan Berger ++ * ++ * 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 ++ ++#include "libqtest.h" ++#include "qemu/module.h" ++#include "tpm-tests.h" ++#include "hw/acpi/tpm.h" ++ ++uint64_t tpm_tis_base_addr = 0xc000000; ++#define MACHINE_OPTIONS "-machine virt,gic-version=max -accel tcg" ++ ++typedef struct TestState { ++ char *src_tpm_path; ++ char *dst_tpm_path; ++ char *uri; ++} TestState; ++ ++static void tpm_tis_swtpm_test(const void *data) ++{ ++ const TestState *ts = data; ++ ++ tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_tis_transfer, ++ "tpm-tis-device", MACHINE_OPTIONS); ++} ++ ++static void tpm_tis_swtpm_migration_test(const void *data) ++{ ++ const TestState *ts = data; ++ ++ tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri, ++ tpm_util_tis_transfer, "tpm-tis-device", ++ MACHINE_OPTIONS); ++} ++ ++int main(int argc, char **argv) ++{ ++ int ret; ++ TestState ts = { 0 }; ++ ++ ts.src_tpm_path = g_dir_make_tmp("qemu-tpm-tis-device-swtpm-test.XXXXXX", ++ NULL); ++ ts.dst_tpm_path = g_dir_make_tmp("qemu-tpm-tis-device-swtpm-test.XXXXXX", ++ NULL); ++ ts.uri = g_strdup_printf("unix:%s/migsocket", ts.src_tpm_path); ++ ++ module_call_init(MODULE_INIT_QOM); ++ g_test_init(&argc, &argv, NULL); ++ ++ qtest_add_data_func("/tpm/tis-swtpm/test", &ts, tpm_tis_swtpm_test); ++ qtest_add_data_func("/tpm/tis-swtpm-migration/test", &ts, ++ tpm_tis_swtpm_migration_test); ++ ret = g_test_run(); ++ ++ g_rmdir(ts.dst_tpm_path); ++ g_free(ts.dst_tpm_path); ++ g_rmdir(ts.src_tpm_path); ++ g_free(ts.src_tpm_path); ++ g_free(ts.uri); ++ ++ return ret; ++} +diff --git a/tests/tpm-tis-device-test.c b/tests/tpm-tis-device-test.c +new file mode 100644 +index 00000000..63ed3644 +--- /dev/null ++++ b/tests/tpm-tis-device-test.c +@@ -0,0 +1,87 @@ ++/* ++ * QTest testcase for SYSBUS TPM TIS ++ * ++ * Copyright (c) 2018 Red Hat, Inc. ++ * Copyright (c) 2018 IBM Corporation ++ * ++ * Authors: ++ * Marc-André Lureau ++ * Stefan Berger ++ * ++ * 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 ++ ++#include "io/channel-socket.h" ++#include "libqtest-single.h" ++#include "qemu/module.h" ++#include "tpm-emu.h" ++#include "tpm-util.h" ++#include "tpm-tis-util.h" ++ ++/* ++ * As the Sysbus tpm-tis-device is instantiated on the ARM virt ++ * platform bus and it is the only sysbus device dynamically ++ * instantiated, it gets plugged at its base address ++ */ ++uint64_t tpm_tis_base_addr = 0xc000000; ++ ++int main(int argc, char **argv) ++{ ++ char *tmp_path = g_dir_make_tmp("qemu-tpm-tis-device-test.XXXXXX", NULL); ++ GThread *thread; ++ TestState test; ++ char *args; ++ int ret; ++ ++ module_call_init(MODULE_INIT_QOM); ++ g_test_init(&argc, &argv, NULL); ++ ++ test.addr = g_new0(SocketAddress, 1); ++ test.addr->type = SOCKET_ADDRESS_TYPE_UNIX; ++ test.addr->u.q_unix.path = g_build_filename(tmp_path, "sock", NULL); ++ g_mutex_init(&test.data_mutex); ++ g_cond_init(&test.data_cond); ++ test.data_cond_signal = false; ++ ++ thread = g_thread_new(NULL, tpm_emu_ctrl_thread, &test); ++ tpm_emu_test_wait_cond(&test); ++ ++ args = g_strdup_printf( ++ "-machine virt,gic-version=max -accel tcg " ++ "-chardev socket,id=chr,path=%s " ++ "-tpmdev emulator,id=dev,chardev=chr " ++ "-device tpm-tis-device,tpmdev=dev", ++ test.addr->u.q_unix.path); ++ qtest_start(args); ++ ++ qtest_add_data_func("/tpm-tis/test_check_localities", &test, ++ tpm_tis_test_check_localities); ++ ++ qtest_add_data_func("/tpm-tis/test_check_access_reg", &test, ++ tpm_tis_test_check_access_reg); ++ ++ qtest_add_data_func("/tpm-tis/test_check_access_reg_seize", &test, ++ tpm_tis_test_check_access_reg_seize); ++ ++ qtest_add_data_func("/tpm-tis/test_check_access_reg_release", &test, ++ tpm_tis_test_check_access_reg_release); ++ ++ qtest_add_data_func("/tpm-tis/test_check_transmit", &test, ++ tpm_tis_test_check_transmit); ++ ++ ret = g_test_run(); ++ ++ qtest_end(); ++ ++ g_thread_join(thread); ++ g_unlink(test.addr->u.q_unix.path); ++ qapi_free_SocketAddress(test.addr); ++ g_rmdir(tmp_path); ++ g_free(tmp_path); ++ g_free(args); ++ return ret; ++} +-- +2.23.0 + diff --git a/test-tpm-tis-Get-prepared-to-share-tests-between-ISA.patch b/test-tpm-tis-Get-prepared-to-share-tests-between-ISA.patch new file mode 100644 index 0000000000000000000000000000000000000000..4c7be00a5f1d015d5da4fcf4791e6a175f0ff9c7 --- /dev/null +++ b/test-tpm-tis-Get-prepared-to-share-tests-between-ISA.patch @@ -0,0 +1,1044 @@ +From c8ed2a1fbe306ecbfb5c7d4156ae81c029829d95 Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Thu, 13 Aug 2020 20:56:54 +0800 +Subject: [PATCH 18/19] test: tpm-tis: Get prepared to share tests between ISA + and sysbus devices + +ISA and sysbus TPM-TIS devices will share their tests. Only +the main() will change (instantiation option is different). +Also the base address of the TPM-TIS device is going to be +different. on x86 it is located at 0xFED40000 while on ARM +it can be located at any location, discovered through the +device tree description. + +So we put shared test functions in a new object module. +Each test needs to set tpm_tis_base_addr global variable. + +Also take benefit of this move to fix "block comments using +a leading */ on a separate line" checkpatch warnings. + +Signed-off-by: Eric Auger +Reviewed-by: Stefan Berger +Message-id: 20200305165149.618-10-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + tests/Makefile.include | 2 +- + tests/tpm-crb-swtpm-test.c | 4 + + tests/tpm-crb-test.c | 3 + + tests/tpm-tis-swtpm-test.c | 3 + + tests/tpm-tis-test.c | 414 +--------------------------------- + tests/tpm-tis-util.c | 451 +++++++++++++++++++++++++++++++++++++ + tests/tpm-tis-util.h | 23 ++ + tests/tpm-util.c | 3 - + tests/tpm-util.h | 5 + + 9 files changed, 493 insertions(+), 415 deletions(-) + create mode 100644 tests/tpm-tis-util.c + create mode 100644 tests/tpm-tis-util.h + +diff --git a/tests/Makefile.include b/tests/Makefile.include +index c151de64..950b32a2 100644 +--- a/tests/Makefile.include ++++ b/tests/Makefile.include +@@ -667,7 +667,7 @@ tests/tpm-crb-swtpm-test$(EXESUF): tests/tpm-crb-swtpm-test.o tests/tpm-emu.o \ + tests/tpm-crb-test$(EXESUF): tests/tpm-crb-test.o tests/tpm-emu.o $(test-io-obj-y) + tests/tpm-tis-swtpm-test$(EXESUF): tests/tpm-tis-swtpm-test.o tests/tpm-emu.o \ + tests/tpm-util.o tests/tpm-tests.o $(test-io-obj-y) +-tests/tpm-tis-test$(EXESUF): tests/tpm-tis-test.o tests/tpm-emu.o $(test-io-obj-y) ++tests/tpm-tis-test$(EXESUF): tests/tpm-tis-test.o tests/tpm-tis-util.o tests/tpm-emu.o $(test-io-obj-y) + tests/test-io-channel-file$(EXESUF): tests/test-io-channel-file.o \ + tests/io-channel-helpers.o $(test-io-obj-y) + tests/test-io-channel-tls$(EXESUF): tests/test-io-channel-tls.o \ +diff --git a/tests/tpm-crb-swtpm-test.c b/tests/tpm-crb-swtpm-test.c +index 5228cb7a..55fdb565 100644 +--- a/tests/tpm-crb-swtpm-test.c ++++ b/tests/tpm-crb-swtpm-test.c +@@ -18,6 +18,10 @@ + #include "libqtest.h" + #include "qemu/module.h" + #include "tpm-tests.h" ++#include "hw/acpi/tpm.h" ++ ++/* Not used but needed for linking */ ++uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE; + + typedef struct TestState { + char *src_tpm_path; +diff --git a/tests/tpm-crb-test.c b/tests/tpm-crb-test.c +index a139caa5..32695810 100644 +--- a/tests/tpm-crb-test.c ++++ b/tests/tpm-crb-test.c +@@ -19,6 +19,9 @@ + #include "qemu/module.h" + #include "tpm-emu.h" + ++/* Not used but needed for linking */ ++uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE; ++ + #define TPM_CMD "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00" + + static void tpm_crb_test(const void *data) +diff --git a/tests/tpm-tis-swtpm-test.c b/tests/tpm-tis-swtpm-test.c +index 9470f157..90131cb3 100644 +--- a/tests/tpm-tis-swtpm-test.c ++++ b/tests/tpm-tis-swtpm-test.c +@@ -18,6 +18,9 @@ + #include "libqtest.h" + #include "qemu/module.h" + #include "tpm-tests.h" ++#include "hw/acpi/tpm.h" ++ ++uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE; + + typedef struct TestState { + char *src_tpm_path; +diff --git a/tests/tpm-tis-test.c b/tests/tpm-tis-test.c +index 92a7e95a..8042de13 100644 +--- a/tests/tpm-tis-test.c ++++ b/tests/tpm-tis-test.c +@@ -1,5 +1,5 @@ + /* +- * QTest testcase for TPM TIS ++ * QTest testcase for ISA TPM TIS + * + * Copyright (c) 2018 Red Hat, Inc. + * Copyright (c) 2018 IBM Corporation +@@ -20,417 +20,9 @@ + #include "libqtest.h" + #include "qemu/module.h" + #include "tpm-emu.h" ++#include "tpm-tis-util.h" + +-#define TIS_REG(LOCTY, REG) \ +- (TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG) +- +-#define DEBUG_TIS_TEST 0 +- +-#define DPRINTF(fmt, ...) do { \ +- if (DEBUG_TIS_TEST) { \ +- printf(fmt, ## __VA_ARGS__); \ +- } \ +-} while (0) +- +-#define DPRINTF_ACCESS \ +- DPRINTF("%s: %d: locty=%d l=%d access=0x%02x pending_request_flag=0x%x\n", \ +- __func__, __LINE__, locty, l, access, pending_request_flag) +- +-#define DPRINTF_STS \ +- DPRINTF("%s: %d: sts = 0x%08x\n", __func__, __LINE__, sts) +- +-static const uint8_t TPM_CMD[12] = +- "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00"; +- +-static void tpm_tis_test_check_localities(const void *data) +-{ +- uint8_t locty; +- uint8_t access; +- uint32_t ifaceid; +- uint32_t capability; +- uint32_t didvid; +- uint32_t rid; +- +- for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES; locty++) { +- access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- capability = readl(TIS_REG(locty, TPM_TIS_REG_INTF_CAPABILITY)); +- g_assert_cmpint(capability, ==, TPM_TIS_CAPABILITIES_SUPPORTED2_0); +- +- ifaceid = readl(TIS_REG(locty, TPM_TIS_REG_INTERFACE_ID)); +- g_assert_cmpint(ifaceid, ==, TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0); +- +- didvid = readl(TIS_REG(locty, TPM_TIS_REG_DID_VID)); +- g_assert_cmpint(didvid, !=, 0); +- g_assert_cmpint(didvid, !=, 0xffffffff); +- +- rid = readl(TIS_REG(locty, TPM_TIS_REG_RID)); +- g_assert_cmpint(rid, !=, 0); +- g_assert_cmpint(rid, !=, 0xffffffff); +- } +-} +- +-static void tpm_tis_test_check_access_reg(const void *data) +-{ +- uint8_t locty; +- uint8_t access; +- +- /* do not test locality 4 (hw only) */ +- for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* request use of locality */ +- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* release access */ +- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), +- TPM_TIS_ACCESS_ACTIVE_LOCALITY); +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- } +-} +- +-/* +- * Test case for seizing access by a higher number locality +- */ +-static void tpm_tis_test_check_access_reg_seize(const void *data) +-{ +- int locty, l; +- uint8_t access; +- uint8_t pending_request_flag; +- +- /* do not test locality 4 (hw only) */ +- for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { +- pending_request_flag = 0; +- +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* request use of locality */ +- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* lower localities cannot seize access */ +- for (l = 0; l < locty; l++) { +- /* lower locality is not active */ +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* try to request use from 'l' */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- +- /* requesting use from 'l' was not possible; +- we must see REQUEST_USE and possibly PENDING_REQUEST */ +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_REQUEST_USE | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* locality 'locty' must be unchanged; +- we must see PENDING_REQUEST */ +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_PENDING_REQUEST | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* try to seize from 'l' */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); +- /* seize from 'l' was not possible */ +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_REQUEST_USE | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* locality 'locty' must be unchanged */ +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_PENDING_REQUEST | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* on the next loop we will have a PENDING_REQUEST flag +- set for locality 'l' */ +- pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; +- } +- +- /* higher localities can 'seize' access but not 'request use'; +- note: this will activate first l+1, then l+2 etc. */ +- for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { +- /* try to 'request use' from 'l' */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- +- /* requesting use from 'l' was not possible; we should see +- REQUEST_USE and may see PENDING_REQUEST */ +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_REQUEST_USE | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* locality 'l-1' must be unchanged; we should always +- see PENDING_REQUEST from 'l' requesting access */ +- access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_PENDING_REQUEST | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* try to seize from 'l' */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); +- +- /* seize from 'l' was possible */ +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* l - 1 should show that it has BEEN_SEIZED */ +- access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_BEEN_SEIZED | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* clear the BEEN_SEIZED flag and make sure it's gone */ +- writeb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS), +- TPM_TIS_ACCESS_BEEN_SEIZED); +- +- access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- } +- +- /* PENDING_REQUEST will not be set if locty = 0 since all localities +- were active; in case of locty = 1, locality 0 will be active +- but no PENDING_REQUEST anywhere */ +- if (locty <= 1) { +- pending_request_flag = 0; +- } +- +- /* release access from l - 1; this activates locty - 1 */ +- l--; +- +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- +- DPRINTF("%s: %d: relinquishing control on l = %d\n", +- __func__, __LINE__, l); +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), +- TPM_TIS_ACCESS_ACTIVE_LOCALITY); +- +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- for (l = locty - 1; l >= 0; l--) { +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* release this locality */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), +- TPM_TIS_ACCESS_ACTIVE_LOCALITY); +- +- if (l == 1) { +- pending_request_flag = 0; +- } +- } +- +- /* no locality may be active now */ +- for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- } +- } +-} +- +-/* +- * Test case for getting access when higher number locality relinquishes access +- */ +-static void tpm_tis_test_check_access_reg_release(const void *data) +-{ +- int locty, l; +- uint8_t access; +- uint8_t pending_request_flag; +- +- /* do not test locality 4 (hw only) */ +- for (locty = TPM_TIS_NUM_LOCALITIES - 2; locty >= 0; locty--) { +- pending_request_flag = 0; +- +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* request use of locality */ +- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* request use of all other localities */ +- for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { +- if (l == locty) { +- continue; +- } +- /* request use of locality 'l' -- we MUST see REQUEST USE and +- may see PENDING_REQUEST */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_REQUEST_USE | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; +- } +- /* release locality 'locty' */ +- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), +- TPM_TIS_ACCESS_ACTIVE_LOCALITY); +- /* highest locality should now be active; release it and make sure the +- next higest locality is active afterwards */ +- for (l = TPM_TIS_NUM_LOCALITIES - 2; l >= 0; l--) { +- if (l == locty) { +- continue; +- } +- /* 'l' should be active now */ +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- /* 'l' relinquishes access */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), +- TPM_TIS_ACCESS_ACTIVE_LOCALITY); +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- if (l == 1 || (locty <= 1 && l == 2)) { +- pending_request_flag = 0; +- } +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- } +- } +-} +- +-/* +- * Test case for transmitting packets +- */ +-static void tpm_tis_test_check_transmit(const void *data) +-{ +- const TestState *s = data; +- uint8_t access; +- uint32_t sts; +- uint16_t bcount; +- size_t i; +- +- /* request use of locality 0 */ +- writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); +- DPRINTF_STS; +- +- g_assert_cmpint(sts & 0xff, ==, 0); +- g_assert_cmpint(sts & TPM_TIS_STS_TPM_FAMILY_MASK, ==, +- TPM_TIS_STS_TPM_FAMILY2_0); +- +- bcount = (sts >> 8) & 0xffff; +- g_assert_cmpint(bcount, >=, 128); +- +- writel(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY); +- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); +- DPRINTF_STS; +- g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_COMMAND_READY); +- +- /* transmit command */ +- for (i = 0; i < sizeof(TPM_CMD); i++) { +- writeb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO), TPM_CMD[i]); +- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); +- DPRINTF_STS; +- if (i < sizeof(TPM_CMD) - 1) { +- g_assert_cmpint(sts & 0xff, ==, +- TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); +- } else { +- g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_VALID); +- } +- g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); +- } +- /* start processing */ +- writeb(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_TPM_GO); +- +- uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND; +- do { +- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); +- if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) { +- break; +- } +- } while (g_get_monotonic_time() < end_time); +- +- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); +- DPRINTF_STS; +- g_assert_cmpint(sts & 0xff, == , +- TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); +- bcount = (sts >> 8) & 0xffff; +- +- /* read response */ +- uint8_t tpm_msg[sizeof(struct tpm_hdr)]; +- g_assert_cmpint(sizeof(tpm_msg), ==, bcount); +- +- for (i = 0; i < sizeof(tpm_msg); i++) { +- tpm_msg[i] = readb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO)); +- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); +- DPRINTF_STS; +- if (sts & TPM_TIS_STS_DATA_AVAILABLE) { +- g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); +- } +- } +- g_assert_cmpmem(tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_msg)); +- +- /* relinquish use of locality 0 */ +- writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_ACTIVE_LOCALITY); +- access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); +-} ++uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE; + + int main(int argc, char **argv) + { +diff --git a/tests/tpm-tis-util.c b/tests/tpm-tis-util.c +new file mode 100644 +index 00000000..9aff503f +--- /dev/null ++++ b/tests/tpm-tis-util.c +@@ -0,0 +1,451 @@ ++/* ++ * QTest testcase for TPM TIS: common test functions used for both ++ * the ISA and SYSBUS devices ++ * ++ * Copyright (c) 2018 Red Hat, Inc. ++ * Copyright (c) 2018 IBM Corporation ++ * ++ * Authors: ++ * Marc-André Lureau ++ * Stefan Berger ++ * ++ * 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 ++ ++#include "hw/acpi/tpm.h" ++#include "io/channel-socket.h" ++#include "libqtest.h" ++#include "qemu/module.h" ++#include "tpm-emu.h" ++#include "tpm-util.h" ++#include "tpm-tis-util.h" ++ ++#define DEBUG_TIS_TEST 0 ++ ++#define DPRINTF(fmt, ...) do { \ ++ if (DEBUG_TIS_TEST) { \ ++ printf(fmt, ## __VA_ARGS__); \ ++ } \ ++} while (0) ++ ++#define DPRINTF_ACCESS \ ++ DPRINTF("%s: %d: locty=%d l=%d access=0x%02x pending_request_flag=0x%x\n", \ ++ __func__, __LINE__, locty, l, access, pending_request_flag) ++ ++#define DPRINTF_STS \ ++ DPRINTF("%s: %d: sts = 0x%08x\n", __func__, __LINE__, sts) ++ ++static const uint8_t TPM_CMD[12] = ++ "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00"; ++ ++void tpm_tis_test_check_localities(const void *data) ++{ ++ uint8_t locty; ++ uint8_t access; ++ uint32_t ifaceid; ++ uint32_t capability; ++ uint32_t didvid; ++ uint32_t rid; ++ ++ for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES; locty++) { ++ access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ capability = readl(TIS_REG(locty, TPM_TIS_REG_INTF_CAPABILITY)); ++ g_assert_cmpint(capability, ==, TPM_TIS_CAPABILITIES_SUPPORTED2_0); ++ ++ ifaceid = readl(TIS_REG(locty, TPM_TIS_REG_INTERFACE_ID)); ++ g_assert_cmpint(ifaceid, ==, TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0); ++ ++ didvid = readl(TIS_REG(locty, TPM_TIS_REG_DID_VID)); ++ g_assert_cmpint(didvid, !=, 0); ++ g_assert_cmpint(didvid, !=, 0xffffffff); ++ ++ rid = readl(TIS_REG(locty, TPM_TIS_REG_RID)); ++ g_assert_cmpint(rid, !=, 0); ++ g_assert_cmpint(rid, !=, 0xffffffff); ++ } ++} ++ ++void tpm_tis_test_check_access_reg(const void *data) ++{ ++ uint8_t locty; ++ uint8_t access; ++ ++ /* do not test locality 4 (hw only) */ ++ for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* request use of locality */ ++ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* release access */ ++ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ } ++} ++ ++/* ++ * Test case for seizing access by a higher number locality ++ */ ++void tpm_tis_test_check_access_reg_seize(const void *data) ++{ ++ int locty, l; ++ uint8_t access; ++ uint8_t pending_request_flag; ++ ++ /* do not test locality 4 (hw only) */ ++ for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { ++ pending_request_flag = 0; ++ ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* request use of locality */ ++ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* lower localities cannot seize access */ ++ for (l = 0; l < locty; l++) { ++ /* lower locality is not active */ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* try to request use from 'l' */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ ++ /* ++ * requesting use from 'l' was not possible; ++ * we must see REQUEST_USE and possibly PENDING_REQUEST ++ */ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_REQUEST_USE | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* ++ * locality 'locty' must be unchanged; ++ * we must see PENDING_REQUEST ++ */ ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_PENDING_REQUEST | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* try to seize from 'l' */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); ++ /* seize from 'l' was not possible */ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_REQUEST_USE | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* locality 'locty' must be unchanged */ ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_PENDING_REQUEST | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* ++ * on the next loop we will have a PENDING_REQUEST flag ++ * set for locality 'l' ++ */ ++ pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; ++ } ++ ++ /* ++ * higher localities can 'seize' access but not 'request use'; ++ * note: this will activate first l+1, then l+2 etc. ++ */ ++ for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { ++ /* try to 'request use' from 'l' */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ ++ /* ++ * requesting use from 'l' was not possible; we should see ++ * REQUEST_USE and may see PENDING_REQUEST ++ */ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_REQUEST_USE | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* ++ * locality 'l-1' must be unchanged; we should always ++ * see PENDING_REQUEST from 'l' requesting access ++ */ ++ access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_PENDING_REQUEST | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* try to seize from 'l' */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); ++ ++ /* seize from 'l' was possible */ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* l - 1 should show that it has BEEN_SEIZED */ ++ access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_BEEN_SEIZED | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* clear the BEEN_SEIZED flag and make sure it's gone */ ++ writeb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS), ++ TPM_TIS_ACCESS_BEEN_SEIZED); ++ ++ access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ } ++ ++ /* ++ * PENDING_REQUEST will not be set if locty = 0 since all localities ++ * were active; in case of locty = 1, locality 0 will be active ++ * but no PENDING_REQUEST anywhere ++ */ ++ if (locty <= 1) { ++ pending_request_flag = 0; ++ } ++ ++ /* release access from l - 1; this activates locty - 1 */ ++ l--; ++ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ ++ DPRINTF("%s: %d: relinquishing control on l = %d\n", ++ __func__, __LINE__, l); ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ for (l = locty - 1; l >= 0; l--) { ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* release this locality */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ ++ if (l == 1) { ++ pending_request_flag = 0; ++ } ++ } ++ ++ /* no locality may be active now */ ++ for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ } ++ } ++} ++ ++/* ++ * Test case for getting access when higher number locality relinquishes access ++ */ ++void tpm_tis_test_check_access_reg_release(const void *data) ++{ ++ int locty, l; ++ uint8_t access; ++ uint8_t pending_request_flag; ++ ++ /* do not test locality 4 (hw only) */ ++ for (locty = TPM_TIS_NUM_LOCALITIES - 2; locty >= 0; locty--) { ++ pending_request_flag = 0; ++ ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* request use of locality */ ++ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* request use of all other localities */ ++ for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { ++ if (l == locty) { ++ continue; ++ } ++ /* ++ * request use of locality 'l' -- we MUST see REQUEST USE and ++ * may see PENDING_REQUEST ++ */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_REQUEST_USE | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; ++ } ++ /* release locality 'locty' */ ++ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ /* ++ * highest locality should now be active; release it and make sure the ++ * next higest locality is active afterwards ++ */ ++ for (l = TPM_TIS_NUM_LOCALITIES - 2; l >= 0; l--) { ++ if (l == locty) { ++ continue; ++ } ++ /* 'l' should be active now */ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ /* 'l' relinquishes access */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ if (l == 1 || (locty <= 1 && l == 2)) { ++ pending_request_flag = 0; ++ } ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ } ++ } ++} ++ ++/* ++ * Test case for transmitting packets ++ */ ++void tpm_tis_test_check_transmit(const void *data) ++{ ++ const TestState *s = data; ++ uint8_t access; ++ uint32_t sts; ++ uint16_t bcount; ++ size_t i; ++ ++ /* request use of locality 0 */ ++ writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); ++ DPRINTF_STS; ++ ++ g_assert_cmpint(sts & 0xff, ==, 0); ++ g_assert_cmpint(sts & TPM_TIS_STS_TPM_FAMILY_MASK, ==, ++ TPM_TIS_STS_TPM_FAMILY2_0); ++ ++ bcount = (sts >> 8) & 0xffff; ++ g_assert_cmpint(bcount, >=, 128); ++ ++ writel(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY); ++ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); ++ DPRINTF_STS; ++ g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_COMMAND_READY); ++ ++ /* transmit command */ ++ for (i = 0; i < sizeof(TPM_CMD); i++) { ++ writeb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO), TPM_CMD[i]); ++ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); ++ DPRINTF_STS; ++ if (i < sizeof(TPM_CMD) - 1) { ++ g_assert_cmpint(sts & 0xff, ==, ++ TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); ++ } else { ++ g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_VALID); ++ } ++ g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); ++ } ++ /* start processing */ ++ writeb(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_TPM_GO); ++ ++ uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND; ++ do { ++ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); ++ if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) { ++ break; ++ } ++ } while (g_get_monotonic_time() < end_time); ++ ++ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); ++ DPRINTF_STS; ++ g_assert_cmpint(sts & 0xff, == , ++ TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); ++ bcount = (sts >> 8) & 0xffff; ++ ++ /* read response */ ++ uint8_t tpm_msg[sizeof(struct tpm_hdr)]; ++ g_assert_cmpint(sizeof(tpm_msg), ==, bcount); ++ ++ for (i = 0; i < sizeof(tpm_msg); i++) { ++ tpm_msg[i] = readb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO)); ++ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); ++ DPRINTF_STS; ++ if (sts & TPM_TIS_STS_DATA_AVAILABLE) { ++ g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); ++ } ++ } ++ g_assert_cmpmem(tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_msg)); ++ ++ /* relinquish use of locality 0 */ ++ writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); ++} +diff --git a/tests/tpm-tis-util.h b/tests/tpm-tis-util.h +new file mode 100644 +index 00000000..d10efe86 +--- /dev/null ++++ b/tests/tpm-tis-util.h +@@ -0,0 +1,23 @@ ++/* ++ * QTest TPM TIS: Common test functions used for both the ++ * ISA and SYSBUS devices ++ * ++ * Copyright (c) 2018 IBM Corporation ++ * ++ * Authors: ++ * Stefan Berger ++ * ++ * 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 TESTS_TPM_TIS_UTIL_H ++#define TESTS_TPM_TIS_UTIL_H ++ ++void tpm_tis_test_check_localities(const void *data); ++void tpm_tis_test_check_access_reg(const void *data); ++void tpm_tis_test_check_access_reg_seize(const void *data); ++void tpm_tis_test_check_access_reg_release(const void *data); ++void tpm_tis_test_check_transmit(const void *data); ++ ++#endif /* TESTS_TPM_TIS_UTIL_H */ +diff --git a/tests/tpm-util.c b/tests/tpm-util.c +index 7ecdae2f..34efae8f 100644 +--- a/tests/tpm-util.c ++++ b/tests/tpm-util.c +@@ -19,9 +19,6 @@ + #include "tpm-util.h" + #include "qapi/qmp/qdict.h" + +-#define TIS_REG(LOCTY, REG) \ +- (TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG) +- + void tpm_util_crb_transfer(QTestState *s, + const unsigned char *req, size_t req_size, + unsigned char *rsp, size_t rsp_size) +diff --git a/tests/tpm-util.h b/tests/tpm-util.h +index 15e39249..3b97d690 100644 +--- a/tests/tpm-util.h ++++ b/tests/tpm-util.h +@@ -15,6 +15,11 @@ + + #include "io/channel-socket.h" + ++extern uint64_t tpm_tis_base_addr; ++ ++#define TIS_REG(LOCTY, REG) \ ++ (tpm_tis_base_addr + ((LOCTY) << 12) + REG) ++ + typedef void (tx_func)(QTestState *s, + const unsigned char *req, size_t req_size, + unsigned char *rsp, size_t rsp_size); +-- +2.23.0 + diff --git a/tests-Disalbe-filemonitor-testcase.patch b/tests-Disalbe-filemonitor-testcase.patch new file mode 100644 index 0000000000000000000000000000000000000000..b389299e35dd49154f6e660ee3d66237b15ec58b --- /dev/null +++ b/tests-Disalbe-filemonitor-testcase.patch @@ -0,0 +1,34 @@ +From 4f1eaa63065594276c11958e963377a09668d44b Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Thu, 6 Aug 2020 10:05:00 +0800 +Subject: [PATCH] tests: Disalbe filemonitor testcase + +Since filemonitor testcase requires that host kernel being a LTS version, +we cannot guarantee that on OBS system. Let's disable it by default. + +Signed-of-by: Ying Fang + +diff --git a/tests/Makefile.include b/tests/Makefile.include +index d8cf00c1..f3273ad3 100644 +--- a/tests/Makefile.include ++++ b/tests/Makefile.include +@@ -117,7 +117,6 @@ ifneq (,$(findstring qemu-ga,$(TOOLS))) + check-unit-$(call land,$(CONFIG_LINUX),$(CONFIG_VIRTIO_SERIAL)) += tests/test-qga$(EXESUF) + endif + check-unit-y += tests/test-timed-average$(EXESUF) +-check-unit-$(CONFIG_INOTIFY1) += tests/test-util-filemonitor$(EXESUF) + check-unit-y += tests/test-util-sockets$(EXESUF) + check-unit-$(CONFIG_BLOCK) += tests/test-authz-simple$(EXESUF) + check-unit-$(CONFIG_BLOCK) += tests/test-authz-list$(EXESUF) +@@ -654,8 +653,6 @@ tests/test-crypto-tlssession$(EXESUF): tests/test-crypto-tlssession.o \ + tests/crypto-tls-x509-helpers.o tests/pkix_asn1_tab.o \ + tests/crypto-tls-psk-helpers.o \ + $(test-crypto-obj-y) +-tests/test-util-filemonitor$(EXESUF): tests/test-util-filemonitor.o \ +- $(test-util-obj-y) + tests/test-util-sockets$(EXESUF): tests/test-util-sockets.o \ + tests/socket-helpers.o $(test-util-obj-y) + tests/test-authz-simple$(EXESUF): tests/test-authz-simple.o $(test-authz-obj-y) +-- +2.23.0 + diff --git a/tpm-Add-the-SysBus-TPM-TIS-device.patch b/tpm-Add-the-SysBus-TPM-TIS-device.patch new file mode 100644 index 0000000000000000000000000000000000000000..e0a6254025932eb942b3a15d16b66d4808a33f42 --- /dev/null +++ b/tpm-Add-the-SysBus-TPM-TIS-device.patch @@ -0,0 +1,231 @@ +From 4fe655326eeae322b621dcc25c53af722d2e1afa Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Tue, 11 Aug 2020 11:23:34 +0800 +Subject: [PATCH 14/19] tpm: Add the SysBus TPM TIS device + +Introduce the tpm-tis-device which is a sysbus device +and is bound to be used on ARM. + +Signed-off-by: Eric Auger +Reviewed-by: Stefan Berger +Tested-by: Ard Biesheuvel +Acked-by: Ard Biesheuvel +Message-id: 20200305165149.618-6-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + hw/tpm/Kconfig | 5 ++ + hw/tpm/Makefile.objs | 1 + + hw/tpm/tpm_tis_sysbus.c | 159 ++++++++++++++++++++++++++++++++++++++++ + include/sysemu/tpm.h | 1 + + 4 files changed, 166 insertions(+) + create mode 100644 hw/tpm/tpm_tis_sysbus.c + +diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig +index 686f8206..4794e7fe 100644 +--- a/hw/tpm/Kconfig ++++ b/hw/tpm/Kconfig +@@ -7,6 +7,11 @@ config TPM_TIS_ISA + depends on TPM && ISA_BUS + select TPM_TIS + ++config TPM_TIS_SYSBUS ++ bool ++ depends on TPM ++ select TPM_TIS ++ + config TPM_TIS + bool + depends on TPM +diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs +index 3ef2036c..f1ec4beb 100644 +--- a/hw/tpm/Makefile.objs ++++ b/hw/tpm/Makefile.objs +@@ -1,6 +1,7 @@ + common-obj-$(CONFIG_TPM) += tpm_util.o + obj-$(call lor,$(CONFIG_TPM_TIS),$(CONFIG_TPM_CRB)) += tpm_ppi.o + common-obj-$(CONFIG_TPM_TIS_ISA) += tpm_tis_isa.o ++common-obj-$(CONFIG_TPM_TIS_SYSBUS) += tpm_tis_sysbus.o + common-obj-$(CONFIG_TPM_TIS) += tpm_tis_common.o + common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o + common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o +diff --git a/hw/tpm/tpm_tis_sysbus.c b/hw/tpm/tpm_tis_sysbus.c +new file mode 100644 +index 00000000..18c02aed +--- /dev/null ++++ b/hw/tpm/tpm_tis_sysbus.c +@@ -0,0 +1,159 @@ ++/* ++ * tpm_tis_sysbus.c - QEMU's TPM TIS SYSBUS Device ++ * ++ * Copyright (C) 2006,2010-2013 IBM Corporation ++ * ++ * Authors: ++ * Stefan Berger ++ * David Safford ++ * ++ * Xen 4 support: Andrease Niederl ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ * Implementation of the TIS interface according to specs found at ++ * http://www.trustedcomputinggroup.org. This implementation currently ++ * supports version 1.3, 21 March 2013 ++ * In the developers menu choose the PC Client section then find the TIS ++ * specification. ++ * ++ * TPM TIS for TPM 2 implementation following TCG PC Client Platform ++ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/qdev-properties.h" ++#include "migration/vmstate.h" ++#include "tpm_util.h" ++#include "hw/sysbus.h" ++#include "tpm_tis.h" ++ ++typedef struct TPMStateSysBus { ++ /*< private >*/ ++ SysBusDevice parent_obj; ++ ++ /*< public >*/ ++ TPMState state; /* not a QOM object */ ++} TPMStateSysBus; ++ ++#define TPM_TIS_SYSBUS(obj) OBJECT_CHECK(TPMStateSysBus, (obj), TYPE_TPM_TIS_SYSBUS) ++ ++static int tpm_tis_pre_save_sysbus(void *opaque) ++{ ++ TPMStateSysBus *sbdev = opaque; ++ ++ return tpm_tis_pre_save(&sbdev->state); ++} ++ ++static const VMStateDescription vmstate_tpm_tis_sysbus = { ++ .name = "tpm-tis", ++ .version_id = 0, ++ .pre_save = tpm_tis_pre_save_sysbus, ++ .fields = (VMStateField[]) { ++ VMSTATE_BUFFER(state.buffer, TPMStateSysBus), ++ VMSTATE_UINT16(state.rw_offset, TPMStateSysBus), ++ VMSTATE_UINT8(state.active_locty, TPMStateSysBus), ++ VMSTATE_UINT8(state.aborting_locty, TPMStateSysBus), ++ VMSTATE_UINT8(state.next_locty, TPMStateSysBus), ++ ++ VMSTATE_STRUCT_ARRAY(state.loc, TPMStateSysBus, TPM_TIS_NUM_LOCALITIES, ++ 0, vmstate_locty, TPMLocality), ++ ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++static void tpm_tis_sysbus_request_completed(TPMIf *ti, int ret) ++{ ++ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(ti); ++ TPMState *s = &sbdev->state; ++ ++ tpm_tis_request_completed(s, ret); ++} ++ ++static enum TPMVersion tpm_tis_sysbus_get_tpm_version(TPMIf *ti) ++{ ++ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(ti); ++ TPMState *s = &sbdev->state; ++ ++ return tpm_tis_get_tpm_version(s); ++} ++ ++static void tpm_tis_sysbus_reset(DeviceState *dev) ++{ ++ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(dev); ++ TPMState *s = &sbdev->state; ++ ++ return tpm_tis_reset(s); ++} ++ ++static Property tpm_tis_sysbus_properties[] = { ++ DEFINE_PROP_UINT32("irq", TPMStateSysBus, state.irq_num, TPM_TIS_IRQ), ++ DEFINE_PROP_TPMBE("tpmdev", TPMStateSysBus, state.be_driver), ++ DEFINE_PROP_BOOL("ppi", TPMStateSysBus, state.ppi_enabled, true), ++ DEFINE_PROP_END_OF_LIST(), ++}; ++ ++static void tpm_tis_sysbus_initfn(Object *obj) ++{ ++ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(obj); ++ TPMState *s = &sbdev->state; ++ ++ memory_region_init_io(&s->mmio, obj, &tpm_tis_memory_ops, ++ s, "tpm-tis-mmio", ++ TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); ++ ++ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); ++ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); ++} ++ ++static void tpm_tis_sysbus_realizefn(DeviceState *dev, Error **errp) ++{ ++ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(dev); ++ TPMState *s = &sbdev->state; ++ ++ if (!tpm_find()) { ++ error_setg(errp, "at most one TPM device is permitted"); ++ return; ++ } ++ ++ if (!s->be_driver) { ++ error_setg(errp, "'tpmdev' property is required"); ++ return; ++ } ++} ++ ++static void tpm_tis_sysbus_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ TPMIfClass *tc = TPM_IF_CLASS(klass); ++ ++ dc->props = tpm_tis_sysbus_properties; ++ dc->vmsd = &vmstate_tpm_tis_sysbus; ++ tc->model = TPM_MODEL_TPM_TIS; ++ dc->realize = tpm_tis_sysbus_realizefn; ++ dc->user_creatable = true; ++ dc->reset = tpm_tis_sysbus_reset; ++ tc->request_completed = tpm_tis_sysbus_request_completed; ++ tc->get_version = tpm_tis_sysbus_get_tpm_version; ++} ++ ++static const TypeInfo tpm_tis_sysbus_info = { ++ .name = TYPE_TPM_TIS_SYSBUS, ++ .parent = TYPE_SYS_BUS_DEVICE, ++ .instance_size = sizeof(TPMStateSysBus), ++ .instance_init = tpm_tis_sysbus_initfn, ++ .class_init = tpm_tis_sysbus_class_init, ++ .interfaces = (InterfaceInfo[]) { ++ { TYPE_TPM_IF }, ++ { } ++ } ++}; ++ ++static void tpm_tis_sysbus_register(void) ++{ ++ type_register_static(&tpm_tis_sysbus_info); ++} ++ ++type_init(tpm_tis_sysbus_register) +diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h +index 1691b92c..f37851b1 100644 +--- a/include/sysemu/tpm.h ++++ b/include/sysemu/tpm.h +@@ -44,6 +44,7 @@ typedef struct TPMIfClass { + } TPMIfClass; + + #define TYPE_TPM_TIS_ISA "tpm-tis" ++#define TYPE_TPM_TIS_SYSBUS "tpm-tis-device" + #define TYPE_TPM_CRB "tpm-crb" + #define TYPE_TPM_SPAPR "tpm-spapr" + +-- +2.23.0 + diff --git a/tpm-Move-tpm_tis_show_buffer-to-tpm_util.c.patch b/tpm-Move-tpm_tis_show_buffer-to-tpm_util.c.patch new file mode 100644 index 0000000000000000000000000000000000000000..93139b5e7f8284cecf6faa9930eaa8e802db13d9 --- /dev/null +++ b/tpm-Move-tpm_tis_show_buffer-to-tpm_util.c.patch @@ -0,0 +1,146 @@ +From c6cf45f38cb6e28cf4db42296fedcd5f26ca610b Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Tue, 21 Jan 2020 10:29:30 -0500 +Subject: [PATCH 03/19] tpm: Move tpm_tis_show_buffer to tpm_util.c +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Stefan Berger +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: David Gibson +Message-Id: <20200121152935.649898-2-stefanb@linux.ibm.com> +Signed-off-by: David Gibson +Signed-off-by: jiangfangjie +--- + hw/tpm/tpm_tis.c | 32 ++++---------------------------- + hw/tpm/tpm_util.c | 25 +++++++++++++++++++++++++ + hw/tpm/tpm_util.h | 3 +++ + hw/tpm/trace-events | 2 +- + 4 files changed, 33 insertions(+), 29 deletions(-) + +diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c +index d6b32128..96a9ac48 100644 +--- a/hw/tpm/tpm_tis.c ++++ b/hw/tpm/tpm_tis.c +@@ -104,30 +104,6 @@ static uint8_t tpm_tis_locality_from_addr(hwaddr addr) + return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7); + } + +-static void tpm_tis_show_buffer(const unsigned char *buffer, +- size_t buffer_size, const char *string) +-{ +- size_t len, i; +- char *line_buffer, *p; +- +- len = MIN(tpm_cmd_get_size(buffer), buffer_size); +- +- /* +- * allocate enough room for 3 chars per buffer entry plus a +- * newline after every 16 chars and a final null terminator. +- */ +- line_buffer = g_malloc(len * 3 + (len / 16) + 1); +- +- for (i = 0, p = line_buffer; i < len; i++) { +- if (i && !(i % 16)) { +- p += sprintf(p, "\n"); +- } +- p += sprintf(p, "%.2X ", buffer[i]); +- } +- trace_tpm_tis_show_buffer(string, len, line_buffer); +- +- g_free(line_buffer); +-} + + /* + * Set the given flags in the STS register by clearing the register but +@@ -153,8 +129,8 @@ static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags) + */ + static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) + { +- if (trace_event_get_state_backends(TRACE_TPM_TIS_SHOW_BUFFER)) { +- tpm_tis_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); ++ if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { ++ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); + } + + /* +@@ -322,8 +298,8 @@ static void tpm_tis_request_completed(TPMIf *ti, int ret) + s->loc[locty].state = TPM_TIS_STATE_COMPLETION; + s->rw_offset = 0; + +- if (trace_event_get_state_backends(TRACE_TPM_TIS_SHOW_BUFFER)) { +- tpm_tis_show_buffer(s->buffer, s->be_buffer_size, "From TPM"); ++ if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { ++ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "From TPM"); + } + + if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) { +diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c +index ee41757e..8643eb50 100644 +--- a/hw/tpm/tpm_util.c ++++ b/hw/tpm/tpm_util.c +@@ -350,3 +350,28 @@ void tpm_sized_buffer_reset(TPMSizedBuffer *tsb) + tsb->buffer = NULL; + tsb->size = 0; + } ++ ++void tpm_util_show_buffer(const unsigned char *buffer, ++ size_t buffer_size, const char *string) ++{ ++ size_t len, i; ++ char *line_buffer, *p; ++ ++ len = MIN(tpm_cmd_get_size(buffer), buffer_size); ++ ++ /* ++ * allocate enough room for 3 chars per buffer entry plus a ++ * newline after every 16 chars and a final null terminator. ++ */ ++ line_buffer = g_malloc(len * 3 + (len / 16) + 1); ++ ++ for (i = 0, p = line_buffer; i < len; i++) { ++ if (i && !(i % 16)) { ++ p += sprintf(p, "\n"); ++ } ++ p += sprintf(p, "%.2X ", buffer[i]); ++ } ++ trace_tpm_util_show_buffer(string, len, line_buffer); ++ ++ g_free(line_buffer); ++} +diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h +index f397ac21..7889081f 100644 +--- a/hw/tpm/tpm_util.h ++++ b/hw/tpm/tpm_util.h +@@ -79,4 +79,7 @@ typedef struct TPMSizedBuffer { + + void tpm_sized_buffer_reset(TPMSizedBuffer *tsb); + ++void tpm_util_show_buffer(const unsigned char *buffer, ++ size_t buffer_size, const char *string); ++ + #endif /* TPM_TPM_UTIL_H */ +diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events +index 0b94aa15..82c45ee5 100644 +--- a/hw/tpm/trace-events ++++ b/hw/tpm/trace-events +@@ -14,6 +14,7 @@ tpm_util_get_buffer_size_len(uint32_t len, size_t expected) "tpm_resp->len = %u, + tpm_util_get_buffer_size_hdr_len2(uint32_t len, size_t expected) "tpm2_resp->hdr.len = %u, expected = %zu" + tpm_util_get_buffer_size_len2(uint32_t len, size_t expected) "tpm2_resp->len = %u, expected = %zu" + tpm_util_get_buffer_size(size_t len) "buffersize of device: %zu" ++tpm_util_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s" + + # tpm_emulator.c + tpm_emulator_set_locality(uint8_t locty) "setting locality to %d" +@@ -36,7 +37,6 @@ tpm_emulator_pre_save(void) "" + tpm_emulator_inst_init(void) "" + + # tpm_tis.c +-tpm_tis_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\nbuf: %s" + tpm_tis_raise_irq(uint32_t irqmask) "Raising IRQ for flag 0x%08x" + tpm_tis_new_active_locality(uint8_t locty) "Active locality is now %d" + tpm_tis_abort(uint8_t locty) "New active locality is %d" +-- +2.23.0 + diff --git a/tpm-Separate-TPM_TIS-and-TPM_TIS_ISA-configs.patch b/tpm-Separate-TPM_TIS-and-TPM_TIS_ISA-configs.patch new file mode 100644 index 0000000000000000000000000000000000000000..97dcaa000b251bd8a4390a5c68e75011aef9401f --- /dev/null +++ b/tpm-Separate-TPM_TIS-and-TPM_TIS_ISA-configs.patch @@ -0,0 +1,108 @@ +From 1eca7dbacabbc8ccc737f320839e7800fef5dfa1 Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Tue, 11 Aug 2020 12:42:31 +0800 +Subject: [PATCH 13/19] tpm: Separate TPM_TIS and TPM_TIS_ISA configs + MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 + Content-Transfer-Encoding: 8bit +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let's separate the compilation of tpm_tis_common.c from +the compilation of tpm_tis_isa.c + +The common part will be also compiled along with the +tpm_tis_sysbus device. + +Signed-off-by: Eric Auger +Reviewed-by: Philippe Mathieu-Daudé +Tested-by: Ard Biesheuvel +Acked-by: Ard Biesheuvel +Message-id: 20200305165149.618-5-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + default-configs/i386-softmmu.mak | 2 +- + hw/i386/Kconfig | 2 +- + hw/tpm/Kconfig | 7 ++++++- + hw/tpm/Makefile.objs | 3 ++- + tests/Makefile.include | 4 ++-- + 5 files changed, 12 insertions(+), 6 deletions(-) + +diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak +index cd5ea391..bdeef670 100644 +--- a/default-configs/i386-softmmu.mak ++++ b/default-configs/i386-softmmu.mak +@@ -17,7 +17,7 @@ + #CONFIG_SGA=n + #CONFIG_TEST_DEVICES=n + #CONFIG_TPM_CRB=n +-#CONFIG_TPM_TIS=n ++#CONFIG_TPM_TIS_ISA=n + #CONFIG_VTD=n + + # Boards: +diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig +index 63504380..60334504 100644 +--- a/hw/i386/Kconfig ++++ b/hw/i386/Kconfig +@@ -17,7 +17,7 @@ config PC + imply SGA + imply TEST_DEVICES + imply TPM_CRB +- imply TPM_TIS ++ imply TPM_TIS_ISA + imply VGA_PCI + imply VIRTIO_VGA + select FDC +diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig +index 9e67d990..686f8206 100644 +--- a/hw/tpm/Kconfig ++++ b/hw/tpm/Kconfig +@@ -2,9 +2,14 @@ config TPMDEV + bool + depends on TPM + +-config TPM_TIS ++config TPM_TIS_ISA + bool + depends on TPM && ISA_BUS ++ select TPM_TIS ++ ++config TPM_TIS ++ bool ++ depends on TPM + select TPMDEV + + config TPM_CRB +diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs +index fcc4c2f2..3ef2036c 100644 +--- a/hw/tpm/Makefile.objs ++++ b/hw/tpm/Makefile.objs +@@ -1,6 +1,7 @@ + common-obj-$(CONFIG_TPM) += tpm_util.o + obj-$(call lor,$(CONFIG_TPM_TIS),$(CONFIG_TPM_CRB)) += tpm_ppi.o +-common-obj-$(CONFIG_TPM_TIS) += tpm_tis_isa.o tpm_tis_common.o ++common-obj-$(CONFIG_TPM_TIS_ISA) += tpm_tis_isa.o ++common-obj-$(CONFIG_TPM_TIS) += tpm_tis_common.o + common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o + common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o + common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o +diff --git a/tests/Makefile.include b/tests/Makefile.include +index f3273ad3..c151de64 100644 +--- a/tests/Makefile.include ++++ b/tests/Makefile.include +@@ -190,8 +190,8 @@ check-qtest-i386-y += tests/q35-test$(EXESUF) + check-qtest-i386-y += tests/vmgenid-test$(EXESUF) + check-qtest-i386-$(CONFIG_TPM_CRB) += tests/tpm-crb-swtpm-test$(EXESUF) + check-qtest-i386-$(CONFIG_TPM_CRB) += tests/tpm-crb-test$(EXESUF) +-check-qtest-i386-$(CONFIG_TPM_TIS) += tests/tpm-tis-swtpm-test$(EXESUF) +-check-qtest-i386-$(CONFIG_TPM_TIS) += tests/tpm-tis-test$(EXESUF) ++check-qtest-i386-$(CONFIG_TPM_TIS_ISA) += tests/tpm-tis-swtpm-test$(EXESUF) ++check-qtest-i386-$(CONFIG_TPM_TIS_ISA) += tests/tpm-tis-test$(EXESUF) + check-qtest-i386-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF) + check-qtest-i386-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF) + check-qtest-i386-$(CONFIG_RTL8139_PCI) += tests/test-filter-redirector$(EXESUF) +-- +2.23.0 + diff --git a/tpm-Separate-tpm_tis-common-functions-from-isa-code.patch b/tpm-Separate-tpm_tis-common-functions-from-isa-code.patch new file mode 100644 index 0000000000000000000000000000000000000000..32f180c98d784b1478268a768b4caed6c8a3fa23 --- /dev/null +++ b/tpm-Separate-tpm_tis-common-functions-from-isa-code.patch @@ -0,0 +1,1194 @@ +From 425f6bc8392c71d2f29b572d19232785d0ab0b73 Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Tue, 11 Aug 2020 02:55:35 +0000 +Subject: [PATCH 12/19] tpm: Separate tpm_tis common functions from isa code + +Move the device agnostic code into tpm_tis_common.c and +put the ISA device specific code into tpm_tis_isa.c + +Signed-off-by: Eric Auger +Reviewed-by: Stefan Berger +Tested-by: Ard Biesheuvel +Acked-by: Ard Biesheuvel +Message-id: 20200305165149.618-4-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + hw/tpm/Makefile.objs | 2 +- + hw/tpm/{tpm_tis.c => tpm_tis.c.orig} | 0 + hw/tpm/tpm_tis.h | 91 +++ + hw/tpm/tpm_tis_common.c | 869 +++++++++++++++++++++++++++ + hw/tpm/tpm_tis_isa.c | 170 ++++++ + 5 files changed, 1131 insertions(+), 1 deletion(-) + rename hw/tpm/{tpm_tis.c => tpm_tis.c.orig} (100%) + create mode 100644 hw/tpm/tpm_tis.h + create mode 100644 hw/tpm/tpm_tis_common.c + create mode 100644 hw/tpm/tpm_tis_isa.c + +diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs +index 85eb99ae..fcc4c2f2 100644 +--- a/hw/tpm/Makefile.objs ++++ b/hw/tpm/Makefile.objs +@@ -1,6 +1,6 @@ + common-obj-$(CONFIG_TPM) += tpm_util.o + obj-$(call lor,$(CONFIG_TPM_TIS),$(CONFIG_TPM_CRB)) += tpm_ppi.o +-common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o ++common-obj-$(CONFIG_TPM_TIS) += tpm_tis_isa.o tpm_tis_common.o + common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o + common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o + common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o +diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c.orig +similarity index 100% +rename from hw/tpm/tpm_tis.c +rename to hw/tpm/tpm_tis.c.orig +diff --git a/hw/tpm/tpm_tis.h b/hw/tpm/tpm_tis.h +new file mode 100644 +index 00000000..55549893 +--- /dev/null ++++ b/hw/tpm/tpm_tis.h +@@ -0,0 +1,91 @@ ++/* ++ * tpm_tis.h - QEMU's TPM TIS common header ++ * ++ * Copyright (C) 2006,2010-2013 IBM Corporation ++ * ++ * Authors: ++ * Stefan Berger ++ * David Safford ++ * ++ * Xen 4 support: Andrease Niederl ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ * Implementation of the TIS interface according to specs found at ++ * http://www.trustedcomputinggroup.org. This implementation currently ++ * supports version 1.3, 21 March 2013 ++ * In the developers menu choose the PC Client section then find the TIS ++ * specification. ++ * ++ * TPM TIS for TPM 2 implementation following TCG PC Client Platform ++ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 ++ */ ++#ifndef TPM_TPM_TIS_H ++#define TPM_TPM_TIS_H ++ ++#include "qemu/osdep.h" ++#include "sysemu/tpm_backend.h" ++#include "tpm_ppi.h" ++ ++#define TPM_TIS_NUM_LOCALITIES 5 /* per spec */ ++#define TPM_TIS_LOCALITY_SHIFT 12 ++#define TPM_TIS_NO_LOCALITY 0xff ++ ++#define TPM_TIS_IS_VALID_LOCTY(x) ((x) < TPM_TIS_NUM_LOCALITIES) ++ ++#define TPM_TIS_BUFFER_MAX 4096 ++ ++typedef enum { ++ TPM_TIS_STATE_IDLE = 0, ++ TPM_TIS_STATE_READY, ++ TPM_TIS_STATE_COMPLETION, ++ TPM_TIS_STATE_EXECUTION, ++ TPM_TIS_STATE_RECEPTION, ++} TPMTISState; ++ ++/* locality data -- all fields are persisted */ ++typedef struct TPMLocality { ++ TPMTISState state; ++ uint8_t access; ++ uint32_t sts; ++ uint32_t iface_id; ++ uint32_t inte; ++ uint32_t ints; ++} TPMLocality; ++ ++typedef struct TPMState { ++ MemoryRegion mmio; ++ ++ unsigned char buffer[TPM_TIS_BUFFER_MAX]; ++ uint16_t rw_offset; ++ ++ uint8_t active_locty; ++ uint8_t aborting_locty; ++ uint8_t next_locty; ++ ++ TPMLocality loc[TPM_TIS_NUM_LOCALITIES]; ++ ++ qemu_irq irq; ++ uint32_t irq_num; ++ ++ TPMBackendCmd cmd; ++ ++ TPMBackend *be_driver; ++ TPMVersion be_tpm_version; ++ ++ size_t be_buffer_size; ++ ++ bool ppi_enabled; ++ TPMPPI ppi; ++} TPMState; ++ ++extern const VMStateDescription vmstate_locty; ++extern const MemoryRegionOps tpm_tis_memory_ops; ++ ++int tpm_tis_pre_save(TPMState *s); ++void tpm_tis_reset(TPMState *s); ++enum TPMVersion tpm_tis_get_tpm_version(TPMState *s); ++void tpm_tis_request_completed(TPMState *s, int ret); ++ ++#endif /* TPM_TPM_TIS_H */ +diff --git a/hw/tpm/tpm_tis_common.c b/hw/tpm/tpm_tis_common.c +new file mode 100644 +index 00000000..9a51c71e +--- /dev/null ++++ b/hw/tpm/tpm_tis_common.c +@@ -0,0 +1,869 @@ ++/* ++ * tpm_tis_common.c - QEMU's TPM TIS interface emulator ++ * device agnostic functions ++ * ++ * Copyright (C) 2006,2010-2013 IBM Corporation ++ * ++ * Authors: ++ * Stefan Berger ++ * David Safford ++ * ++ * Xen 4 support: Andrease Niederl ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ * Implementation of the TIS interface according to specs found at ++ * http://www.trustedcomputinggroup.org. This implementation currently ++ * supports version 1.3, 21 March 2013 ++ * In the developers menu choose the PC Client section then find the TIS ++ * specification. ++ * ++ * TPM TIS for TPM 2 implementation following TCG PC Client Platform ++ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 ++ */ ++#include "qemu/osdep.h" ++#include "hw/isa/isa.h" ++#include "qapi/error.h" ++#include "qemu/module.h" ++ ++#include "hw/acpi/tpm.h" ++#include "hw/pci/pci_ids.h" ++#include "sysemu/tpm_backend.h" ++#include "tpm_int.h" ++#include "tpm_util.h" ++#include "tpm_ppi.h" ++#include "trace.h" ++ ++#include "tpm_tis.h" ++ ++#define DEBUG_TIS 0 ++ ++/* local prototypes */ ++ ++static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, ++ unsigned size); ++ ++/* utility functions */ ++ ++static uint8_t tpm_tis_locality_from_addr(hwaddr addr) ++{ ++ return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7); ++} ++ ++ ++/* ++ * Set the given flags in the STS register by clearing the register but ++ * preserving the SELFTEST_DONE and TPM_FAMILY_MASK flags and then setting ++ * the new flags. ++ * ++ * The SELFTEST_DONE flag is acquired from the backend that determines it by ++ * peeking into TPM commands. ++ * ++ * A VM suspend/resume will preserve the flag by storing it into the VM ++ * device state, but the backend will not remember it when QEMU is started ++ * again. Therefore, we cache the flag here. Once set, it will not be unset ++ * except by a reset. ++ */ ++static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags) ++{ ++ l->sts &= TPM_TIS_STS_SELFTEST_DONE | TPM_TIS_STS_TPM_FAMILY_MASK; ++ l->sts |= flags; ++} ++ ++/* ++ * Send a request to the TPM. ++ */ ++static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) ++{ ++ if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { ++ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); ++ } ++ ++ /* ++ * rw_offset serves as length indicator for length of data; ++ * it's reset when the response comes back ++ */ ++ s->loc[locty].state = TPM_TIS_STATE_EXECUTION; ++ ++ s->cmd = (TPMBackendCmd) { ++ .locty = locty, ++ .in = s->buffer, ++ .in_len = s->rw_offset, ++ .out = s->buffer, ++ .out_len = s->be_buffer_size, ++ }; ++ ++ tpm_backend_deliver_request(s->be_driver, &s->cmd); ++} ++ ++/* raise an interrupt if allowed */ ++static void tpm_tis_raise_irq(TPMState *s, uint8_t locty, uint32_t irqmask) ++{ ++ if (!TPM_TIS_IS_VALID_LOCTY(locty)) { ++ return; ++ } ++ ++ if ((s->loc[locty].inte & TPM_TIS_INT_ENABLED) && ++ (s->loc[locty].inte & irqmask)) { ++ trace_tpm_tis_raise_irq(irqmask); ++ qemu_irq_raise(s->irq); ++ s->loc[locty].ints |= irqmask; ++ } ++} ++ ++static uint32_t tpm_tis_check_request_use_except(TPMState *s, uint8_t locty) ++{ ++ uint8_t l; ++ ++ for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { ++ if (l == locty) { ++ continue; ++ } ++ if ((s->loc[l].access & TPM_TIS_ACCESS_REQUEST_USE)) { ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty) ++{ ++ bool change = (s->active_locty != new_active_locty); ++ bool is_seize; ++ uint8_t mask; ++ ++ if (change && TPM_TIS_IS_VALID_LOCTY(s->active_locty)) { ++ is_seize = TPM_TIS_IS_VALID_LOCTY(new_active_locty) && ++ s->loc[new_active_locty].access & TPM_TIS_ACCESS_SEIZE; ++ ++ if (is_seize) { ++ mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ } else { ++ mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY| ++ TPM_TIS_ACCESS_REQUEST_USE); ++ } ++ /* reset flags on the old active locality */ ++ s->loc[s->active_locty].access &= mask; ++ ++ if (is_seize) { ++ s->loc[s->active_locty].access |= TPM_TIS_ACCESS_BEEN_SEIZED; ++ } ++ } ++ ++ s->active_locty = new_active_locty; ++ ++ trace_tpm_tis_new_active_locality(s->active_locty); ++ ++ if (TPM_TIS_IS_VALID_LOCTY(new_active_locty)) { ++ /* set flags on the new active locality */ ++ s->loc[new_active_locty].access |= TPM_TIS_ACCESS_ACTIVE_LOCALITY; ++ s->loc[new_active_locty].access &= ~(TPM_TIS_ACCESS_REQUEST_USE | ++ TPM_TIS_ACCESS_SEIZE); ++ } ++ ++ if (change) { ++ tpm_tis_raise_irq(s, s->active_locty, TPM_TIS_INT_LOCALITY_CHANGED); ++ } ++} ++ ++/* abort -- this function switches the locality */ ++static void tpm_tis_abort(TPMState *s) ++{ ++ s->rw_offset = 0; ++ ++ trace_tpm_tis_abort(s->next_locty); ++ ++ /* ++ * Need to react differently depending on who's aborting now and ++ * which locality will become active afterwards. ++ */ ++ if (s->aborting_locty == s->next_locty) { ++ s->loc[s->aborting_locty].state = TPM_TIS_STATE_READY; ++ tpm_tis_sts_set(&s->loc[s->aborting_locty], ++ TPM_TIS_STS_COMMAND_READY); ++ tpm_tis_raise_irq(s, s->aborting_locty, TPM_TIS_INT_COMMAND_READY); ++ } ++ ++ /* locality after abort is another one than the current one */ ++ tpm_tis_new_active_locality(s, s->next_locty); ++ ++ s->next_locty = TPM_TIS_NO_LOCALITY; ++ /* nobody's aborting a command anymore */ ++ s->aborting_locty = TPM_TIS_NO_LOCALITY; ++} ++ ++/* prepare aborting current command */ ++static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty) ++{ ++ uint8_t busy_locty; ++ ++ assert(TPM_TIS_IS_VALID_LOCTY(newlocty)); ++ ++ s->aborting_locty = locty; /* may also be TPM_TIS_NO_LOCALITY */ ++ s->next_locty = newlocty; /* locality after successful abort */ ++ ++ /* ++ * only abort a command using an interrupt if currently executing ++ * a command AND if there's a valid connection to the vTPM. ++ */ ++ for (busy_locty = 0; busy_locty < TPM_TIS_NUM_LOCALITIES; busy_locty++) { ++ if (s->loc[busy_locty].state == TPM_TIS_STATE_EXECUTION) { ++ /* ++ * request the backend to cancel. Some backends may not ++ * support it ++ */ ++ tpm_backend_cancel_cmd(s->be_driver); ++ return; ++ } ++ } ++ ++ tpm_tis_abort(s); ++} ++ ++/* ++ * Callback from the TPM to indicate that the response was received. ++ */ ++void tpm_tis_request_completed(TPMState *s, int ret) ++{ ++ uint8_t locty = s->cmd.locty; ++ uint8_t l; ++ ++ assert(TPM_TIS_IS_VALID_LOCTY(locty)); ++ ++ if (s->cmd.selftest_done) { ++ for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { ++ s->loc[l].sts |= TPM_TIS_STS_SELFTEST_DONE; ++ } ++ } ++ ++ /* FIXME: report error if ret != 0 */ ++ tpm_tis_sts_set(&s->loc[locty], ++ TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); ++ s->loc[locty].state = TPM_TIS_STATE_COMPLETION; ++ s->rw_offset = 0; ++ ++ if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { ++ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "From TPM"); ++ } ++ ++ if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) { ++ tpm_tis_abort(s); ++ } ++ ++ tpm_tis_raise_irq(s, locty, ++ TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID); ++} ++ ++/* ++ * Read a byte of response data ++ */ ++static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty) ++{ ++ uint32_t ret = TPM_TIS_NO_DATA_BYTE; ++ uint16_t len; ++ ++ if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) { ++ len = MIN(tpm_cmd_get_size(&s->buffer), ++ s->be_buffer_size); ++ ++ ret = s->buffer[s->rw_offset++]; ++ if (s->rw_offset >= len) { ++ /* got last byte */ ++ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); ++ tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID); ++ } ++ trace_tpm_tis_data_read(ret, s->rw_offset - 1); ++ } ++ ++ return ret; ++} ++ ++#ifdef DEBUG_TIS ++static void tpm_tis_dump_state(TPMState *s, hwaddr addr) ++{ ++ static const unsigned regs[] = { ++ TPM_TIS_REG_ACCESS, ++ TPM_TIS_REG_INT_ENABLE, ++ TPM_TIS_REG_INT_VECTOR, ++ TPM_TIS_REG_INT_STATUS, ++ TPM_TIS_REG_INTF_CAPABILITY, ++ TPM_TIS_REG_STS, ++ TPM_TIS_REG_DID_VID, ++ TPM_TIS_REG_RID, ++ 0xfff}; ++ int idx; ++ uint8_t locty = tpm_tis_locality_from_addr(addr); ++ hwaddr base = addr & ~0xfff; ++ ++ printf("tpm_tis: active locality : %d\n" ++ "tpm_tis: state of locality %d : %d\n" ++ "tpm_tis: register dump:\n", ++ s->active_locty, ++ locty, s->loc[locty].state); ++ ++ for (idx = 0; regs[idx] != 0xfff; idx++) { ++ printf("tpm_tis: 0x%04x : 0x%08x\n", regs[idx], ++ (int)tpm_tis_mmio_read(s, base + regs[idx], 4)); ++ } ++ ++ printf("tpm_tis: r/w offset : %d\n" ++ "tpm_tis: result buffer : ", ++ s->rw_offset); ++ for (idx = 0; ++ idx < MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size); ++ idx++) { ++ printf("%c%02x%s", ++ s->rw_offset == idx ? '>' : ' ', ++ s->buffer[idx], ++ ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : ""); ++ } ++ printf("\n"); ++} ++#endif ++ ++/* ++ * Read a register of the TIS interface ++ * See specs pages 33-63 for description of the registers ++ */ ++static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, ++ unsigned size) ++{ ++ TPMState *s = opaque; ++ uint16_t offset = addr & 0xffc; ++ uint8_t shift = (addr & 0x3) * 8; ++ uint32_t val = 0xffffffff; ++ uint8_t locty = tpm_tis_locality_from_addr(addr); ++ uint32_t avail; ++ uint8_t v; ++ ++ if (tpm_backend_had_startup_error(s->be_driver)) { ++ return 0; ++ } ++ ++ switch (offset) { ++ case TPM_TIS_REG_ACCESS: ++ /* never show the SEIZE flag even though we use it internally */ ++ val = s->loc[locty].access & ~TPM_TIS_ACCESS_SEIZE; ++ /* the pending flag is always calculated */ ++ if (tpm_tis_check_request_use_except(s, locty)) { ++ val |= TPM_TIS_ACCESS_PENDING_REQUEST; ++ } ++ val |= !tpm_backend_get_tpm_established_flag(s->be_driver); ++ break; ++ case TPM_TIS_REG_INT_ENABLE: ++ val = s->loc[locty].inte; ++ break; ++ case TPM_TIS_REG_INT_VECTOR: ++ val = s->irq_num; ++ break; ++ case TPM_TIS_REG_INT_STATUS: ++ val = s->loc[locty].ints; ++ break; ++ case TPM_TIS_REG_INTF_CAPABILITY: ++ switch (s->be_tpm_version) { ++ case TPM_VERSION_UNSPEC: ++ val = 0; ++ break; ++ case TPM_VERSION_1_2: ++ val = TPM_TIS_CAPABILITIES_SUPPORTED1_3; ++ break; ++ case TPM_VERSION_2_0: ++ val = TPM_TIS_CAPABILITIES_SUPPORTED2_0; ++ break; ++ } ++ break; ++ case TPM_TIS_REG_STS: ++ if (s->active_locty == locty) { ++ if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) { ++ val = TPM_TIS_BURST_COUNT( ++ MIN(tpm_cmd_get_size(&s->buffer), ++ s->be_buffer_size) ++ - s->rw_offset) | s->loc[locty].sts; ++ } else { ++ avail = s->be_buffer_size - s->rw_offset; ++ /* ++ * byte-sized reads should not return 0x00 for 0x100 ++ * available bytes. ++ */ ++ if (size == 1 && avail > 0xff) { ++ avail = 0xff; ++ } ++ val = TPM_TIS_BURST_COUNT(avail) | s->loc[locty].sts; ++ } ++ } ++ break; ++ case TPM_TIS_REG_DATA_FIFO: ++ case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END: ++ if (s->active_locty == locty) { ++ if (size > 4 - (addr & 0x3)) { ++ /* prevent access beyond FIFO */ ++ size = 4 - (addr & 0x3); ++ } ++ val = 0; ++ shift = 0; ++ while (size > 0) { ++ switch (s->loc[locty].state) { ++ case TPM_TIS_STATE_COMPLETION: ++ v = tpm_tis_data_read(s, locty); ++ break; ++ default: ++ v = TPM_TIS_NO_DATA_BYTE; ++ break; ++ } ++ val |= (v << shift); ++ shift += 8; ++ size--; ++ } ++ shift = 0; /* no more adjustments */ ++ } ++ break; ++ case TPM_TIS_REG_INTERFACE_ID: ++ val = s->loc[locty].iface_id; ++ break; ++ case TPM_TIS_REG_DID_VID: ++ val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID; ++ break; ++ case TPM_TIS_REG_RID: ++ val = TPM_TIS_TPM_RID; ++ break; ++#ifdef DEBUG_TIS ++ case TPM_TIS_REG_DEBUG: ++ tpm_tis_dump_state(s, addr); ++ break; ++#endif ++ } ++ ++ if (shift) { ++ val >>= shift; ++ } ++ ++ trace_tpm_tis_mmio_read(size, addr, val); ++ ++ return val; ++} ++ ++/* ++ * Write a value to a register of the TIS interface ++ * See specs pages 33-63 for description of the registers ++ */ ++static void tpm_tis_mmio_write(void *opaque, hwaddr addr, ++ uint64_t val, unsigned size) ++{ ++ TPMState *s = opaque; ++ uint16_t off = addr & 0xffc; ++ uint8_t shift = (addr & 0x3) * 8; ++ uint8_t locty = tpm_tis_locality_from_addr(addr); ++ uint8_t active_locty, l; ++ int c, set_new_locty = 1; ++ uint16_t len; ++ uint32_t mask = (size == 1) ? 0xff : ((size == 2) ? 0xffff : ~0); ++ ++ trace_tpm_tis_mmio_write(size, addr, val); ++ ++ if (locty == 4) { ++ trace_tpm_tis_mmio_write_locty4(); ++ return; ++ } ++ ++ if (tpm_backend_had_startup_error(s->be_driver)) { ++ return; ++ } ++ ++ val &= mask; ++ ++ if (shift) { ++ val <<= shift; ++ mask <<= shift; ++ } ++ ++ mask ^= 0xffffffff; ++ ++ switch (off) { ++ case TPM_TIS_REG_ACCESS: ++ ++ if ((val & TPM_TIS_ACCESS_SEIZE)) { ++ val &= ~(TPM_TIS_ACCESS_REQUEST_USE | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ } ++ ++ active_locty = s->active_locty; ++ ++ if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) { ++ /* give up locality if currently owned */ ++ if (s->active_locty == locty) { ++ trace_tpm_tis_mmio_write_release_locty(locty); ++ ++ uint8_t newlocty = TPM_TIS_NO_LOCALITY; ++ /* anybody wants the locality ? */ ++ for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) { ++ if ((s->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) { ++ trace_tpm_tis_mmio_write_locty_req_use(c); ++ newlocty = c; ++ break; ++ } ++ } ++ trace_tpm_tis_mmio_write_next_locty(newlocty); ++ ++ if (TPM_TIS_IS_VALID_LOCTY(newlocty)) { ++ set_new_locty = 0; ++ tpm_tis_prep_abort(s, locty, newlocty); ++ } else { ++ active_locty = TPM_TIS_NO_LOCALITY; ++ } ++ } else { ++ /* not currently the owner; clear a pending request */ ++ s->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE; ++ } ++ } ++ ++ if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) { ++ s->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED; ++ } ++ ++ if ((val & TPM_TIS_ACCESS_SEIZE)) { ++ /* ++ * allow seize if a locality is active and the requesting ++ * locality is higher than the one that's active ++ * OR ++ * allow seize for requesting locality if no locality is ++ * active ++ */ ++ while ((TPM_TIS_IS_VALID_LOCTY(s->active_locty) && ++ locty > s->active_locty) || ++ !TPM_TIS_IS_VALID_LOCTY(s->active_locty)) { ++ bool higher_seize = FALSE; ++ ++ /* already a pending SEIZE ? */ ++ if ((s->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) { ++ break; ++ } ++ ++ /* check for ongoing seize by a higher locality */ ++ for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) { ++ if ((s->loc[l].access & TPM_TIS_ACCESS_SEIZE)) { ++ higher_seize = TRUE; ++ break; ++ } ++ } ++ ++ if (higher_seize) { ++ break; ++ } ++ ++ /* cancel any seize by a lower locality */ ++ for (l = 0; l < locty; l++) { ++ s->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE; ++ } ++ ++ s->loc[locty].access |= TPM_TIS_ACCESS_SEIZE; ++ ++ trace_tpm_tis_mmio_write_locty_seized(locty, s->active_locty); ++ trace_tpm_tis_mmio_write_init_abort(); ++ ++ set_new_locty = 0; ++ tpm_tis_prep_abort(s, s->active_locty, locty); ++ break; ++ } ++ } ++ ++ if ((val & TPM_TIS_ACCESS_REQUEST_USE)) { ++ if (s->active_locty != locty) { ++ if (TPM_TIS_IS_VALID_LOCTY(s->active_locty)) { ++ s->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE; ++ } else { ++ /* no locality active -> make this one active now */ ++ active_locty = locty; ++ } ++ } ++ } ++ ++ if (set_new_locty) { ++ tpm_tis_new_active_locality(s, active_locty); ++ } ++ ++ break; ++ case TPM_TIS_REG_INT_ENABLE: ++ if (s->active_locty != locty) { ++ break; ++ } ++ ++ s->loc[locty].inte &= mask; ++ s->loc[locty].inte |= (val & (TPM_TIS_INT_ENABLED | ++ TPM_TIS_INT_POLARITY_MASK | ++ TPM_TIS_INTERRUPTS_SUPPORTED)); ++ break; ++ case TPM_TIS_REG_INT_VECTOR: ++ /* hard wired -- ignore */ ++ break; ++ case TPM_TIS_REG_INT_STATUS: ++ if (s->active_locty != locty) { ++ break; ++ } ++ ++ /* clearing of interrupt flags */ ++ if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) && ++ (s->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) { ++ s->loc[locty].ints &= ~val; ++ if (s->loc[locty].ints == 0) { ++ qemu_irq_lower(s->irq); ++ trace_tpm_tis_mmio_write_lowering_irq(); ++ } ++ } ++ s->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED); ++ break; ++ case TPM_TIS_REG_STS: ++ if (s->active_locty != locty) { ++ break; ++ } ++ ++ if (s->be_tpm_version == TPM_VERSION_2_0) { ++ /* some flags that are only supported for TPM 2 */ ++ if (val & TPM_TIS_STS_COMMAND_CANCEL) { ++ if (s->loc[locty].state == TPM_TIS_STATE_EXECUTION) { ++ /* ++ * request the backend to cancel. Some backends may not ++ * support it ++ */ ++ tpm_backend_cancel_cmd(s->be_driver); ++ } ++ } ++ ++ if (val & TPM_TIS_STS_RESET_ESTABLISHMENT_BIT) { ++ if (locty == 3 || locty == 4) { ++ tpm_backend_reset_tpm_established_flag(s->be_driver, locty); ++ } ++ } ++ } ++ ++ val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO | ++ TPM_TIS_STS_RESPONSE_RETRY); ++ ++ if (val == TPM_TIS_STS_COMMAND_READY) { ++ switch (s->loc[locty].state) { ++ ++ case TPM_TIS_STATE_READY: ++ s->rw_offset = 0; ++ break; ++ ++ case TPM_TIS_STATE_IDLE: ++ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_COMMAND_READY); ++ s->loc[locty].state = TPM_TIS_STATE_READY; ++ tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY); ++ break; ++ ++ case TPM_TIS_STATE_EXECUTION: ++ case TPM_TIS_STATE_RECEPTION: ++ /* abort currently running command */ ++ trace_tpm_tis_mmio_write_init_abort(); ++ tpm_tis_prep_abort(s, locty, locty); ++ break; ++ ++ case TPM_TIS_STATE_COMPLETION: ++ s->rw_offset = 0; ++ /* shortcut to ready state with C/R set */ ++ s->loc[locty].state = TPM_TIS_STATE_READY; ++ if (!(s->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) { ++ tpm_tis_sts_set(&s->loc[locty], ++ TPM_TIS_STS_COMMAND_READY); ++ tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY); ++ } ++ s->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE); ++ break; ++ ++ } ++ } else if (val == TPM_TIS_STS_TPM_GO) { ++ switch (s->loc[locty].state) { ++ case TPM_TIS_STATE_RECEPTION: ++ if ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) { ++ tpm_tis_tpm_send(s, locty); ++ } ++ break; ++ default: ++ /* ignore */ ++ break; ++ } ++ } else if (val == TPM_TIS_STS_RESPONSE_RETRY) { ++ switch (s->loc[locty].state) { ++ case TPM_TIS_STATE_COMPLETION: ++ s->rw_offset = 0; ++ tpm_tis_sts_set(&s->loc[locty], ++ TPM_TIS_STS_VALID| ++ TPM_TIS_STS_DATA_AVAILABLE); ++ break; ++ default: ++ /* ignore */ ++ break; ++ } ++ } ++ break; ++ case TPM_TIS_REG_DATA_FIFO: ++ case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END: ++ /* data fifo */ ++ if (s->active_locty != locty) { ++ break; ++ } ++ ++ if (s->loc[locty].state == TPM_TIS_STATE_IDLE || ++ s->loc[locty].state == TPM_TIS_STATE_EXECUTION || ++ s->loc[locty].state == TPM_TIS_STATE_COMPLETION) { ++ /* drop the byte */ ++ } else { ++ trace_tpm_tis_mmio_write_data2send(val, size); ++ if (s->loc[locty].state == TPM_TIS_STATE_READY) { ++ s->loc[locty].state = TPM_TIS_STATE_RECEPTION; ++ tpm_tis_sts_set(&s->loc[locty], ++ TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); ++ } ++ ++ val >>= shift; ++ if (size > 4 - (addr & 0x3)) { ++ /* prevent access beyond FIFO */ ++ size = 4 - (addr & 0x3); ++ } ++ ++ while ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) { ++ if (s->rw_offset < s->be_buffer_size) { ++ s->buffer[s->rw_offset++] = ++ (uint8_t)val; ++ val >>= 8; ++ size--; ++ } else { ++ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); ++ } ++ } ++ ++ /* check for complete packet */ ++ if (s->rw_offset > 5 && ++ (s->loc[locty].sts & TPM_TIS_STS_EXPECT)) { ++ /* we have a packet length - see if we have all of it */ ++ bool need_irq = !(s->loc[locty].sts & TPM_TIS_STS_VALID); ++ ++ len = tpm_cmd_get_size(&s->buffer); ++ if (len > s->rw_offset) { ++ tpm_tis_sts_set(&s->loc[locty], ++ TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); ++ } else { ++ /* packet complete */ ++ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); ++ } ++ if (need_irq) { ++ tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID); ++ } ++ } ++ } ++ break; ++ case TPM_TIS_REG_INTERFACE_ID: ++ if (val & TPM_TIS_IFACE_ID_INT_SEL_LOCK) { ++ for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { ++ s->loc[l].iface_id |= TPM_TIS_IFACE_ID_INT_SEL_LOCK; ++ } ++ } ++ break; ++ } ++} ++ ++const MemoryRegionOps tpm_tis_memory_ops = { ++ .read = tpm_tis_mmio_read, ++ .write = tpm_tis_mmio_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++ .valid = { ++ .min_access_size = 1, ++ .max_access_size = 4, ++ }, ++}; ++ ++/* ++ * Get the TPMVersion of the backend device being used ++ */ ++enum TPMVersion tpm_tis_get_tpm_version(TPMState *s) ++{ ++ if (tpm_backend_had_startup_error(s->be_driver)) { ++ return TPM_VERSION_UNSPEC; ++ } ++ ++ return tpm_backend_get_tpm_version(s->be_driver); ++} ++ ++/* ++ * This function is called when the machine starts, resets or due to ++ * S3 resume. ++ */ ++void tpm_tis_reset(TPMState *s) ++{ ++ int c; ++ ++ s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); ++ s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver), ++ TPM_TIS_BUFFER_MAX); ++ ++ if (s->ppi_enabled) { ++ tpm_ppi_reset(&s->ppi); ++ } ++ tpm_backend_reset(s->be_driver); ++ ++ s->active_locty = TPM_TIS_NO_LOCALITY; ++ s->next_locty = TPM_TIS_NO_LOCALITY; ++ s->aborting_locty = TPM_TIS_NO_LOCALITY; ++ ++ for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) { ++ s->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS; ++ switch (s->be_tpm_version) { ++ case TPM_VERSION_UNSPEC: ++ break; ++ case TPM_VERSION_1_2: ++ s->loc[c].sts = TPM_TIS_STS_TPM_FAMILY1_2; ++ s->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3; ++ break; ++ case TPM_VERSION_2_0: ++ s->loc[c].sts = TPM_TIS_STS_TPM_FAMILY2_0; ++ s->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0; ++ break; ++ } ++ s->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL; ++ s->loc[c].ints = 0; ++ s->loc[c].state = TPM_TIS_STATE_IDLE; ++ ++ s->rw_offset = 0; ++ } ++ ++ if (tpm_backend_startup_tpm(s->be_driver, s->be_buffer_size) < 0) { ++ exit(1); ++ } ++} ++ ++/* persistent state handling */ ++ ++int tpm_tis_pre_save(TPMState *s) ++{ ++ uint8_t locty = s->active_locty; ++ ++ trace_tpm_tis_pre_save(locty, s->rw_offset); ++ ++ if (DEBUG_TIS) { ++ tpm_tis_dump_state(s, 0); ++ } ++ ++ /* ++ * Synchronize with backend completion. ++ */ ++ tpm_backend_finish_sync(s->be_driver); ++ ++ return 0; ++} ++ ++const VMStateDescription vmstate_locty = { ++ .name = "tpm-tis/locty", ++ .version_id = 0, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT32(state, TPMLocality), ++ VMSTATE_UINT32(inte, TPMLocality), ++ VMSTATE_UINT32(ints, TPMLocality), ++ VMSTATE_UINT8(access, TPMLocality), ++ VMSTATE_UINT32(sts, TPMLocality), ++ VMSTATE_UINT32(iface_id, TPMLocality), ++ VMSTATE_END_OF_LIST(), ++ } ++}; ++ +diff --git a/hw/tpm/tpm_tis_isa.c b/hw/tpm/tpm_tis_isa.c +new file mode 100644 +index 00000000..45e25c02 +--- /dev/null ++++ b/hw/tpm/tpm_tis_isa.c +@@ -0,0 +1,170 @@ ++/* ++ * tpm_tis_isa.c - QEMU's TPM TIS ISA Device ++ * ++ * Copyright (C) 2006,2010-2013 IBM Corporation ++ * ++ * Authors: ++ * Stefan Berger ++ * David Safford ++ * ++ * Xen 4 support: Andrease Niederl ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ * Implementation of the TIS interface according to specs found at ++ * http://www.trustedcomputinggroup.org. This implementation currently ++ * supports version 1.3, 21 March 2013 ++ * In the developers menu choose the PC Client section then find the TIS ++ * specification. ++ * ++ * TPM TIS for TPM 2 implementation following TCG PC Client Platform ++ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/isa/isa.h" ++#include "hw/qdev-properties.h" ++#include "migration/vmstate.h" ++#include "tpm_util.h" ++#include "tpm_tis.h" ++ ++typedef struct TPMStateISA { ++ /*< private >*/ ++ ISADevice parent_obj; ++ ++ /*< public >*/ ++ TPMState state; /* not a QOM object */ ++} TPMStateISA; ++ ++#define TPM_TIS_ISA(obj) OBJECT_CHECK(TPMStateISA, (obj), TYPE_TPM_TIS_ISA) ++ ++static int tpm_tis_pre_save_isa(void *opaque) ++{ ++ TPMStateISA *isadev = opaque; ++ ++ return tpm_tis_pre_save(&isadev->state); ++} ++ ++static const VMStateDescription vmstate_tpm_tis_isa = { ++ .name = "tpm-tis", ++ .version_id = 0, ++ .pre_save = tpm_tis_pre_save_isa, ++ .fields = (VMStateField[]) { ++ VMSTATE_BUFFER(state.buffer, TPMStateISA), ++ VMSTATE_UINT16(state.rw_offset, TPMStateISA), ++ VMSTATE_UINT8(state.active_locty, TPMStateISA), ++ VMSTATE_UINT8(state.aborting_locty, TPMStateISA), ++ VMSTATE_UINT8(state.next_locty, TPMStateISA), ++ ++ VMSTATE_STRUCT_ARRAY(state.loc, TPMStateISA, TPM_TIS_NUM_LOCALITIES, 0, ++ vmstate_locty, TPMLocality), ++ ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++static void tpm_tis_isa_request_completed(TPMIf *ti, int ret) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(ti); ++ TPMState *s = &isadev->state; ++ ++ tpm_tis_request_completed(s, ret); ++} ++ ++static enum TPMVersion tpm_tis_isa_get_tpm_version(TPMIf *ti) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(ti); ++ TPMState *s = &isadev->state; ++ ++ return tpm_tis_get_tpm_version(s); ++} ++ ++static void tpm_tis_isa_reset(DeviceState *dev) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(dev); ++ TPMState *s = &isadev->state; ++ ++ return tpm_tis_reset(s); ++} ++ ++static Property tpm_tis_isa_properties[] = { ++ DEFINE_PROP_UINT32("irq", TPMStateISA, state.irq_num, TPM_TIS_IRQ), ++ DEFINE_PROP_TPMBE("tpmdev", TPMStateISA, state.be_driver), ++ DEFINE_PROP_BOOL("ppi", TPMStateISA, state.ppi_enabled, true), ++ DEFINE_PROP_END_OF_LIST(), ++}; ++ ++static void tpm_tis_isa_initfn(Object *obj) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(obj); ++ TPMState *s = &isadev->state; ++ ++ memory_region_init_io(&s->mmio, obj, &tpm_tis_memory_ops, ++ s, "tpm-tis-mmio", ++ TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); ++} ++ ++static void tpm_tis_isa_realizefn(DeviceState *dev, Error **errp) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(dev); ++ TPMState *s = &isadev->state; ++ ++ if (!tpm_find()) { ++ error_setg(errp, "at most one TPM device is permitted"); ++ return; ++ } ++ ++ if (!s->be_driver) { ++ error_setg(errp, "'tpmdev' property is required"); ++ return; ++ } ++ if (s->irq_num > 15) { ++ error_setg(errp, "IRQ %d is outside valid range of 0 to 15", ++ s->irq_num); ++ return; ++ } ++ ++ isa_init_irq(ISA_DEVICE(dev), &s->irq, s->irq_num); ++ ++ memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)), ++ TPM_TIS_ADDR_BASE, &s->mmio); ++ ++ if (s->ppi_enabled) { ++ tpm_ppi_init(&s->ppi, isa_address_space(ISA_DEVICE(dev)), ++ TPM_PPI_ADDR_BASE, OBJECT(dev)); ++ } ++} ++ ++static void tpm_tis_isa_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ TPMIfClass *tc = TPM_IF_CLASS(klass); ++ ++ dc->props = tpm_tis_isa_properties; ++ dc->vmsd = &vmstate_tpm_tis_isa; ++ tc->model = TPM_MODEL_TPM_TIS; ++ dc->realize = tpm_tis_isa_realizefn; ++ dc->reset = tpm_tis_isa_reset; ++ tc->request_completed = tpm_tis_isa_request_completed; ++ tc->get_version = tpm_tis_isa_get_tpm_version; ++} ++ ++static const TypeInfo tpm_tis_isa_info = { ++ .name = TYPE_TPM_TIS_ISA, ++ .parent = TYPE_ISA_DEVICE, ++ .instance_size = sizeof(TPMStateISA), ++ .instance_init = tpm_tis_isa_initfn, ++ .class_init = tpm_tis_isa_class_init, ++ .interfaces = (InterfaceInfo[]) { ++ { TYPE_TPM_IF }, ++ { } ++ } ++}; ++ ++static void tpm_tis_isa_register(void) ++{ ++ type_register_static(&tpm_tis_isa_info); ++} ++ ++type_init(tpm_tis_isa_register) +-- +2.23.0 + diff --git a/tpm-Use-TPMState-as-a-common-struct.patch b/tpm-Use-TPMState-as-a-common-struct.patch new file mode 100644 index 0000000000000000000000000000000000000000..61a1dd037bb2356cb7307d53f82732af404ed4e2 --- /dev/null +++ b/tpm-Use-TPMState-as-a-common-struct.patch @@ -0,0 +1,314 @@ +From c57e57c86f9d3c13b33746436bc1f09db88d4d42 Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Tue, 11 Aug 2020 02:52:12 +0000 +Subject: [PATCH 11/19] tpm: Use TPMState as a common struct + +As we plan to introduce a SysBus TPM TIS device, let's +make the TPMState a common struct usable by both the +ISADevice and the SysBusDevice. TPMStateISA embeds the +struct and inherits from the ISADevice. + +The prototype of functions bound to be used by both +the ISA and SysBus devices is changed to take TPMState +handle. + +A bunch of structs also are renamed to be specialized +for the ISA device. Besides those transformations, no +functional change is expected. + +Signed-off-by: Eric Auger +Reviewed-by: Stefan Berger +Tested-by: Ard Biesheuvel +Acked-by: Ard Biesheuvel +Message-id: 20200305165149.618-3-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + hw/tpm/tpm_tis.c | 147 +++++++++++++++++++++++++++++------------------ + 1 file changed, 92 insertions(+), 55 deletions(-) + +diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c +index 49d44652..735a528f 100644 +--- a/hw/tpm/tpm_tis.c ++++ b/hw/tpm/tpm_tis.c +@@ -62,7 +62,6 @@ typedef struct TPMLocality { + } TPMLocality; + + typedef struct TPMState { +- ISADevice busdev; + MemoryRegion mmio; + + unsigned char buffer[TPM_TIS_BUFFER_MAX]; +@@ -88,7 +87,15 @@ typedef struct TPMState { + TPMPPI ppi; + } TPMState; + +-#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS_ISA) ++typedef struct TPMStateISA { ++ /*< private >*/ ++ ISADevice parent_obj; ++ ++ /*< public >*/ ++ TPMState state; /* not a QOM object */ ++} TPMStateISA; ++ ++#define TPM_TIS_ISA(obj) OBJECT_CHECK(TPMStateISA, (obj), TYPE_TPM_TIS_ISA) + + #define DEBUG_TIS 0 + +@@ -278,9 +285,8 @@ static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty) + /* + * Callback from the TPM to indicate that the response was received. + */ +-static void tpm_tis_request_completed(TPMIf *ti, int ret) ++static void tpm_tis_request_completed(TPMState *s, int ret) + { +- TPMState *s = TPM(ti); + uint8_t locty = s->cmd.locty; + uint8_t l; + +@@ -335,7 +341,7 @@ static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty) + } + + #ifdef DEBUG_TIS +-static void tpm_tis_dump_state(void *opaque, hwaddr addr) ++static void tpm_tis_dump_state(TPMState *s, hwaddr addr) + { + static const unsigned regs[] = { + TPM_TIS_REG_ACCESS, +@@ -350,7 +356,6 @@ static void tpm_tis_dump_state(void *opaque, hwaddr addr) + int idx; + uint8_t locty = tpm_tis_locality_from_addr(addr); + hwaddr base = addr & ~0xfff; +- TPMState *s = opaque; + + printf("tpm_tis: active locality : %d\n" + "tpm_tis: state of locality %d : %d\n" +@@ -360,7 +365,7 @@ static void tpm_tis_dump_state(void *opaque, hwaddr addr) + + for (idx = 0; regs[idx] != 0xfff; idx++) { + printf("tpm_tis: 0x%04x : 0x%08x\n", regs[idx], +- (int)tpm_tis_mmio_read(opaque, base + regs[idx], 4)); ++ (int)tpm_tis_mmio_read(s, base + regs[idx], 4)); + } + + printf("tpm_tis: r/w offset : %d\n" +@@ -485,7 +490,7 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, + break; + #ifdef DEBUG_TIS + case TPM_TIS_REG_DEBUG: +- tpm_tis_dump_state(opaque, addr); ++ tpm_tis_dump_state(s, addr); + break; + #endif + } +@@ -832,10 +837,8 @@ static const MemoryRegionOps tpm_tis_memory_ops = { + /* + * Get the TPMVersion of the backend device being used + */ +-static enum TPMVersion tpm_tis_get_tpm_version(TPMIf *ti) ++static enum TPMVersion tpm_tis_get_tpm_version(TPMState *s) + { +- TPMState *s = TPM(ti); +- + if (tpm_backend_had_startup_error(s->be_driver)) { + return TPM_VERSION_UNSPEC; + } +@@ -847,9 +850,8 @@ static enum TPMVersion tpm_tis_get_tpm_version(TPMIf *ti) + * This function is called when the machine starts, resets or due to + * S3 resume. + */ +-static void tpm_tis_reset(DeviceState *dev) ++static void tpm_tis_reset(TPMState *s) + { +- TPMState *s = TPM(dev); + int c; + + s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); +@@ -893,15 +895,14 @@ static void tpm_tis_reset(DeviceState *dev) + + /* persistent state handling */ + +-static int tpm_tis_pre_save(void *opaque) ++static int tpm_tis_pre_save(TPMState *s) + { +- TPMState *s = opaque; + uint8_t locty = s->active_locty; + + trace_tpm_tis_pre_save(locty, s->rw_offset); + + if (DEBUG_TIS) { +- tpm_tis_dump_state(opaque, 0); ++ tpm_tis_dump_state(s, 0); + } + + /* +@@ -926,34 +927,78 @@ static const VMStateDescription vmstate_locty = { + } + }; + +-static const VMStateDescription vmstate_tpm_tis = { ++/* ISA */ ++ ++static int tpm_tis_pre_save_isa(void *opaque) ++{ ++ TPMStateISA *isadev = opaque; ++ ++ return tpm_tis_pre_save(&isadev->state); ++} ++ ++static const VMStateDescription vmstate_tpm_tis_isa = { + .name = "tpm-tis", + .version_id = 0, +- .pre_save = tpm_tis_pre_save, ++ .pre_save = tpm_tis_pre_save_isa, + .fields = (VMStateField[]) { +- VMSTATE_BUFFER(buffer, TPMState), +- VMSTATE_UINT16(rw_offset, TPMState), +- VMSTATE_UINT8(active_locty, TPMState), +- VMSTATE_UINT8(aborting_locty, TPMState), +- VMSTATE_UINT8(next_locty, TPMState), ++ VMSTATE_BUFFER(state.buffer, TPMStateISA), ++ VMSTATE_UINT16(state.rw_offset, TPMStateISA), ++ VMSTATE_UINT8(state.active_locty, TPMStateISA), ++ VMSTATE_UINT8(state.aborting_locty, TPMStateISA), ++ VMSTATE_UINT8(state.next_locty, TPMStateISA), + +- VMSTATE_STRUCT_ARRAY(loc, TPMState, TPM_TIS_NUM_LOCALITIES, 0, ++ VMSTATE_STRUCT_ARRAY(state.loc, TPMStateISA, TPM_TIS_NUM_LOCALITIES, 0, + vmstate_locty, TPMLocality), + + VMSTATE_END_OF_LIST() + } + }; + +-static Property tpm_tis_properties[] = { +- DEFINE_PROP_UINT32("irq", TPMState, irq_num, TPM_TIS_IRQ), +- DEFINE_PROP_TPMBE("tpmdev", TPMState, be_driver), +- DEFINE_PROP_BOOL("ppi", TPMState, ppi_enabled, true), ++static void tpm_tis_isa_request_completed(TPMIf *ti, int ret) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(ti); ++ TPMState *s = &isadev->state; ++ ++ tpm_tis_request_completed(s, ret); ++} ++ ++static enum TPMVersion tpm_tis_isa_get_tpm_version(TPMIf *ti) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(ti); ++ TPMState *s = &isadev->state; ++ ++ return tpm_tis_get_tpm_version(s); ++} ++ ++static void tpm_tis_isa_reset(DeviceState *dev) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(dev); ++ TPMState *s = &isadev->state; ++ ++ return tpm_tis_reset(s); ++} ++ ++static Property tpm_tis_isa_properties[] = { ++ DEFINE_PROP_UINT32("irq", TPMStateISA, state.irq_num, TPM_TIS_IRQ), ++ DEFINE_PROP_TPMBE("tpmdev", TPMStateISA, state.be_driver), ++ DEFINE_PROP_BOOL("ppi", TPMStateISA, state.ppi_enabled, true), + DEFINE_PROP_END_OF_LIST(), + }; + +-static void tpm_tis_realizefn(DeviceState *dev, Error **errp) ++static void tpm_tis_isa_initfn(Object *obj) + { +- TPMState *s = TPM(dev); ++ TPMStateISA *isadev = TPM_TIS_ISA(obj); ++ TPMState *s = &isadev->state; ++ ++ memory_region_init_io(&s->mmio, obj, &tpm_tis_memory_ops, ++ s, "tpm-tis-mmio", ++ TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); ++} ++ ++static void tpm_tis_isa_realizefn(DeviceState *dev, Error **errp) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(dev); ++ TPMState *s = &isadev->state; + + if (!tpm_find()) { + error_setg(errp, "at most one TPM device is permitted"); +@@ -970,55 +1015,47 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp) + return; + } + +- isa_init_irq(&s->busdev, &s->irq, s->irq_num); ++ isa_init_irq(ISA_DEVICE(dev), &s->irq, s->irq_num); + + memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)), + TPM_TIS_ADDR_BASE, &s->mmio); + + if (s->ppi_enabled) { + tpm_ppi_init(&s->ppi, isa_address_space(ISA_DEVICE(dev)), +- TPM_PPI_ADDR_BASE, OBJECT(s)); ++ TPM_PPI_ADDR_BASE, OBJECT(dev)); + } + } + +-static void tpm_tis_initfn(Object *obj) +-{ +- TPMState *s = TPM(obj); +- +- memory_region_init_io(&s->mmio, OBJECT(s), &tpm_tis_memory_ops, +- s, "tpm-tis-mmio", +- TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); +-} +- +-static void tpm_tis_class_init(ObjectClass *klass, void *data) ++static void tpm_tis_isa_class_init(ObjectClass *klass, void *data) + { + DeviceClass *dc = DEVICE_CLASS(klass); + TPMIfClass *tc = TPM_IF_CLASS(klass); + +- dc->realize = tpm_tis_realizefn; +- dc->props = tpm_tis_properties; +- dc->reset = tpm_tis_reset; +- dc->vmsd = &vmstate_tpm_tis; ++ dc->props = tpm_tis_isa_properties; ++ dc->vmsd = &vmstate_tpm_tis_isa; + tc->model = TPM_MODEL_TPM_TIS; +- tc->get_version = tpm_tis_get_tpm_version; +- tc->request_completed = tpm_tis_request_completed; ++ dc->realize = tpm_tis_isa_realizefn; ++ dc->reset = tpm_tis_isa_reset; ++ tc->request_completed = tpm_tis_isa_request_completed; ++ tc->get_version = tpm_tis_isa_get_tpm_version; ++ + } + +-static const TypeInfo tpm_tis_info = { ++static const TypeInfo tpm_tis_isa_info = { + .name = TYPE_TPM_TIS_ISA, + .parent = TYPE_ISA_DEVICE, +- .instance_size = sizeof(TPMState), +- .instance_init = tpm_tis_initfn, +- .class_init = tpm_tis_class_init, ++ .instance_size = sizeof(TPMStateISA), ++ .instance_init = tpm_tis_isa_initfn, ++ .class_init = tpm_tis_isa_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_TPM_IF }, + { } + } + }; + +-static void tpm_tis_register(void) ++static void tpm_tis_isa_register(void) + { +- type_register_static(&tpm_tis_info); ++ type_register_static(&tpm_tis_isa_info); + } + +-type_init(tpm_tis_register) ++type_init(tpm_tis_isa_register) +-- +2.23.0 + diff --git a/tpm-ppi-page-align-PPI-RAM.patch b/tpm-ppi-page-align-PPI-RAM.patch new file mode 100644 index 0000000000000000000000000000000000000000..d7ba2c876605392e79d887b89a4a274cb51660d4 --- /dev/null +++ b/tpm-ppi-page-align-PPI-RAM.patch @@ -0,0 +1,43 @@ +From 26b54c545f253049faa633ff886132602ff47241 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Fri, 3 Jan 2020 11:39:59 +0400 +Subject: [PATCH 02/19] tpm-ppi: page-align PPI RAM +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +post-copy migration fails on destination with error such as: +2019-12-26T10:22:44.714644Z qemu-kvm: ram_block_discard_range: +Unaligned start address: 0x559d2afae9a0 + +Use qemu_memalign() to constrain the PPI RAM memory alignment. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Marc-André Lureau +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Dr. David Alan Gilbert +Reviewed-by: Stefan Berger +Signed-off-by: Stefan Berger +Message-id: 20200103074000.1006389-3-marcandre.lureau@redhat.com +Signed-off-by: jiangfangjie +--- + hw/tpm/tpm_ppi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/tpm/tpm_ppi.c b/hw/tpm/tpm_ppi.c +index cd8205f2..6509ffd4 100644 +--- a/hw/tpm/tpm_ppi.c ++++ b/hw/tpm/tpm_ppi.c +@@ -44,7 +44,8 @@ void tpm_ppi_reset(TPMPPI *tpmppi) + void tpm_ppi_init(TPMPPI *tpmppi, struct MemoryRegion *m, + hwaddr addr, Object *obj) + { +- tpmppi->buf = g_malloc0(HOST_PAGE_ALIGN(TPM_PPI_ADDR_SIZE)); ++ tpmppi->buf = qemu_memalign(qemu_real_host_page_size, ++ HOST_PAGE_ALIGN(TPM_PPI_ADDR_SIZE)); + memory_region_init_ram_device_ptr(&tpmppi->ram, obj, "tpm-ppi", + TPM_PPI_ADDR_SIZE, tpmppi->buf); + vmstate_register_ram(&tpmppi->ram, DEVICE(obj)); +-- +2.23.0 + diff --git a/tpm-rename-TPM_TIS-into-TPM_TIS_ISA.patch b/tpm-rename-TPM_TIS-into-TPM_TIS_ISA.patch new file mode 100644 index 0000000000000000000000000000000000000000..ea6e1d28a10cb6d29ba1c1c76245ef6749825ba2 --- /dev/null +++ b/tpm-rename-TPM_TIS-into-TPM_TIS_ISA.patch @@ -0,0 +1,101 @@ +From 7974f8ffd75171be106a1ce2705878abbb6c4477 Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 5 Mar 2020 17:51:40 +0100 +Subject: [PATCH 10/19] tpm: rename TPM_TIS into TPM_TIS_ISA +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +As we plan to introduce a sysbus TPM_TIS, let's rename +TPM_TIS into TPM_TIS_ISA. + +Signed-off-by: Eric Auger +Reviewed-by: Stefan Berger +Reviewed-by: Philippe Mathieu-Daudé +Tested-by: Ard Biesheuvel +Acked-by: Ard Biesheuvel +Message-id: 20200305165149.618-2-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + hw/i386/acpi-build.c | 6 +++--- + hw/tpm/tpm_tis.c | 4 ++-- + include/sysemu/tpm.h | 6 +++--- + 3 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index c97731ec..093f7d93 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -2007,7 +2007,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, + } + } + +- if (TPM_IS_TIS(tpm_find())) { ++ if (TPM_IS_TIS_ISA(tpm_find())) { + aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE, + TPM_TIS_ADDR_SIZE, AML_READ_WRITE)); + } +@@ -2178,7 +2178,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, + /* Scan all PCI buses. Generate tables to support hotplug. */ + build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en); + +- if (TPM_IS_TIS(tpm)) { ++ if (TPM_IS_TIS_ISA(tpm)) { + if (misc->tpm_version == TPM_VERSION_2_0) { + dev = aml_device("TPM"); + aml_append(dev, aml_name_decl("_HID", +@@ -2285,7 +2285,7 @@ build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog) + (char *)&tpm2_ptr->log_area_start_address - table_data->data; + + tpm2_ptr->platform_class = cpu_to_le16(TPM2_ACPI_CLASS_CLIENT); +- if (TPM_IS_TIS(tpm_find())) { ++ if (TPM_IS_TIS_ISA(tpm_find())) { + tpm2_ptr->control_area_address = cpu_to_le64(0); + tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO); + } else if (TPM_IS_CRB(tpm_find())) { +diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c +index 96a9ac48..49d44652 100644 +--- a/hw/tpm/tpm_tis.c ++++ b/hw/tpm/tpm_tis.c +@@ -88,7 +88,7 @@ typedef struct TPMState { + TPMPPI ppi; + } TPMState; + +-#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS) ++#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS_ISA) + + #define DEBUG_TIS 0 + +@@ -1005,7 +1005,7 @@ static void tpm_tis_class_init(ObjectClass *klass, void *data) + } + + static const TypeInfo tpm_tis_info = { +- .name = TYPE_TPM_TIS, ++ .name = TYPE_TPM_TIS_ISA, + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(TPMState), + .instance_init = tpm_tis_initfn, +diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h +index 15979a36..1691b92c 100644 +--- a/include/sysemu/tpm.h ++++ b/include/sysemu/tpm.h +@@ -43,12 +43,12 @@ typedef struct TPMIfClass { + enum TPMVersion (*get_version)(TPMIf *obj); + } TPMIfClass; + +-#define TYPE_TPM_TIS "tpm-tis" ++#define TYPE_TPM_TIS_ISA "tpm-tis" + #define TYPE_TPM_CRB "tpm-crb" + #define TYPE_TPM_SPAPR "tpm-spapr" + +-#define TPM_IS_TIS(chr) \ +- object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS) ++#define TPM_IS_TIS_ISA(chr) \ ++ object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS_ISA) + #define TPM_IS_CRB(chr) \ + object_dynamic_cast(OBJECT(chr), TYPE_TPM_CRB) + #define TPM_IS_SPAPR(chr) \ +-- +2.23.0 + diff --git a/tpm_spapr-Support-TPM-for-ppc64-using-CRQ-based-inte.patch b/tpm_spapr-Support-TPM-for-ppc64-using-CRQ-based-inte.patch new file mode 100644 index 0000000000000000000000000000000000000000..ffc0b62ed7ef655056cfd1280282b768f22ad501 --- /dev/null +++ b/tpm_spapr-Support-TPM-for-ppc64-using-CRQ-based-inte.patch @@ -0,0 +1,552 @@ +From 14402a8ca57fb722eb324d141fafb41ef06f4c2b Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Tue, 21 Jan 2020 10:29:32 -0500 +Subject: [PATCH 06/19] tpm_spapr: Support TPM for ppc64 using CRQ based + interface + +Implement support for TPM on ppc64 by implementing the vTPM CRQ interface +as a frontend. It can use the tpm_emulator driver backend with the external +swtpm. + +The Linux vTPM driver for ppc64 works with this emulation. + +This TPM emulator also handles the TPM 2 case. + +Signed-off-by: Stefan Berger +Reviewed-by: David Gibson +Message-Id: <20200121152935.649898-4-stefanb@linux.ibm.com> +Signed-off-by: David Gibson +Signed-off-by: jiangfangjie +--- + docs/specs/tpm.txt | 20 ++- + hw/tpm/Kconfig | 6 + + hw/tpm/Makefile.objs | 1 + + hw/tpm/tpm_spapr.c | 379 +++++++++++++++++++++++++++++++++++++++++++ + hw/tpm/trace-events | 12 ++ + include/sysemu/tpm.h | 3 + + qapi/tpm.json | 6 +- + 7 files changed, 423 insertions(+), 4 deletions(-) + create mode 100644 hw/tpm/tpm_spapr.c + +diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt +index 9c8cca04..9c3e67d8 100644 +--- a/docs/specs/tpm.txt ++++ b/docs/specs/tpm.txt +@@ -34,6 +34,12 @@ The CRB interface makes a memory mapped IO region in the area 0xfed40000 - + QEMU files related to TPM CRB interface: + - hw/tpm/tpm_crb.c + ++ ++pSeries (ppc64) machines offer a tpm-spapr device model. ++ ++QEMU files related to the SPAPR interface: ++ - hw/tpm/tpm_spapr.c ++ + = fw_cfg interface = + + The bios/firmware may read the "etc/tpm/config" fw_cfg entry for +@@ -281,7 +287,7 @@ swtpm socket --tpmstate dir=/tmp/mytpm1 \ + --log level=20 + + Command line to start QEMU with the TPM emulator device communicating with +-the swtpm: ++the swtpm (x86): + + qemu-system-x86_64 -display sdl -accel kvm \ + -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ +@@ -289,6 +295,18 @@ qemu-system-x86_64 -display sdl -accel kvm \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-tis,tpmdev=tpm0 test.img + ++In case a pSeries machine is emulated, use the following command line: ++ ++qemu-system-ppc64 -display sdl -machine pseries,accel=kvm \ ++ -m 1024 -bios slof.bin -boot menu=on \ ++ -nodefaults -device VGA -device pci-ohci -device usb-kbd \ ++ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ ++ -tpmdev emulator,id=tpm0,chardev=chrtpm \ ++ -device tpm-spapr,tpmdev=tpm0 \ ++ -device spapr-vscsi,id=scsi0,reg=0x00002000 \ ++ -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \ ++ -drive file=test.img,format=raw,if=none,id=drive-virtio-disk0 ++ + + In case SeaBIOS is used as firmware, it should show the TPM menu item + after entering the menu with 'ESC'. +diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig +index 4c8ee87d..4d4ab085 100644 +--- a/hw/tpm/Kconfig ++++ b/hw/tpm/Kconfig +@@ -22,3 +22,9 @@ config TPM_EMULATOR + bool + default y + depends on TPMDEV ++ ++config TPM_SPAPR ++ bool ++ default n ++ depends on TPM && PSERIES ++ select TPMDEV +diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs +index de0b85d0..85eb99ae 100644 +--- a/hw/tpm/Makefile.objs ++++ b/hw/tpm/Makefile.objs +@@ -4,3 +4,4 @@ common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o + common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o + common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o + common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o ++obj-$(CONFIG_TPM_SPAPR) += tpm_spapr.o +diff --git a/hw/tpm/tpm_spapr.c b/hw/tpm/tpm_spapr.c +new file mode 100644 +index 00000000..1db9696a +--- /dev/null ++++ b/hw/tpm/tpm_spapr.c +@@ -0,0 +1,379 @@ ++/* ++ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator ++ * ++ * PAPR Virtual TPM ++ * ++ * Copyright (c) 2015, 2017, 2019 IBM Corporation. ++ * ++ * Authors: ++ * Stefan Berger ++ * ++ * This code is licensed under the GPL version 2 or later. See the ++ * COPYING file in the top-level directory. ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/error-report.h" ++#include "qapi/error.h" ++#include "hw/qdev-properties.h" ++#include "migration/vmstate.h" ++ ++#include "sysemu/tpm_backend.h" ++#include "tpm_int.h" ++#include "tpm_util.h" ++ ++#include "hw/ppc/spapr.h" ++#include "hw/ppc/spapr_vio.h" ++#include "trace.h" ++ ++#define DEBUG_SPAPR 0 ++ ++#define VIO_SPAPR_VTPM(obj) \ ++ OBJECT_CHECK(SpaprTpmState, (obj), TYPE_TPM_SPAPR) ++ ++typedef struct TpmCrq { ++ uint8_t valid; /* 0x80: cmd; 0xc0: init crq */ ++ /* 0x81-0x83: CRQ message response */ ++ uint8_t msg; /* see below */ ++ uint16_t len; /* len of TPM request; len of TPM response */ ++ uint32_t data; /* rtce_dma_handle when sending TPM request */ ++ uint64_t reserved; ++} TpmCrq; ++ ++#define SPAPR_VTPM_VALID_INIT_CRQ_COMMAND 0xC0 ++#define SPAPR_VTPM_VALID_COMMAND 0x80 ++#define SPAPR_VTPM_MSG_RESULT 0x80 ++ ++/* msg types for valid = SPAPR_VTPM_VALID_INIT_CRQ */ ++#define SPAPR_VTPM_INIT_CRQ_RESULT 0x1 ++#define SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT 0x2 ++ ++/* msg types for valid = SPAPR_VTPM_VALID_CMD */ ++#define SPAPR_VTPM_GET_VERSION 0x1 ++#define SPAPR_VTPM_TPM_COMMAND 0x2 ++#define SPAPR_VTPM_GET_RTCE_BUFFER_SIZE 0x3 ++#define SPAPR_VTPM_PREPARE_TO_SUSPEND 0x4 ++ ++/* response error messages */ ++#define SPAPR_VTPM_VTPM_ERROR 0xff ++ ++/* error codes */ ++#define SPAPR_VTPM_ERR_COPY_IN_FAILED 0x3 ++#define SPAPR_VTPM_ERR_COPY_OUT_FAILED 0x4 ++ ++#define TPM_SPAPR_BUFFER_MAX 4096 ++ ++typedef struct { ++ SpaprVioDevice vdev; ++ ++ TpmCrq crq; /* track single TPM command */ ++ ++ uint8_t state; ++#define SPAPR_VTPM_STATE_NONE 0 ++#define SPAPR_VTPM_STATE_EXECUTION 1 ++#define SPAPR_VTPM_STATE_COMPLETION 2 ++ ++ unsigned char *buffer; ++ ++ TPMBackendCmd cmd; ++ ++ TPMBackend *be_driver; ++ TPMVersion be_tpm_version; ++ ++ size_t be_buffer_size; ++} SpaprTpmState; ++ ++/* ++ * Send a request to the TPM. ++ */ ++static void tpm_spapr_tpm_send(SpaprTpmState *s) ++{ ++ if (trace_event_get_state_backends(TRACE_TPM_SPAPR_SHOW_BUFFER)) { ++ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); ++ } ++ ++ s->state = SPAPR_VTPM_STATE_EXECUTION; ++ s->cmd = (TPMBackendCmd) { ++ .locty = 0, ++ .in = s->buffer, ++ .in_len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size), ++ .out = s->buffer, ++ .out_len = s->be_buffer_size, ++ }; ++ ++ tpm_backend_deliver_request(s->be_driver, &s->cmd); ++} ++ ++static int tpm_spapr_process_cmd(SpaprTpmState *s, uint64_t dataptr) ++{ ++ long rc; ++ ++ /* a max. of be_buffer_size bytes can be transported */ ++ rc = spapr_vio_dma_read(&s->vdev, dataptr, ++ s->buffer, s->be_buffer_size); ++ if (rc) { ++ error_report("tpm_spapr_got_payload: DMA read failure"); ++ } ++ /* let vTPM handle any malformed request */ ++ tpm_spapr_tpm_send(s); ++ ++ return rc; ++} ++ ++static inline int spapr_tpm_send_crq(struct SpaprVioDevice *dev, TpmCrq *crq) ++{ ++ return spapr_vio_send_crq(dev, (uint8_t *)crq); ++} ++ ++static int tpm_spapr_do_crq(struct SpaprVioDevice *dev, uint8_t *crq_data) ++{ ++ SpaprTpmState *s = VIO_SPAPR_VTPM(dev); ++ TpmCrq local_crq; ++ TpmCrq *crq = &s->crq; /* requests only */ ++ int rc; ++ uint8_t valid = crq_data[0]; ++ uint8_t msg = crq_data[1]; ++ ++ trace_tpm_spapr_do_crq(valid, msg); ++ ++ switch (valid) { ++ case SPAPR_VTPM_VALID_INIT_CRQ_COMMAND: /* Init command/response */ ++ ++ /* Respond to initialization request */ ++ switch (msg) { ++ case SPAPR_VTPM_INIT_CRQ_RESULT: ++ trace_tpm_spapr_do_crq_crq_result(); ++ memset(&local_crq, 0, sizeof(local_crq)); ++ local_crq.valid = SPAPR_VTPM_VALID_INIT_CRQ_COMMAND; ++ local_crq.msg = SPAPR_VTPM_INIT_CRQ_RESULT; ++ spapr_tpm_send_crq(dev, &local_crq); ++ break; ++ ++ case SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT: ++ trace_tpm_spapr_do_crq_crq_complete_result(); ++ memset(&local_crq, 0, sizeof(local_crq)); ++ local_crq.valid = SPAPR_VTPM_VALID_INIT_CRQ_COMMAND; ++ local_crq.msg = SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT; ++ spapr_tpm_send_crq(dev, &local_crq); ++ break; ++ } ++ ++ break; ++ case SPAPR_VTPM_VALID_COMMAND: /* Payloads */ ++ switch (msg) { ++ case SPAPR_VTPM_TPM_COMMAND: ++ trace_tpm_spapr_do_crq_tpm_command(); ++ if (s->state == SPAPR_VTPM_STATE_EXECUTION) { ++ return H_BUSY; ++ } ++ memcpy(crq, crq_data, sizeof(*crq)); ++ ++ rc = tpm_spapr_process_cmd(s, be32_to_cpu(crq->data)); ++ ++ if (rc == H_SUCCESS) { ++ crq->valid = be16_to_cpu(0); ++ } else { ++ local_crq.valid = SPAPR_VTPM_MSG_RESULT; ++ local_crq.msg = SPAPR_VTPM_VTPM_ERROR; ++ local_crq.len = cpu_to_be16(0); ++ local_crq.data = cpu_to_be32(SPAPR_VTPM_ERR_COPY_IN_FAILED); ++ spapr_tpm_send_crq(dev, &local_crq); ++ } ++ break; ++ ++ case SPAPR_VTPM_GET_RTCE_BUFFER_SIZE: ++ trace_tpm_spapr_do_crq_tpm_get_rtce_buffer_size(s->be_buffer_size); ++ local_crq.valid = SPAPR_VTPM_VALID_COMMAND; ++ local_crq.msg = SPAPR_VTPM_GET_RTCE_BUFFER_SIZE | ++ SPAPR_VTPM_MSG_RESULT; ++ local_crq.len = cpu_to_be16(s->be_buffer_size); ++ spapr_tpm_send_crq(dev, &local_crq); ++ break; ++ ++ case SPAPR_VTPM_GET_VERSION: ++ local_crq.valid = SPAPR_VTPM_VALID_COMMAND; ++ local_crq.msg = SPAPR_VTPM_GET_VERSION | SPAPR_VTPM_MSG_RESULT; ++ local_crq.len = cpu_to_be16(0); ++ switch (s->be_tpm_version) { ++ case TPM_VERSION_1_2: ++ local_crq.data = cpu_to_be32(1); ++ break; ++ case TPM_VERSION_2_0: ++ local_crq.data = cpu_to_be32(2); ++ break; ++ default: ++ g_assert_not_reached(); ++ break; ++ } ++ trace_tpm_spapr_do_crq_get_version(be32_to_cpu(local_crq.data)); ++ spapr_tpm_send_crq(dev, &local_crq); ++ break; ++ ++ case SPAPR_VTPM_PREPARE_TO_SUSPEND: ++ trace_tpm_spapr_do_crq_prepare_to_suspend(); ++ local_crq.valid = SPAPR_VTPM_VALID_COMMAND; ++ local_crq.msg = SPAPR_VTPM_PREPARE_TO_SUSPEND | ++ SPAPR_VTPM_MSG_RESULT; ++ spapr_tpm_send_crq(dev, &local_crq); ++ break; ++ ++ default: ++ trace_tpm_spapr_do_crq_unknown_msg_type(crq->msg); ++ } ++ break; ++ default: ++ trace_tpm_spapr_do_crq_unknown_crq(valid, msg); ++ }; ++ ++ return H_SUCCESS; ++} ++ ++static void tpm_spapr_request_completed(TPMIf *ti, int ret) ++{ ++ SpaprTpmState *s = VIO_SPAPR_VTPM(ti); ++ TpmCrq *crq = &s->crq; ++ uint32_t len; ++ int rc; ++ ++ s->state = SPAPR_VTPM_STATE_COMPLETION; ++ ++ /* a max. of be_buffer_size bytes can be transported */ ++ len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size); ++ rc = spapr_vio_dma_write(&s->vdev, be32_to_cpu(crq->data), ++ s->buffer, len); ++ ++ if (trace_event_get_state_backends(TRACE_TPM_SPAPR_SHOW_BUFFER)) { ++ tpm_util_show_buffer(s->buffer, len, "From TPM"); ++ } ++ ++ crq->valid = SPAPR_VTPM_MSG_RESULT; ++ if (rc == H_SUCCESS) { ++ crq->msg = SPAPR_VTPM_TPM_COMMAND | SPAPR_VTPM_MSG_RESULT; ++ crq->len = cpu_to_be16(len); ++ } else { ++ error_report("%s: DMA write failure", __func__); ++ crq->msg = SPAPR_VTPM_VTPM_ERROR; ++ crq->len = cpu_to_be16(0); ++ crq->data = cpu_to_be32(SPAPR_VTPM_ERR_COPY_OUT_FAILED); ++ } ++ ++ rc = spapr_tpm_send_crq(&s->vdev, crq); ++ if (rc) { ++ error_report("%s: Error sending response", __func__); ++ } ++} ++ ++static int tpm_spapr_do_startup_tpm(SpaprTpmState *s, size_t buffersize) ++{ ++ return tpm_backend_startup_tpm(s->be_driver, buffersize); ++} ++ ++static const char *tpm_spapr_get_dt_compatible(SpaprVioDevice *dev) ++{ ++ SpaprTpmState *s = VIO_SPAPR_VTPM(dev); ++ ++ switch (s->be_tpm_version) { ++ case TPM_VERSION_1_2: ++ return "IBM,vtpm"; ++ case TPM_VERSION_2_0: ++ return "IBM,vtpm20"; ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++static void tpm_spapr_reset(SpaprVioDevice *dev) ++{ ++ SpaprTpmState *s = VIO_SPAPR_VTPM(dev); ++ ++ s->state = SPAPR_VTPM_STATE_NONE; ++ ++ s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); ++ ++ s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver), ++ TPM_SPAPR_BUFFER_MAX); ++ ++ tpm_backend_reset(s->be_driver); ++ tpm_spapr_do_startup_tpm(s, s->be_buffer_size); ++} ++ ++static enum TPMVersion tpm_spapr_get_version(TPMIf *ti) ++{ ++ SpaprTpmState *s = VIO_SPAPR_VTPM(ti); ++ ++ if (tpm_backend_had_startup_error(s->be_driver)) { ++ return TPM_VERSION_UNSPEC; ++ } ++ ++ return tpm_backend_get_tpm_version(s->be_driver); ++} ++ ++static const VMStateDescription vmstate_spapr_vtpm = { ++ .name = "tpm-spapr", ++ .unmigratable = 1, ++}; ++ ++static Property tpm_spapr_properties[] = { ++ DEFINE_SPAPR_PROPERTIES(SpaprTpmState, vdev), ++ DEFINE_PROP_TPMBE("tpmdev", SpaprTpmState, be_driver), ++ DEFINE_PROP_END_OF_LIST(), ++}; ++ ++static void tpm_spapr_realizefn(SpaprVioDevice *dev, Error **errp) ++{ ++ SpaprTpmState *s = VIO_SPAPR_VTPM(dev); ++ ++ if (!tpm_find()) { ++ error_setg(errp, "at most one TPM device is permitted"); ++ return; ++ } ++ ++ dev->crq.SendFunc = tpm_spapr_do_crq; ++ ++ if (!s->be_driver) { ++ error_setg(errp, "'tpmdev' property is required"); ++ return; ++ } ++ s->buffer = g_malloc(TPM_SPAPR_BUFFER_MAX); ++} ++ ++static void tpm_spapr_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); ++ TPMIfClass *tc = TPM_IF_CLASS(klass); ++ ++ k->realize = tpm_spapr_realizefn; ++ k->reset = tpm_spapr_reset; ++ k->dt_name = "vtpm"; ++ k->dt_type = "IBM,vtpm"; ++ k->get_dt_compatible = tpm_spapr_get_dt_compatible; ++ k->signal_mask = 0x00000001; ++ set_bit(DEVICE_CATEGORY_MISC, dc->categories); ++ dc->props = tpm_spapr_properties; ++ k->rtce_window_size = 0x10000000; ++ dc->vmsd = &vmstate_spapr_vtpm; ++ ++ tc->model = TPM_MODEL_TPM_SPAPR; ++ tc->get_version = tpm_spapr_get_version; ++ tc->request_completed = tpm_spapr_request_completed; ++} ++ ++static const TypeInfo tpm_spapr_info = { ++ .name = TYPE_TPM_SPAPR, ++ .parent = TYPE_VIO_SPAPR_DEVICE, ++ .instance_size = sizeof(SpaprTpmState), ++ .class_init = tpm_spapr_class_init, ++ .interfaces = (InterfaceInfo[]) { ++ { TYPE_TPM_IF }, ++ { } ++ } ++}; ++ ++static void tpm_spapr_register_types(void) ++{ ++ type_register_static(&tpm_spapr_info); ++} ++ ++type_init(tpm_spapr_register_types) +diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events +index 82c45ee5..edbe1bd7 100644 +--- a/hw/tpm/trace-events ++++ b/hw/tpm/trace-events +@@ -55,3 +55,15 @@ tpm_tis_pre_save(uint8_t locty, uint32_t rw_offset) "locty: %d, rw_offset = %u" + + # tpm_ppi.c + tpm_ppi_memset(uint8_t *ptr, size_t size) "memset: %p %zu" ++ ++# hw/tpm/tpm_spapr.c ++tpm_spapr_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s" ++tpm_spapr_do_crq(uint8_t raw1, uint8_t raw2) "1st 2 bytes in CRQ: 0x%02x 0x%02x" ++tpm_spapr_do_crq_crq_result(void) "SPAPR_VTPM_INIT_CRQ_RESULT" ++tpm_spapr_do_crq_crq_complete_result(void) "SPAPR_VTPM_INIT_CRQ_COMP_RESULT" ++tpm_spapr_do_crq_tpm_command(void) "got TPM command payload" ++tpm_spapr_do_crq_tpm_get_rtce_buffer_size(size_t buffersize) "response: buffer size is %zu" ++tpm_spapr_do_crq_get_version(uint32_t version) "response: version %u" ++tpm_spapr_do_crq_prepare_to_suspend(void) "response: preparing to suspend" ++tpm_spapr_do_crq_unknown_msg_type(uint8_t type) "Unknown message type 0x%02x" ++tpm_spapr_do_crq_unknown_crq(uint8_t raw1, uint8_t raw2) "unknown CRQ 0x%02x 0x%02x ..." +diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h +index 5b541a71..15979a36 100644 +--- a/include/sysemu/tpm.h ++++ b/include/sysemu/tpm.h +@@ -45,11 +45,14 @@ typedef struct TPMIfClass { + + #define TYPE_TPM_TIS "tpm-tis" + #define TYPE_TPM_CRB "tpm-crb" ++#define TYPE_TPM_SPAPR "tpm-spapr" + + #define TPM_IS_TIS(chr) \ + object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS) + #define TPM_IS_CRB(chr) \ + object_dynamic_cast(OBJECT(chr), TYPE_TPM_CRB) ++#define TPM_IS_SPAPR(chr) \ ++ object_dynamic_cast(OBJECT(chr), TYPE_TPM_SPAPR) + + /* returns NULL unless there is exactly one TPM device */ + static inline TPMIf *tpm_find(void) +diff --git a/qapi/tpm.json b/qapi/tpm.json +index b30323bb..63878aa0 100644 +--- a/qapi/tpm.json ++++ b/qapi/tpm.json +@@ -12,11 +12,11 @@ + # + # @tpm-tis: TPM TIS model + # @tpm-crb: TPM CRB model (since 2.12) ++# @tpm-spapr: TPM SPAPR model (since 5.0) + # + # Since: 1.5 + ## +-{ 'enum': 'TpmModel', 'data': [ 'tpm-tis', 'tpm-crb' ] } +- ++{ 'enum': 'TpmModel', 'data': [ 'tpm-tis', 'tpm-crb', 'tpm-spapr' ] } + ## + # @query-tpm-models: + # +@@ -29,7 +29,7 @@ + # Example: + # + # -> { "execute": "query-tpm-models" } +-# <- { "return": [ "tpm-tis", "tpm-crb" ] } ++# <- { "return": [ "tpm-tis", "tpm-crb", "tpm-spapr" ] } + # + ## + { 'command': 'query-tpm-models', 'returns': ['TpmModel'] } +-- +2.23.0 + diff --git a/tpm_spapr-Support-suspend-and-resume.patch b/tpm_spapr-Support-suspend-and-resume.patch new file mode 100644 index 0000000000000000000000000000000000000000..55ed521a261fe5c058d9f6b95334c0884cdfd7ea --- /dev/null +++ b/tpm_spapr-Support-suspend-and-resume.patch @@ -0,0 +1,119 @@ +From 2948d9712a7058bcdca6732101874beb1a6e00a9 Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Tue, 21 Jan 2020 10:29:33 -0500 +Subject: [PATCH 07/19] tpm_spapr: Support suspend and resume +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Extend the tpm_spapr frontend with VM suspend and resume support. + +Signed-off-by: Stefan Berger +Message-Id: <20200121152935.649898-5-stefanb@linux.ibm.com> +Reviewed-by: Marc-André Lureau +Signed-off-by: David Gibson +Signed-off-by: jiangfangjie +--- + hw/tpm/tpm_spapr.c | 52 ++++++++++++++++++++++++++++++++++++++++++++- + hw/tpm/trace-events | 2 ++ + 2 files changed, 53 insertions(+), 1 deletion(-) + +diff --git a/hw/tpm/tpm_spapr.c b/hw/tpm/tpm_spapr.c +index 1db9696a..8ba561f4 100644 +--- a/hw/tpm/tpm_spapr.c ++++ b/hw/tpm/tpm_spapr.c +@@ -76,6 +76,8 @@ typedef struct { + + unsigned char *buffer; + ++ uint32_t numbytes; /* number of bytes to deliver on resume */ ++ + TPMBackendCmd cmd; + + TPMBackend *be_driver; +@@ -240,6 +242,14 @@ static void tpm_spapr_request_completed(TPMIf *ti, int ret) + + /* a max. of be_buffer_size bytes can be transported */ + len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size); ++ ++ if (runstate_check(RUN_STATE_FINISH_MIGRATE)) { ++ trace_tpm_spapr_caught_response(len); ++ /* defer delivery of response until .post_load */ ++ s->numbytes = len; ++ return; ++ } ++ + rc = spapr_vio_dma_write(&s->vdev, be32_to_cpu(crq->data), + s->buffer, len); + +@@ -288,6 +298,7 @@ static void tpm_spapr_reset(SpaprVioDevice *dev) + SpaprTpmState *s = VIO_SPAPR_VTPM(dev); + + s->state = SPAPR_VTPM_STATE_NONE; ++ s->numbytes = 0; + + s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); + +@@ -309,9 +320,48 @@ static enum TPMVersion tpm_spapr_get_version(TPMIf *ti) + return tpm_backend_get_tpm_version(s->be_driver); + } + ++/* persistent state handling */ ++ ++static int tpm_spapr_pre_save(void *opaque) ++{ ++ SpaprTpmState *s = opaque; ++ ++ tpm_backend_finish_sync(s->be_driver); ++ /* ++ * we cannot deliver the results to the VM since DMA would touch VM memory ++ */ ++ ++ return 0; ++} ++ ++static int tpm_spapr_post_load(void *opaque, int version_id) ++{ ++ SpaprTpmState *s = opaque; ++ ++ if (s->numbytes) { ++ trace_tpm_spapr_post_load(); ++ /* deliver the results to the VM via DMA */ ++ tpm_spapr_request_completed(TPM_IF(s), 0); ++ s->numbytes = 0; ++ } ++ ++ return 0; ++} ++ + static const VMStateDescription vmstate_spapr_vtpm = { + .name = "tpm-spapr", +- .unmigratable = 1, ++ .pre_save = tpm_spapr_pre_save, ++ .post_load = tpm_spapr_post_load, ++ .fields = (VMStateField[]) { ++ VMSTATE_SPAPR_VIO(vdev, SpaprTpmState), ++ ++ VMSTATE_UINT8(state, SpaprTpmState), ++ VMSTATE_UINT32(numbytes, SpaprTpmState), ++ VMSTATE_VBUFFER_UINT32(buffer, SpaprTpmState, 0, NULL, numbytes), ++ /* remember DMA address */ ++ VMSTATE_UINT32(crq.data, SpaprTpmState), ++ VMSTATE_END_OF_LIST(), ++ } + }; + + static Property tpm_spapr_properties[] = { +diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events +index edbe1bd7..b97eea24 100644 +--- a/hw/tpm/trace-events ++++ b/hw/tpm/trace-events +@@ -67,3 +67,5 @@ tpm_spapr_do_crq_get_version(uint32_t version) "response: version %u" + tpm_spapr_do_crq_prepare_to_suspend(void) "response: preparing to suspend" + tpm_spapr_do_crq_unknown_msg_type(uint8_t type) "Unknown message type 0x%02x" + tpm_spapr_do_crq_unknown_crq(uint8_t raw1, uint8_t raw2) "unknown CRQ 0x%02x 0x%02x ..." ++tpm_spapr_post_load(void) "Delivering TPM response after resume" ++tpm_spapr_caught_response(uint32_t v) "Caught response to deliver after resume: %u bytes" +-- +2.23.0 + diff --git a/usbredir-fix-buffer-overflow-on-vmload.patch b/usbredir-fix-buffer-overflow-on-vmload.patch new file mode 100644 index 0000000000000000000000000000000000000000..4a43c35cad37bcece9822ddf61033c18dd7edfc4 --- /dev/null +++ b/usbredir-fix-buffer-overflow-on-vmload.patch @@ -0,0 +1,54 @@ +From 66fce891aecec3969d1ba979cf0a9a6df70afecd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Wed, 7 Aug 2019 12:40:48 +0400 +Subject: [PATCH] usbredir: fix buffer-overflow on vmload +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If interface_count is NO_INTERFACE_INFO, let's not access the arrays +out-of-bounds. + +==994==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x625000243930 at pc 0x5642068086a8 bp 0x7f0b6f9ffa50 sp 0x7f0b6f9ffa40 +READ of size 1 at 0x625000243930 thread T0 + #0 0x5642068086a7 in usbredir_check_bulk_receiving /home/elmarco/src/qemu/hw/usb/redirect.c:1503 + #1 0x56420681301c in usbredir_post_load /home/elmarco/src/qemu/hw/usb/redirect.c:2154 + #2 0x5642068a56c2 in vmstate_load_state /home/elmarco/src/qemu/migration/vmstate.c:168 + #3 0x56420688e2ac in vmstate_load /home/elmarco/src/qemu/migration/savevm.c:829 + #4 0x5642068980cb in qemu_loadvm_section_start_full /home/elmarco/src/qemu/migration/savevm.c:2211 + #5 0x564206899645 in qemu_loadvm_state_main /home/elmarco/src/qemu/migration/savevm.c:2395 + #6 0x5642068998cf in qemu_loadvm_state /home/elmarco/src/qemu/migration/savevm.c:2467 + #7 0x56420685f3e9 in process_incoming_migration_co /home/elmarco/src/qemu/migration/migration.c:449 + #8 0x564207106c47 in coroutine_trampoline /home/elmarco/src/qemu/util/coroutine-ucontext.c:115 + #9 0x7f0c0604e37f (/lib64/libc.so.6+0x4d37f) + +Signed-off-by: Marc-André Lureau +Reviewed-by: Liam Merwick +Reviewed-by: Li Qiang +Reviewed-by: Philippe Mathieu-Daudé +Message-id: 20190807084048.4258-1-marcandre.lureau@redhat.com +Signed-off-by: Gerd Hoffmann +Signed-off-by: Zhenyu Ye +--- + hw/usb/redirect.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 998fc6e4..9764a579 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -1495,6 +1495,11 @@ static void usbredir_check_bulk_receiving(USBRedirDevice *dev) + for (i = EP2I(USB_DIR_IN); i < MAX_ENDPOINTS; i++) { + dev->endpoint[i].bulk_receiving_enabled = 0; + } ++ ++ if (dev->interface_info.interface_count == NO_INTERFACE_INFO) { ++ return; ++ } ++ + for (i = 0; i < dev->interface_info.interface_count; i++) { + quirks = usb_get_quirks(dev->device_info.vendor_id, + dev->device_info.product_id, +-- +2.22.0.windows.1 + diff --git a/vhost-user-blk-delay-vhost_user_blk_disconnect.patch b/vhost-user-blk-delay-vhost_user_blk_disconnect.patch new file mode 100644 index 0000000000000000000000000000000000000000..422e2a17b028d83690cc620a57829260c76aab52 --- /dev/null +++ b/vhost-user-blk-delay-vhost_user_blk_disconnect.patch @@ -0,0 +1,90 @@ +From 632a841b6ba547906b475250f5c2cb46774ab4af Mon Sep 17 00:00:00 2001 +From: Dima Stepanov +Date: Thu, 28 May 2020 12:11:19 +0300 +Subject: [PATCH 14/14] vhost-user-blk: delay vhost_user_blk_disconnect + +A socket write during vhost-user communication may trigger a disconnect +event, calling vhost_user_blk_disconnect() and clearing all the +vhost_dev structures holding data that vhost-user functions expect to +remain valid to roll back initialization correctly. Delay the cleanup to +keep vhost_dev structure valid. +There are two possible states to handle: +1. RUN_STATE_PRELAUNCH: skip bh oneshot call and perform disconnect in +the caller routine. +2. RUN_STATE_RUNNING: delay by using bh + +BH changes are based on the similar changes for the vhost-user-net +device: + commit e7c83a885f865128ae3cf1946f8cb538b63cbfba + "vhost-user: delay vhost_user_stop" + +Signed-off-by: Dima Stepanov +Message-Id: <69b73b94dcd066065595266c852810e0863a0895.1590396396.git.dimastep@yandex-team.ru> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Li Feng +Reviewed-by: Raphael Norwitz +Signed-off-by: Peng Liang +--- + hw/block/vhost-user-blk.c | 38 +++++++++++++++++++++++++++++++++++++- + 1 file changed, 37 insertions(+), 1 deletion(-) + +diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c +index dc66f8a5febd..6b719d1d80e1 100644 +--- a/hw/block/vhost-user-blk.c ++++ b/hw/block/vhost-user-blk.c +@@ -346,6 +346,19 @@ static void vhost_user_blk_disconnect(DeviceState *dev) + vhost_dev_cleanup(&s->dev); + } + ++static void vhost_user_blk_event(void *opaque, int event); ++ ++static void vhost_user_blk_chr_closed_bh(void *opaque) ++{ ++ DeviceState *dev = opaque; ++ VirtIODevice *vdev = VIRTIO_DEVICE(dev); ++ VHostUserBlk *s = VHOST_USER_BLK(vdev); ++ ++ vhost_user_blk_disconnect(dev); ++ qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, vhost_user_blk_event, ++ NULL, opaque, NULL, true); ++} ++ + static void vhost_user_blk_event(void *opaque, int event) + { + DeviceState *dev = opaque; +@@ -360,7 +373,30 @@ static void vhost_user_blk_event(void *opaque, int event) + } + break; + case CHR_EVENT_CLOSED: +- vhost_user_blk_disconnect(dev); ++ /* ++ * A close event may happen during a read/write, but vhost ++ * code assumes the vhost_dev remains setup, so delay the ++ * stop & clear. There are two possible paths to hit this ++ * disconnect event: ++ * 1. When VM is in the RUN_STATE_PRELAUNCH state. The ++ * vhost_user_blk_device_realize() is a caller. ++ * 2. In tha main loop phase after VM start. ++ * ++ * For p2 the disconnect event will be delayed. We can't ++ * do the same for p1, because we are not running the loop ++ * at this moment. So just skip this step and perform ++ * disconnect in the caller function. ++ * ++ * TODO: maybe it is a good idea to make the same fix ++ * for other vhost-user devices. ++ */ ++ if (runstate_is_running()) { ++ AioContext *ctx = qemu_get_current_aio_context(); ++ ++ qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, NULL, NULL, ++ NULL, NULL, false); ++ aio_bh_schedule_oneshot(ctx, vhost_user_blk_chr_closed_bh, opaque); ++ } + break; + } + } +-- +2.26.2 + diff --git a/virtio-blk-delete-vqs-on-the-error-path-in-realize.patch b/virtio-blk-delete-vqs-on-the-error-path-in-realize.patch new file mode 100644 index 0000000000000000000000000000000000000000..205f663470d3aa594910bd19e2be8547d226e1a8 --- /dev/null +++ b/virtio-blk-delete-vqs-on-the-error-path-in-realize.patch @@ -0,0 +1,45 @@ +From ec8a25fec9898f46a6a94aa4f328fe02948b3d59 Mon Sep 17 00:00:00 2001 +From: Pan Nengyuan +Date: Sat, 28 Mar 2020 08:57:04 +0800 +Subject: [PATCH 12/14] virtio-blk: delete vqs on the error path in realize() + +virtio_vqs forgot to free on the error path in realize(). Fix that. + +The asan stack: +Direct leak of 14336 byte(s) in 1 object(s) allocated from: + #0 0x7f58b93fd970 in __interceptor_calloc (/lib64/libasan.so.5+0xef970) + #1 0x7f58b858249d in g_malloc0 (/lib64/libglib-2.0.so.0+0x5249d) + #2 0x5562cc627f49 in virtio_add_queue /mnt/sdb/qemu/hw/virtio/virtio.c:2413 + #3 0x5562cc4b524a in virtio_blk_device_realize /mnt/sdb/qemu/hw/block/virtio-blk.c:1202 + #4 0x5562cc613050 in virtio_device_realize /mnt/sdb/qemu/hw/virtio/virtio.c:3615 + #5 0x5562ccb7a568 in device_set_realized /mnt/sdb/qemu/hw/core/qdev.c:891 + #6 0x5562cd39cd45 in property_set_bool /mnt/sdb/qemu/qom/object.c:2238 + +Reported-by: Euler Robot +Signed-off-by: Pan Nengyuan +Reviewed-by: Stefano Garzarella +Message-Id: <20200328005705.29898-2-pannengyuan@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Peng Liang +--- + hw/block/virtio-blk.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c +index cbb3729158fe..703ed4c93bff 100644 +--- a/hw/block/virtio-blk.c ++++ b/hw/block/virtio-blk.c +@@ -1173,6 +1173,9 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) + virtio_blk_data_plane_create(vdev, conf, &s->dataplane, &err); + if (err != NULL) { + error_propagate(errp, err); ++ for (i = 0; i < conf->num_queues; i++) { ++ virtio_del_queue(vdev, i); ++ } + virtio_cleanup(vdev); + return; + } +-- +2.26.2 + diff --git a/virtio-pci-fix-queue_enable-write.patch b/virtio-pci-fix-queue_enable-write.patch new file mode 100644 index 0000000000000000000000000000000000000000..481b41bbf11f4ebb94ae8fd746b13ad4ac41555d --- /dev/null +++ b/virtio-pci-fix-queue_enable-write.patch @@ -0,0 +1,58 @@ +From aebd6a1512e03ba51f6824fcdbaa09f67e9ff5e2 Mon Sep 17 00:00:00 2001 +From: Jason Wang +Date: Wed, 10 Jun 2020 13:43:51 +0800 +Subject: [PATCH 11/11] virtio-pci: fix queue_enable write + +Spec said: The driver uses this to selectively prevent the device from +executing requests from this virtqueue. 1 - enabled; 0 - disabled. + +Though write 0 to queue_enable is forbidden by the spec, we should not +assume that the value is 1. + +Fix this by ignore the write value other than 1. + +Signed-off-by: Jason Wang +Message-Id: <20200610054351.15811-1-jasowang@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Stefano Garzarella +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: BiaoXiang Ye +--- + hw/virtio/virtio-pci.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index b4b0ed26..4b8845a6 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -1259,16 +1259,20 @@ static void virtio_pci_common_write(void *opaque, hwaddr addr, + virtio_queue_set_vector(vdev, vdev->queue_sel, val); + break; + case VIRTIO_PCI_COMMON_Q_ENABLE: +- virtio_queue_set_num(vdev, vdev->queue_sel, +- proxy->vqs[vdev->queue_sel].num); +- virtio_queue_set_rings(vdev, vdev->queue_sel, ++ if (val == 1) { ++ virtio_queue_set_num(vdev, vdev->queue_sel, ++ proxy->vqs[vdev->queue_sel].num); ++ virtio_queue_set_rings(vdev, vdev->queue_sel, + ((uint64_t)proxy->vqs[vdev->queue_sel].desc[1]) << 32 | + proxy->vqs[vdev->queue_sel].desc[0], + ((uint64_t)proxy->vqs[vdev->queue_sel].avail[1]) << 32 | + proxy->vqs[vdev->queue_sel].avail[0], + ((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 | + proxy->vqs[vdev->queue_sel].used[0]); +- proxy->vqs[vdev->queue_sel].enabled = 1; ++ proxy->vqs[vdev->queue_sel].enabled = 1; ++ } else { ++ virtio_error(vdev, "wrong value for queue_enable %"PRIx64, val); ++ } + break; + case VIRTIO_PCI_COMMON_Q_DESCLO: + proxy->vqs[vdev->queue_sel].desc[0] = val; +-- +2.27.0.dirty + diff --git a/virtio-serial-bus-Plug-memory-leak-on-realize-error-.patch b/virtio-serial-bus-Plug-memory-leak-on-realize-error-.patch new file mode 100644 index 0000000000000000000000000000000000000000..02069901b096cd09b0f30dbef9d55e3fe6dc920d --- /dev/null +++ b/virtio-serial-bus-Plug-memory-leak-on-realize-error-.patch @@ -0,0 +1,65 @@ +From 0d93f5455489274201b1054d987b12f8e8a6206e Mon Sep 17 00:00:00 2001 +From: Pan Nengyuan +Date: Mon, 9 Mar 2020 10:17:38 +0800 +Subject: [PATCH 11/14] virtio-serial-bus: Plug memory leak on realize() error + paths + +We neglect to free port->bh on the error paths. Fix that. +Reproducer: + {'execute': 'device_add', 'arguments': {'id': 'virtio_serial_pci0', 'driver': 'virtio-serial-pci', 'bus': 'pci.0', 'addr': '0x5'}, 'id': 'yVkZcGgV'} + {'execute': 'device_add', 'arguments': {'id': 'port1', 'driver': 'virtserialport', 'name': 'port1', 'chardev': 'channel1', 'bus': 'virtio_serial_pci0.0', 'nr': 1}, 'id': '3dXdUgJA'} + {'execute': 'device_add', 'arguments': {'id': 'port2', 'driver': 'virtserialport', 'name': 'port2', 'chardev': 'channel2', 'bus': 'virtio_serial_pci0.0', 'nr': 1}, 'id': 'qLzcCkob'} + {'execute': 'device_add', 'arguments': {'id': 'port2', 'driver': 'virtserialport', 'name': 'port2', 'chardev': 'channel2', 'bus': 'virtio_serial_pci0.0', 'nr': 2}, 'id': 'qLzcCkob'} + +The leak stack: +Direct leak of 40 byte(s) in 1 object(s) allocated from: + #0 0x7f04a8008ae8 in __interceptor_malloc (/lib64/libasan.so.5+0xefae8) + #1 0x7f04a73cf1d5 in g_malloc (/lib64/libglib-2.0.so.0+0x531d5) + #2 0x56273eaee484 in aio_bh_new /mnt/sdb/backup/qemu/util/async.c:125 + #3 0x56273eafe9a8 in qemu_bh_new /mnt/sdb/backup/qemu/util/main-loop.c:532 + #4 0x56273d52e62e in virtser_port_device_realize /mnt/sdb/backup/qemu/hw/char/virtio-serial-bus.c:946 + #5 0x56273dcc5040 in device_set_realized /mnt/sdb/backup/qemu/hw/core/qdev.c:891 + #6 0x56273e5ebbce in property_set_bool /mnt/sdb/backup/qemu/qom/object.c:2238 + #7 0x56273e5e5a9c in object_property_set /mnt/sdb/backup/qemu/qom/object.c:1324 + #8 0x56273e5ef5f8 in object_property_set_qobject /mnt/sdb/backup/qemu/qom/qom-qobject.c:26 + #9 0x56273e5e5e6a in object_property_set_bool /mnt/sdb/backup/qemu/qom/object.c:1390 + #10 0x56273daa40de in qdev_device_add /mnt/sdb/backup/qemu/qdev-monitor.c:680 + #11 0x56273daa53e9 in qmp_device_add /mnt/sdb/backup/qemu/qdev-monitor.c:805 + +Fixes: 199646d81522509ac2dba6d28c31e8c7d807bc93 +Reported-by: Euler Robot +Signed-off-by: Pan Nengyuan +Reviewed-by: Markus Armbruster +Reviewed-by: Amit Shah +Message-Id: <20200309021738.30072-1-pannengyuan@huawei.com> +Reviewed-by: Laurent Vivier +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Peng Liang +--- + hw/char/virtio-serial-bus.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c +index f7a54f261b21..2d23dae6d2b7 100644 +--- a/hw/char/virtio-serial-bus.c ++++ b/hw/char/virtio-serial-bus.c +@@ -940,7 +940,6 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp) + Error *err = NULL; + + port->vser = bus->vser; +- port->bh = qemu_bh_new(flush_queued_data_bh, port); + + assert(vsc->have_data); + +@@ -989,6 +988,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp) + return; + } + ++ port->bh = qemu_bh_new(flush_queued_data_bh, port); + port->elem = NULL; + } + +-- +2.26.2 + diff --git a/xhci-fix-valid.max_access_size-to-access-address-reg.patch b/xhci-fix-valid.max_access_size-to-access-address-reg.patch new file mode 100644 index 0000000000000000000000000000000000000000..466cbf2667efaf26cc65c160c8223659abb0c288 --- /dev/null +++ b/xhci-fix-valid.max_access_size-to-access-address-reg.patch @@ -0,0 +1,62 @@ +From a71d1847aa780b3c4062e582ab400a7fea0413b3 Mon Sep 17 00:00:00 2001 +From: Laurent Vivier +Date: Tue, 21 Jul 2020 10:33:22 +0200 +Subject: [PATCH 01/11] xhci: fix valid.max_access_size to access address + registers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +QEMU XHCI advertises AC64 (64-bit addressing) but doesn't allow +64-bit mode access in "runtime" and "operational" MemoryRegionOps. + +Set the max_access_size based on sizeof(dma_addr_t) as AC64 is set. + +XHCI specs: +"If the xHC supports 64-bit addressing (AC64 = ‘1’), then software +should write 64-bit registers using only Qword accesses. If a +system is incapable of issuing Qword accesses, then writes to the +64-bit address fields shall be performed using 2 Dword accesses; +low Dword-first, high-Dword second. If the xHC supports 32-bit +addressing (AC64 = ‘0’), then the high Dword of registers containing +64-bit address fields are unused and software should write addresses +using only Dword accesses" + +The problem has been detected with SLOF, as linux kernel always accesses +registers using 32-bit access even if AC64 is set and revealed by +5d971f9e6725 ("memory: Revert "memory: accept mismatching sizes in memory_region_access_valid"") + +Suggested-by: Alexey Kardashevskiy +Signed-off-by: Laurent Vivier +Message-id: 20200721083322.90651-1-lvivier@redhat.com +Signed-off-by: Gerd Hoffmann +Signed-off-by: BiaoXiang Ye +--- + hw/usb/hcd-xhci.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index a21485fe..24565de1 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -3171,7 +3171,7 @@ static const MemoryRegionOps xhci_oper_ops = { + .read = xhci_oper_read, + .write = xhci_oper_write, + .valid.min_access_size = 4, +- .valid.max_access_size = 4, ++ .valid.max_access_size = sizeof(dma_addr_t), + .endianness = DEVICE_LITTLE_ENDIAN, + }; + +@@ -3187,7 +3187,7 @@ static const MemoryRegionOps xhci_runtime_ops = { + .read = xhci_runtime_read, + .write = xhci_runtime_write, + .valid.min_access_size = 4, +- .valid.max_access_size = 4, ++ .valid.max_access_size = sizeof(dma_addr_t), + .endianness = DEVICE_LITTLE_ENDIAN, + }; + +-- +2.27.0.dirty +