From nobody Sat Apr 11 17:07:29 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1775772442; cv=none; d=zohomail.com; s=zohoarc; b=n/pu7RT7H+6LMBLEmPYl6biX61o03btsOEiDhCo28XF3lqNIBfjlgq2BSWmRyvK7oYFRXdiUrUZl3pAN7NKqxKRdTeqSYe4fIe8TYfk2SRLgBksKf83IExqpTcMn1E/mrQywIMhd13dZFOjlhhVhqDdos7frPOOUKhw4tjKGPVQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775772442; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=HzcLg/55mgZkhCbHFQ8GjJiM5YvvJzpxOoFNIcHsiRY=; b=JyfyIVjBsCZ4UmSwtQQUM3PxkGIkNvD9gCA3ePNJlVAk3JEPNd2ciCgChEXgWinyNNJE4SmxcLD8lx4MySvoP2AWQHm71DyfPbVxDmjUbmsxDc4DTjJpeRUqU/skZKvTkI6x8fMT99s/+RlDtwM4PmZmcyn/2vFpndBFqY6luLs= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1775772442847354.31833062712997; Thu, 9 Apr 2026 15:07:22 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wAxWB-00087V-LC; Thu, 09 Apr 2026 18:06:31 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wAxW9-00086v-SZ for qemu-devel@nongnu.org; Thu, 09 Apr 2026 18:06:29 -0400 Received: from mail-dy1-x132b.google.com ([2607:f8b0:4864:20::132b]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wAxW7-0000aX-3h for qemu-devel@nongnu.org; Thu, 09 Apr 2026 18:06:29 -0400 Received: by mail-dy1-x132b.google.com with SMTP id 5a478bee46e88-2c156c4a9efso2080802eec.1 for ; Thu, 09 Apr 2026 15:06:26 -0700 (PDT) Received: from localhost.localdomain ([2804:7f4:c030:bb40:195d:78fd:ecba:d45]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2d561bde68bsm1534567eec.17.2026.04.09.15.06.22 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 09 Apr 2026 15:06:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775772385; x=1776377185; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=HzcLg/55mgZkhCbHFQ8GjJiM5YvvJzpxOoFNIcHsiRY=; b=GGMXY4xg90+6znECYeIkRiRlj1snzNmG3RZE6dDLpUZ+W7uoZEkU9/mdTek/wXUFp+ u1Vgew82ACnfuiCVoWRPBtLR7ngjDFaTtwrk9jOC7R+QOI8Hr4xTFIivx4V/22BjFtL5 zk5jtsgl4Sw2gEHtRRViD+20nHmBTds/UDJOJiSIbeIv/QJ07dLlhaD9GxLKnZCfwn1k y6yh6i25r4X5ppjIUaNnRqFgrhlq41LqjtqPOhHLYLS2LwPS3RU7tXaerg7puZWTb0wG b9xKU0FytP3wFrONT2GiKr35KkfF1FEW408wGf1OrhbGHih/60yv2p+BISOaisDfWJmX 5Inw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775772385; x=1776377185; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=HzcLg/55mgZkhCbHFQ8GjJiM5YvvJzpxOoFNIcHsiRY=; b=Dy8BcOFP3DcgqmLhqmEzv/OWaOEJDDFpoqlth9r6eB6kbtlG4DPCnTjaYnWBbfqJrl PJnR6wOFR9w6VS3jFqb3l3/PTulSwaVJCVPFBA18vk4Wry1RrbjlczY53+kU5+fOShTw iLwfRpjfjhz3dbMY+gBOpzF2S49W1nVv5wV0ZBl4PUccb5ZzEzRJZoYNXKyOWVy+Y4eb vSQ3xnNF12SdF3WFAZy/N4HbndSpVIfUcU6mCCqi4ZhAgHdMzFN4ODVnvNX3zY1Fn8P0 zF+xC3aTzXhZ1AWcUuTVxpsdzaspGpJvWgnGFAUyQGhPfEjPAko55GSptND99q4tNNto q0mg== X-Gm-Message-State: AOJu0Ywul+RjP9IUSFFqiWSjVSCs6HV0ixy923O/WvHX3evHY1r0k2El 9VBb3U8uLDYuqDepvGqLDXnun9ohRr/2D/2fm55DcE+Pkjz6mb1aFTC8n3UKiC89 X-Gm-Gg: AeBDiesEngnATeWppreGq2dh7E5FpToLUAn9bI2kqohFfLyKQ5cvhhA8rQ/+2Zdx5A2 PGN4BwHO7o5lhOJYglcsYpx+aGxhu3VgemiAmP2TX9yRtsZHylv3x+MCnFsYkmngVuk22FWw4NV kIRSgO8ODZzY6cwfplUBDsxeSDSF2YbL4OK62ept5i/ZyoWyGE8UoAxmwXxXq/GfZ7WaDf5lxkY JH14IePoLkgoonBEue8P2v/RDr/kKU3mlbG9BWMHNvMZ2wYAO0M2ELOWbvdQ1bhArQb+RTrI5Pr BvB5/4MYU2Ku3RN6CZCNGg/+pYj9eBEKtm1a6BGDOu8xNFhJ2bKBU/5hTigVOZm31H0WmtcbDU5 KKgboR88DGqCEqS6pX30zvB+f7fXSNnyVCYpGHH6IfQs5wyHbAdd0nCbrsZxGOMy5DoluXA62MJ x0MUxg/BMuUVrFuD/H5fgsNSGLYkIR0ruJfWdsJxOSQD2VPBuuS/Wwe36G0FIR5A== X-Received: by 2002:a05:693c:310a:b0:2ca:2f21:64da with SMTP id 5a478bee46e88-2d5841c5483mr537755eec.0.1775772385302; Thu, 09 Apr 2026 15:06:25 -0700 (PDT) From: Lucas Amaral To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, agraf@csgraf.de, peter.maydell@linaro.org, mohamed@unpredictable.fr, alex.bennee@linaro.org, richard.henderson@linaro.org, Lucas Amaral Subject: [PATCH v6 1/6] target/arm/emulate: add ISV=0 emulation library with 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: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::132b; 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, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, 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 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1775772444570158500 Add a shared emulation library for AArch64 load/store instructions that cause ISV=3D0 data aborts under hardware virtualization (HVF, WHPX). When the Instruction Syndrome Valid bit is clear, the hypervisor cannot determine the faulting instruction's target register or access size from the syndrome alone. This library fetches and decodes the instruction using a decodetree-generated decoder, then emulates it by accessing the vCPU's register file (CPUARMState) and guest memory via get_phys_addr() for MMU translation and address_space_read/write() for physical access. This patch establishes the framework and adds load/store single with immediate addressing =E2=80=94 the most common ISV=3D0 trigger. Subsequent patches add register-offset, pair, exclusive, and atomic instructions. Instruction coverage: - STR/LDR (GPR): unscaled, post-indexed, unprivileged, pre-indexed, unsigned offset =E2=80=94 all sizes (8/16/32/64-bit), sign/zero extensi= on - STR/LDR (SIMD/FP): same addressing modes, 8-128 bit elements - PRFM: prefetch treated as NOP - DC cache maintenance (SYS CRn=3DC7): NOP on MMIO This library uses its own a64-ldst.decode rather than sharing target/arm/tcg/a64.decode. TCG's trans_* functions are a compiler: they emit IR ops into a translation block for later execution. This library's trans_* functions are an interpreter: they execute directly against the vCPU register file and memory. The decodetree-generated dispatcher calls trans_* by name, so both cannot coexist in the same translation unit. Decode patterns are kept consistent with TCG's where possible. Decodetree differences from TCG: - &ldst_imm adds a 'u' flag to distinguish 9-bit signed vs 12-bit unsigned immediate forms. TCG uses %uimm_scaled to pre-scale the unsigned immediate at decode time; here imm:12 is extracted raw and the handler scales it. Signed-off-by: Lucas Amaral Reviewed-by: Mohamed Mediouni --- target/arm/emulate/a64-ldst.decode | 129 +++++++++++++ target/arm/emulate/arm_emulate.c | 288 +++++++++++++++++++++++++++++ target/arm/emulate/arm_emulate.h | 30 +++ target/arm/emulate/meson.build | 8 + target/arm/meson.build | 1 + 5 files changed, 456 insertions(+) create mode 100644 target/arm/emulate/a64-ldst.decode create mode 100644 target/arm/emulate/arm_emulate.c create mode 100644 target/arm/emulate/arm_emulate.h create mode 100644 target/arm/emulate/meson.build diff --git a/target/arm/emulate/a64-ldst.decode b/target/arm/emulate/a64-ld= st.decode new file mode 100644 index 00000000..c887dcba --- /dev/null +++ b/target/arm/emulate/a64-ldst.decode @@ -0,0 +1,129 @@ +# AArch64 load/store instruction patterns for ISV=3D0 emulation +# +# Copyright (c) 2026 Lucas Amaral +# +# SPDX-License-Identifier: GPL-2.0-or-later + +### Argument sets + +# Load/store immediate (unscaled, pre/post-index, unprivileged, unsigned o= ffset) +# 'u' flag: 0 =3D 9-bit signed immediate (byte offset), 1 =3D 12-bit unsig= ned (needs << sz) +&ldst_imm rt rn imm sz sign w p unpriv ext u + +### Format templates + +# Load/store immediate (9-bit signed) +@ldst_imm .. ... . .. .. . imm:s9 .. rn:5 rt:5 &ldst_imm u=3D0 unp= riv=3D0 p=3D0 w=3D0 +@ldst_imm_pre .. ... . .. .. . imm:s9 .. rn:5 rt:5 &ldst_imm u=3D0 unp= riv=3D0 p=3D0 w=3D1 +@ldst_imm_post .. ... . .. .. . imm:s9 .. rn:5 rt:5 &ldst_imm u=3D0 unp= riv=3D0 p=3D1 w=3D1 +@ldst_imm_user .. ... . .. .. . imm:s9 .. rn:5 rt:5 &ldst_imm u=3D0 unp= riv=3D1 p=3D0 w=3D0 + +# Load/store unsigned offset (12-bit, handler scales by << sz) +@ldst_uimm .. ... . .. .. imm:12 rn:5 rt:5 &ldst_imm u=3D1 unp= riv=3D0 p=3D0 w=3D0 + +### Load/store register =E2=80=94 unscaled immediate (LDUR/STUR) + +# GPR +STR_i sz:2 111 0 00 00 0 ......... 00 ..... ..... @ldst_imm s= ign=3D0 ext=3D0 +LDR_i 00 111 0 00 01 0 ......... 00 ..... ..... @ldst_imm s= ign=3D0 ext=3D1 sz=3D0 +LDR_i 01 111 0 00 01 0 ......... 00 ..... ..... @ldst_imm s= ign=3D0 ext=3D1 sz=3D1 +LDR_i 10 111 0 00 01 0 ......... 00 ..... ..... @ldst_imm s= ign=3D0 ext=3D1 sz=3D2 +LDR_i 11 111 0 00 01 0 ......... 00 ..... ..... @ldst_imm s= ign=3D0 ext=3D0 sz=3D3 +LDR_i 00 111 0 00 10 0 ......... 00 ..... ..... @ldst_imm s= ign=3D1 ext=3D0 sz=3D0 +LDR_i 01 111 0 00 10 0 ......... 00 ..... ..... @ldst_imm s= ign=3D1 ext=3D0 sz=3D1 +LDR_i 10 111 0 00 10 0 ......... 00 ..... ..... @ldst_imm s= ign=3D1 ext=3D0 sz=3D2 +LDR_i 00 111 0 00 11 0 ......... 00 ..... ..... @ldst_imm s= ign=3D1 ext=3D1 sz=3D0 +LDR_i 01 111 0 00 11 0 ......... 00 ..... ..... @ldst_imm s= ign=3D1 ext=3D1 sz=3D1 + +# SIMD/FP +STR_v_i sz:2 111 1 00 00 0 ......... 00 ..... ..... @ldst_imm s= ign=3D0 ext=3D0 +STR_v_i 00 111 1 00 10 0 ......... 00 ..... ..... @ldst_imm s= ign=3D0 ext=3D0 sz=3D4 +LDR_v_i sz:2 111 1 00 01 0 ......... 00 ..... ..... @ldst_imm s= ign=3D0 ext=3D0 +LDR_v_i 00 111 1 00 11 0 ......... 00 ..... ..... @ldst_imm s= ign=3D0 ext=3D0 sz=3D4 + +### Load/store register =E2=80=94 post-indexed + +# GPR +STR_i sz:2 111 0 00 00 0 ......... 01 ..... ..... @ldst_imm_p= ost sign=3D0 ext=3D0 +LDR_i 00 111 0 00 01 0 ......... 01 ..... ..... @ldst_imm_p= ost sign=3D0 ext=3D1 sz=3D0 +LDR_i 01 111 0 00 01 0 ......... 01 ..... ..... @ldst_imm_p= ost sign=3D0 ext=3D1 sz=3D1 +LDR_i 10 111 0 00 01 0 ......... 01 ..... ..... @ldst_imm_p= ost sign=3D0 ext=3D1 sz=3D2 +LDR_i 11 111 0 00 01 0 ......... 01 ..... ..... @ldst_imm_p= ost sign=3D0 ext=3D0 sz=3D3 +LDR_i 00 111 0 00 10 0 ......... 01 ..... ..... @ldst_imm_p= ost sign=3D1 ext=3D0 sz=3D0 +LDR_i 01 111 0 00 10 0 ......... 01 ..... ..... @ldst_imm_p= ost sign=3D1 ext=3D0 sz=3D1 +LDR_i 10 111 0 00 10 0 ......... 01 ..... ..... @ldst_imm_p= ost sign=3D1 ext=3D0 sz=3D2 +LDR_i 00 111 0 00 11 0 ......... 01 ..... ..... @ldst_imm_p= ost sign=3D1 ext=3D1 sz=3D0 +LDR_i 01 111 0 00 11 0 ......... 01 ..... ..... @ldst_imm_p= ost sign=3D1 ext=3D1 sz=3D1 + +# SIMD/FP +STR_v_i sz:2 111 1 00 00 0 ......... 01 ..... ..... @ldst_imm_p= ost sign=3D0 ext=3D0 +STR_v_i 00 111 1 00 10 0 ......... 01 ..... ..... @ldst_imm_p= ost sign=3D0 ext=3D0 sz=3D4 +LDR_v_i sz:2 111 1 00 01 0 ......... 01 ..... ..... @ldst_imm_p= ost sign=3D0 ext=3D0 +LDR_v_i 00 111 1 00 11 0 ......... 01 ..... ..... @ldst_imm_p= ost sign=3D0 ext=3D0 sz=3D4 + +### Load/store register =E2=80=94 unprivileged + +# GPR only (no SIMD/FP unprivileged forms) +STR_i sz:2 111 0 00 00 0 ......... 10 ..... ..... @ldst_imm_u= ser sign=3D0 ext=3D0 +LDR_i 00 111 0 00 01 0 ......... 10 ..... ..... @ldst_imm_u= ser sign=3D0 ext=3D1 sz=3D0 +LDR_i 01 111 0 00 01 0 ......... 10 ..... ..... @ldst_imm_u= ser sign=3D0 ext=3D1 sz=3D1 +LDR_i 10 111 0 00 01 0 ......... 10 ..... ..... @ldst_imm_u= ser sign=3D0 ext=3D1 sz=3D2 +LDR_i 11 111 0 00 01 0 ......... 10 ..... ..... @ldst_imm_u= ser sign=3D0 ext=3D0 sz=3D3 +LDR_i 00 111 0 00 10 0 ......... 10 ..... ..... @ldst_imm_u= ser sign=3D1 ext=3D0 sz=3D0 +LDR_i 01 111 0 00 10 0 ......... 10 ..... ..... @ldst_imm_u= ser sign=3D1 ext=3D0 sz=3D1 +LDR_i 10 111 0 00 10 0 ......... 10 ..... ..... @ldst_imm_u= ser sign=3D1 ext=3D0 sz=3D2 +LDR_i 00 111 0 00 11 0 ......... 10 ..... ..... @ldst_imm_u= ser sign=3D1 ext=3D1 sz=3D0 +LDR_i 01 111 0 00 11 0 ......... 10 ..... ..... @ldst_imm_u= ser sign=3D1 ext=3D1 sz=3D1 + +### Load/store register =E2=80=94 pre-indexed + +# GPR +STR_i sz:2 111 0 00 00 0 ......... 11 ..... ..... @ldst_imm_p= re sign=3D0 ext=3D0 +LDR_i 00 111 0 00 01 0 ......... 11 ..... ..... @ldst_imm_p= re sign=3D0 ext=3D1 sz=3D0 +LDR_i 01 111 0 00 01 0 ......... 11 ..... ..... @ldst_imm_p= re sign=3D0 ext=3D1 sz=3D1 +LDR_i 10 111 0 00 01 0 ......... 11 ..... ..... @ldst_imm_p= re sign=3D0 ext=3D1 sz=3D2 +LDR_i 11 111 0 00 01 0 ......... 11 ..... ..... @ldst_imm_p= re sign=3D0 ext=3D0 sz=3D3 +LDR_i 00 111 0 00 10 0 ......... 11 ..... ..... @ldst_imm_p= re sign=3D1 ext=3D0 sz=3D0 +LDR_i 01 111 0 00 10 0 ......... 11 ..... ..... @ldst_imm_p= re sign=3D1 ext=3D0 sz=3D1 +LDR_i 10 111 0 00 10 0 ......... 11 ..... ..... @ldst_imm_p= re sign=3D1 ext=3D0 sz=3D2 +LDR_i 00 111 0 00 11 0 ......... 11 ..... ..... @ldst_imm_p= re sign=3D1 ext=3D1 sz=3D0 +LDR_i 01 111 0 00 11 0 ......... 11 ..... ..... @ldst_imm_p= re sign=3D1 ext=3D1 sz=3D1 + +# SIMD/FP +STR_v_i sz:2 111 1 00 00 0 ......... 11 ..... ..... @ldst_imm_p= re sign=3D0 ext=3D0 +STR_v_i 00 111 1 00 10 0 ......... 11 ..... ..... @ldst_imm_p= re sign=3D0 ext=3D0 sz=3D4 +LDR_v_i sz:2 111 1 00 01 0 ......... 11 ..... ..... @ldst_imm_p= re sign=3D0 ext=3D0 +LDR_v_i 00 111 1 00 11 0 ......... 11 ..... ..... @ldst_imm_p= re sign=3D0 ext=3D0 sz=3D4 + +### PRFM =E2=80=94 unscaled immediate: prefetch is a NOP + +NOP 11 111 0 00 10 0 --------- 00 ----- ----- + +### Load/store register =E2=80=94 unsigned offset + +# GPR +STR_i sz:2 111 0 01 00 ............ ..... ..... @ldst_uimm= sign=3D0 ext=3D0 +LDR_i 00 111 0 01 01 ............ ..... ..... @ldst_uimm= sign=3D0 ext=3D1 sz=3D0 +LDR_i 01 111 0 01 01 ............ ..... ..... @ldst_uimm= sign=3D0 ext=3D1 sz=3D1 +LDR_i 10 111 0 01 01 ............ ..... ..... @ldst_uimm= sign=3D0 ext=3D1 sz=3D2 +LDR_i 11 111 0 01 01 ............ ..... ..... @ldst_uimm= sign=3D0 ext=3D0 sz=3D3 +LDR_i 00 111 0 01 10 ............ ..... ..... @ldst_uimm= sign=3D1 ext=3D0 sz=3D0 +LDR_i 01 111 0 01 10 ............ ..... ..... @ldst_uimm= sign=3D1 ext=3D0 sz=3D1 +LDR_i 10 111 0 01 10 ............ ..... ..... @ldst_uimm= sign=3D1 ext=3D0 sz=3D2 +LDR_i 00 111 0 01 11 ............ ..... ..... @ldst_uimm= sign=3D1 ext=3D1 sz=3D0 +LDR_i 01 111 0 01 11 ............ ..... ..... @ldst_uimm= sign=3D1 ext=3D1 sz=3D1 + +# PRFM =E2=80=94 unsigned offset +NOP 11 111 0 01 10 ------------ ----- ----- + +# SIMD/FP +STR_v_i sz:2 111 1 01 00 ............ ..... ..... @ldst_uimm= sign=3D0 ext=3D0 +STR_v_i 00 111 1 01 10 ............ ..... ..... @ldst_uimm= sign=3D0 ext=3D0 sz=3D4 +LDR_v_i sz:2 111 1 01 01 ............ ..... ..... @ldst_uimm= sign=3D0 ext=3D0 +LDR_v_i 00 111 1 01 11 ............ ..... ..... @ldst_uimm= sign=3D0 ext=3D0 sz=3D4 + +### System instructions =E2=80=94 DC cache maintenance + +# SYS with CRn=3DC7 covers all data cache operations (DC CIVAC, CVAC, etc.= ). +# On MMIO regions, cache maintenance is a harmless no-op. +NOP 1101 0101 0000 1 --- 0111 ---- --- ----- diff --git a/target/arm/emulate/arm_emulate.c b/target/arm/emulate/arm_emul= ate.c new file mode 100644 index 00000000..bedbdb3e --- /dev/null +++ b/target/arm/emulate/arm_emulate.c @@ -0,0 +1,288 @@ +/* + * AArch64 instruction emulation for ISV=3D0 data aborts + * + * Copyright (c) 2026 Lucas Amaral + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "arm_emulate.h" +#include "target/arm/cpu.h" +#include "target/arm/internals.h" +#include "exec/cpu-common.h" +#include "system/memory.h" +#include "exec/target_page.h" +#include "qemu/bitops.h" +#include "qemu/bswap.h" + +/* Named "DisasContext" as required by the decodetree code generator */ +typedef struct { + CPUState *cpu; + CPUARMState *env; + ArmEmulResult result; + bool be_data; +} DisasContext; + +#include "decode-a64-ldst.c.inc" + +/* GPR data access (Rt, Rs, Rt2) -- register 31 =3D XZR */ + +static uint64_t gpr_read(DisasContext *ctx, int reg) +{ + if (reg =3D=3D 31) { + return 0; /* XZR */ + } + return ctx->env->xregs[reg]; +} + +static void gpr_write(DisasContext *ctx, int reg, uint64_t val) +{ + if (reg =3D=3D 31) { + return; /* XZR -- discard */ + } + ctx->env->xregs[reg] =3D val; + ctx->cpu->vcpu_dirty =3D true; +} + +/* Base register access (Rn) -- register 31 =3D SP */ + +static uint64_t base_read(DisasContext *ctx, int rn) +{ + return ctx->env->xregs[rn]; +} + +static void base_write(DisasContext *ctx, int rn, uint64_t val) +{ + ctx->env->xregs[rn] =3D val; + ctx->cpu->vcpu_dirty =3D true; +} + +/* SIMD/FP register access */ + +static void fpreg_read(DisasContext *ctx, int reg, void *buf, int size) +{ + memcpy(buf, &ctx->env->vfp.zregs[reg], size); +} + +static void fpreg_write(DisasContext *ctx, int reg, const void *buf, int s= ize) +{ + memset(&ctx->env->vfp.zregs[reg], 0, sizeof(ctx->env->vfp.zregs[reg])); + memcpy(&ctx->env->vfp.zregs[reg], buf, size); + ctx->cpu->vcpu_dirty =3D true; +} + +/* + * Memory access via guest MMU translation. + * + * Translates the virtual address through the guest page tables using + * get_phys_addr(), then performs the access on the resulting physical + * address via address_space_read/write(). Each page-sized chunk is + * translated independently, so accesses that span a page boundary + * are handled correctly even when the pages map to different physical + * addresses. + */ + +static int mem_access(DisasContext *ctx, uint64_t va, void *buf, int size, + MMUAccessType access_type) +{ + ARMMMUIdx mmu_idx =3D arm_mmu_idx(ctx->env); + + while (size > 0) { + int chunk =3D MIN(size, TARGET_PAGE_SIZE - (va & ~TARGET_PAGE_MASK= )); + GetPhysAddrResult res =3D {}; + ARMMMUFaultInfo fi =3D {}; + + if (get_phys_addr(ctx->env, va, access_type, 0, mmu_idx, + &res, &fi)) { + ctx->result =3D ARM_EMUL_ERR_MEM; + return -1; + } + + AddressSpace *as =3D arm_addressspace(ctx->cpu, res.f.attrs); + MemTxResult txr; + + if (access_type =3D=3D MMU_DATA_STORE) { + txr =3D address_space_write(as, res.f.phys_addr, res.f.attrs, + buf, chunk); + } else { + txr =3D address_space_read(as, res.f.phys_addr, res.f.attrs, + buf, chunk); + } + + if (txr !=3D MEMTX_OK) { + ctx->result =3D ARM_EMUL_ERR_MEM; + return -1; + } + + va +=3D chunk; + buf +=3D chunk; + size -=3D chunk; + } + return 0; +} + +static int mem_read(DisasContext *ctx, uint64_t va, void *buf, int size) +{ + return mem_access(ctx, va, buf, size, MMU_DATA_LOAD); +} + +static int mem_write(DisasContext *ctx, uint64_t va, const void *buf, int = size) +{ + return mem_access(ctx, va, (void *)buf, size, MMU_DATA_STORE); +} + +/* + * Endian-aware GPR <-> memory buffer helpers. + * + * mem_read/mem_write transfer raw bytes between guest VA and a host buffe= r. + * mem_ld/mem_st convert between a uint64_t register value and the guest + * byte order in a memory buffer. + */ + +static uint64_t mem_ld(DisasContext *ctx, const void *buf, int size) +{ + return ctx->be_data ? ldn_be_p(buf, size) : ldn_le_p(buf, size); +} + +static void mem_st(DisasContext *ctx, void *buf, int size, uint64_t val) +{ + if (ctx->be_data) { + stn_be_p(buf, size, val); + } else { + stn_le_p(buf, size, val); + } +} + +/* Apply sign/zero extension */ +static uint64_t load_extend(uint64_t val, int sz, int sign, int ext) +{ + int data_bits =3D 8 << sz; + + if (sign) { + val =3D sextract64(val, 0, data_bits); + if (ext) { + /* Sign-extend to 32 bits (W register) */ + val &=3D 0xFFFFFFFF; + } + } else if (ext) { + /* Zero-extend to 32 bits (W register) */ + val &=3D 0xFFFFFFFF; + } + return val; +} + +/* Load/store single -- immediate (GPR) (DDI 0487 C3.3.8 -- C3.3.13) */ + +static bool trans_STR_i(DisasContext *ctx, arg_ldst_imm *a) +{ + int esize =3D (a->sz <=3D 3) ? (1 << a->sz) : 16; + int64_t offset =3D a->u ? ((int64_t)(uint64_t)a->imm << a->sz) + : (int64_t)a->imm; + uint64_t base =3D base_read(ctx, a->rn); + uint64_t va =3D a->p ? base : base + offset; + + uint8_t buf[16]; + uint64_t val =3D gpr_read(ctx, a->rt); + mem_st(ctx, buf, esize, val); + if (mem_write(ctx, va, buf, esize) !=3D 0) { + return true; + } + + if (a->w) { + base_write(ctx, a->rn, base + offset); + } + return true; +} + +static bool trans_LDR_i(DisasContext *ctx, arg_ldst_imm *a) +{ + int esize =3D (a->sz <=3D 3) ? (1 << a->sz) : 16; + int64_t offset =3D a->u ? ((int64_t)(uint64_t)a->imm << a->sz) + : (int64_t)a->imm; + uint64_t base =3D base_read(ctx, a->rn); + uint64_t va =3D a->p ? base : base + offset; + uint8_t buf[16]; + + if (mem_read(ctx, va, buf, esize) !=3D 0) { + return true; + } + + uint64_t val =3D mem_ld(ctx, buf, esize); + val =3D load_extend(val, a->sz, a->sign, a->ext); + gpr_write(ctx, a->rt, val); + + if (a->w) { + base_write(ctx, a->rn, base + offset); + } + return true; +} + +/* + * Load/store single -- immediate (SIMD/FP) + * STR_v_i / LDR_v_i (DDI 0487 C3.3.10) + */ + +static bool trans_STR_v_i(DisasContext *ctx, arg_ldst_imm *a) +{ + int esize =3D (a->sz <=3D 3) ? (1 << a->sz) : 16; + int64_t offset =3D a->u ? ((int64_t)(uint64_t)a->imm << a->sz) + : (int64_t)a->imm; + uint64_t base =3D base_read(ctx, a->rn); + uint64_t va =3D a->p ? base : base + offset; + uint8_t buf[16]; + + fpreg_read(ctx, a->rt, buf, esize); + if (mem_write(ctx, va, buf, esize) !=3D 0) { + return true; + } + + if (a->w) { + base_write(ctx, a->rn, base + offset); + } + return true; +} + +static bool trans_LDR_v_i(DisasContext *ctx, arg_ldst_imm *a) +{ + int esize =3D (a->sz <=3D 3) ? (1 << a->sz) : 16; + int64_t offset =3D a->u ? ((int64_t)(uint64_t)a->imm << a->sz) + : (int64_t)a->imm; + uint64_t base =3D base_read(ctx, a->rn); + uint64_t va =3D a->p ? base : base + offset; + uint8_t buf[16]; + + if (mem_read(ctx, va, buf, esize) !=3D 0) { + return true; + } + + fpreg_write(ctx, a->rt, buf, esize); + + if (a->w) { + base_write(ctx, a->rn, base + offset); + } + return true; +} + +/* PRFM, DC cache maintenance -- treated as NOP */ +static bool trans_NOP(DisasContext *ctx, arg_NOP *a) +{ + return true; +} + +/* Entry point */ + +ArmEmulResult arm_emul_insn(CPUArchState *env, uint32_t insn) +{ + DisasContext ctx =3D { + .cpu =3D env_cpu(env), + .env =3D env, + .result =3D ARM_EMUL_OK, + .be_data =3D arm_cpu_data_is_big_endian(env), + }; + + if (!decode_a64_ldst(&ctx, insn)) { + return ARM_EMUL_UNHANDLED; + } + + return ctx.result; +} diff --git a/target/arm/emulate/arm_emulate.h b/target/arm/emulate/arm_emul= ate.h new file mode 100644 index 00000000..7fe29839 --- /dev/null +++ b/target/arm/emulate/arm_emulate.h @@ -0,0 +1,30 @@ +/* + * AArch64 instruction emulation library + * + * Copyright (c) 2026 Lucas Amaral + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef ARM_EMULATE_H +#define ARM_EMULATE_H + +#include "qemu/osdep.h" + +/** + * ArmEmulResult - return status from arm_emul_insn() + */ +typedef enum { + ARM_EMUL_OK, /* Instruction emulated successfully */ + ARM_EMUL_UNHANDLED, /* Instruction not recognized by decoder */ + ARM_EMUL_ERR_MEM, /* Memory access failed */ +} ArmEmulResult; + +/** + * arm_emul_insn - decode and emulate one AArch64 instruction + * + * Caller must synchronize CPU state and fetch @insn before calling. + */ +ArmEmulResult arm_emul_insn(CPUArchState *env, uint32_t insn); + +#endif /* ARM_EMULATE_H */ diff --git a/target/arm/emulate/meson.build b/target/arm/emulate/meson.build new file mode 100644 index 00000000..e5455bd2 --- /dev/null +++ b/target/arm/emulate/meson.build @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +gen_a64_ldst =3D decodetree.process('a64-ldst.decode', + extra_args: ['--static-decode=3Ddecode_a64_ldst']) + +arm_common_system_ss.add(when: 'TARGET_AARCH64', if_true: [ + gen_a64_ldst, files('arm_emulate.c') +]) diff --git a/target/arm/meson.build b/target/arm/meson.build index 6e0e504a..a4b2291b 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -57,6 +57,7 @@ arm_common_system_ss.add(files( 'vfp_fpscr.c', )) =20 +subdir('emulate') subdir('hvf') subdir('whpx') =20 --=20 2.52.0 From nobody Sat Apr 11 17:07:29 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1775772442; cv=none; d=zohomail.com; s=zohoarc; b=HBV7KT2WjhmObQJOy/Oz/DmYiQiKIyHCithzjqMwrXGyYgs/7NJS2QVCsJMAfKuPsXK60kKR0h5jLJhna2X3TVUUYVlEA7u5A9YM+QTiEvYJWIJRlZ98W2DeDahM4eaKco1+tH0OGLYTmbobzE4P0CE/7118uabHDerjCmGxUms= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775772442; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=WsQoO7k2uaSfcDFMikzprY7q7WWInbI4W7i2YiYJ+go=; b=FxY3zRafJ18Jnf6POGtjXLe0G5IDGMExZ2LR1r16aA2Smu159LrF9wpjytseAo70nY1IkhrgLS4qBCirE/PLW7WUlBO4gNHSRAzuCnYVnPnZT8sNKON5XDCHB7jyWbn4sd/HKd3NvEArFHIJGUMB0NgtHnZzGbkQuNeU7x0gyG0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1775772442217134.70510287621642; Thu, 9 Apr 2026 15:07:22 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wAxWE-00088G-Ft; Thu, 09 Apr 2026 18:06:34 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wAxWD-00087l-4A for qemu-devel@nongnu.org; Thu, 09 Apr 2026 18:06:33 -0400 Received: from mail-dy1-x1332.google.com ([2607:f8b0:4864:20::1332]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wAxWB-0000bI-BE for qemu-devel@nongnu.org; Thu, 09 Apr 2026 18:06:32 -0400 Received: by mail-dy1-x1332.google.com with SMTP id 5a478bee46e88-2bd9a485bd6so2862787eec.1 for ; Thu, 09 Apr 2026 15:06:31 -0700 (PDT) Received: from localhost.localdomain ([2804:7f4:c030:bb40:195d:78fd:ecba:d45]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2d561bde68bsm1534567eec.17.2026.04.09.15.06.25 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 09 Apr 2026 15:06:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775772390; x=1776377190; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=WsQoO7k2uaSfcDFMikzprY7q7WWInbI4W7i2YiYJ+go=; b=YmC3QJvj2HtbSv3ZacHuXgqXUkqwLaXNcVOjIpW0gDoEPLdFDKCHX+qk8oDcGpxquE FdBBugBNR4aCDDTSwCoFdQ5zYM4tdDxZdg/e9OnPpkUoBu84/y9b17S/LxekHPlcM72B iCettOWlYdOT00unPI4cP7VAjR//pm5D+BIuHmzbp02b6irhKN24T5J+GB4OeHxHvklo BeXTRIrQ2sCjYWgot4LJiYS16z4hta8dx8NIX0YueFM/gVNg5/ZDgQyvJ+2qZZv7JUuu 2tNcReSBZkWgqWo+arXh8GWGPJ7mGCtEac3BNzPO4CyosJx2gQ5yiqreX48bDnKm29Nq 8Aaw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775772390; x=1776377190; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=WsQoO7k2uaSfcDFMikzprY7q7WWInbI4W7i2YiYJ+go=; b=k0yzX0NW0GKYBDekYwSDkapbua9Fb+ZRhXZa8JIZBdnKPxeVa/NOGGX8ZdYUSE3dr9 I7KyBdZNs2aSpGcuDPCrW9Ff1HYz8O/9ID+F+IaBVWfy5Vdokt6BkTXug8ibPbSOpl5T ss+Go23nhJB/JuFTiVtndqfo1Bws7QJV8BrDT+TLav3spHAupyuF9JJJk6gJmz5Hu+bK Rzsbbo2ldTGHFS6QojK8Lp/7f9hmBaLuc6El7rLrV0Uzpq70IFkiO8mVBBksv7TMXlWK 3+z3JX0ODOtZfCClkF45V/XyhfM11nzc3Cc8GUEIGv5AoPea6pyYJikqD7vqrzCc+786 MFVA== X-Gm-Message-State: AOJu0YxS/FHWriaaiVVRnUC8gFc5QPcEiwOXfo81usiq8k58aU+/to7u 6cXLuyvbpx6AWTzYFB3wdBuzcqLBYO++L/ryRnWnFOu35mbW1Ku+LcR9HgX8CQ6Q X-Gm-Gg: AeBDietPDnhlXJlt+ORdmd4RzbbuQCgPHJlH5UzppupeIS+YL4xEM0yn4nPv0eO8Pj7 n8olJf4sl7imD0vGmnwvw2Cem4DIGQ6GqN5z3BRvjWIrqd0pVs8zfaczP4GffXLNBnBUhL6RBV6 MuTL3fZtRNg4YSGCtRUbCjZ/W72wNs2xAEAUnJU/Wyi0Ihg3CfCLt7TTEQMpc0q2wbS7UuNaFeF W01SuDNVoU0dxNfSqsp+7WThmLZIwgfp0vEmxe9N5WTGqbALlnUHjgoLYotq4rDBGSqjyzEkxDK N9kIihrxr6a/nxa9htxiraR30/FiTy1f8IxmwthxCkJed7P1HZth9gYld+Yfl6Rv61cgUFl9iJ3 xE0BIsGvYq7kHP44eBa7L9Lq3dAglrRRYL/4Uf9yQ2fMaPfBSaTq/TvXmaJnxLDtbvTwy0lGxvu fv0FTGOf9oAaAcVq+VNViKAVc8GsnvNJJ9nq3qKoQZfYzz7iYl8vNaW8MEza3Zew== X-Received: by 2002:a05:7300:cb0a:b0:2d3:dff7:13b1 with SMTP id 5a478bee46e88-2d589463ba1mr515379eec.15.1775772389525; Thu, 09 Apr 2026 15:06:29 -0700 (PDT) From: Lucas Amaral To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, agraf@csgraf.de, peter.maydell@linaro.org, mohamed@unpredictable.fr, alex.bennee@linaro.org, richard.henderson@linaro.org, Lucas Amaral Subject: [PATCH v6 2/6] target/arm/emulate: add load/store register offset Date: Thu, 9 Apr 2026 19:06:10 -0300 Message-ID: <20260409220614.65558-3-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: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::1332; envelope-from=lucaaamaral@gmail.com; helo=mail-dy1-x1332.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, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham 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 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1775772445237154100 Add emulation for load/store register offset addressing mode (DDI 0487 C3.3.9). The offset register value is extended via UXTB/UXTH/UXTW/UXTX/SXTB/SXTH/SXTW/SXTX and optionally shifted by the element size. Instruction coverage: - STR/LDR (GPR): register offset with extend, all sizes - STR/LDR (SIMD/FP): register offset with extend, 8-128 bit - PRFM register offset: NOP Signed-off-by: Lucas Amaral Reviewed-by: Mohamed Mediouni --- target/arm/emulate/a64-ldst.decode | 29 ++++++++ target/arm/emulate/arm_emulate.c | 106 +++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) diff --git a/target/arm/emulate/a64-ldst.decode b/target/arm/emulate/a64-ld= st.decode index c887dcba..af6babe1 100644 --- a/target/arm/emulate/a64-ldst.decode +++ b/target/arm/emulate/a64-ldst.decode @@ -10,6 +10,9 @@ # 'u' flag: 0 =3D 9-bit signed immediate (byte offset), 1 =3D 12-bit unsig= ned (needs << sz) &ldst_imm rt rn imm sz sign w p unpriv ext u =20 +# Load/store register offset +&ldst rm rn rt sign ext sz opt s + ### Format templates =20 # Load/store immediate (9-bit signed) @@ -21,6 +24,9 @@ # Load/store unsigned offset (12-bit, handler scales by << sz) @ldst_uimm .. ... . .. .. imm:12 rn:5 rt:5 &ldst_imm u=3D1 unp= riv=3D0 p=3D0 w=3D0 =20 +# Load/store register offset +@ldst .. ... . .. .. . rm:5 opt:3 s:1 .. rn:5 rt:5 &ldst + ### Load/store register =E2=80=94 unscaled immediate (LDUR/STUR) =20 # GPR @@ -122,6 +128,29 @@ STR_v_i 00 111 1 01 10 ............ ..... ....= . @ldst_uimm sign=3D LDR_v_i sz:2 111 1 01 01 ............ ..... ..... @ldst_uimm= sign=3D0 ext=3D0 LDR_v_i 00 111 1 01 11 ............ ..... ..... @ldst_uimm= sign=3D0 ext=3D0 sz=3D4 =20 +### Load/store register =E2=80=94 register offset + +# GPR +STR sz:2 111 0 00 00 1 ..... ... . 10 ..... ..... @ldst sign= =3D0 ext=3D0 +LDR 00 111 0 00 01 1 ..... ... . 10 ..... ..... @ldst sign= =3D0 ext=3D1 sz=3D0 +LDR 01 111 0 00 01 1 ..... ... . 10 ..... ..... @ldst sign= =3D0 ext=3D1 sz=3D1 +LDR 10 111 0 00 01 1 ..... ... . 10 ..... ..... @ldst sign= =3D0 ext=3D1 sz=3D2 +LDR 11 111 0 00 01 1 ..... ... . 10 ..... ..... @ldst sign= =3D0 ext=3D0 sz=3D3 +LDR 00 111 0 00 10 1 ..... ... . 10 ..... ..... @ldst sign= =3D1 ext=3D0 sz=3D0 +LDR 01 111 0 00 10 1 ..... ... . 10 ..... ..... @ldst sign= =3D1 ext=3D0 sz=3D1 +LDR 10 111 0 00 10 1 ..... ... . 10 ..... ..... @ldst sign= =3D1 ext=3D0 sz=3D2 +LDR 00 111 0 00 11 1 ..... ... . 10 ..... ..... @ldst sign= =3D1 ext=3D1 sz=3D0 +LDR 01 111 0 00 11 1 ..... ... . 10 ..... ..... @ldst sign= =3D1 ext=3D1 sz=3D1 + +# PRFM =E2=80=94 register offset +NOP 11 111 0 00 10 1 ----- -1- - 10 ----- ----- + +# SIMD/FP +STR_v sz:2 111 1 00 00 1 ..... ... . 10 ..... ..... @ldst sign= =3D0 ext=3D0 +STR_v 00 111 1 00 10 1 ..... ... . 10 ..... ..... @ldst sign= =3D0 ext=3D0 sz=3D4 +LDR_v sz:2 111 1 00 01 1 ..... ... . 10 ..... ..... @ldst sign= =3D0 ext=3D0 +LDR_v 00 111 1 00 11 1 ..... ... . 10 ..... ..... @ldst sign= =3D0 ext=3D0 sz=3D4 + ### System instructions =E2=80=94 DC cache maintenance =20 # SYS with CRn=3DC7 covers all data cache operations (DC CIVAC, CVAC, etc.= ). diff --git a/target/arm/emulate/arm_emulate.c b/target/arm/emulate/arm_emul= ate.c index bedbdb3e..79f42d44 100644 --- a/target/arm/emulate/arm_emulate.c +++ b/target/arm/emulate/arm_emulate.c @@ -263,6 +263,112 @@ static bool trans_LDR_v_i(DisasContext *ctx, arg_ldst= _imm *a) return true; } =20 +/* Register offset extension (DDI 0487 C6.2.131) */ + +static uint64_t extend_reg(uint64_t val, int option, int shift) +{ + switch (option) { + case 0: /* UXTB */ + val =3D (uint8_t)val; + break; + case 1: /* UXTH */ + val =3D (uint16_t)val; + break; + case 2: /* UXTW */ + val =3D (uint32_t)val; + break; + case 3: /* UXTX / LSL */ + break; + case 4: /* SXTB */ + val =3D (int64_t)(int8_t)val; + break; + case 5: /* SXTH */ + val =3D (int64_t)(int16_t)val; + break; + case 6: /* SXTW */ + val =3D (int64_t)(int32_t)val; + break; + case 7: /* SXTX */ + break; + } + return val << shift; +} + +/* + * Load/store single -- register offset (GPR) + * STR / LDR (DDI 0487 C3.3.9) + */ + +static bool trans_STR(DisasContext *ctx, arg_ldst *a) +{ + int esize =3D (a->sz <=3D 3) ? (1 << a->sz) : 16; + int shift =3D a->s ? a->sz : 0; + uint64_t rm_val =3D gpr_read(ctx, a->rm); + uint64_t offset =3D extend_reg(rm_val, a->opt, shift); + uint64_t va =3D base_read(ctx, a->rn) + offset; + + uint8_t buf[16]; + uint64_t val =3D gpr_read(ctx, a->rt); + mem_st(ctx, buf, esize, val); + mem_write(ctx, va, buf, esize); + return true; +} + +static bool trans_LDR(DisasContext *ctx, arg_ldst *a) +{ + int esize =3D (a->sz <=3D 3) ? (1 << a->sz) : 16; + int shift =3D a->s ? a->sz : 0; + uint64_t rm_val =3D gpr_read(ctx, a->rm); + uint64_t offset =3D extend_reg(rm_val, a->opt, shift); + uint64_t va =3D base_read(ctx, a->rn) + offset; + uint8_t buf[16]; + + if (mem_read(ctx, va, buf, esize) !=3D 0) { + return true; + } + + uint64_t val =3D mem_ld(ctx, buf, esize); + val =3D load_extend(val, a->sz, a->sign, a->ext); + gpr_write(ctx, a->rt, val); + return true; +} + +/* + * Load/store single -- register offset (SIMD/FP) + * STR_v / LDR_v (DDI 0487 C3.3.10) + */ + +static bool trans_STR_v(DisasContext *ctx, arg_ldst *a) +{ + int esize =3D (a->sz <=3D 3) ? (1 << a->sz) : 16; + int shift =3D a->s ? a->sz : 0; + uint64_t rm_val =3D gpr_read(ctx, a->rm); + uint64_t offset =3D extend_reg(rm_val, a->opt, shift); + uint64_t va =3D base_read(ctx, a->rn) + offset; + uint8_t buf[16]; + + fpreg_read(ctx, a->rt, buf, esize); + mem_write(ctx, va, buf, esize); + return true; +} + +static bool trans_LDR_v(DisasContext *ctx, arg_ldst *a) +{ + int esize =3D (a->sz <=3D 3) ? (1 << a->sz) : 16; + int shift =3D a->s ? a->sz : 0; + uint64_t rm_val =3D gpr_read(ctx, a->rm); + uint64_t offset =3D extend_reg(rm_val, a->opt, shift); + uint64_t va =3D base_read(ctx, a->rn) + offset; + uint8_t buf[16]; + + if (mem_read(ctx, va, buf, esize) !=3D 0) { + return true; + } + + fpreg_write(ctx, a->rt, buf, esize); + return true; +} + /* PRFM, DC cache maintenance -- treated as NOP */ static bool trans_NOP(DisasContext *ctx, arg_NOP *a) { --=20 2.52.0 From nobody Sat Apr 11 17:07:29 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1775772460; cv=none; d=zohomail.com; s=zohoarc; b=ezu0kKIuTt+iz1GKkiS9oCr09A+H4XIpbu5ixnMJJ3Z0u66d6vXm4d3165ifYoXAxrieOTulbjeIZixeHqIc3+A1YkXhFKzwgKkLiLwOBHnNrXBzDqDBKwirafdxictSXanic+rfPqzyfggJ4mmTIi1OaE6Y/hvkqyMpECpXt8E= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775772460; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=9hYjt5TP5fiILetOflamrBDH1HToT8NoGi40uxHb3Qw=; b=Xetpf+SQndv38uOCQmgrNzCHqixg/m6/IB4/OHFPt1hjoXOx3E/yLMQ6g+Jy48emZ2/KQJHsFZJ2LBQpZNxtodn2B6ANrL7mhmnUvNMWfi8stxuBXOpmJ2AWjsHkXUsjCBR6GxYxqKLUyesKPdpQaOqgyWpJCEeGy8b1zyJlMCQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1775772460041989.3635822328198; Thu, 9 Apr 2026 15:07:40 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wAxWJ-00089l-Hz; Thu, 09 Apr 2026 18:06:39 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wAxWH-00088p-UB for qemu-devel@nongnu.org; Thu, 09 Apr 2026 18:06:37 -0400 Received: from mail-dy1-x1334.google.com ([2607:f8b0:4864:20::1334]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wAxWF-0000bj-Nu for qemu-devel@nongnu.org; Thu, 09 Apr 2026 18:06:37 -0400 Received: by mail-dy1-x1334.google.com with SMTP id 5a478bee46e88-2c54c68db4dso2370619eec.0 for ; Thu, 09 Apr 2026 15:06:35 -0700 (PDT) Received: from localhost.localdomain ([2804:7f4:c030:bb40:195d:78fd:ecba:d45]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2d561bde68bsm1534567eec.17.2026.04.09.15.06.29 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 09 Apr 2026 15:06:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775772394; x=1776377194; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=9hYjt5TP5fiILetOflamrBDH1HToT8NoGi40uxHb3Qw=; b=Ox19hzQ6s0TCJJohcsgjIjPdiHFgZl9O0iQ1GTLCTwTjdcqgHdAxGeiIqBbwJhln4v qZ1tkExiIJL27D0WrTIL/rCM+SmL+VDgbMQOMTdfEEf8Q4WlYw6+66HF1yte4LEDRsi7 eqrcGYvCKQFn7jyf21PNvMASFgKYb+CnYGsKyaD5K+l3Lx2XxXi2b7Jk8xQjvIC4SPG2 u1tg9u+Z0ECGrn1/UpErPTDQW/3rmW7hywntDrV6xS6atJSxqqfzp1XbQcr6KZMIhtES ZcYZmD4GKT7BC5Iw9YxJkJDEy9K6+ioni2Fiojxj+l1PAsUviLaR1YMnHSl3hiAhhBbR pxug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775772394; x=1776377194; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=9hYjt5TP5fiILetOflamrBDH1HToT8NoGi40uxHb3Qw=; b=owqPE4+dlzDWqHphqfymQPVHV1b+PE9/b1nhzQ/nR2rJBXy+ByuNpR/WQ4ehb73q+j ipooU2TG2Wwh8Dj4dpcGeHcQ4rys9LQhJOlYMXvZoZ9mEkfoA+Ef3rSZh9zcuiEhvlu1 44gtJxxR/kzAo7WgX31Nl90R/XB8X54wcrBPEBNha5tDd6SeSPriWMS3B65WBga8i5A6 pMph2JXt1sB1X8XSjZM7J2GsMRiO8dI10jf0u++4MJxSOYwe8e7KWyV+BavhHfXcuZvR R5M65vXR33YKtqAtmhnZRMs0X2RtporWPeP2R+ytTDh6LoJZU9bDqrwn6M7vC5/CRSvk MOpg== X-Gm-Message-State: AOJu0YxcWZgySBzqCxsBrkzGBPnQ1e/z+zi9j6T9AWKLEF7aqqK/NgNE GI1sfVSCHOg3Rqt7Icul+q2HTP3o8AtFkfoFsBinAKxAiZQTGBR7EMLG3VK1b+8V X-Gm-Gg: AeBDies4pVxfUZ2WvAb0+JS8eervdvk+MPExEdMr4icph+rjb2LLgRUpzWa64MyB7Nn vkypaZaAXHdBjYz06Z0I2r/l8m79cfF/8Kx8dxr7Y52tEJcYjoFOpNwnwI/jQu6wrlDt15KA24N GbW8Txs7s/mcqbaF8sIS+800957JM8iY89pkDklMisEI3/Ajgoh2elSjOARR5ntG/E7qLod4a7b zxy9Y/sUMEGwfSEw4vX/qpXokK7qFQGE8k5GmXjAsmjI6sBQDASU9Clah3pRHdnJdsXl9mpx9YT tGNb07gwH3yyuDeZAkQglUN9XcWOhGyLcYmOGL7DTB3PbTHE2sRtkkul5F/QPR5eTX1/DZSR7na MeJPXAjl5kBz7Dd4tLj/v9vTvS/7IHTjLrYCtF9duQH0E64JerfZeSTg9E6OZs/4R9NlRnXZs+R t0qWeBPx0rJ6IJaXk03t3QcgJ/PSKuuOH0MSgeSUvrAIC/Yf8GrwxYphogOhuymIOwfdhmjoX0 X-Received: by 2002:a05:7300:6da8:b0:2c4:a862:2368 with SMTP id 5a478bee46e88-2d5871bcb93mr529162eec.2.1775772393713; Thu, 09 Apr 2026 15:06:33 -0700 (PDT) From: Lucas Amaral To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, agraf@csgraf.de, peter.maydell@linaro.org, mohamed@unpredictable.fr, alex.bennee@linaro.org, richard.henderson@linaro.org, Lucas Amaral Subject: [PATCH v6 3/6] target/arm/emulate: add load/store pair Date: Thu, 9 Apr 2026 19:06:11 -0300 Message-ID: <20260409220614.65558-4-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: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::1334; envelope-from=lucaaamaral@gmail.com; helo=mail-dy1-x1334.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, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, 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 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1775772462251158500 Add emulation for load/store pair instructions (DDI 0487 C3.3.14 -- C3.3.16). All addressing modes are covered: non-temporal (STNP/LDNP), post-indexed, signed offset, and pre-indexed. Instruction coverage: - STP/LDP (GPR): 32/64-bit pairs, all addressing modes - STP/LDP (SIMD/FP): 32/64/128-bit pairs, all addressing modes - LDPSW: sign-extending 32-bit pair load - STGP: store allocation tag pair (tag operation is NOP for MMIO) Signed-off-by: Lucas Amaral Reviewed-by: Mohamed Mediouni --- target/arm/emulate/a64-ldst.decode | 68 ++++++++++++++++++ target/arm/emulate/arm_emulate.c | 108 +++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+) diff --git a/target/arm/emulate/a64-ldst.decode b/target/arm/emulate/a64-ld= st.decode index af6babe1..f3de3f86 100644 --- a/target/arm/emulate/a64-ldst.decode +++ b/target/arm/emulate/a64-ldst.decode @@ -10,6 +10,9 @@ # 'u' flag: 0 =3D 9-bit signed immediate (byte offset), 1 =3D 12-bit unsig= ned (needs << sz) &ldst_imm rt rn imm sz sign w p unpriv ext u =20 +# Load/store pair (GPR and SIMD/FP) +&ldstpair rt2 rt rn imm sz sign w p + # Load/store register offset &ldst rm rn rt sign ext sz opt s =20 @@ -24,6 +27,9 @@ # Load/store unsigned offset (12-bit, handler scales by << sz) @ldst_uimm .. ... . .. .. imm:12 rn:5 rt:5 &ldst_imm u=3D1 unp= riv=3D0 p=3D0 w=3D0 =20 +# Load/store pair: imm7 is signed, scaled by element size in handler +@ldstpair .. ... . ... . imm:s7 rt2:5 rn:5 rt:5 &ldstpair + # Load/store register offset @ldst .. ... . .. .. . rm:5 opt:3 s:1 .. rn:5 rt:5 &ldst =20 @@ -128,6 +134,68 @@ STR_v_i 00 111 1 01 10 ............ ..... ....= . @ldst_uimm sign=3D LDR_v_i sz:2 111 1 01 01 ............ ..... ..... @ldst_uimm= sign=3D0 ext=3D0 LDR_v_i 00 111 1 01 11 ............ ..... ..... @ldst_uimm= sign=3D0 ext=3D0 sz=3D4 =20 +### Load/store pair =E2=80=94 non-temporal (STNP/LDNP) + +# STNP/LDNP: offset only, no writeback. Non-temporal hint ignored. +STP 00 101 0 000 0 ....... ..... ..... ..... @ldstpair = sz=3D2 sign=3D0 p=3D0 w=3D0 +LDP 00 101 0 000 1 ....... ..... ..... ..... @ldstpair = sz=3D2 sign=3D0 p=3D0 w=3D0 +STP 10 101 0 000 0 ....... ..... ..... ..... @ldstpair = sz=3D3 sign=3D0 p=3D0 w=3D0 +LDP 10 101 0 000 1 ....... ..... ..... ..... @ldstpair = sz=3D3 sign=3D0 p=3D0 w=3D0 +STP_v 00 101 1 000 0 ....... ..... ..... ..... @ldstpair = sz=3D2 sign=3D0 p=3D0 w=3D0 +LDP_v 00 101 1 000 1 ....... ..... ..... ..... @ldstpair = sz=3D2 sign=3D0 p=3D0 w=3D0 +STP_v 01 101 1 000 0 ....... ..... ..... ..... @ldstpair = sz=3D3 sign=3D0 p=3D0 w=3D0 +LDP_v 01 101 1 000 1 ....... ..... ..... ..... @ldstpair = sz=3D3 sign=3D0 p=3D0 w=3D0 +STP_v 10 101 1 000 0 ....... ..... ..... ..... @ldstpair = sz=3D4 sign=3D0 p=3D0 w=3D0 +LDP_v 10 101 1 000 1 ....... ..... ..... ..... @ldstpair = sz=3D4 sign=3D0 p=3D0 w=3D0 + +### Load/store pair =E2=80=94 post-indexed + +STP 00 101 0 001 0 ....... ..... ..... ..... @ldstpair = sz=3D2 sign=3D0 p=3D1 w=3D1 +LDP 00 101 0 001 1 ....... ..... ..... ..... @ldstpair = sz=3D2 sign=3D0 p=3D1 w=3D1 +LDP 01 101 0 001 1 ....... ..... ..... ..... @ldstpair = sz=3D2 sign=3D1 p=3D1 w=3D1 +STP 10 101 0 001 0 ....... ..... ..... ..... @ldstpair = sz=3D3 sign=3D0 p=3D1 w=3D1 +LDP 10 101 0 001 1 ....... ..... ..... ..... @ldstpair = sz=3D3 sign=3D0 p=3D1 w=3D1 +STP_v 00 101 1 001 0 ....... ..... ..... ..... @ldstpair = sz=3D2 sign=3D0 p=3D1 w=3D1 +LDP_v 00 101 1 001 1 ....... ..... ..... ..... @ldstpair = sz=3D2 sign=3D0 p=3D1 w=3D1 +STP_v 01 101 1 001 0 ....... ..... ..... ..... @ldstpair = sz=3D3 sign=3D0 p=3D1 w=3D1 +LDP_v 01 101 1 001 1 ....... ..... ..... ..... @ldstpair = sz=3D3 sign=3D0 p=3D1 w=3D1 +STP_v 10 101 1 001 0 ....... ..... ..... ..... @ldstpair = sz=3D4 sign=3D0 p=3D1 w=3D1 +LDP_v 10 101 1 001 1 ....... ..... ..... ..... @ldstpair = sz=3D4 sign=3D0 p=3D1 w=3D1 + +### Load/store pair =E2=80=94 signed offset + +STP 00 101 0 010 0 ....... ..... ..... ..... @ldstpair = sz=3D2 sign=3D0 p=3D0 w=3D0 +LDP 00 101 0 010 1 ....... ..... ..... ..... @ldstpair = sz=3D2 sign=3D0 p=3D0 w=3D0 +LDP 01 101 0 010 1 ....... ..... ..... ..... @ldstpair = sz=3D2 sign=3D1 p=3D0 w=3D0 +STP 10 101 0 010 0 ....... ..... ..... ..... @ldstpair = sz=3D3 sign=3D0 p=3D0 w=3D0 +LDP 10 101 0 010 1 ....... ..... ..... ..... @ldstpair = sz=3D3 sign=3D0 p=3D0 w=3D0 +STP_v 00 101 1 010 0 ....... ..... ..... ..... @ldstpair = sz=3D2 sign=3D0 p=3D0 w=3D0 +LDP_v 00 101 1 010 1 ....... ..... ..... ..... @ldstpair = sz=3D2 sign=3D0 p=3D0 w=3D0 +STP_v 01 101 1 010 0 ....... ..... ..... ..... @ldstpair = sz=3D3 sign=3D0 p=3D0 w=3D0 +LDP_v 01 101 1 010 1 ....... ..... ..... ..... @ldstpair = sz=3D3 sign=3D0 p=3D0 w=3D0 +STP_v 10 101 1 010 0 ....... ..... ..... ..... @ldstpair = sz=3D4 sign=3D0 p=3D0 w=3D0 +LDP_v 10 101 1 010 1 ....... ..... ..... ..... @ldstpair = sz=3D4 sign=3D0 p=3D0 w=3D0 + +### Load/store pair =E2=80=94 pre-indexed + +STP 00 101 0 011 0 ....... ..... ..... ..... @ldstpair = sz=3D2 sign=3D0 p=3D0 w=3D1 +LDP 00 101 0 011 1 ....... ..... ..... ..... @ldstpair = sz=3D2 sign=3D0 p=3D0 w=3D1 +LDP 01 101 0 011 1 ....... ..... ..... ..... @ldstpair = sz=3D2 sign=3D1 p=3D0 w=3D1 +STP 10 101 0 011 0 ....... ..... ..... ..... @ldstpair = sz=3D3 sign=3D0 p=3D0 w=3D1 +LDP 10 101 0 011 1 ....... ..... ..... ..... @ldstpair = sz=3D3 sign=3D0 p=3D0 w=3D1 +STP_v 00 101 1 011 0 ....... ..... ..... ..... @ldstpair = sz=3D2 sign=3D0 p=3D0 w=3D1 +LDP_v 00 101 1 011 1 ....... ..... ..... ..... @ldstpair = sz=3D2 sign=3D0 p=3D0 w=3D1 +STP_v 01 101 1 011 0 ....... ..... ..... ..... @ldstpair = sz=3D3 sign=3D0 p=3D0 w=3D1 +LDP_v 01 101 1 011 1 ....... ..... ..... ..... @ldstpair = sz=3D3 sign=3D0 p=3D0 w=3D1 +STP_v 10 101 1 011 0 ....... ..... ..... ..... @ldstpair = sz=3D4 sign=3D0 p=3D0 w=3D1 +LDP_v 10 101 1 011 1 ....... ..... ..... ..... @ldstpair = sz=3D4 sign=3D0 p=3D0 w=3D1 + +### Load/store pair =E2=80=94 STGP (store allocation tag + pair) + +STGP 01 101 0 001 0 ....... ..... ..... ..... @ldstpair = sz=3D3 sign=3D0 p=3D1 w=3D1 +STGP 01 101 0 010 0 ....... ..... ..... ..... @ldstpair = sz=3D3 sign=3D0 p=3D0 w=3D0 +STGP 01 101 0 011 0 ....... ..... ..... ..... @ldstpair = sz=3D3 sign=3D0 p=3D0 w=3D1 + ### Load/store register =E2=80=94 register offset =20 # GPR diff --git a/target/arm/emulate/arm_emulate.c b/target/arm/emulate/arm_emul= ate.c index 79f42d44..2d86b90f 100644 --- a/target/arm/emulate/arm_emulate.c +++ b/target/arm/emulate/arm_emulate.c @@ -171,6 +171,114 @@ static uint64_t load_extend(uint64_t val, int sz, int= sign, int ext) return val; } =20 +/* + * Load/store pair: STP, LDP, STNP, LDNP, STGP, LDPSW + * (DDI 0487 C3.3.14 -- C3.3.16) + */ + +static bool trans_STP(DisasContext *ctx, arg_ldstpair *a) +{ + int esize =3D 1 << a->sz; /* 4 or 8 bytes */ + int64_t offset =3D (int64_t)a->imm << a->sz; + uint64_t base =3D base_read(ctx, a->rn); + uint64_t va =3D a->p ? base : base + offset; /* post-index: unmodified= base */ + uint8_t buf[16]; /* max 2 x 8 bytes */ + + mem_st(ctx, buf, esize, gpr_read(ctx, a->rt)); + mem_st(ctx, buf + esize, esize, gpr_read(ctx, a->rt2)); + + if (mem_write(ctx, va, buf, 2 * esize) !=3D 0) { + return true; + } + + if (a->w) { + base_write(ctx, a->rn, base + offset); + } + return true; +} + +static bool trans_LDP(DisasContext *ctx, arg_ldstpair *a) +{ + int esize =3D 1 << a->sz; + int64_t offset =3D (int64_t)a->imm << a->sz; + uint64_t base =3D base_read(ctx, a->rn); + uint64_t va =3D a->p ? base : base + offset; + uint8_t buf[16]; + + if (mem_read(ctx, va, buf, 2 * esize) !=3D 0) { + return true; + } + uint64_t v1 =3D mem_ld(ctx, buf, esize); + uint64_t v2 =3D mem_ld(ctx, buf + esize, esize); + + /* LDPSW: sign-extend 32-bit values to 64-bit (sign=3D1, sz=3D2) */ + if (a->sign) { + v1 =3D sextract64(v1, 0, 8 * esize); + v2 =3D sextract64(v2, 0, 8 * esize); + } + + gpr_write(ctx, a->rt, v1); + gpr_write(ctx, a->rt2, v2); + + if (a->w) { + base_write(ctx, a->rn, base + offset); + } + return true; +} + +/* STGP: tag operation is a NOP for emulation; data stored via STP */ +static bool trans_STGP(DisasContext *ctx, arg_ldstpair *a) +{ + return trans_STP(ctx, a); +} + +/* + * SIMD/FP load/store pair: STP_v, LDP_v + * (DDI 0487 C3.3.14 -- C3.3.16) + */ + +static bool trans_STP_v(DisasContext *ctx, arg_ldstpair *a) +{ + int esize =3D 1 << a->sz; /* 4, 8, or 16 bytes */ + int64_t offset =3D (int64_t)a->imm << a->sz; + uint64_t base =3D base_read(ctx, a->rn); + uint64_t va =3D a->p ? base : base + offset; + uint8_t buf[32]; /* max 2 x 16 bytes */ + + fpreg_read(ctx, a->rt, buf, esize); + fpreg_read(ctx, a->rt2, buf + esize, esize); + + if (mem_write(ctx, va, buf, 2 * esize) !=3D 0) { + return true; + } + + if (a->w) { + base_write(ctx, a->rn, base + offset); + } + return true; +} + +static bool trans_LDP_v(DisasContext *ctx, arg_ldstpair *a) +{ + int esize =3D 1 << a->sz; + int64_t offset =3D (int64_t)a->imm << a->sz; + uint64_t base =3D base_read(ctx, a->rn); + uint64_t va =3D a->p ? base : base + offset; + uint8_t buf[32]; + + if (mem_read(ctx, va, buf, 2 * esize) !=3D 0) { + return true; + } + + fpreg_write(ctx, a->rt, buf, esize); + fpreg_write(ctx, a->rt2, buf + esize, esize); + + if (a->w) { + base_write(ctx, a->rn, base + offset); + } + return true; +} + /* Load/store single -- immediate (GPR) (DDI 0487 C3.3.8 -- C3.3.13) */ =20 static bool trans_STR_i(DisasContext *ctx, arg_ldst_imm *a) --=20 2.52.0 From nobody Sat Apr 11 17:07:29 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1775772462; cv=none; d=zohomail.com; s=zohoarc; b=KxqH3AvUXAqQkGhAimm4vkoeKLqP3vPu8PNH/cp5oULgH05L8PMVmgirc+6tByP9ScF9wvmkAvLPuWLtOiaTQpEdausHEnKZdp0Zpndn9aARxpbacR3Jzm38nyNbjAHw2shfLC0FBSqlkE9fBFgZZsHvBlBhBdCAKeblZ+KVThM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775772462; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=8eMPJQLlf+3OGRaso7a3nCpBSTalIXEmmU/N+0pBWN0=; b=P6Ui+OlmS4r1gTvBMMBPp2B98Kn5ZEYhpx3gGZfuZXb8eKEi4gm8qVVGeqerahRWCQ6HMiwidlcvAqOdZFCkXbzWEhap+zozczLNkTM6swHeCkL+S9BbVzKDnDJpGOTLNPQC5r9RMKwl6rmKs1WRiJI6k2L8SSJcD1aMcssOsPQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1775772462418547.2932367346908; Thu, 9 Apr 2026 15:07:42 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wAxWM-0008AE-D9; Thu, 09 Apr 2026 18:06:42 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wAxWL-00089y-Gx for qemu-devel@nongnu.org; Thu, 09 Apr 2026 18:06:41 -0400 Received: from mail-dy1-x1329.google.com ([2607:f8b0:4864:20::1329]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wAxWJ-0000c2-Ow for qemu-devel@nongnu.org; Thu, 09 Apr 2026 18:06:41 -0400 Received: by mail-dy1-x1329.google.com with SMTP id 5a478bee46e88-2cf1646bd11so2355487eec.1 for ; Thu, 09 Apr 2026 15:06:39 -0700 (PDT) Received: from localhost.localdomain ([2804:7f4:c030:bb40:195d:78fd:ecba:d45]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2d561bde68bsm1534567eec.17.2026.04.09.15.06.34 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 09 Apr 2026 15:06:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775772398; x=1776377198; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=8eMPJQLlf+3OGRaso7a3nCpBSTalIXEmmU/N+0pBWN0=; b=EJqH9Or3fWjvw3NNz7EYHYV9Momvz4Cfu8UtsvZPmwwVzIqpjY5OyD0AG4nlgbgTZm zIxooWKxMLunOp0TLGB0WhWrvI4CvA0ONM6iNQKiYmLyG8Uw68XbRtW04jyMJq22wnMi xNHDHhimgDqGWx2Xe77ES5M2kbRqGWMniGQaaaecBMv0zZS3pMZsTLyG2iEFTFbWbNjr jq0IOMQH7THX2BwZH4Blu4Y/v5hY0E3GCt6Tks2xmIkmUGypng2eqzO2deRC1+lmnupE LCGH7mamXLN6LmD8uGDV02m73RUxVwM7GcAh+zekcNt1XXlwDhWn/BS9qPRJ68t5jb0E DucA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775772398; x=1776377198; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=8eMPJQLlf+3OGRaso7a3nCpBSTalIXEmmU/N+0pBWN0=; b=PYijqx4t5jWvT7cVgifHfmVAoNItRZQ0Wnj4PR8r9wMQ54gQA53hcGHgv2EU44k04a zZbzS2EhNlVZ0Wnry6Qi5prH5OsViW5n4K9DRlQyyunheoGfNDiSKxuObdZg/SQvrj0B 9kZ9LtU6NIfgCyrwPd03rrMWqj1GiPUkx2RNZZ80BsSkIxKjem6VqPNAgkAoBmkJkm/Q EIJV/pW3zLdKwheaXcd/PKmPdOUJ7N0yLwLd+9YiHBF+pwi17+q1Th4aDri47BhoH/yW NopGGz+p0patIAv/oyaZ22Z9Mg5LkRGHAn6pQ84TIbmsHeH9Rlfnkrxk7kyLErioXkgq NoAA== X-Gm-Message-State: AOJu0YzJAMd9GopKbGmjzG+bYXP9A9C4U2DWSnpNLhQ7LggfDxV3Fwdn s8oyXwdAwlwhqsneIqE8UTvT0+gmjek+qmpR4iFuZisTHphnRKMZKrs2cIds/V0E X-Gm-Gg: AeBDies+E+BY/rpRrvDcj/hkWrQjTbNlDRhgcv0EIw1FGn1nqhNtSfiu0f+eAx4gJ4X mCPEn0iAB1aJE9rmUA5enTjGxbRjnpJpIJzgTKT3fJFY0SPggtz2K2BadaJQY/86ApIs8VB5O4D 2dRoTxRriragcbpa8gYRRrWo29RA+RchsMayAYU7VI1AN70muvG1cE0XZ5Blw7tnk7swYSqsDNo Ei8puwW9VZwnKzQr4DvIlrUnLdBh9WmsSKoIkTBPiBA4r5kB25LXGrbWgN0xwTtQP0YPQf5yQOI z61xywF0l0wR0E2cJypCLB1DBXAjiBmbH5dAy72DN7cYPA589f+PFplwmPMX/MqEgJ0+f9G4eQs w84hdnx0Bw0llXSWwppbTYfzVdaiS8/tdD8w6qpylsWljdd3qiV01+Yq6tsc/xxNSefeo/8YT93 e+oFUEApu8oAlA/npyn3IglVGPPwIWm3WWvu8qjyvd9Tw2Fv2K1lQCnyoueYFVcA== X-Received: by 2002:a05:7301:6788:b0:2c0:cc90:a71 with SMTP id 5a478bee46e88-2d5873b3c6amr536067eec.8.1775772397860; Thu, 09 Apr 2026 15:06:37 -0700 (PDT) From: Lucas Amaral To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, agraf@csgraf.de, peter.maydell@linaro.org, mohamed@unpredictable.fr, alex.bennee@linaro.org, richard.henderson@linaro.org, Lucas Amaral Subject: [PATCH v6 4/6] target/arm/emulate: add load/store exclusive Date: Thu, 9 Apr 2026 19:06:12 -0300 Message-ID: <20260409220614.65558-5-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: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::1329; envelope-from=lucaaamaral@gmail.com; helo=mail-dy1-x1329.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, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham 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 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1775772464594154100 Add emulation for load/store exclusive instructions (DDI 0487 C3.3.6). Exclusive monitors have no meaning on emulated MMIO accesses, so STXR always reports success (Rs=3D0) and LDXR does not set a monitor. Instruction coverage: - STXR/STLXR: exclusive store, 8/16/32/64-bit - LDXR/LDAXR: exclusive load, 8/16/32/64-bit - STXP/STLXP: exclusive store pair, 32/64-bit - LDXP/LDAXP: exclusive load pair, 32/64-bit STXP/LDXP use two explicit decode patterns (sz=3D2, sz=3D3) for the 32/64-bit size variants. Signed-off-by: Lucas Amaral Reviewed-by: Mohamed Mediouni --- target/arm/emulate/a64-ldst.decode | 22 ++++++++++ target/arm/emulate/arm_emulate.c | 70 ++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/target/arm/emulate/a64-ldst.decode b/target/arm/emulate/a64-ld= st.decode index f3de3f86..fadf6fd2 100644 --- a/target/arm/emulate/a64-ldst.decode +++ b/target/arm/emulate/a64-ldst.decode @@ -10,6 +10,9 @@ # 'u' flag: 0 =3D 9-bit signed immediate (byte offset), 1 =3D 12-bit unsig= ned (needs << sz) &ldst_imm rt rn imm sz sign w p unpriv ext u =20 +# Load/store exclusive +&stxr rn rt rt2 rs sz lasr + # Load/store pair (GPR and SIMD/FP) &ldstpair rt2 rt rn imm sz sign w p =20 @@ -18,6 +21,9 @@ =20 ### Format templates =20 +# Exclusives +@stxr sz:2 ...... ... rs:5 lasr:1 rt2:5 rn:5 rt:5 &stxr + # Load/store immediate (9-bit signed) @ldst_imm .. ... . .. .. . imm:s9 .. rn:5 rt:5 &ldst_imm u=3D0 unp= riv=3D0 p=3D0 w=3D0 @ldst_imm_pre .. ... . .. .. . imm:s9 .. rn:5 rt:5 &ldst_imm u=3D0 unp= riv=3D0 p=3D0 w=3D1 @@ -134,6 +140,22 @@ STR_v_i 00 111 1 01 10 ............ ..... ....= . @ldst_uimm sign=3D LDR_v_i sz:2 111 1 01 01 ............ ..... ..... @ldst_uimm= sign=3D0 ext=3D0 LDR_v_i 00 111 1 01 11 ............ ..... ..... @ldst_uimm= sign=3D0 ext=3D0 sz=3D4 =20 +### Load/store exclusive + +# STXR / STLXR (sz encodes 8/16/32/64-bit) +STXR .. 001000 000 ..... . ..... ..... ..... @stxr + +# LDXR / LDAXR +LDXR .. 001000 010 ..... . ..... ..... ..... @stxr + +# STXP / STLXP (bit[31]=3D1, bit[30]=3Dsf =E2=86=92 sz=3D2 for 32-bit, sz= =3D3 for 64-bit) +STXP 10 001000 001 rs:5 lasr:1 rt2:5 rn:5 rt:5 &stxr sz=3D2 +STXP 11 001000 001 rs:5 lasr:1 rt2:5 rn:5 rt:5 &stxr sz=3D3 + +# LDXP / LDAXP +LDXP 10 001000 011 rs:5 lasr:1 rt2:5 rn:5 rt:5 &stxr sz=3D2 +LDXP 11 001000 011 rs:5 lasr:1 rt2:5 rn:5 rt:5 &stxr sz=3D3 + ### Load/store pair =E2=80=94 non-temporal (STNP/LDNP) =20 # STNP/LDNP: offset only, no writeback. Non-temporal hint ignored. diff --git a/target/arm/emulate/arm_emulate.c b/target/arm/emulate/arm_emul= ate.c index 2d86b90f..7f876355 100644 --- a/target/arm/emulate/arm_emulate.c +++ b/target/arm/emulate/arm_emulate.c @@ -477,6 +477,76 @@ static bool trans_LDR_v(DisasContext *ctx, arg_ldst *a) return true; } =20 +/* + * Load/store exclusive: STXR, LDXR, STXP, LDXP + * (DDI 0487 C3.3.6) + * + * Exclusive monitors have no meaning on MMIO. STXR always reports + * success (Rs=3D0) and LDXR does not set an exclusive monitor. + */ + +static bool trans_STXR(DisasContext *ctx, arg_stxr *a) +{ + int esize =3D 1 << a->sz; + uint64_t va =3D base_read(ctx, a->rn); + uint8_t buf[8]; + + mem_st(ctx, buf, esize, gpr_read(ctx, a->rt)); + if (mem_write(ctx, va, buf, esize) !=3D 0) { + return true; + } + + /* Report success -- no exclusive monitor on emulated access */ + gpr_write(ctx, a->rs, 0); + return true; +} + +static bool trans_LDXR(DisasContext *ctx, arg_stxr *a) +{ + int esize =3D 1 << a->sz; + uint64_t va =3D base_read(ctx, a->rn); + uint8_t buf[8]; + + if (mem_read(ctx, va, buf, esize) !=3D 0) { + return true; + } + + gpr_write(ctx, a->rt, mem_ld(ctx, buf, esize)); + return true; +} + +static bool trans_STXP(DisasContext *ctx, arg_stxr *a) +{ + int esize =3D 1 << a->sz; /* sz=3D2->4, sz=3D3->8 */ + uint64_t va =3D base_read(ctx, a->rn); + uint8_t buf[16]; + + mem_st(ctx, buf, esize, gpr_read(ctx, a->rt)); + mem_st(ctx, buf + esize, esize, gpr_read(ctx, a->rt2)); + + if (mem_write(ctx, va, buf, 2 * esize) !=3D 0) { + return true; + } + + gpr_write(ctx, a->rs, 0); /* success */ + return true; +} + +static bool trans_LDXP(DisasContext *ctx, arg_stxr *a) +{ + int esize =3D 1 << a->sz; + uint64_t va =3D base_read(ctx, a->rn); + uint8_t buf[16]; + + if (mem_read(ctx, va, buf, 2 * esize) !=3D 0) { + return true; + } + + gpr_write(ctx, a->rt, mem_ld(ctx, buf, esize)); + gpr_write(ctx, a->rt2, mem_ld(ctx, buf + esize, esize)); + return true; +} + /* PRFM, DC cache maintenance -- treated as NOP */ static bool trans_NOP(DisasContext *ctx, arg_NOP *a) { --=20 2.52.0 From nobody Sat Apr 11 17:07:29 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1775772483; cv=none; d=zohomail.com; s=zohoarc; b=gtAQDeK1ORn7p/MGjztDL8CXV45fDBjfuEJW5k6gTmyHvZlY62DtvbAioXcbKPCLE1WufO5WvLl/DrxbVBBqk9+1edu7KK2fTY6NPPK8seDjX32TrS0uD7ARoTFNWoSjY74h1UYybCx9ErdKwd5ktl/Lo7WMw4UV13kpIx65UIg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775772483; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=lbIyOfnciDg6afzmMw7/atMx/iFETQJzz2oWEz1fQAg=; b=he3yCyjV9hSy48Gc6TgE7KpGtVUdsNNItV3LfR8326PRezIBlmSR/UTkphH/uM9t4P4xzNmz+ZW1gyUYJsjKwIfqJf1MEtmN9snXDnBPMhgdlxYFFdvY7PJDmwYcmraWGGoWP9ooO3w5Y9ery8rw3OIus4z6dPxS/Ya8cWVdurk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1775772483231158.52694578288117; Thu, 9 Apr 2026 15:08:03 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wAxWR-0008Go-OR; Thu, 09 Apr 2026 18:06:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wAxWP-0008Ar-Jh for qemu-devel@nongnu.org; Thu, 09 Apr 2026 18:06:45 -0400 Received: from mail-dy1-x132d.google.com ([2607:f8b0:4864:20::132d]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wAxWN-0000cl-Cz for qemu-devel@nongnu.org; Thu, 09 Apr 2026 18:06:45 -0400 Received: by mail-dy1-x132d.google.com with SMTP id 5a478bee46e88-2ba9c484e5eso1507649eec.1 for ; Thu, 09 Apr 2026 15:06:43 -0700 (PDT) Received: from localhost.localdomain ([2804:7f4:c030:bb40:195d:78fd:ecba:d45]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2d561bde68bsm1534567eec.17.2026.04.09.15.06.38 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 09 Apr 2026 15:06:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775772402; x=1776377202; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=lbIyOfnciDg6afzmMw7/atMx/iFETQJzz2oWEz1fQAg=; b=EpK1SovZZZV0NGDNHV7/k0vCsQOSGkF34dwzsjVpzbYyLY3GobLQ98MGMLuaHYgEse rv7TrJWGKsgwX8J2Pi+DaE3HQoPXD0qQj56VhIHwZ5s+Je2H1yhdft46tKBZCELdgSYU KLBuH48vV6DR+8U/ytCyPMJThSPBdP4vdA7wfab6pRc2Yb7U71cQCJWGzcg4y2JS9Akr nr8omoHStdqx21AKvo7ccdY8sBmIy9H4962yifSaqgYDsnsGrWpCREtcyqptL1OB/Owm 1JmEA5TG4zHDC8e6VOq49GRRMSuStl3RxhxRl1mFRhv+AJ6Es3HT7pQJwLsiHtRDoq19 h38Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775772402; x=1776377202; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=lbIyOfnciDg6afzmMw7/atMx/iFETQJzz2oWEz1fQAg=; b=ciA7McVYqI2BLqhhidv53WyeKRvrVBpoeQu9fDW9Irxw8iz0qVt0fu3plR5z6jRmqW 6rZGHp15g7yw6pdNkDjfPDw42CeK2SRRNzbq7MlRkoqV20bry4uBKWCS8xGwIpRms90W zoBAl4BraKx7B7pxBQ1qJ4Htb+lIdLXanvugp9OkbnquBQvqwM8lflnRRO/1gIORviIl RgbJ9EI+4JkchenJ1aF0mtOoLCay6BIcWsty1micG5pov1HCs7BxlOHirAkJSzaKYc86 5NSUL0UCaWAOloEwDL0KUgeTwNJQZSubmxdOS2FO4UN9D7siUMtPYSbhtnWsE4+QG8AH KRMQ== X-Gm-Message-State: AOJu0Yw/qZwE81stxzgQdX1NPq4jwhVtwSoHSg9ouOJzki+ytfWSLJag 58H5HscD8DwaAmPQccROEAa9Gf+XBkFd+a9qIUGtQOVBBX5oOvGxXbGNc7p9ldgE X-Gm-Gg: AeBDies+QPh4dRSalLDbaeoQ1zAtxOG08oTFoxUv6quQG1jlhqNPJiOpqPia6Qmnai8 z0DrDIUYVApOWBBeANVzjpZ24zXt/xVf9bhCpHSDGPZoyu3qlNSnY8TPCb3T5O6Bwaxp8dPQtcp umRuQap57geA8WyKLSx5RGcof2Pb1GYKmqg+3f52z1uEKsgnxlrInY3GsopM1sON1fHFxEawx4a vBI5sJbH9FPD+OPiaRrXAzw8pKwXZyD76S+rP/UelUkCx+Y70g1+nZxFnMsgjiwnrY3k3gLSHuN c357YQkaLUlXReJvae3jGCcaQN8icbf0yIiKOSryAUzLD+9fdvnAIDKK9buslmrExuxiEY3kDKF aYyQq5xDYShnBMO7vJjvlPU1BIwOsWJDGutq2iSGTeYm58Yh2A4IPUbUedQA4cD1tAqVyqIQ4Eg YZgSKZQliiBRZBclehtdl1h+VM0g23S/a7qRkrkbSKYJqhvJ6Af0cTceKcB2mJJ3pWovkJJTdP X-Received: by 2002:a05:693c:3114:b0:2be:fe8:8b0d with SMTP id 5a478bee46e88-2d5887a3180mr530792eec.22.1775772401494; Thu, 09 Apr 2026 15:06:41 -0700 (PDT) From: Lucas Amaral To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, agraf@csgraf.de, peter.maydell@linaro.org, mohamed@unpredictable.fr, alex.bennee@linaro.org, richard.henderson@linaro.org, Lucas Amaral Subject: [PATCH v6 5/6] target/arm/emulate: add atomic, compare-and-swap, and PAC load Date: Thu, 9 Apr 2026 19:06:13 -0300 Message-ID: <20260409220614.65558-6-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: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::132d; envelope-from=lucaaamaral@gmail.com; helo=mail-dy1-x132d.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, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, 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 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1775772485250154101 Add emulation for remaining ISV=3D0 load/store instruction classes. Atomic memory operations (DDI 0487 C3.3.2): - LDADD, LDCLR, LDEOR, LDSET: arithmetic/logic atomics - LDSMAX, LDSMIN, LDUMAX, LDUMIN: signed/unsigned min/max - SWP: atomic swap Non-atomic read-modify-write, sufficient for MMIO where concurrent access is not a concern. Acquire/release semantics are ignored. Compare-and-swap (DDI 0487 C3.3.1): - CAS/CASA/CASAL/CASL: single-register compare-and-swap - CASP/CASPA/CASPAL/CASPL: register-pair compare-and-swap CASP validates even register pairs; odd or r31 returns UNHANDLED. Load with PAC (DDI 0487 C6.2.121): - LDRAA/LDRAB: pointer-authenticated load, offset/pre-indexed Pointer authentication is not emulated (equivalent to auth always succeeding), which is correct for MMIO since PAC is a software security mechanism, not a memory access semantic. Decodetree differences from TCG: - %ldra_imm extracts the raw S:imm9 field; the handler scales by << 3. TCG applies !function=3Dtimes_8 in the formatter. - @ldra uses wildcards for fixed opcode bits that TCG locks down (bits 31:30, bit 20, bit 11); the fixed bits are matched by the instruction pattern instead. - @cas is an explicit format template; TCG uses inline field extraction. CASP uses two explicit decode patterns for the 32/64-bit size variants. LDRA's offset immediate is stored raw in the decode; the handler scales by << 3. Signed-off-by: Lucas Amaral Reviewed-by: Mohamed Mediouni --- target/arm/emulate/a64-ldst.decode | 45 ++++++ target/arm/emulate/arm_emulate.c | 233 +++++++++++++++++++++++++++++ 2 files changed, 278 insertions(+) diff --git a/target/arm/emulate/a64-ldst.decode b/target/arm/emulate/a64-ld= st.decode index fadf6fd2..9292bfdf 100644 --- a/target/arm/emulate/a64-ldst.decode +++ b/target/arm/emulate/a64-ldst.decode @@ -16,6 +16,16 @@ # Load/store pair (GPR and SIMD/FP) &ldstpair rt2 rt rn imm sz sign w p =20 +# Atomic memory operations +&atomic rs rn rt a r sz + +# Compare-and-swap +&cas rs rn rt sz a r + +# Load with PAC (LDRAA/LDRAB, FEAT_PAuth) +%ldra_imm 22:s1 12:9 +&ldra rt rn imm m w + # Load/store register offset &ldst rm rn rt sign ext sz opt s =20 @@ -36,6 +46,15 @@ # Load/store pair: imm7 is signed, scaled by element size in handler @ldstpair .. ... . ... . imm:s7 rt2:5 rn:5 rt:5 &ldstpair =20 +# Atomics +@atomic sz:2 ... . .. a:1 r:1 . rs:5 . ... .. rn:5 rt:5 &atomic + +# Compare-and-swap: sz extracted by pattern (CAS) or set constant (CASP) +@cas .. ...... . a:1 . rs:5 r:1 ..... rn:5 rt:5 &cas + +# Load with PAC +@ldra .. ... . .. m:1 . . ......... w:1 . rn:5 rt:5 &ldra im= m=3D%ldra_imm + # Load/store register offset @ldst .. ... . .. .. . rm:5 opt:3 s:1 .. rn:5 rt:5 &ldst =20 @@ -241,6 +260,32 @@ STR_v 00 111 1 00 10 1 ..... ... . 10 ..... = ..... @ldst sign=3D0 ext=3D LDR_v sz:2 111 1 00 01 1 ..... ... . 10 ..... ..... @ldst sign= =3D0 ext=3D0 LDR_v 00 111 1 00 11 1 ..... ... . 10 ..... ..... @ldst sign= =3D0 ext=3D0 sz=3D4 =20 +### Compare-and-swap + +# CAS / CASA / CASAL / CASL +CAS sz:2 001000 1 . 1 ..... . 11111 ..... ..... @cas + +# CASP / CASPA / CASPAL / CASPL (pair: Rt,Rt+1 and Rs,Rs+1) +CASP 00 001000 0 . 1 ..... . 11111 ..... ..... @cas sz=3D2 +CASP 01 001000 0 . 1 ..... . 11111 ..... ..... @cas sz=3D3 + +### Atomic memory operations + +LDADD .. 111 0 00 . . 1 ..... 0000 00 ..... ..... @atomic +LDCLR .. 111 0 00 . . 1 ..... 0001 00 ..... ..... @atomic +LDEOR .. 111 0 00 . . 1 ..... 0010 00 ..... ..... @atomic +LDSET .. 111 0 00 . . 1 ..... 0011 00 ..... ..... @atomic +LDSMAX .. 111 0 00 . . 1 ..... 0100 00 ..... ..... @atomic +LDSMIN .. 111 0 00 . . 1 ..... 0101 00 ..... ..... @atomic +LDUMAX .. 111 0 00 . . 1 ..... 0110 00 ..... ..... @atomic +LDUMIN .. 111 0 00 . . 1 ..... 0111 00 ..... ..... @atomic +SWP .. 111 0 00 . . 1 ..... 1000 00 ..... ..... @atomic + +### Load with PAC (FEAT_PAuth) + +# LDRAA (M=3D0) / LDRAB (M=3D1), offset (W=3D0) / pre-indexed (W=3D1) +LDRA 11 111 0 00 . . 1 ......... . 1 ..... ..... @ldra + ### System instructions =E2=80=94 DC cache maintenance =20 # SYS with CRn=3DC7 covers all data cache operations (DC CIVAC, CVAC, etc.= ). diff --git a/target/arm/emulate/arm_emulate.c b/target/arm/emulate/arm_emul= ate.c index 7f876355..6601c9dc 100644 --- a/target/arm/emulate/arm_emulate.c +++ b/target/arm/emulate/arm_emulate.c @@ -547,6 +547,239 @@ static bool trans_LDXP(DisasContext *ctx, arg_stxr *a) return true; } =20 +/* + * Atomic memory operations (DDI 0487 C3.3.2) + * + * Non-atomic read-modify-write; sufficient for MMIO. + * Acquire/release semantics ignored (sequentially consistent by design). + */ + +typedef uint64_t (*atomic_op_fn)(uint64_t old, uint64_t operand, int bits); + +static uint64_t atomic_add(uint64_t old, uint64_t op, int bits) +{ + return old + op; +} + +static uint64_t atomic_clr(uint64_t old, uint64_t op, int bits) +{ + return old & ~op; +} + +static uint64_t atomic_eor(uint64_t old, uint64_t op, int bits) +{ + return old ^ op; +} + +static uint64_t atomic_set(uint64_t old, uint64_t op, int bits) +{ + return old | op; +} + +static uint64_t atomic_smax(uint64_t old, uint64_t op, int bits) +{ + int64_t a =3D sextract64(old, 0, bits); + int64_t b =3D sextract64(op, 0, bits); + return (a >=3D b) ? old : op; +} + +static uint64_t atomic_smin(uint64_t old, uint64_t op, int bits) +{ + int64_t a =3D sextract64(old, 0, bits); + int64_t b =3D sextract64(op, 0, bits); + return (a <=3D b) ? old : op; +} + +static uint64_t atomic_umax(uint64_t old, uint64_t op, int bits) +{ + uint64_t mask =3D (bits =3D=3D 64) ? UINT64_MAX : (1ULL << bits) - 1; + return ((old & mask) >=3D (op & mask)) ? old : op; +} + +static uint64_t atomic_umin(uint64_t old, uint64_t op, int bits) +{ + uint64_t mask =3D (bits =3D=3D 64) ? UINT64_MAX : (1ULL << bits) - 1; + return ((old & mask) <=3D (op & mask)) ? old : op; +} + +static bool do_atomic(DisasContext *ctx, arg_atomic *a, atomic_op_fn fn) +{ + int esize =3D 1 << a->sz; + int bits =3D 8 * esize; + uint64_t va =3D base_read(ctx, a->rn); + uint8_t buf[8]; + + if (mem_read(ctx, va, buf, esize) !=3D 0) { + return true; + } + + uint64_t old =3D mem_ld(ctx, buf, esize); + uint64_t operand =3D gpr_read(ctx, a->rs); + uint64_t result =3D fn(old, operand, bits); + + mem_st(ctx, buf, esize, result); + if (mem_write(ctx, va, buf, esize) !=3D 0) { + return true; + } + + /* Rt receives the old value (before modification) */ + gpr_write(ctx, a->rt, old); + return true; +} + +static bool trans_LDADD(DisasContext *ctx, arg_atomic *a) +{ + return do_atomic(ctx, a, atomic_add); +} + +static bool trans_LDCLR(DisasContext *ctx, arg_atomic *a) +{ + return do_atomic(ctx, a, atomic_clr); +} + +static bool trans_LDEOR(DisasContext *ctx, arg_atomic *a) +{ + return do_atomic(ctx, a, atomic_eor); +} + +static bool trans_LDSET(DisasContext *ctx, arg_atomic *a) +{ + return do_atomic(ctx, a, atomic_set); +} + +static bool trans_LDSMAX(DisasContext *ctx, arg_atomic *a) +{ + return do_atomic(ctx, a, atomic_smax); +} + +static bool trans_LDSMIN(DisasContext *ctx, arg_atomic *a) +{ + return do_atomic(ctx, a, atomic_smin); +} + +static bool trans_LDUMAX(DisasContext *ctx, arg_atomic *a) +{ + return do_atomic(ctx, a, atomic_umax); +} + +static bool trans_LDUMIN(DisasContext *ctx, arg_atomic *a) +{ + return do_atomic(ctx, a, atomic_umin); +} + +static bool trans_SWP(DisasContext *ctx, arg_atomic *a) +{ + int esize =3D 1 << a->sz; + uint64_t va =3D base_read(ctx, a->rn); + uint8_t buf[8]; + + if (mem_read(ctx, va, buf, esize) !=3D 0) { + return true; + } + + uint64_t old =3D mem_ld(ctx, buf, esize); + mem_st(ctx, buf, esize, gpr_read(ctx, a->rs)); + if (mem_write(ctx, va, buf, esize) !=3D 0) { + return true; + } + + gpr_write(ctx, a->rt, old); + return true; +} + +/* Compare-and-swap: CAS, CASP (DDI 0487 C3.3.1) */ + +static bool trans_CAS(DisasContext *ctx, arg_cas *a) +{ + int esize =3D 1 << a->sz; + uint64_t va =3D base_read(ctx, a->rn); + uint8_t buf[8]; + + if (mem_read(ctx, va, buf, esize) !=3D 0) { + return true; + } + + uint64_t current =3D mem_ld(ctx, buf, esize); + uint64_t mask =3D (esize =3D=3D 8) ? UINT64_MAX : (1ULL << (8 * esize)= ) - 1; + uint64_t compare =3D gpr_read(ctx, a->rs) & mask; + + if ((current & mask) =3D=3D compare) { + uint64_t newval =3D gpr_read(ctx, a->rt) & mask; + mem_st(ctx, buf, esize, newval); + if (mem_write(ctx, va, buf, esize) !=3D 0) { + return true; + } + } + + /* Rs receives the old memory value (whether or not swap occurred) */ + gpr_write(ctx, a->rs, current); + return true; +} + +/* CASP: compare-and-swap pair (Rs,Rs+1 compared; Rt,Rt+1 stored) */ +static bool trans_CASP(DisasContext *ctx, arg_cas *a) +{ + /* CASP requires even register pairs; odd or r31 is UNPREDICTABLE */ + if ((a->rs & 1) || a->rs >=3D 31 || (a->rt & 1) || a->rt >=3D 31) { + return false; + } + + int esize =3D 1 << a->sz; /* per-register size */ + uint64_t va =3D base_read(ctx, a->rn); + uint8_t buf[16]; + + if (mem_read(ctx, va, buf, 2 * esize) !=3D 0) { + return true; + } + uint64_t cur1 =3D mem_ld(ctx, buf, esize); + uint64_t cur2 =3D mem_ld(ctx, buf + esize, esize); + + uint64_t mask =3D (esize =3D=3D 8) ? UINT64_MAX : (1ULL << (8 * esize)= ) - 1; + uint64_t cmp1 =3D gpr_read(ctx, a->rs) & mask; + uint64_t cmp2 =3D gpr_read(ctx, a->rs + 1) & mask; + + if ((cur1 & mask) =3D=3D cmp1 && (cur2 & mask) =3D=3D cmp2) { + uint64_t new1 =3D gpr_read(ctx, a->rt) & mask; + uint64_t new2 =3D gpr_read(ctx, a->rt + 1) & mask; + mem_st(ctx, buf, esize, new1); + mem_st(ctx, buf + esize, esize, new2); + if (mem_write(ctx, va, buf, 2 * esize) !=3D 0) { + return true; + } + } + + gpr_write(ctx, a->rs, cur1); + gpr_write(ctx, a->rs + 1, cur2); + return true; +} + +/* + * Load with PAC: LDRAA / LDRAB (FEAT_PAuth) + * (DDI 0487 C6.2.121) + * + * Pointer authentication is not emulated -- the base register is used + * directly (equivalent to auth always succeeding). + */ + +static bool trans_LDRA(DisasContext *ctx, arg_ldra *a) +{ + int64_t offset =3D (int64_t)a->imm << 3; /* S:imm9, scaled by 8 */ + uint64_t base =3D base_read(ctx, a->rn); + uint64_t va =3D base + offset; /* auth not emulated */ + uint8_t buf[8]; + + if (mem_read(ctx, va, buf, 8) !=3D 0) { + return true; + } + + gpr_write(ctx, a->rt, mem_ld(ctx, buf, 8)); + + if (a->w) { + base_write(ctx, a->rn, va); + } + return true; +} + /* PRFM, DC cache maintenance -- treated as NOP */ static bool trans_NOP(DisasContext *ctx, arg_NOP *a) { --=20 2.52.0 From nobody Sat Apr 11 17:07:29 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com Return-Path: Received: from lists.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 177577244268596.56787456506595; Thu, 9 Apr 2026 15:07:22 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wAxWT-0008K3-FL; Thu, 09 Apr 2026 18:06:49 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wAxWS-0008IQ-Hb for qemu-devel@nongnu.org; Thu, 09 Apr 2026 18:06:48 -0400 Received: from mail-dy1-x1332.google.com ([2607:f8b0:4864:20::1332]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wAxWQ-0000d7-Ku for qemu-devel@nongnu.org; Thu, 09 Apr 2026 18:06:48 -0400 Received: by mail-dy1-x1332.google.com with SMTP id 5a478bee46e88-2cc4c693d59so971785eec.1 for ; Thu, 09 Apr 2026 15:06:46 -0700 (PDT) Received: from localhost.localdomain ([2804:7f4:c030:bb40:195d:78fd:ecba:d45]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2d561bde68bsm1534567eec.17.2026.04.09.15.06.41 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 09 Apr 2026 15:06:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775772405; x=1776377205; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=VoJVdciZFaewroq0cySKl+vu/S+aD/kerrA4/hB7jSw=; b=kMhxRzX+KqRMLJI2Y7HOEVZkxbpmG+T80eMgG6aWzMA3Ks6e7pveo8SxzJrfL5WseH QN5zrnUDUr4Xx+jdzGn3/9SnWyXQ4uNc0mPChXcXNPKSlacVo0i00jrTKAbo85YQWuyp VMKjM0JzHxQa7/ljpbjO+FdQ3aDbF72M+I/XjDg/ApAjmUGTj/o3E7hTPTRyHh4hHxjG cNoddiZbfqPKuAPaZlQa/NFvlJfD6vgZxdH4xeTWZcF4p+SFgJF+yaze1HC+ORS2Noxi lnFSQT9zYOKdbu5UcN+1iKY8tpiibvjAGcx+jxdy5thjPcAR4SJYSDpK2egZ0mOdAI32 MCcA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775772405; x=1776377205; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=VoJVdciZFaewroq0cySKl+vu/S+aD/kerrA4/hB7jSw=; b=D2/a6fJwc/wtpxUOf5xgmRqlKTvO2s7YYO0zf50tUZ2ov0IpvFQu0ATghBUNzhy5zR nKt+qrIC160VsBzxbzUIUUglz2+7b2ler0F+/xQaZ7nSljM5vgxzXVIwF+jHS0VPZEzp BiGLMwVPSmZBJuR+3eQF/EeqplUWkmae+MLfVyHrnfoK1R7LmMKTe8FMoAvI32iDMxL4 fo2KPPv81ysNBjD8ymQ5Gp+3L/52LvD3Np0Dejzk5FspX2RzptLCA5v6cB4gCFnNDuQu sSHqG9ZHl6yZGZwOlxHC1H749X6hKIOevfo1awI3Af0FB9CkGnZFR3J3d/lgQjh3aWzI DrDA== X-Gm-Message-State: AOJu0YxnwjNnZeZjXQ68GY/r0y5E+hAXsCCkC+iEScvPKWdRnBza/dRO 7CUVUbS5Wly17Bvv2uxHtN92bELoN9PFAQg3byyY/FHaVFJGkU/NjT3pODD+SQXv X-Gm-Gg: AeBDieudzMmZSUjSUzEd499bEVB38H/R/pIHurvn8Ik/3tz1j68w4deMQOpLyTQ0nUk xQz091rfHW+b5YPC/XdU7J7PE+c/wj+O9++96iCvpniRxiec8A6xsUwE0yDFJrjKWa6DInKKEAx 2n4qkJfSUZ3qIt7YBrYPx1zsIIfNmJpu68YHlFpxUY7mwM0O0rCb+Q6qtakVMvc0HrMkg/vSMxP xXNcL5rcFIRc/zGuN2DTRQbK62dm3J47px9ZwDSgme9stggWwq+B/dniQOa2bEH1QAq7jjyJom6 0m4/iJFztFSnrxFRP07IgevgvkUKNJ+ojgeo3ORmHapubG9C+PJ1iMO+ExpY1n0XTfHXPUJo07+ 2Ru5uoqkg6TwmTcR7/sW2qxe5dGSSXt4ROWy3bLhsUq2YRxIzDlWeraBNLMV3GKaEn1S3xyqcAb k+yxl2+SuSmEd8ZqFs/a2X8XmjB9SJSzqNBA+rj/uV+uql+JvtX8OhmAaZpX9zjw== X-Received: by 2002:a05:7300:6d03:b0:2c1:778:d897 with SMTP id 5a478bee46e88-2d5888a07c5mr501111eec.21.1775772404920; Thu, 09 Apr 2026 15:06:44 -0700 (PDT) From: Lucas Amaral To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, agraf@csgraf.de, peter.maydell@linaro.org, mohamed@unpredictable.fr, alex.bennee@linaro.org, richard.henderson@linaro.org, Lucas Amaral Subject: [PATCH v6 6/6] target/arm/hvf, whpx: wire ISV=0 emulation for data aborts Date: Thu, 9 Apr 2026 19:06:14 -0300 Message-ID: <20260409220614.65558-7-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-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::1332; envelope-from=lucaaamaral@gmail.com; helo=mail-dy1-x1332.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, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham 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 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1775772445238154100 Content-Type: text/plain; charset="utf-8" When a data abort with ISV=3D0 occurs during MMIO emulation, the syndrome register does not carry the access size or target register. Previously this hit an assert(isv) and killed the VM. Replace the assert with instruction fetch + decode + emulate using the shared library in target/arm/emulate/. The faulting instruction is read from guest memory via cpu_memory_rw_debug(), decoded by the decodetree- generated decoder, and emulated against the vCPU register file. Both HVF (macOS) and WHPX (Windows Hyper-V) use the same pattern: 1. cpu_synchronize_state() to flush hypervisor registers 2. Fetch 4-byte instruction at env->pc 3. arm_emul_insn(env, insn) 4. On success, advance PC past the emulated instruction If the instruction is unhandled or a memory error occurs, a synchronous external abort is injected into the guest via syn_data_abort_no_iss() with fnv=3D1 and fsc=3D0x10, matching the syndrome that KVM uses in kvm_inject_arm_sea(). The guest kernel's fault handler then reports the error through its normal data abort path. WHPX adds a whpx_inject_data_abort() helper and adjusts the whpx_handle_mmio() return convention so the caller skips PC advancement when an exception has been injected. Signed-off-by: Lucas Amaral --- target/arm/hvf/hvf.c | 46 ++++++++++++++++++++++++++-- target/arm/whpx/whpx-all.c | 61 +++++++++++++++++++++++++++++++++++++- 2 files changed, 103 insertions(+), 4 deletions(-) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 5fc8f6bb..000e54bd 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -32,6 +32,7 @@ #include "arm-powerctl.h" #include "target/arm/cpu.h" #include "target/arm/internals.h" +#include "emulate/arm_emulate.h" #include "target/arm/multiprocessing.h" #include "target/arm/gtimer.h" #include "target/arm/trace.h" @@ -2175,10 +2176,49 @@ static int hvf_handle_exception(CPUState *cpu, hv_v= cpu_exit_exception_t *excp) assert(!s1ptw); =20 /* - * TODO: ISV will be 0 for SIMD or SVE accesses. - * Inject the exception into the guest. + * ISV=3D0: syndrome doesn't carry access size/register info. + * Fetch and emulate via target/arm/emulate/. */ - assert(isv); + if (!isv) { + ARMCPU *arm_cpu =3D ARM_CPU(cpu); + CPUARMState *env =3D &arm_cpu->env; + uint32_t insn; + ArmEmulResult r; + + cpu_synchronize_state(cpu); + + if (cpu_memory_rw_debug(cpu, env->pc, + (uint8_t *)&insn, 4, false) !=3D 0) { + bool same_el =3D arm_current_el(env) =3D=3D 1; + uint32_t esr =3D syn_data_abort_no_iss(same_el, + 1, 0, 0, 0, iswrite, 0x10); + + error_report("HVF: cannot read insn at pc=3D0x%" PRIx64, + (uint64_t)env->pc); + env->exception.vaddress =3D excp->virtual_address; + hvf_raise_exception(cpu, EXCP_DATA_ABORT, esr, 1); + break; + } + + r =3D arm_emul_insn(env, insn); + if (r =3D=3D ARM_EMUL_UNHANDLED || r =3D=3D ARM_EMUL_ERR_MEM) { + bool same_el =3D arm_current_el(env) =3D=3D 1; + uint32_t esr =3D syn_data_abort_no_iss(same_el, + 1, 0, 0, 0, iswrite, 0x10); + + error_report("HVF: ISV=3D0 %s insn 0x%08x at " + "pc=3D0x%" PRIx64 ", injecting data abort", + r =3D=3D ARM_EMUL_UNHANDLED ? "unhandled" + : "memory error", + insn, (uint64_t)env->pc); + env->exception.vaddress =3D excp->virtual_address; + hvf_raise_exception(cpu, EXCP_DATA_ABORT, esr, 1); + break; + } + + advance_pc =3D true; + break; + } =20 /* * Emulate MMIO. diff --git a/target/arm/whpx/whpx-all.c b/target/arm/whpx/whpx-all.c index 513551be..0c04073e 100644 --- a/target/arm/whpx/whpx-all.c +++ b/target/arm/whpx/whpx-all.c @@ -29,6 +29,7 @@ #include "syndrome.h" #include "target/arm/cpregs.h" #include "internals.h" +#include "emulate/arm_emulate.h" =20 #include "system/whpx-internal.h" #include "system/whpx-accel-ops.h" @@ -352,6 +353,27 @@ static void whpx_set_gp_reg(CPUState *cpu, int rt, uin= t64_t val) whpx_set_reg(cpu, reg, reg_val); } =20 +/* + * Inject a synchronous external abort (data abort) into the guest. + * Used when ISV=3D0 instruction emulation fails. Matches the syndrome + * that KVM uses in kvm_inject_arm_sea(). + */ +static void whpx_inject_data_abort(CPUState *cpu, bool iswrite) +{ + ARMCPU *arm_cpu =3D ARM_CPU(cpu); + CPUARMState *env =3D &arm_cpu->env; + bool same_el =3D arm_current_el(env) =3D=3D 1; + uint32_t esr =3D syn_data_abort_no_iss(same_el, 1, 0, 0, 0, iswrite, 0= x10); + + cpu->exception_index =3D EXCP_DATA_ABORT; + env->exception.target_el =3D 1; + env->exception.syndrome =3D esr; + + bql_lock(); + arm_cpu_do_interrupt(cpu); + bql_unlock(); +} + static int whpx_handle_mmio(CPUState *cpu, WHV_MEMORY_ACCESS_CONTEXT *ctx) { uint64_t syndrome =3D ctx->Syndrome; @@ -366,7 +388,40 @@ static int whpx_handle_mmio(CPUState *cpu, WHV_MEMORY_= ACCESS_CONTEXT *ctx) uint64_t val =3D 0; =20 assert(!cm); - assert(isv); + + /* + * ISV=3D0: syndrome doesn't carry access size/register info. + * Fetch and decode the faulting instruction via the emulation library. + */ + if (!isv) { + ARMCPU *arm_cpu =3D ARM_CPU(cpu); + CPUARMState *env =3D &arm_cpu->env; + uint32_t insn; + ArmEmulResult r; + + cpu_synchronize_state(cpu); + + if (cpu_memory_rw_debug(cpu, env->pc, + (uint8_t *)&insn, 4, false) !=3D 0) { + error_report("WHPX: cannot read insn at pc=3D0x%" PRIx64, + (uint64_t)env->pc); + whpx_inject_data_abort(cpu, iswrite); + return 1; + } + + r =3D arm_emul_insn(env, insn); + if (r =3D=3D ARM_EMUL_UNHANDLED || r =3D=3D ARM_EMUL_ERR_MEM) { + error_report("WHPX: ISV=3D0 %s insn 0x%08x at " + "pc=3D0x%" PRIx64 ", injecting data abort", + r =3D=3D ARM_EMUL_UNHANDLED ? "unhandled" + : "memory error", + insn, (uint64_t)env->pc); + whpx_inject_data_abort(cpu, iswrite); + return 1; + } + + return 0; + } =20 if (iswrite) { val =3D whpx_get_gp_reg(cpu, srt); @@ -451,6 +506,10 @@ int whpx_vcpu_run(CPUState *cpu) } =20 ret =3D whpx_handle_mmio(cpu, &vcpu->exit_ctx.MemoryAccess); + if (ret > 0) { + advance_pc =3D false; + ret =3D 0; + } break; case WHvRunVpExitReasonCanceled: cpu->exception_index =3D EXCP_INTERRUPT; --=20 2.52.0