From nobody Mon May 15 15:42:23 2023 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4QKkC34m5jz4BlV1; Mon, 15 May 2023 15:42:23 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4QKkC34K9kz3H0h; Mon, 15 May 2023 15:42:23 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1684165343; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=HLkF/QLAlapuGTtud/FhTBouC6k8DoHPEUtZGPod2Ak=; b=EITncPQv3H3C7aYoEovuCPPN/57/wjU7IH1Z/MvrvRk6JphpAabVRed+VfyZTUvTNtcPx0 rTodn2xQsHfT/6/c5oIwu5PXLuhruvrjRqqPFMtK65pImHVk+PUe4/IhHgFU2JEWLuVWko ddd0sayCcP3KNzNuoxuCqCIBKGrRogRwVMIuiOGUaLl+FAIXkPN+GoBnIAeOzKyvfF5m/d VxNinEMJgn/KyA2NC29T1+Cl5UU/M/4ptzjSSJ4DpTIRlz38/VRgIrVrrjrsAnmwfMWJnH 3spZituy8csuB0BfHQugdIyWD+AjjQwN+ny3wxriSO1a+tEA19cUEBpS8coJFQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1684165343; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=HLkF/QLAlapuGTtud/FhTBouC6k8DoHPEUtZGPod2Ak=; b=MSEWHOQhs4/TugvMx00BUMbDy2t4JQb08QklwBout4u4/2sqHogBxIz/mZvohXqcFuJ6O4 AVxHdfg23OVmRdkddGCXGL6cm1Qazm7ayC7AIguLHZps1dfWNcgGuevl1NypbQFfL2mKUg XJfQ061uoZUNgbUYoT4P4vYb83Irrl9owJmdQXt0tz1LbLcD9/GccVUZVOfz/mbrT/hCGo IbN52jPUs9uiraUBHxmaHwdf5UaVA2VBvmhX/lOATGJG/7abtzo7w6egAOOy0i1lLjVtKZ cdSPb9jflhm2KdP6TaKO/wEUlwp9QsdZLM1I8Is77ep5oDkKg8WUG2nfoJM9hQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1684165343; a=rsa-sha256; cv=none; b=dSkTWHSXx6g4oFSbrnvuqMUG0mhe7Mhyu/dkD8Ttl9YjYaRZeJ4de/TAarM3SknePRX1Oj FwV2GOtXBBlyPnZbENAB4dg7yjafhh3D6wkeBY5KSNh1Cta+zl+3UbhieD+1LC7CgLm2ux tgGCMyjyJqdT0NkNRJYib+/rJYFqCMN0is9uQk4UjZGsCuIZhRevg8eJah0vk//kyxgLp5 W9dqlIF71aTUn8tEh42AdkPmuE+7qJTD/NDj+7/+o7LaFAZGPpRUvCukVqE3ps0zRj08Ml Ww8fc05kZP/PStrKtLCbD1Nyl+Vt7FRs3qFeYfYt0ps4IPgQzAjIkI2FcU4V+A== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4QKkC33NgPzmHw; Mon, 15 May 2023 15:42:23 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 34FFgNj9071755; Mon, 15 May 2023 15:42:23 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 34FFgN7D071754; Mon, 15 May 2023 15:42:23 GMT (envelope-from git) Date: Mon, 15 May 2023 15:42:23 GMT Message-Id: <202305151542.34FFgN7D071754@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kyle Evans Subject: git: 4b500174dd2d - main - arm64: emulate swp/swpb instructions List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kevans X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 4b500174dd2d1e16dcb87c22364f724472c82edc Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=4b500174dd2d1e16dcb87c22364f724472c82edc commit 4b500174dd2d1e16dcb87c22364f724472c82edc Author: Kyle Evans AuthorDate: 2023-05-15 15:42:10 +0000 Commit: Kyle Evans CommitDate: 2023-05-15 15:42:10 +0000 arm64: emulate swp/swpb instructions Add another undefined instruction handler for compat32 and watch out for SWP/SWPB instructions. SWP/SWPB were deprecated in ARMv6 and declared obsolete in ARMv7, but this implementation is motivated by some proprietary software that still uses SWP/SWPB. Because it's deprecated, emulation is pushed back behind a sysctl that defaults to OFF in GENERIC so that it doesn't potentially adversely affect package builds; it's unknown whether software may test for a functional swp/swpb instruction with the desire of using it later, so we err on the side of caution to ensure we don't end up with swp/swpb use in freebsd/arm packages (which are built on aarch64). The EMUL_SWP config option may be used to enable emulation by default in environments where emulation is desired and won't really be turned off. Reviewed by: andrew, mmel (both earlier version) Sponsored by: Stormshield Sponsored by: Klara, Inc. Differential Revision: https://reviews.freebsd.org/D39667 --- sys/arm64/arm64/freebsd32_machdep.c | 4 + sys/arm64/arm64/undefined.c | 162 ++++++++++++++++++++++++++++++++++++ sys/conf/options.arm64 | 2 + 3 files changed, 168 insertions(+) diff --git a/sys/arm64/arm64/freebsd32_machdep.c b/sys/arm64/arm64/freebsd32_machdep.c index 5fadef74df87..44f35f1b2abf 100644 --- a/sys/arm64/arm64/freebsd32_machdep.c +++ b/sys/arm64/arm64/freebsd32_machdep.c @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -55,6 +56,9 @@ _Static_assert(sizeof(struct siginfo32) == 64, "struct siginfo32 size incorrect" extern void freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); +SYSCTL_NODE(_compat, OID_AUTO, arm, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, + "32-bit mode"); + /* * The first two fields of a ucontext_t are the signal mask and the machine * context. The next field is uc_link; we want to avoid destroying the link diff --git a/sys/arm64/arm64/undefined.c b/sys/arm64/arm64/undefined.c index 1feb242db060..7f436aaef6e5 100644 --- a/sys/arm64/arm64/undefined.c +++ b/sys/arm64/arm64/undefined.c @@ -39,14 +39,47 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include +#include #include +#define _MD_WANT_SWAPWORD +#include +#include #include #include +#include +#include + +/* Low bit masked off */ +#define INSN_COND(insn) ((insn >> 28) & ~0x1) +#define INSN_COND_INVERTED(insn) ((insn >> 28) & 0x1) +#define INSN_COND_EQ 0x00 /* NE */ +#define INSN_COND_CS 0x02 /* CC */ +#define INSN_COND_MI 0x04 /* PL */ +#define INSN_COND_VS 0x06 /* VC */ +#define INSN_COND_HI 0x08 /* LS */ +#define INSN_COND_GE 0x0a /* LT */ +#define INSN_COND_GT 0x0c /* LE */ +#define INSN_COND_AL 0x0e /* Always */ + MALLOC_DEFINE(M_UNDEF, "undefhandler", "Undefined instruction handler data"); +#ifdef COMPAT_FREEBSD32 +#ifndef EMUL_SWP +#define EMUL_SWP 0 +#endif + +SYSCTL_DECL(_compat_arm); + +static bool compat32_emul_swp = EMUL_SWP; +SYSCTL_BOOL(_compat_arm, OID_AUTO, emul_swp, + CTLFLAG_RWTUN | CTLFLAG_MPSAFE, &compat32_emul_swp, 0, + "Enable SWP/SWPB emulation"); +#endif + struct undef_handler { LIST_ENTRY(undef_handler) uh_link; undef_handler_t uh_handler; @@ -88,6 +121,54 @@ id_aa64mmfr2_handler(vm_offset_t va, uint32_t insn, struct trapframe *frame, return (0); } +static bool +arm_cond_match(uint32_t insn, struct trapframe *frame) +{ + uint64_t spsr; + uint32_t cond; + bool invert; + bool match; + + /* + * Generally based on the function of the same name in NetBSD, though + * condition bits left in their original position rather than shifting + * over the low bit that indicates inversion for quicker sanity checking + * against spec. + */ + spsr = frame->tf_spsr; + cond = INSN_COND(insn); + invert = INSN_COND_INVERTED(insn); + + switch (cond) { + case INSN_COND_EQ: + match = (spsr & PSR_Z) != 0; + break; + case INSN_COND_CS: + match = (spsr & PSR_C) != 0; + break; + case INSN_COND_MI: + match = (spsr & PSR_N) != 0; + break; + case INSN_COND_VS: + match = (spsr & PSR_V) != 0; + break; + case INSN_COND_HI: + match = (spsr & (PSR_C | PSR_Z)) == PSR_C; + break; + case INSN_COND_GE: + match = (!(spsr & PSR_N) == !(spsr & PSR_V)); + break; + case INSN_COND_GT: + match = !(spsr & PSR_Z) && (!(spsr & PSR_N) == !(spsr & PSR_V)); + break; + case INSN_COND_AL: + match = true; + break; + } + + return (!match != !invert); +} + #ifdef COMPAT_FREEBSD32 /* arm32 GDB breakpoints */ #define GDB_BREAKPOINT 0xe6000011 @@ -113,6 +194,86 @@ gdb_trapper(vm_offset_t va, uint32_t insn, struct trapframe *frame, } return 0; } + +static int +swp_emulate(vm_offset_t va, uint32_t insn, struct trapframe *frame, + uint32_t esr) +{ + ksiginfo_t ksi; + struct thread *td; + vm_offset_t vaddr; + uint64_t *regs; + uint32_t val; + int attempts, error, Rn, Rd, Rm; + bool is_swpb; + + td = curthread; + + /* + * swp, swpb only; there are no Thumb swp/swpb instructions so we can + * safely bail out if we're in Thumb mode. + */ + if (!compat32_emul_swp || !SV_PROC_FLAG(td->td_proc, SV_ILP32) || + (frame->tf_spsr & PSR_T) != 0) + return (0); + else if ((insn & 0x0fb00ff0) != 0x01000090) + return (0); + else if (!arm_cond_match(insn, frame)) + goto next; /* Handled, but does nothing */ + + Rn = (insn & 0xf0000) >> 16; + Rd = (insn & 0xf000) >> 12; + Rm = (insn & 0xf); + + regs = frame->tf_x; + vaddr = regs[Rn] & 0xffffffff; + val = regs[Rm]; + + /* Enforce alignment for swp. */ + is_swpb = (insn & 0x00400000) != 0; + if (!is_swpb && (vaddr & 3) != 0) + goto fault; + + attempts = 0; + + do { + if (is_swpb) { + uint8_t bval; + + bval = val; + error = swapueword8((void *)vaddr, &bval); + val = bval; + } else { + error = swapueword32((void *)vaddr, &val); + } + + if (error == -1) + goto fault; + + /* + * Avoid potential DoS, e.g., on CPUs that don't implement + * global monitors. + */ + if (error != 0 && (++attempts % 5) == 0) + maybe_yield(); + } while (error != 0); + + regs[Rd] = val; + +next: + /* No thumb SWP/SWPB */ + frame->tf_elr += 4; //INSN_SIZE; + + return (1); +fault: + ksiginfo_init_trap(&ksi); + ksi.ksi_signo = SIGSEGV; + ksi.ksi_code = SEGV_MAPERR; + ksi.ksi_addr = (void *)va; + trapsignal(td, &ksi); + + return (1); +} #endif void @@ -125,6 +286,7 @@ undef_init(void) install_undef_handler(false, id_aa64mmfr2_handler); #ifdef COMPAT_FREEBSD32 install_undef_handler(true, gdb_trapper); + install_undef_handler(true, swp_emulate); #endif } diff --git a/sys/conf/options.arm64 b/sys/conf/options.arm64 index 26c7c87e49e2..0d2a5f177754 100644 --- a/sys/conf/options.arm64 +++ b/sys/conf/options.arm64 @@ -14,6 +14,8 @@ PERTHREAD_SSP opt_global.h # Binary compatibility COMPAT_FREEBSD32 opt_global.h +# Emulate SWP/SWPB for COMPAT_FREEBSD32 +EMUL_SWP opt_global.h # EFI Runtime services support EFIRT opt_efirt.h