get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 2221596,
    "url": "http://patchwork.ozlabs.org/api/1.1/patches/2221596/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260409220614.65558-2-lucaaamaral@gmail.com/",
    "project": {
        "id": 14,
        "url": "http://patchwork.ozlabs.org/api/1.1/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": ""
    },
    "msgid": "<20260409220614.65558-2-lucaaamaral@gmail.com>",
    "date": "2026-04-09T22:06:09",
    "name": "[v6,1/6] target/arm/emulate: add ISV=0 emulation library with load/store immediate",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "05e863772e207d03b3cd618f0911d3cb1a490cd7",
    "submitter": {
        "id": 92822,
        "url": "http://patchwork.ozlabs.org/api/1.1/people/92822/?format=api",
        "name": "Lucas Amaral",
        "email": "lucaaamaral@gmail.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260409220614.65558-2-lucaaamaral@gmail.com/mbox/",
    "series": [
        {
            "id": 499364,
            "url": "http://patchwork.ozlabs.org/api/1.1/series/499364/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=499364",
            "date": "2026-04-09T22:06:10",
            "name": "target/arm: ISV=0 data abort emulation library",
            "version": 6,
            "mbox": "http://patchwork.ozlabs.org/series/499364/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2221596/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2221596/checks/",
    "tags": {},
    "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\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=GGMXY4xg;\n\tdkim-atps=neutral",
            "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)"
        ],
        "Received": [
            "from lists.gnu.org (lists1p.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 4fsDZ64Mgbz1yGb\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 10 Apr 2026 08:07:24 +1000 (AEST)",
            "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 1wAxWB-00087V-LC; Thu, 09 Apr 2026 18:06:31 -0400",
            "from eggs.gnu.org ([2001:470:142:3::10])\n by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <lucaaamaral@gmail.com>)\n id 1wAxW9-00086v-SZ\n for qemu-devel@nongnu.org; Thu, 09 Apr 2026 18:06:29 -0400",
            "from mail-dy1-x132b.google.com ([2607:f8b0:4864:20::132b])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)\n (Exim 4.90_1) (envelope-from <lucaaamaral@gmail.com>)\n id 1wAxW7-0000aX-3h\n for qemu-devel@nongnu.org; Thu, 09 Apr 2026 18:06:29 -0400",
            "by mail-dy1-x132b.google.com with SMTP id\n 5a478bee46e88-2c156c4a9efso2080802eec.1\n for <qemu-devel@nongnu.org>; Thu, 09 Apr 2026 15:06:26 -0700 (PDT)",
            "from localhost.localdomain ([2804:7f4:c030:bb40:195d:78fd:ecba:d45])\n by smtp.gmail.com with ESMTPSA id\n 5a478bee46e88-2d561bde68bsm1534567eec.17.2026.04.09.15.06.22\n (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);\n Thu, 09 Apr 2026 15:06:24 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20251104; t=1775772385; x=1776377185; darn=nongnu.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=HzcLg/55mgZkhCbHFQ8GjJiM5YvvJzpxOoFNIcHsiRY=;\n b=GGMXY4xg90+6znECYeIkRiRlj1snzNmG3RZE6dDLpUZ+W7uoZEkU9/mdTek/wXUFp+\n u1Vgew82ACnfuiCVoWRPBtLR7ngjDFaTtwrk9jOC7R+QOI8Hr4xTFIivx4V/22BjFtL5\n zk5jtsgl4Sw2gEHtRRViD+20nHmBTds/UDJOJiSIbeIv/QJ07dLlhaD9GxLKnZCfwn1k\n y6yh6i25r4X5ppjIUaNnRqFgrhlq41LqjtqPOhHLYLS2LwPS3RU7tXaerg7puZWTb0wG\n b9xKU0FytP3wFrONT2GiKr35KkfF1FEW408wGf1OrhbGHih/60yv2p+BISOaisDfWJmX\n 5Inw==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1775772385; x=1776377185;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=HzcLg/55mgZkhCbHFQ8GjJiM5YvvJzpxOoFNIcHsiRY=;\n b=Dy8BcOFP3DcgqmLhqmEzv/OWaOEJDDFpoqlth9r6eB6kbtlG4DPCnTjaYnWBbfqJrl\n PJnR6wOFR9w6VS3jFqb3l3/PTulSwaVJCVPFBA18vk4Wry1RrbjlczY53+kU5+fOShTw\n iLwfRpjfjhz3dbMY+gBOpzF2S49W1nVv5wV0ZBl4PUccb5ZzEzRJZoYNXKyOWVy+Y4eb\n vSQ3xnNF12SdF3WFAZy/N4HbndSpVIfUcU6mCCqi4ZhAgHdMzFN4ODVnvNX3zY1Fn8P0\n zF+xC3aTzXhZ1AWcUuTVxpsdzaspGpJvWgnGFAUyQGhPfEjPAko55GSptND99q4tNNto\n q0mg==",
        "X-Gm-Message-State": "AOJu0Ywul+RjP9IUSFFqiWSjVSCs6HV0ixy923O/WvHX3evHY1r0k2El\n 9VBb3U8uLDYuqDepvGqLDXnun9ohRr/2D/2fm55DcE+Pkjz6mb1aFTC8n3UKiC89",
        "X-Gm-Gg": "AeBDiesEngnATeWppreGq2dh7E5FpToLUAn9bI2kqohFfLyKQ5cvhhA8rQ/+2Zdx5A2\n PGN4BwHO7o5lhOJYglcsYpx+aGxhu3VgemiAmP2TX9yRtsZHylv3x+MCnFsYkmngVuk22FWw4NV\n kIRSgO8ODZzY6cwfplUBDsxeSDSF2YbL4OK62ept5i/ZyoWyGE8UoAxmwXxXq/GfZ7WaDf5lxkY\n JH14IePoLkgoonBEue8P2v/RDr/kKU3mlbG9BWMHNvMZ2wYAO0M2ELOWbvdQ1bhArQb+RTrI5Pr\n BvB5/4MYU2Ku3RN6CZCNGg/+pYj9eBEKtm1a6BGDOu8xNFhJ2bKBU/5hTigVOZm31H0WmtcbDU5\n KKgboR88DGqCEqS6pX30zvB+f7fXSNnyVCYpGHH6IfQs5wyHbAdd0nCbrsZxGOMy5DoluXA62MJ\n x0MUxg/BMuUVrFuD/H5fgsNSGLYkIR0ruJfWdsJxOSQD2VPBuuS/Wwe36G0FIR5A==",
        "X-Received": "by 2002:a05:693c:310a:b0:2ca:2f21:64da with SMTP id\n 5a478bee46e88-2d5841c5483mr537755eec.0.1775772385302;\n Thu, 09 Apr 2026 15:06:25 -0700 (PDT)",
        "From": "Lucas Amaral <lucaaamaral@gmail.com>",
        "To": "qemu-devel@nongnu.org",
        "Cc": "qemu-arm@nongnu.org, agraf@csgraf.de, peter.maydell@linaro.org,\n mohamed@unpredictable.fr, alex.bennee@linaro.org,\n richard.henderson@linaro.org, Lucas Amaral <lucaaamaral@gmail.com>",
        "Subject": "[PATCH v6 1/6] target/arm/emulate: add ISV=0 emulation library with\n load/store immediate",
        "Date": "Thu,  9 Apr 2026 19:06:09 -0300",
        "Message-ID": "<20260409220614.65558-2-lucaaamaral@gmail.com>",
        "X-Mailer": "git-send-email 2.52.0",
        "In-Reply-To": "<20260409220614.65558-1-lucaaamaral@gmail.com>",
        "References": "<20260409220614.65558-1-lucaaamaral@gmail.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=UTF-8",
        "Content-Transfer-Encoding": "8bit",
        "Received-SPF": "pass client-ip=2607:f8b0:4864:20::132b;\n envelope-from=lucaaamaral@gmail.com; helo=mail-dy1-x132b.google.com",
        "X-Spam_score_int": "-20",
        "X-Spam_score": "-2.1",
        "X-Spam_bar": "--",
        "X-Spam_report": "(-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,\n DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001,\n RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,\n SPF_PASS=-0.001 autolearn=unavailable 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": "Add a shared emulation library for AArch64 load/store instructions that\ncause ISV=0 data aborts under hardware virtualization (HVF, WHPX).\n\nWhen the Instruction Syndrome Valid bit is clear, the hypervisor cannot\ndetermine the faulting instruction's target register or access size from\nthe syndrome alone.  This library fetches and decodes the instruction\nusing a decodetree-generated decoder, then emulates it by accessing the\nvCPU's register file (CPUARMState) and guest memory via get_phys_addr()\nfor MMU translation and address_space_read/write() for physical access.\n\nThis patch establishes the framework and adds load/store single with\nimmediate addressing — the most common ISV=0 trigger.  Subsequent\npatches add register-offset, pair, exclusive, and atomic instructions.\n\nInstruction coverage:\n  - STR/LDR (GPR): unscaled, post-indexed, unprivileged, pre-indexed,\n    unsigned offset — all sizes (8/16/32/64-bit), sign/zero extension\n  - STR/LDR (SIMD/FP): same addressing modes, 8-128 bit elements\n  - PRFM: prefetch treated as NOP\n  - DC cache maintenance (SYS CRn=C7): NOP on MMIO\n\nThis library uses its own a64-ldst.decode rather than sharing\ntarget/arm/tcg/a64.decode.  TCG's trans_* functions are a compiler:\nthey emit IR ops into a translation block for later execution.  This\nlibrary's trans_* functions are an interpreter: they execute directly\nagainst the vCPU register file and memory.  The decodetree-generated\ndispatcher calls trans_* by name, so both cannot coexist in the same\ntranslation unit.  Decode patterns are kept consistent with TCG's\nwhere possible.\n\nDecodetree differences from TCG:\n  - &ldst_imm adds a 'u' flag to distinguish 9-bit signed vs 12-bit\n    unsigned immediate forms.  TCG uses %uimm_scaled to pre-scale\n    the unsigned immediate at decode time; here imm:12 is extracted\n    raw and the handler scales it.\n\nSigned-off-by: Lucas Amaral <lucaaamaral@gmail.com>\n---\n target/arm/emulate/a64-ldst.decode | 129 +++++++++++++\n target/arm/emulate/arm_emulate.c   | 288 +++++++++++++++++++++++++++++\n target/arm/emulate/arm_emulate.h   |  30 +++\n target/arm/emulate/meson.build     |   8 +\n target/arm/meson.build             |   1 +\n 5 files changed, 456 insertions(+)\n create mode 100644 target/arm/emulate/a64-ldst.decode\n create mode 100644 target/arm/emulate/arm_emulate.c\n create mode 100644 target/arm/emulate/arm_emulate.h\n create mode 100644 target/arm/emulate/meson.build",
    "diff": "diff --git a/target/arm/emulate/a64-ldst.decode b/target/arm/emulate/a64-ldst.decode\nnew file mode 100644\nindex 00000000..c887dcba\n--- /dev/null\n+++ b/target/arm/emulate/a64-ldst.decode\n@@ -0,0 +1,129 @@\n+# AArch64 load/store instruction patterns for ISV=0 emulation\n+#\n+# Copyright (c) 2026 Lucas Amaral <lucaaamaral@gmail.com>\n+#\n+# SPDX-License-Identifier: GPL-2.0-or-later\n+\n+### Argument sets\n+\n+# Load/store immediate (unscaled, pre/post-index, unprivileged, unsigned offset)\n+# 'u' flag: 0 = 9-bit signed immediate (byte offset), 1 = 12-bit unsigned (needs << sz)\n+&ldst_imm       rt rn imm sz sign w p unpriv ext u\n+\n+### Format templates\n+\n+# Load/store immediate (9-bit signed)\n+@ldst_imm       .. ... . .. .. . imm:s9 .. rn:5 rt:5   &ldst_imm u=0 unpriv=0 p=0 w=0\n+@ldst_imm_pre   .. ... . .. .. . imm:s9 .. rn:5 rt:5   &ldst_imm u=0 unpriv=0 p=0 w=1\n+@ldst_imm_post  .. ... . .. .. . imm:s9 .. rn:5 rt:5   &ldst_imm u=0 unpriv=0 p=1 w=1\n+@ldst_imm_user  .. ... . .. .. . imm:s9 .. rn:5 rt:5   &ldst_imm u=0 unpriv=1 p=0 w=0\n+\n+# Load/store unsigned offset (12-bit, handler scales by << sz)\n+@ldst_uimm      .. ... . .. .. imm:12 rn:5 rt:5        &ldst_imm u=1 unpriv=0 p=0 w=0\n+\n+### Load/store register — unscaled immediate (LDUR/STUR)\n+\n+# GPR\n+STR_i           sz:2 111 0 00 00 0 ......... 00 ..... .....    @ldst_imm sign=0 ext=0\n+LDR_i           00 111 0 00 01 0 ......... 00 ..... .....      @ldst_imm sign=0 ext=1 sz=0\n+LDR_i           01 111 0 00 01 0 ......... 00 ..... .....      @ldst_imm sign=0 ext=1 sz=1\n+LDR_i           10 111 0 00 01 0 ......... 00 ..... .....      @ldst_imm sign=0 ext=1 sz=2\n+LDR_i           11 111 0 00 01 0 ......... 00 ..... .....      @ldst_imm sign=0 ext=0 sz=3\n+LDR_i           00 111 0 00 10 0 ......... 00 ..... .....      @ldst_imm sign=1 ext=0 sz=0\n+LDR_i           01 111 0 00 10 0 ......... 00 ..... .....      @ldst_imm sign=1 ext=0 sz=1\n+LDR_i           10 111 0 00 10 0 ......... 00 ..... .....      @ldst_imm sign=1 ext=0 sz=2\n+LDR_i           00 111 0 00 11 0 ......... 00 ..... .....      @ldst_imm sign=1 ext=1 sz=0\n+LDR_i           01 111 0 00 11 0 ......... 00 ..... .....      @ldst_imm sign=1 ext=1 sz=1\n+\n+# SIMD/FP\n+STR_v_i         sz:2 111 1 00 00 0 ......... 00 ..... .....    @ldst_imm sign=0 ext=0\n+STR_v_i         00 111 1 00 10 0 ......... 00 ..... .....      @ldst_imm sign=0 ext=0 sz=4\n+LDR_v_i         sz:2 111 1 00 01 0 ......... 00 ..... .....    @ldst_imm sign=0 ext=0\n+LDR_v_i         00 111 1 00 11 0 ......... 00 ..... .....      @ldst_imm sign=0 ext=0 sz=4\n+\n+### Load/store register — post-indexed\n+\n+# GPR\n+STR_i           sz:2 111 0 00 00 0 ......... 01 ..... .....    @ldst_imm_post sign=0 ext=0\n+LDR_i           00 111 0 00 01 0 ......... 01 ..... .....      @ldst_imm_post sign=0 ext=1 sz=0\n+LDR_i           01 111 0 00 01 0 ......... 01 ..... .....      @ldst_imm_post sign=0 ext=1 sz=1\n+LDR_i           10 111 0 00 01 0 ......... 01 ..... .....      @ldst_imm_post sign=0 ext=1 sz=2\n+LDR_i           11 111 0 00 01 0 ......... 01 ..... .....      @ldst_imm_post sign=0 ext=0 sz=3\n+LDR_i           00 111 0 00 10 0 ......... 01 ..... .....      @ldst_imm_post sign=1 ext=0 sz=0\n+LDR_i           01 111 0 00 10 0 ......... 01 ..... .....      @ldst_imm_post sign=1 ext=0 sz=1\n+LDR_i           10 111 0 00 10 0 ......... 01 ..... .....      @ldst_imm_post sign=1 ext=0 sz=2\n+LDR_i           00 111 0 00 11 0 ......... 01 ..... .....      @ldst_imm_post sign=1 ext=1 sz=0\n+LDR_i           01 111 0 00 11 0 ......... 01 ..... .....      @ldst_imm_post sign=1 ext=1 sz=1\n+\n+# SIMD/FP\n+STR_v_i         sz:2 111 1 00 00 0 ......... 01 ..... .....    @ldst_imm_post sign=0 ext=0\n+STR_v_i         00 111 1 00 10 0 ......... 01 ..... .....      @ldst_imm_post sign=0 ext=0 sz=4\n+LDR_v_i         sz:2 111 1 00 01 0 ......... 01 ..... .....    @ldst_imm_post sign=0 ext=0\n+LDR_v_i         00 111 1 00 11 0 ......... 01 ..... .....      @ldst_imm_post sign=0 ext=0 sz=4\n+\n+### Load/store register — unprivileged\n+\n+# GPR only (no SIMD/FP unprivileged forms)\n+STR_i           sz:2 111 0 00 00 0 ......... 10 ..... .....    @ldst_imm_user sign=0 ext=0\n+LDR_i           00 111 0 00 01 0 ......... 10 ..... .....      @ldst_imm_user sign=0 ext=1 sz=0\n+LDR_i           01 111 0 00 01 0 ......... 10 ..... .....      @ldst_imm_user sign=0 ext=1 sz=1\n+LDR_i           10 111 0 00 01 0 ......... 10 ..... .....      @ldst_imm_user sign=0 ext=1 sz=2\n+LDR_i           11 111 0 00 01 0 ......... 10 ..... .....      @ldst_imm_user sign=0 ext=0 sz=3\n+LDR_i           00 111 0 00 10 0 ......... 10 ..... .....      @ldst_imm_user sign=1 ext=0 sz=0\n+LDR_i           01 111 0 00 10 0 ......... 10 ..... .....      @ldst_imm_user sign=1 ext=0 sz=1\n+LDR_i           10 111 0 00 10 0 ......... 10 ..... .....      @ldst_imm_user sign=1 ext=0 sz=2\n+LDR_i           00 111 0 00 11 0 ......... 10 ..... .....      @ldst_imm_user sign=1 ext=1 sz=0\n+LDR_i           01 111 0 00 11 0 ......... 10 ..... .....      @ldst_imm_user sign=1 ext=1 sz=1\n+\n+### Load/store register — pre-indexed\n+\n+# GPR\n+STR_i           sz:2 111 0 00 00 0 ......... 11 ..... .....    @ldst_imm_pre sign=0 ext=0\n+LDR_i           00 111 0 00 01 0 ......... 11 ..... .....      @ldst_imm_pre sign=0 ext=1 sz=0\n+LDR_i           01 111 0 00 01 0 ......... 11 ..... .....      @ldst_imm_pre sign=0 ext=1 sz=1\n+LDR_i           10 111 0 00 01 0 ......... 11 ..... .....      @ldst_imm_pre sign=0 ext=1 sz=2\n+LDR_i           11 111 0 00 01 0 ......... 11 ..... .....      @ldst_imm_pre sign=0 ext=0 sz=3\n+LDR_i           00 111 0 00 10 0 ......... 11 ..... .....      @ldst_imm_pre sign=1 ext=0 sz=0\n+LDR_i           01 111 0 00 10 0 ......... 11 ..... .....      @ldst_imm_pre sign=1 ext=0 sz=1\n+LDR_i           10 111 0 00 10 0 ......... 11 ..... .....      @ldst_imm_pre sign=1 ext=0 sz=2\n+LDR_i           00 111 0 00 11 0 ......... 11 ..... .....      @ldst_imm_pre sign=1 ext=1 sz=0\n+LDR_i           01 111 0 00 11 0 ......... 11 ..... .....      @ldst_imm_pre sign=1 ext=1 sz=1\n+\n+# SIMD/FP\n+STR_v_i         sz:2 111 1 00 00 0 ......... 11 ..... .....    @ldst_imm_pre sign=0 ext=0\n+STR_v_i         00 111 1 00 10 0 ......... 11 ..... .....      @ldst_imm_pre sign=0 ext=0 sz=4\n+LDR_v_i         sz:2 111 1 00 01 0 ......... 11 ..... .....    @ldst_imm_pre sign=0 ext=0\n+LDR_v_i         00 111 1 00 11 0 ......... 11 ..... .....      @ldst_imm_pre sign=0 ext=0 sz=4\n+\n+### PRFM — unscaled immediate: prefetch is a NOP\n+\n+NOP             11 111 0 00 10 0 --------- 00 ----- -----\n+\n+### Load/store register — unsigned offset\n+\n+# GPR\n+STR_i           sz:2 111 0 01 00 ............ ..... .....       @ldst_uimm sign=0 ext=0\n+LDR_i           00 111 0 01 01 ............ ..... .....         @ldst_uimm sign=0 ext=1 sz=0\n+LDR_i           01 111 0 01 01 ............ ..... .....         @ldst_uimm sign=0 ext=1 sz=1\n+LDR_i           10 111 0 01 01 ............ ..... .....         @ldst_uimm sign=0 ext=1 sz=2\n+LDR_i           11 111 0 01 01 ............ ..... .....         @ldst_uimm sign=0 ext=0 sz=3\n+LDR_i           00 111 0 01 10 ............ ..... .....         @ldst_uimm sign=1 ext=0 sz=0\n+LDR_i           01 111 0 01 10 ............ ..... .....         @ldst_uimm sign=1 ext=0 sz=1\n+LDR_i           10 111 0 01 10 ............ ..... .....         @ldst_uimm sign=1 ext=0 sz=2\n+LDR_i           00 111 0 01 11 ............ ..... .....         @ldst_uimm sign=1 ext=1 sz=0\n+LDR_i           01 111 0 01 11 ............ ..... .....         @ldst_uimm sign=1 ext=1 sz=1\n+\n+# PRFM — unsigned offset\n+NOP             11 111 0 01 10 ------------ ----- -----\n+\n+# SIMD/FP\n+STR_v_i         sz:2 111 1 01 00 ............ ..... .....       @ldst_uimm sign=0 ext=0\n+STR_v_i         00 111 1 01 10 ............ ..... .....         @ldst_uimm sign=0 ext=0 sz=4\n+LDR_v_i         sz:2 111 1 01 01 ............ ..... .....       @ldst_uimm sign=0 ext=0\n+LDR_v_i         00 111 1 01 11 ............ ..... .....         @ldst_uimm sign=0 ext=0 sz=4\n+\n+### System instructions — DC cache maintenance\n+\n+# SYS with CRn=C7 covers all data cache operations (DC CIVAC, CVAC, etc.).\n+# On MMIO regions, cache maintenance is a harmless no-op.\n+NOP             1101 0101 0000 1 --- 0111 ---- --- -----\ndiff --git a/target/arm/emulate/arm_emulate.c b/target/arm/emulate/arm_emulate.c\nnew file mode 100644\nindex 00000000..bedbdb3e\n--- /dev/null\n+++ b/target/arm/emulate/arm_emulate.c\n@@ -0,0 +1,288 @@\n+/*\n+ * AArch64 instruction emulation for ISV=0 data aborts\n+ *\n+ * Copyright (c) 2026 Lucas Amaral <lucaaamaral@gmail.com>\n+ *\n+ * SPDX-License-Identifier: GPL-2.0-or-later\n+ */\n+\n+#include \"arm_emulate.h\"\n+#include \"target/arm/cpu.h\"\n+#include \"target/arm/internals.h\"\n+#include \"exec/cpu-common.h\"\n+#include \"system/memory.h\"\n+#include \"exec/target_page.h\"\n+#include \"qemu/bitops.h\"\n+#include \"qemu/bswap.h\"\n+\n+/* Named \"DisasContext\" as required by the decodetree code generator */\n+typedef struct {\n+    CPUState *cpu;\n+    CPUARMState *env;\n+    ArmEmulResult result;\n+    bool be_data;\n+} DisasContext;\n+\n+#include \"decode-a64-ldst.c.inc\"\n+\n+/* GPR data access (Rt, Rs, Rt2) -- register 31 = XZR */\n+\n+static uint64_t gpr_read(DisasContext *ctx, int reg)\n+{\n+    if (reg == 31) {\n+        return 0;  /* XZR */\n+    }\n+    return ctx->env->xregs[reg];\n+}\n+\n+static void gpr_write(DisasContext *ctx, int reg, uint64_t val)\n+{\n+    if (reg == 31) {\n+        return;  /* XZR -- discard */\n+    }\n+    ctx->env->xregs[reg] = val;\n+    ctx->cpu->vcpu_dirty = true;\n+}\n+\n+/* Base register access (Rn) -- register 31 = SP */\n+\n+static uint64_t base_read(DisasContext *ctx, int rn)\n+{\n+    return ctx->env->xregs[rn];\n+}\n+\n+static void base_write(DisasContext *ctx, int rn, uint64_t val)\n+{\n+    ctx->env->xregs[rn] = val;\n+    ctx->cpu->vcpu_dirty = true;\n+}\n+\n+/* SIMD/FP register access */\n+\n+static void fpreg_read(DisasContext *ctx, int reg, void *buf, int size)\n+{\n+    memcpy(buf, &ctx->env->vfp.zregs[reg], size);\n+}\n+\n+static void fpreg_write(DisasContext *ctx, int reg, const void *buf, int size)\n+{\n+    memset(&ctx->env->vfp.zregs[reg], 0, sizeof(ctx->env->vfp.zregs[reg]));\n+    memcpy(&ctx->env->vfp.zregs[reg], buf, size);\n+    ctx->cpu->vcpu_dirty = true;\n+}\n+\n+/*\n+ * Memory access via guest MMU translation.\n+ *\n+ * Translates the virtual address through the guest page tables using\n+ * get_phys_addr(), then performs the access on the resulting physical\n+ * address via address_space_read/write().  Each page-sized chunk is\n+ * translated independently, so accesses that span a page boundary\n+ * are handled correctly even when the pages map to different physical\n+ * addresses.\n+ */\n+\n+static int mem_access(DisasContext *ctx, uint64_t va, void *buf, int size,\n+                      MMUAccessType access_type)\n+{\n+    ARMMMUIdx mmu_idx = arm_mmu_idx(ctx->env);\n+\n+    while (size > 0) {\n+        int chunk = MIN(size, TARGET_PAGE_SIZE - (va & ~TARGET_PAGE_MASK));\n+        GetPhysAddrResult res = {};\n+        ARMMMUFaultInfo fi = {};\n+\n+        if (get_phys_addr(ctx->env, va, access_type, 0, mmu_idx,\n+                          &res, &fi)) {\n+            ctx->result = ARM_EMUL_ERR_MEM;\n+            return -1;\n+        }\n+\n+        AddressSpace *as = arm_addressspace(ctx->cpu, res.f.attrs);\n+        MemTxResult txr;\n+\n+        if (access_type == MMU_DATA_STORE) {\n+            txr = address_space_write(as, res.f.phys_addr, res.f.attrs,\n+                                      buf, chunk);\n+        } else {\n+            txr = address_space_read(as, res.f.phys_addr, res.f.attrs,\n+                                     buf, chunk);\n+        }\n+\n+        if (txr != MEMTX_OK) {\n+            ctx->result = ARM_EMUL_ERR_MEM;\n+            return -1;\n+        }\n+\n+        va += chunk;\n+        buf += chunk;\n+        size -= chunk;\n+    }\n+    return 0;\n+}\n+\n+static int mem_read(DisasContext *ctx, uint64_t va, void *buf, int size)\n+{\n+    return mem_access(ctx, va, buf, size, MMU_DATA_LOAD);\n+}\n+\n+static int mem_write(DisasContext *ctx, uint64_t va, const void *buf, int size)\n+{\n+    return mem_access(ctx, va, (void *)buf, size, MMU_DATA_STORE);\n+}\n+\n+/*\n+ * Endian-aware GPR <-> memory buffer helpers.\n+ *\n+ * mem_read/mem_write transfer raw bytes between guest VA and a host buffer.\n+ * mem_ld/mem_st convert between a uint64_t register value and the guest\n+ * byte order in a memory buffer.\n+ */\n+\n+static uint64_t mem_ld(DisasContext *ctx, const void *buf, int size)\n+{\n+    return ctx->be_data ? ldn_be_p(buf, size) : ldn_le_p(buf, size);\n+}\n+\n+static void mem_st(DisasContext *ctx, void *buf, int size, uint64_t val)\n+{\n+    if (ctx->be_data) {\n+        stn_be_p(buf, size, val);\n+    } else {\n+        stn_le_p(buf, size, val);\n+    }\n+}\n+\n+/* Apply sign/zero extension */\n+static uint64_t load_extend(uint64_t val, int sz, int sign, int ext)\n+{\n+    int data_bits = 8 << sz;\n+\n+    if (sign) {\n+        val = sextract64(val, 0, data_bits);\n+        if (ext) {\n+            /* Sign-extend to 32 bits (W register) */\n+            val &= 0xFFFFFFFF;\n+        }\n+    } else if (ext) {\n+        /* Zero-extend to 32 bits (W register) */\n+        val &= 0xFFFFFFFF;\n+    }\n+    return val;\n+}\n+\n+/* Load/store single -- immediate (GPR) (DDI 0487 C3.3.8 -- C3.3.13) */\n+\n+static bool trans_STR_i(DisasContext *ctx, arg_ldst_imm *a)\n+{\n+    int esize = (a->sz <= 3) ? (1 << a->sz) : 16;\n+    int64_t offset = a->u ? ((int64_t)(uint64_t)a->imm << a->sz)\n+                          : (int64_t)a->imm;\n+    uint64_t base = base_read(ctx, a->rn);\n+    uint64_t va = a->p ? base : base + offset;\n+\n+    uint8_t buf[16];\n+    uint64_t val = gpr_read(ctx, a->rt);\n+    mem_st(ctx, buf, esize, val);\n+    if (mem_write(ctx, va, buf, esize) != 0) {\n+        return true;\n+    }\n+\n+    if (a->w) {\n+        base_write(ctx, a->rn, base + offset);\n+    }\n+    return true;\n+}\n+\n+static bool trans_LDR_i(DisasContext *ctx, arg_ldst_imm *a)\n+{\n+    int esize = (a->sz <= 3) ? (1 << a->sz) : 16;\n+    int64_t offset = a->u ? ((int64_t)(uint64_t)a->imm << a->sz)\n+                          : (int64_t)a->imm;\n+    uint64_t base = base_read(ctx, a->rn);\n+    uint64_t va = a->p ? base : base + offset;\n+    uint8_t buf[16];\n+\n+    if (mem_read(ctx, va, buf, esize) != 0) {\n+        return true;\n+    }\n+\n+    uint64_t val = mem_ld(ctx, buf, esize);\n+    val = load_extend(val, a->sz, a->sign, a->ext);\n+    gpr_write(ctx, a->rt, val);\n+\n+    if (a->w) {\n+        base_write(ctx, a->rn, base + offset);\n+    }\n+    return true;\n+}\n+\n+/*\n+ * Load/store single -- immediate (SIMD/FP)\n+ * STR_v_i / LDR_v_i (DDI 0487 C3.3.10)\n+ */\n+\n+static bool trans_STR_v_i(DisasContext *ctx, arg_ldst_imm *a)\n+{\n+    int esize = (a->sz <= 3) ? (1 << a->sz) : 16;\n+    int64_t offset = a->u ? ((int64_t)(uint64_t)a->imm << a->sz)\n+                          : (int64_t)a->imm;\n+    uint64_t base = base_read(ctx, a->rn);\n+    uint64_t va = a->p ? base : base + offset;\n+    uint8_t buf[16];\n+\n+    fpreg_read(ctx, a->rt, buf, esize);\n+    if (mem_write(ctx, va, buf, esize) != 0) {\n+        return true;\n+    }\n+\n+    if (a->w) {\n+        base_write(ctx, a->rn, base + offset);\n+    }\n+    return true;\n+}\n+\n+static bool trans_LDR_v_i(DisasContext *ctx, arg_ldst_imm *a)\n+{\n+    int esize = (a->sz <= 3) ? (1 << a->sz) : 16;\n+    int64_t offset = a->u ? ((int64_t)(uint64_t)a->imm << a->sz)\n+                          : (int64_t)a->imm;\n+    uint64_t base = base_read(ctx, a->rn);\n+    uint64_t va = a->p ? base : base + offset;\n+    uint8_t buf[16];\n+\n+    if (mem_read(ctx, va, buf, esize) != 0) {\n+        return true;\n+    }\n+\n+    fpreg_write(ctx, a->rt, buf, esize);\n+\n+    if (a->w) {\n+        base_write(ctx, a->rn, base + offset);\n+    }\n+    return true;\n+}\n+\n+/* PRFM, DC cache maintenance -- treated as NOP */\n+static bool trans_NOP(DisasContext *ctx, arg_NOP *a)\n+{\n+    return true;\n+}\n+\n+/* Entry point */\n+\n+ArmEmulResult arm_emul_insn(CPUArchState *env, uint32_t insn)\n+{\n+    DisasContext ctx = {\n+        .cpu = env_cpu(env),\n+        .env = env,\n+        .result = ARM_EMUL_OK,\n+        .be_data = arm_cpu_data_is_big_endian(env),\n+    };\n+\n+    if (!decode_a64_ldst(&ctx, insn)) {\n+        return ARM_EMUL_UNHANDLED;\n+    }\n+\n+    return ctx.result;\n+}\ndiff --git a/target/arm/emulate/arm_emulate.h b/target/arm/emulate/arm_emulate.h\nnew file mode 100644\nindex 00000000..7fe29839\n--- /dev/null\n+++ b/target/arm/emulate/arm_emulate.h\n@@ -0,0 +1,30 @@\n+/*\n+ * AArch64 instruction emulation library\n+ *\n+ * Copyright (c) 2026 Lucas Amaral <lucaaamaral@gmail.com>\n+ *\n+ * SPDX-License-Identifier: GPL-2.0-or-later\n+ */\n+\n+#ifndef ARM_EMULATE_H\n+#define ARM_EMULATE_H\n+\n+#include \"qemu/osdep.h\"\n+\n+/**\n+ * ArmEmulResult - return status from arm_emul_insn()\n+ */\n+typedef enum {\n+    ARM_EMUL_OK,         /* Instruction emulated successfully */\n+    ARM_EMUL_UNHANDLED,  /* Instruction not recognized by decoder */\n+    ARM_EMUL_ERR_MEM,    /* Memory access failed */\n+} ArmEmulResult;\n+\n+/**\n+ * arm_emul_insn - decode and emulate one AArch64 instruction\n+ *\n+ * Caller must synchronize CPU state and fetch @insn before calling.\n+ */\n+ArmEmulResult arm_emul_insn(CPUArchState *env, uint32_t insn);\n+\n+#endif /* ARM_EMULATE_H */\ndiff --git a/target/arm/emulate/meson.build b/target/arm/emulate/meson.build\nnew file mode 100644\nindex 00000000..e5455bd2\n--- /dev/null\n+++ b/target/arm/emulate/meson.build\n@@ -0,0 +1,8 @@\n+# SPDX-License-Identifier: GPL-2.0-or-later\n+\n+gen_a64_ldst = decodetree.process('a64-ldst.decode',\n+    extra_args: ['--static-decode=decode_a64_ldst'])\n+\n+arm_common_system_ss.add(when: 'TARGET_AARCH64', if_true: [\n+    gen_a64_ldst, files('arm_emulate.c')\n+])\ndiff --git a/target/arm/meson.build b/target/arm/meson.build\nindex 6e0e504a..a4b2291b 100644\n--- a/target/arm/meson.build\n+++ b/target/arm/meson.build\n@@ -57,6 +57,7 @@ arm_common_system_ss.add(files(\n   'vfp_fpscr.c',\n ))\n \n+subdir('emulate')\n subdir('hvf')\n subdir('whpx')\n \n",
    "prefixes": [
        "v6",
        "1/6"
    ]
}