From nobody Sat May 4 12:55:06 2024 Delivered-To: importer2@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1623231540; cv=none; d=zohomail.com; s=zohoarc; b=e/8AkKF4vX8yC9JN19SLltLunjRiTgvOEKVLR9cy/ZFYlwjunwYh+nRDbMcT3O2KumBNPP4uMt+xKUnooDjALabc4tB/YQ8+Xey24ilmlfFJduaG2fYCUdlQ+hnWsfwx0tvTXrKWPf8K9Dcqh6/6/X6GbBTum0LiCNAIpDZKMNI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1623231540; h=Content-Transfer-Encoding:Date:From:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Sender:Subject:To; bh=3GglEI+lKPnC5aLUe4GSexshdO1w/At2osEr7+BahWQ=; b=AyTrIzyPGYURZrodfx9lq6LssMkGpoK0534/3kJo+qB9aeEP4lWa3K6YhutPxClDf9bguJBKo0uqkLZ4/xmAsqFyE18hKYnhQJQVSr3El7VgjqgOC7lxdYFpMIuAewpyw4diUOD+qDN8SXz/3vRYc02dSl+kAk6iViJ92yQLmz8= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer2=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1623231540812743.2741214671751; Wed, 9 Jun 2021 02:39:00 -0700 (PDT) Received: from localhost ([::1]:51418 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lqufr-0008Vd-KN for importer2@patchew.org; Wed, 09 Jun 2021 05:38:59 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:34802) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lqucp-0006CK-0L for qemu-devel@nongnu.org; Wed, 09 Jun 2021 05:35:51 -0400 Received: from mail.ilande.co.uk ([2001:41c9:1:41f::167]:34920 helo=mail.default.ilande.bv.iomart.io) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lqucm-0004Zt-GE for qemu-devel@nongnu.org; Wed, 09 Jun 2021 05:35:50 -0400 Received: from host109-155-147-70.range109-155.btcentralplus.com ([109.155.147.70] helo=kentang.home) by mail.default.ilande.bv.iomart.io with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lqucV-00051e-Rl; Wed, 09 Jun 2021 10:35:36 +0100 From: Mark Cave-Ayland To: qemu-devel@nongnu.org, richard.henderson@linaro.org, alex.bennee@linaro.org, peter.maydell@linaro.org Date: Wed, 9 Jun 2021 10:35:28 +0100 Message-Id: <20210609093528.9616-1-mark.cave-ayland@ilande.co.uk> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-SA-Exim-Connect-IP: 109.155.147.70 X-SA-Exim-Mail-From: mark.cave-ayland@ilande.co.uk Subject: [RFC PATCH] cputlb: implement load_helper_unaligned() for unaligned loads X-SA-Exim-Version: 4.2.1 (built Wed, 08 May 2019 21:11:16 +0000) X-SA-Exim-Scanned: Yes (on mail.default.ilande.bv.iomart.io) 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+importer2=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2001:41c9:1:41f::167; envelope-from=mark.cave-ayland@ilande.co.uk; helo=mail.default.ilande.bv.iomart.io X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer2=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" [RFC because this is currently only lightly tested and there have been some discussions about whether this should be handled elsewhere in the memory AP= I] If an unaligned load is required then the load is split into 2 separate acc= esses and combined together within load_helper(). This does not work correctly wi= th MMIO accesses because the original access size is used for both individual accesses causing the little and big endian combine to return the wrong resu= lt. There is already a similar solution in place for store_helper() where an un= aligned access is handled by a separate store_helper_unaligned() function which ins= tead of using the original access size, uses a single-byte access size to shift = and combine the result correctly regardless of the orignal access size or endia= n. Implement a similar load_helper_unaligned() function which uses the same ap= proach for unaligned loads to return the correct result according to the original = test case. Signed-off-by: Mark Cave-Ayland Resolves: https://gitlab.com/qemu-project/qemu/-/issues/360 --- accel/tcg/cputlb.c | 99 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 82 insertions(+), 17 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index f24348e979..1845929e99 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1851,6 +1851,85 @@ load_memop(const void *haddr, MemOp op) } } =20 +static uint64_t __attribute__((noinline)) +load_helper_unaligned(CPUArchState *env, target_ulong addr, uintptr_t reta= ddr, + size_t size, uintptr_t mmu_idx, bool code_read, + bool big_endian) +{ + uintptr_t index, index2; + CPUTLBEntry *entry, *entry2; + const size_t tlb_off =3D code_read ? + offsetof(CPUTLBEntry, addr_code) : offsetof(CPUTLBEntry, addr_read= ); + const MMUAccessType access_type =3D + code_read ? MMU_INST_FETCH : MMU_DATA_LOAD; + target_ulong page2, tlb_addr, tlb_addr2; + uint64_t val =3D 0; + TCGMemOpIdx oi; + size_t size2; + int i; + + /* + * Ensure the second page is in the TLB. Note that the first page + * is already guaranteed to be filled, and that the second page + * cannot evict the first. + */ + page2 =3D (addr + size) & TARGET_PAGE_MASK; + size2 =3D (addr + size) & ~TARGET_PAGE_MASK; + index2 =3D tlb_index(env, mmu_idx, page2); + entry2 =3D tlb_entry(env, mmu_idx, page2); + + tlb_addr2 =3D code_read ? entry2->addr_code : entry2->addr_read; + if (!tlb_hit_page(tlb_addr2, page2)) { + if (!victim_tlb_hit(env, mmu_idx, index2, tlb_off, page2)) { + tlb_fill(env_cpu(env), page2, size2, access_type, + mmu_idx, retaddr); + index2 =3D tlb_index(env, mmu_idx, page2); + entry2 =3D tlb_entry(env, mmu_idx, page2); + } + tlb_addr2 =3D code_read ? entry2->addr_code : entry2->addr_read; + } + + index =3D tlb_index(env, mmu_idx, addr); + entry =3D tlb_entry(env, mmu_idx, addr); + tlb_addr =3D code_read ? entry->addr_code : entry->addr_read; + + /* + * Handle watchpoints + */ + if (unlikely(tlb_addr & TLB_WATCHPOINT)) { + cpu_check_watchpoint(env_cpu(env), addr, size - size2, + env_tlb(env)->d[mmu_idx].iotlb[index].attrs, + BP_MEM_READ, retaddr); + } + if (unlikely(tlb_addr2 & TLB_WATCHPOINT)) { + cpu_check_watchpoint(env_cpu(env), page2, size2, + env_tlb(env)->d[mmu_idx].iotlb[index2].attrs, + BP_MEM_READ, retaddr); + } + + /* + * XXX: not efficient, but simple. + * This loop must go in the forward direction to avoid issues + * with self-modifying code in Windows 64-bit. + */ + oi =3D make_memop_idx(MO_UB, mmu_idx); + if (big_endian) { + for (i =3D 0; i < size; ++i) { + /* Big-endian load. */ + uint8_t val8 =3D helper_ret_ldub_mmu(env, addr + i, oi, retadd= r); + val |=3D val8 << (((size - 1) * 8) - (i * 8)); + } + } else { + for (i =3D 0; i < size; ++i) { + /* Little-endian load. */ + uint8_t val8 =3D helper_ret_ldub_mmu(env, addr + i, oi, retadd= r); + val |=3D val8 << (i * 8); + } + } + + return val; +} + static inline uint64_t QEMU_ALWAYS_INLINE load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr, MemOp op, bool code_read, @@ -1893,7 +1972,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCG= MemOpIdx oi, CPUIOTLBEntry *iotlbentry; bool need_swap; =20 - /* For anything that is unaligned, recurse through full_load. */ + /* For anything that is unaligned, recurse through byte loads. */ if ((addr & (size - 1)) !=3D 0) { goto do_unaligned_access; } @@ -1932,23 +2011,9 @@ load_helper(CPUArchState *env, target_ulong addr, TC= GMemOpIdx oi, if (size > 1 && unlikely((addr & ~TARGET_PAGE_MASK) + size - 1 >=3D TARGET_PAGE_SIZE)) { - target_ulong addr1, addr2; - uint64_t r1, r2; - unsigned shift; do_unaligned_access: - addr1 =3D addr & ~((target_ulong)size - 1); - addr2 =3D addr1 + size; - r1 =3D full_load(env, addr1, oi, retaddr); - r2 =3D full_load(env, addr2, oi, retaddr); - shift =3D (addr & (size - 1)) * 8; - - if (memop_big_endian(op)) { - /* Big-endian combine. */ - res =3D (r1 << shift) | (r2 >> ((size * 8) - shift)); - } else { - /* Little-endian combine. */ - res =3D (r1 >> shift) | (r2 << ((size * 8) - shift)); - } + res =3D load_helper_unaligned(env, addr, retaddr, size, mmu_idx, + code_read, memop_big_endian(op)); return res & MAKE_64BIT_MASK(0, size * 8); } =20 --=20 2.20.1