get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/2217953/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2217953,
    "url": "http://patchwork.ozlabs.org/api/patches/2217953/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260331040659.401397-2-tangtao1634@phytium.com.cn/",
    "project": {
        "id": 14,
        "url": "http://patchwork.ozlabs.org/api/projects/14/?format=api",
        "name": "QEMU Development",
        "link_name": "qemu-devel",
        "list_id": "qemu-devel.nongnu.org",
        "list_email": "qemu-devel@nongnu.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20260331040659.401397-2-tangtao1634@phytium.com.cn>",
    "list_archive_url": null,
    "date": "2026-03-31T04:06:56",
    "name": "[1/4] tests/qtest: Add attrs support to qtest server memory commands",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "8a8fd151c8abe072fe62ef97fe319c1820ba51bd",
    "submitter": {
        "id": 91412,
        "url": "http://patchwork.ozlabs.org/api/people/91412/?format=api",
        "name": "Tao Tang",
        "email": "tangtao1634@phytium.com.cn"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260331040659.401397-2-tangtao1634@phytium.com.cn/mbox/",
    "series": [
        {
            "id": 498122,
            "url": "http://patchwork.ozlabs.org/api/series/498122/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=498122",
            "date": "2026-03-31T04:06:55",
            "name": "tests/qtest: Add memory-access attributes (secure/space)",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/498122/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2217953/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2217953/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": [
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)",
            "hzbj-icmmx-6; spf=neutral smtp.mail=tangtao163\n 4@phytium.com.cn;"
        ],
        "Received": [
            "from lists.gnu.org (lists.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4flF4T51Xdz1xtJ\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 31 Mar 2026 15:09:29 +1100 (AEDT)",
            "from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1w7QOZ-0001BC-WB; Tue, 31 Mar 2026 00:08:04 -0400",
            "from eggs.gnu.org ([2001:470:142:3::10])\n by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <tangtao1634@phytium.com.cn>)\n id 1w7QON-000102-DI; Tue, 31 Mar 2026 00:07:51 -0400",
            "from sgoci-sdnproxy-4.icoremail.net ([129.150.39.64])\n by eggs.gnu.org with esmtp (Exim 4.90_1)\n (envelope-from <tangtao1634@phytium.com.cn>)\n id 1w7QOI-0002F2-MM; Tue, 31 Mar 2026 00:07:51 -0400",
            "from prodtpl.icoremail.net (unknown [10.12.1.20])\n by hzbj-icmmx-6 (Coremail) with SMTP id AQAAfwDn7qKFSMtpdcg9AA--.20365S2;\n Tue, 31 Mar 2026 12:07:33 +0800 (CST)",
            "from phytium.com.cn (unknown [218.76.62.144])\n by mail (Coremail) with SMTP id AQAAf8DwSJR6SMtpYqQHAA--.18366S4;\n Tue, 31 Mar 2026 12:07:28 +0800 (CST)"
        ],
        "From": "Tao Tang <tangtao1634@phytium.com.cn>",
        "To": "Fabiano Rosas <farosas@suse.de>, Laurent Vivier <lvivier@redhat.com>,\n Paolo Bonzini <pbonzini@redhat.com>",
        "Cc": "qemu-devel@nongnu.org, qemu-arm@nongnu.org,\n Peter Maydell <peter.maydell@linaro.org>,\n Chen Baozi <chenbaozi@phytium.com.cn>,\n Pierrick Bouvier <pierrick.bouvier@linaro.org>,\n Chao Liu <chao.liu.zevorn@gmail.com>, Tao Tang <tangtao1634@phytium.com.cn>",
        "Subject": "[PATCH 1/4] tests/qtest: Add attrs support to qtest server memory\n commands",
        "Date": "Tue, 31 Mar 2026 12:06:56 +0800",
        "Message-Id": "<20260331040659.401397-2-tangtao1634@phytium.com.cn>",
        "X-Mailer": "git-send-email 2.34.1",
        "In-Reply-To": "<20260331040659.401397-1-tangtao1634@phytium.com.cn>",
        "References": "<20260331040659.401397-1-tangtao1634@phytium.com.cn>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-CM-TRANSID": "AQAAf8DwSJR6SMtpYqQHAA--.18366S4",
        "X-CM-SenderInfo": "pwdqw3tdrrljuu6sx5pwlxzhxfrphubq/1tbiAQAKBWnJfH8GCQACsg",
        "X-Coremail-Antispam": "1Uk129KBjvAXoW3uryrCryftrykCrW3tw4DCFg_yoW8Wry7Zo\n WfKFnIya4Ut3Z7Cr929r1DJ34DXay5ur1DAwsYywn8Kay8Wryq9a98JFsxWa4jqayrGryk\n X3WfXr4fXFy0v397n29KB7ZKAUJUUUU8529EdanIXcx71UUUUU7KY7ZEXasCq-sGcSsGvf\n J3UbIjqfuFe4nvWSU8nxnvy29KBjDU0xBIdaVrnUUvcSsGvfC2KfnxnUUI43ZEXa7xR_UU\n UUUUUUU==",
        "Received-SPF": "pass client-ip=129.150.39.64;\n envelope-from=tangtao1634@phytium.com.cn; helo=sgoci-sdnproxy-4.icoremail.net",
        "X-Spam_score_int": "1",
        "X-Spam_score": "0.1",
        "X-Spam_bar": "/",
        "X-Spam_report": "(0.1 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_MSPIKE_H3=-0.01,\n RCVD_IN_MSPIKE_WL=-0.01, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=1,\n RCVD_IN_VALIDITY_RPBL_BLOCKED=1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001,\n WEIRD_QUOTING=0.001 autolearn=no autolearn_force=no",
        "X-Spam_action": "no action",
        "X-BeenThere": "qemu-devel@nongnu.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "qemu development <qemu-devel.nongnu.org>",
        "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.nongnu.org/archive/html/qemu-devel>",
        "List-Post": "<mailto:qemu-devel@nongnu.org>",
        "List-Help": "<mailto:qemu-devel-request@nongnu.org?subject=help>",
        "List-Subscribe": "<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>",
        "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org",
        "Sender": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org"
    },
    "content": "Extend qtest memory access commands to accept an optional attrs argument.\n\nSupported attrs:\n- secure (x86/Arm)\n- space=non-secure|secure|root|realm (Arm-only)\n\nFor memory commands, parse attrs, select the corresponding AddressSpace\nwith cpu_asidx_from_attrs(), and issue accesses with the matching\nMemTxAttrs.\n\nCover scalar and bulk memory commands, including:\n- read{b,w,l,q} / write{b,w,l,q}\n- read / write\n- b64read / b64write\n- memset\n\nAlso reject invalid attrs and excessive arguments, and document the new\ncommand forms in qtest.c, and use qtest_send_memtx_error() to return\nERR for memory access failures.\n\nPreserve legacy no-attrs semantics for compatibility: those commands\ncontinue to ignore MemTxResult and return OK.\n\nSigned-off-by: Tao Tang <tangtao1634@phytium.com.cn>\n---\n system/qtest.c | 420 +++++++++++++++++++++++++++++++++++++++++++------\n 1 file changed, 368 insertions(+), 52 deletions(-)",
    "diff": "diff --git a/system/qtest.c b/system/qtest.c\nindex cf90cd53ad..f330c158d0 100644\n--- a/system/qtest.c\n+++ b/system/qtest.c\n@@ -22,6 +22,7 @@\n #include \"hw/core/qdev.h\"\n #include \"hw/core/irq.h\"\n #include \"hw/core/cpu.h\"\n+#include \"hw/arm/arm-security.h\"\n #include \"qemu/accel.h\"\n #include \"system/cpu-timers.h\"\n #include \"qemu/config-file.h\"\n@@ -113,6 +114,14 @@ static void *qtest_server_send_opaque;\n  * PIO and memory access:\n  * \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n  *\n+ * Memory access commands allow specifying memory transaction attributes,\n+ * which is useful for testing devices that behave differently based on\n+ * security state (e.g., Arm TrustZone/CCA or System Management Mode in x86).\n+ *\n+ * Only the following attributes are supported by the qtest server:\n+ * ``secure`` sets MemTxAttrs.secure=1 (x86/Arm).\n+ * ``space=...`` is Arm-specific and accepts: non-secure, secure, root, realm.\n+ *\n  * .. code-block:: none\n  *\n  *  > outb ADDR VALUE\n@@ -208,6 +217,36 @@ static void *qtest_server_send_opaque;\n  *  > memset ADDR SIZE VALUE\n  *  < OK\n  *\n+ * Memory commands accept an optional ATTRS argument after their existing\n+ * operands:\n+ *\n+ * .. code-block:: none\n+ *\n+ *  > read{b,w,l,q} ADDR [ATTRS]\n+ *  > write{b,w,l,q} ADDR VALUE [ATTRS]\n+ *  > read ADDR SIZE [ATTRS]\n+ *  > write ADDR SIZE DATA [ATTRS]\n+ *  > b64read ADDR SIZE [ATTRS]\n+ *  > b64write ADDR SIZE B64_DATA [ATTRS]\n+ *  > memset ADDR SIZE VALUE [ATTRS]\n+ *\n+ * Representative examples:\n+ *\n+ * .. code-block:: none\n+ *\n+ *  > readl ADDR secure\n+ *  < OK VALUE\n+ *\n+ * .. code-block:: none\n+ *\n+ *  > b64read ADDR SIZE space=root\n+ *  < OK B64_DATA\n+ *\n+ * .. code-block:: none\n+ *\n+ *  > writeq ADDR VALUE space=realm\n+ *  < OK\n+ *\n  * ADDR, SIZE, VALUE are all integers parsed with strtoul() with a base of 0.\n  * For 'memset' a zero size is permitted and does nothing.\n  *\n@@ -353,6 +392,141 @@ static void qtest_install_gpio_out_intercept(DeviceState *dev, const char *name,\n     *disconnected = qdev_intercept_gpio_out(dev, icpt, name, n);\n }\n \n+static bool qtest_parse_mem_attrs(CharFrontend *chr, const char *arg,\n+                                  MemTxAttrs *attrs)\n+{\n+    if (!arg) {\n+        *attrs = MEMTXATTRS_UNSPECIFIED;\n+        return true;\n+    }\n+\n+    if (strcmp(arg, \"secure\") == 0) {\n+        *attrs = (MemTxAttrs){ .secure = 1 };\n+        return true;\n+    }\n+\n+    if (strncmp(arg, \"space=\", 6) == 0) {\n+        const char *space = arg + 6;\n+        ARMSecuritySpace sec_space;\n+\n+        if (!target_arm() && !target_aarch64()) {\n+            qtest_send(chr, \"ERR space=<...> is Arm-specific\\n\");\n+            return false;\n+        }\n+\n+        if (strcmp(space, \"non-secure\") == 0) {\n+            sec_space = ARMSS_NonSecure;\n+        } else if (strcmp(space, \"secure\") == 0) {\n+            sec_space = ARMSS_Secure;\n+        } else if (strcmp(space, \"root\") == 0) {\n+            sec_space = ARMSS_Root;\n+        } else if (strcmp(space, \"realm\") == 0) {\n+            sec_space = ARMSS_Realm;\n+        } else {\n+            qtest_send(chr, \"ERR invalid space value. Valid space: \"\n+                            \"secure/non-secure/root/realm\\n\");\n+            return false;\n+        }\n+\n+        *attrs = (MemTxAttrs){\n+            .space = sec_space,\n+            .secure = arm_space_is_secure(sec_space),\n+        };\n+        return true;\n+    }\n+\n+    qtest_send(chr, \"ERR invalid attrs argument\\n\");\n+    return false;\n+}\n+\n+static bool qtest_get_mem_as(CharFrontend *chr, MemTxAttrs attrs,\n+                             AddressSpace **as)\n+{\n+    int asidx;\n+\n+    /*\n+     * cpu_asidx_from_attrs mainly uses attrs to call ->asidx_from_attrs. We use\n+     * first_cpu as it's readily available.\n+     */\n+\n+    asidx = cpu_asidx_from_attrs(first_cpu, attrs);\n+    *as = cpu_get_address_space(first_cpu, asidx);\n+    if (!*as) {\n+        qtest_send(chr, \"ERR address space unavailable for attrs\\n\");\n+        return false;\n+    }\n+\n+    return true;\n+}\n+\n+static void qtest_send_memtx_error(CharFrontend *chr, MemTxResult result)\n+{\n+    qtest_sendf(chr, \"ERR memory access failed 0x%x\\n\", result);\n+}\n+\n+static MemTxResult qtest_write_sized(AddressSpace *as, uint64_t addr,\n+                                     MemTxAttrs attrs, uint64_t value,\n+                                     char size)\n+{\n+    switch (size) {\n+    case 'b': {\n+        uint8_t data = value;\n+        return address_space_write(as, addr, attrs, &data, 1);\n+    }\n+    case 'w': {\n+        uint16_t data = value;\n+        tswap16s(&data);\n+        return address_space_write(as, addr, attrs, &data, 2);\n+    }\n+    case 'l': {\n+        uint32_t data = value;\n+        tswap32s(&data);\n+        return address_space_write(as, addr, attrs, &data, 4);\n+    }\n+    case 'q': {\n+        uint64_t data = value;\n+        tswap64s(&data);\n+        return address_space_write(as, addr, attrs, &data, 8);\n+    }\n+    default:\n+        g_assert_not_reached();\n+    }\n+}\n+\n+static MemTxResult qtest_read_sized(AddressSpace *as, uint64_t addr,\n+                                    MemTxAttrs attrs, char size,\n+                                    uint64_t *value)\n+{\n+    switch (size) {\n+    case 'b': {\n+        uint8_t data = 0;\n+        MemTxResult result = address_space_read(as, addr, attrs, &data, 1);\n+        *value = data;\n+        return result;\n+    }\n+    case 'w': {\n+        uint16_t data = 0;\n+        MemTxResult result = address_space_read(as, addr, attrs, &data, 2);\n+        *value = tswap16(data);\n+        return result;\n+    }\n+    case 'l': {\n+        uint32_t data = 0;\n+        MemTxResult result = address_space_read(as, addr, attrs, &data, 4);\n+        *value = tswap32(data);\n+        return result;\n+    }\n+    case 'q': {\n+        uint64_t data = 0;\n+        MemTxResult result = address_space_read(as, addr, attrs, &data, 8);\n+        *value = tswap64(data);\n+        return result;\n+    }\n+    default:\n+        g_assert_not_reached();\n+    }\n+}\n+\n static void qtest_process_command(CharFrontend *chr, gchar **words)\n {\n     const gchar *command;\n@@ -510,33 +684,38 @@ static void qtest_process_command(CharFrontend *chr, gchar **words)\n                strcmp(words[0], \"writeq\") == 0) {\n         uint64_t addr;\n         uint64_t value;\n+        bool has_attrs;\n+        MemTxResult result;\n+        MemTxAttrs attrs;\n+        AddressSpace *as;\n         int ret;\n \n         g_assert(words[1] && words[2]);\n+        if (words[3] && words[4]) {\n+            qtest_send(chr, \"ERR too many arguments\\n\");\n+            return;\n+        }\n         ret = qemu_strtou64(words[1], NULL, 0, &addr);\n         g_assert(ret == 0);\n         ret = qemu_strtou64(words[2], NULL, 0, &value);\n         g_assert(ret == 0);\n+        has_attrs = words[3] != NULL;\n+        if (!has_attrs) {\n+            qtest_write_sized(first_cpu->as, addr,\n+                              MEMTXATTRS_UNSPECIFIED,\n+                              value, words[0][5]);\n+            qtest_send(chr, \"OK\\n\");\n+            return;\n+        }\n+        if (!qtest_parse_mem_attrs(chr, words[3], &attrs) ||\n+            !qtest_get_mem_as(chr, attrs, &as)) {\n+            return;\n+        }\n \n-        if (words[0][5] == 'b') {\n-            uint8_t data = value;\n-            address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED,\n-                                &data, 1);\n-        } else if (words[0][5] == 'w') {\n-            uint16_t data = value;\n-            tswap16s(&data);\n-            address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED,\n-                                &data, 2);\n-        } else if (words[0][5] == 'l') {\n-            uint32_t data = value;\n-            tswap32s(&data);\n-            address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED,\n-                                &data, 4);\n-        } else if (words[0][5] == 'q') {\n-            uint64_t data = value;\n-            tswap64s(&data);\n-            address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED,\n-                                &data, 8);\n+        result = qtest_write_sized(as, addr, attrs, value, words[0][5]);\n+        if (result != MEMTX_OK) {\n+            qtest_send_memtx_error(chr, result);\n+            return;\n         }\n         qtest_send(chr, \"OK\\n\");\n     } else if (strcmp(words[0], \"readb\") == 0 ||\n@@ -544,51 +723,83 @@ static void qtest_process_command(CharFrontend *chr, gchar **words)\n                strcmp(words[0], \"readl\") == 0 ||\n                strcmp(words[0], \"readq\") == 0) {\n         uint64_t addr;\n-        uint64_t value = UINT64_C(-1);\n+        uint64_t value = 0;\n+        bool has_attrs;\n+        MemTxResult result;\n+        MemTxAttrs attrs;\n+        AddressSpace *as;\n         int ret;\n \n         g_assert(words[1]);\n+        if (words[2] && words[3]) {\n+            qtest_send(chr, \"ERR too many arguments\\n\");\n+            return;\n+        }\n         ret = qemu_strtou64(words[1], NULL, 0, &addr);\n         g_assert(ret == 0);\n+        has_attrs = words[2] != NULL;\n+        if (!has_attrs) {\n+            qtest_read_sized(first_cpu->as, addr,\n+                             MEMTXATTRS_UNSPECIFIED,\n+                             words[0][4], &value);\n+            qtest_sendf(chr, \"OK 0x%016\" PRIx64 \"\\n\", value);\n+            return;\n+        }\n+        if (!qtest_parse_mem_attrs(chr, words[2], &attrs) ||\n+            !qtest_get_mem_as(chr, attrs, &as)) {\n+            return;\n+        }\n \n-        if (words[0][4] == 'b') {\n-            uint8_t data;\n-            address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED,\n-                               &data, 1);\n-            value = data;\n-        } else if (words[0][4] == 'w') {\n-            uint16_t data;\n-            address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED,\n-                               &data, 2);\n-            value = tswap16(data);\n-        } else if (words[0][4] == 'l') {\n-            uint32_t data;\n-            address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED,\n-                               &data, 4);\n-            value = tswap32(data);\n-        } else if (words[0][4] == 'q') {\n-            address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED,\n-                               &value, 8);\n-            tswap64s(&value);\n+        result = qtest_read_sized(as, addr, attrs, words[0][4], &value);\n+        if (result != MEMTX_OK) {\n+            qtest_send_memtx_error(chr, result);\n+            return;\n         }\n         qtest_sendf(chr, \"OK 0x%016\" PRIx64 \"\\n\", value);\n     } else if (strcmp(words[0], \"read\") == 0) {\n         g_autoptr(GString) enc = NULL;\n         uint64_t addr, len;\n         uint8_t *data;\n+        bool has_attrs;\n+        MemTxResult result;\n+        MemTxAttrs attrs;\n+        AddressSpace *as;\n         int ret;\n \n         g_assert(words[1] && words[2]);\n+        if (words[3] && words[4]) {\n+            qtest_send(chr, \"ERR too many arguments\\n\");\n+            return;\n+        }\n         ret = qemu_strtou64(words[1], NULL, 0, &addr);\n         g_assert(ret == 0);\n         ret = qemu_strtou64(words[2], NULL, 0, &len);\n         g_assert(ret == 0);\n         /* We'd send garbage to libqtest if len is 0 */\n         g_assert(len);\n+        has_attrs = words[3] != NULL;\n+        if (!has_attrs) {\n+            data = g_malloc0(len);\n+            address_space_read(first_cpu->as, addr,\n+                               MEMTXATTRS_UNSPECIFIED,\n+                               data, len);\n+            enc = qemu_hexdump_line(NULL, data, len, 0, 0);\n+            qtest_sendf(chr, \"OK 0x%s\\n\", enc->str);\n+            g_free(data);\n+            return;\n+        }\n+        if (!qtest_parse_mem_attrs(chr, words[3], &attrs) ||\n+            !qtest_get_mem_as(chr, attrs, &as)) {\n+            return;\n+        }\n \n         data = g_malloc(len);\n-        address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, data,\n-                           len);\n+        result = address_space_read(as, addr, attrs, data, len);\n+        if (result != MEMTX_OK) {\n+            g_free(data);\n+            qtest_send_memtx_error(chr, result);\n+            return;\n+        }\n \n         enc = qemu_hexdump_line(NULL, data, len, 0, 0);\n \n@@ -599,17 +810,45 @@ static void qtest_process_command(CharFrontend *chr, gchar **words)\n         uint64_t addr, len;\n         uint8_t *data;\n         gchar *b64_data;\n+        bool has_attrs;\n+        MemTxResult result;\n+        MemTxAttrs attrs;\n+        AddressSpace *as;\n         int ret;\n \n         g_assert(words[1] && words[2]);\n+        if (words[3] && words[4]) {\n+            qtest_send(chr, \"ERR too many arguments\\n\");\n+            return;\n+        }\n         ret = qemu_strtou64(words[1], NULL, 0, &addr);\n         g_assert(ret == 0);\n         ret = qemu_strtou64(words[2], NULL, 0, &len);\n         g_assert(ret == 0);\n+        has_attrs = words[3] != NULL;\n+        if (!has_attrs) {\n+            data = g_malloc0(len);\n+            address_space_read(first_cpu->as, addr,\n+                               MEMTXATTRS_UNSPECIFIED,\n+                               data, len);\n+            b64_data = g_base64_encode(data, len);\n+            qtest_sendf(chr, \"OK %s\\n\", b64_data);\n+            g_free(data);\n+            g_free(b64_data);\n+            return;\n+        }\n+        if (!qtest_parse_mem_attrs(chr, words[3], &attrs) ||\n+            !qtest_get_mem_as(chr, attrs, &as)) {\n+            return;\n+        }\n \n         data = g_malloc(len);\n-        address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, data,\n-                           len);\n+        result = address_space_read(as, addr, attrs, data, len);\n+        if (result != MEMTX_OK) {\n+            g_free(data);\n+            qtest_send_memtx_error(chr, result);\n+            return;\n+        }\n         b64_data = g_base64_encode(data, len);\n         qtest_sendf(chr, \"OK %s\\n\", b64_data);\n \n@@ -619,13 +858,22 @@ static void qtest_process_command(CharFrontend *chr, gchar **words)\n         uint64_t addr, len, i;\n         uint8_t *data;\n         size_t data_len;\n+        bool has_attrs;\n+        MemTxResult result;\n+        MemTxAttrs attrs;\n+        AddressSpace *as;\n         int ret;\n \n         g_assert(words[1] && words[2] && words[3]);\n+        if (words[4] && words[5]) {\n+            qtest_send(chr, \"ERR too many arguments\\n\");\n+            return;\n+        }\n         ret = qemu_strtou64(words[1], NULL, 0, &addr);\n         g_assert(ret == 0);\n         ret = qemu_strtou64(words[2], NULL, 0, &len);\n         g_assert(ret == 0);\n+        has_attrs = words[4] != NULL;\n \n         data_len = strlen(words[3]);\n         if (data_len < 3) {\n@@ -642,46 +890,100 @@ static void qtest_process_command(CharFrontend *chr, gchar **words)\n                 data[i] = 0;\n             }\n         }\n-        address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, data,\n-                            len);\n+        if (!has_attrs) {\n+            address_space_write(first_cpu->as, addr,\n+                                MEMTXATTRS_UNSPECIFIED,\n+                                data, len);\n+            g_free(data);\n+            qtest_send(chr, \"OK\\n\");\n+            return;\n+        }\n+        if (!qtest_parse_mem_attrs(chr, words[4], &attrs) ||\n+            !qtest_get_mem_as(chr, attrs, &as)) {\n+            g_free(data);\n+            return;\n+        }\n+        result = address_space_write(as, addr, attrs, data, len);\n         g_free(data);\n+        if (result != MEMTX_OK) {\n+            qtest_send_memtx_error(chr, result);\n+            return;\n+        }\n \n         qtest_send(chr, \"OK\\n\");\n     } else if (strcmp(words[0], \"memset\") == 0) {\n         uint64_t addr, len;\n-        uint8_t *data;\n         unsigned long pattern;\n+        bool has_attrs;\n+        MemTxResult result;\n+        MemTxAttrs attrs;\n+        AddressSpace *as;\n         int ret;\n \n         g_assert(words[1] && words[2] && words[3]);\n+        if (words[4] && words[5]) {\n+            qtest_send(chr, \"ERR too many arguments\\n\");\n+            return;\n+        }\n         ret = qemu_strtou64(words[1], NULL, 0, &addr);\n         g_assert(ret == 0);\n         ret = qemu_strtou64(words[2], NULL, 0, &len);\n         g_assert(ret == 0);\n         ret = qemu_strtoul(words[3], NULL, 0, &pattern);\n         g_assert(ret == 0);\n+        has_attrs = words[4] != NULL;\n+        if (!has_attrs) {\n+            if (len) {\n+                uint8_t *data = g_malloc(len);\n+\n+                memset(data, pattern, len);\n+                address_space_write(first_cpu->as, addr,\n+                                    MEMTXATTRS_UNSPECIFIED,\n+                                    data, len);\n+                g_free(data);\n+            }\n+            qtest_send(chr, \"OK\\n\");\n+            return;\n+        }\n+        if (!qtest_parse_mem_attrs(chr, words[4], &attrs) ||\n+            !qtest_get_mem_as(chr, attrs, &as)) {\n+            return;\n+        }\n \n         if (len) {\n-            data = g_malloc(len);\n+            uint8_t *data = g_malloc(len);\n+\n             memset(data, pattern, len);\n-            address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED,\n-                                data, len);\n+            result = address_space_write(as, addr, attrs, data, len);\n             g_free(data);\n+            if (result != MEMTX_OK) {\n+                qtest_send_memtx_error(chr, result);\n+                return;\n+            }\n         }\n \n         qtest_send(chr, \"OK\\n\");\n-    }  else if (strcmp(words[0], \"b64write\") == 0) {\n+    } else if (strcmp(words[0], \"b64write\") == 0) {\n         uint64_t addr, len;\n         uint8_t *data;\n         size_t data_len;\n         gsize out_len;\n+        bool has_attrs;\n+        MemTxResult result;\n+        MemTxAttrs attrs;\n+        AddressSpace *as;\n         int ret;\n \n         g_assert(words[1] && words[2] && words[3]);\n+        if (words[4] && words[5]) {\n+            qtest_send(chr, \"ERR too many arguments\\n\");\n+            return;\n+        }\n         ret = qemu_strtou64(words[1], NULL, 0, &addr);\n         g_assert(ret == 0);\n         ret = qemu_strtou64(words[2], NULL, 0, &len);\n         g_assert(ret == 0);\n+        has_attrs = words[4] != NULL;\n \n         data_len = strlen(words[3]);\n         if (data_len < 3) {\n@@ -697,8 +999,22 @@ static void qtest_process_command(CharFrontend *chr, gchar **words)\n             out_len = MIN(out_len, len);\n         }\n \n-        address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, data,\n-                            len);\n+        if (!has_attrs) {\n+            address_space_write(first_cpu->as, addr,\n+                                MEMTXATTRS_UNSPECIFIED,\n+                                data, len);\n+            qtest_send(chr, \"OK\\n\");\n+            return;\n+        }\n+        if (!qtest_parse_mem_attrs(chr, words[4], &attrs) ||\n+            !qtest_get_mem_as(chr, attrs, &as)) {\n+            return;\n+        }\n+        result = address_space_write(as, addr, attrs, data, len);\n+        if (result != MEMTX_OK) {\n+            qtest_send_memtx_error(chr, result);\n+            return;\n+        }\n \n         qtest_send(chr, \"OK\\n\");\n     } else if (strcmp(words[0], \"endianness\") == 0) {\n",
    "prefixes": [
        "1/4"
    ]
}