get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 808364,
    "url": "http://patchwork.ozlabs.org/api/patches/808364/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/linux-imx/patch/1504198860-12951-12-git-send-email-Dave.Martin@arm.com/",
    "project": {
        "id": 19,
        "url": "http://patchwork.ozlabs.org/api/projects/19/?format=api",
        "name": "Linux IMX development",
        "link_name": "linux-imx",
        "list_id": "linux-imx-kernel.lists.patchwork.ozlabs.org",
        "list_email": "linux-imx-kernel@lists.patchwork.ozlabs.org",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<1504198860-12951-12-git-send-email-Dave.Martin@arm.com>",
    "list_archive_url": null,
    "date": "2017-08-31T17:00:43",
    "name": "[v2,11/28] arm64/sve: Core task context handling",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "5458c4ffcdf116343b44bb0ad71a7f0628930481",
    "submitter": {
        "id": 26612,
        "url": "http://patchwork.ozlabs.org/api/people/26612/?format=api",
        "name": "Dave Martin",
        "email": "Dave.Martin@arm.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/linux-imx/patch/1504198860-12951-12-git-send-email-Dave.Martin@arm.com/mbox/",
    "series": [
        {
            "id": 883,
            "url": "http://patchwork.ozlabs.org/api/series/883/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/linux-imx/list/?series=883",
            "date": "2017-08-31T17:00:33",
            "name": "ARM Scalable Vector Extension (SVE)",
            "version": 2,
            "mbox": "http://patchwork.ozlabs.org/series/883/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/808364/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/808364/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org>",
        "X-Original-To": "incoming-imx@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming-imx@bilbo.ozlabs.org",
        "Authentication-Results": [
            "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=lists.infradead.org\n\t(client-ip=65.50.211.133; helo=bombadil.infradead.org;\n\tenvelope-from=linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org;\n\treceiver=<UNKNOWN>)",
            "ozlabs.org; dkim=pass (2048-bit key;\n\tunprotected) header.d=lists.infradead.org\n\theader.i=@lists.infradead.org\n\theader.b=\"WDc5/lf0\"; dkim-atps=neutral"
        ],
        "Received": [
            "from bombadil.infradead.org (bombadil.infradead.org\n\t[65.50.211.133])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xjpmM5T1zz9s81\n\tfor <incoming-imx@patchwork.ozlabs.org>;\n\tFri,  1 Sep 2017 03:10:43 +1000 (AEST)",
            "from localhost ([127.0.0.1] helo=bombadil.infradead.org)\n\tby bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux))\n\tid 1dnSzE-0008Ae-9C; Thu, 31 Aug 2017 17:10:36 +0000",
            "from foss.arm.com ([217.140.101.70])\n\tby bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux))\n\tid 1dnSqt-0007LR-MY for linux-arm-kernel@lists.infradead.org;\n\tThu, 31 Aug 2017 17:02:22 +0000",
            "from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249])\n\tby usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 6AD041715;\n\tThu, 31 Aug 2017 10:01:36 -0700 (PDT)",
            "from e103592.cambridge.arm.com (usa-sjc-imap-foss1.foss.arm.com\n\t[10.72.51.249])\n\tby usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id\n\tBE7493F58F; Thu, 31 Aug 2017 10:01:34 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;\n\td=lists.infradead.org; s=bombadil.20170209; h=Sender:\n\tContent-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post:\n\tList-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:\n\tMessage-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description:\n\tResent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:\n\tList-Owner; bh=jJ2zpJDkwpHZyilYOZNA8+Q2LThp8+iiIWMOYveRWDQ=;\n\tb=WDc5/lf0czGkIG\n\t6slIJPHURUjb2QK57J4SuYmV+TLy3FL0Sge8AKWEM2Laki/R+4hKbg59ikUkrg4zis9r8/TbJB4ab\n\t1JF0qyO8E24wrYmTLwaz8S5je/MNNfZxHNN71j8xE4jkNKKAahZZXc3X0C2Jsj/nf3emNug8Tj3zO\n\tRGdoQ9OxqrA7dXbnJSbqpI5kFd5cRhzQnMv7V4XIA8aIomWavmjGoflWiCROfs+ySDHrw917Vfuqt\n\t/Huo4jAtyz38w1TGASCOH+O40xlZx1ZKhLTRca9Y8AjS16Tl+0w4nHRbOpeigf2PEmSwYXrnzbVLR\n\tvWuqisdj98L0vJ7Z+EYw==;",
        "From": "Dave Martin <Dave.Martin@arm.com>",
        "To": "linux-arm-kernel@lists.infradead.org",
        "Subject": "[PATCH v2 11/28] arm64/sve: Core task context handling",
        "Date": "Thu, 31 Aug 2017 18:00:43 +0100",
        "Message-Id": "<1504198860-12951-12-git-send-email-Dave.Martin@arm.com>",
        "X-Mailer": "git-send-email 2.1.4",
        "In-Reply-To": "<1504198860-12951-1-git-send-email-Dave.Martin@arm.com>",
        "References": "<1504198860-12951-1-git-send-email-Dave.Martin@arm.com>",
        "MIME-Version": "1.0",
        "X-CRM114-Version": "20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 ",
        "X-CRM114-CacheID": "sfid-20170831_100200_042520_02C4DD4F ",
        "X-CRM114-Status": "GOOD (  31.78  )",
        "X-Spam-Score": "-6.9 (------)",
        "X-Spam-Report": "SpamAssassin version 3.4.1 on bombadil.infradead.org summary:\n\tContent analysis details:   (-6.9 points)\n\tpts rule name              description\n\t---- ----------------------\n\t--------------------------------------------------\n\t-5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/,\n\thigh trust [217.140.101.70 listed in list.dnswl.org]\n\t-0.0 SPF_PASS               SPF: sender matches SPF record\n\t-0.0 RP_MATCHES_RCVD Envelope sender domain matches handover relay\n\tdomain\n\t-1.9 BAYES_00               BODY: Bayes spam probability is 0 to 1%\n\t[score: 0.0000]",
        "X-BeenThere": "linux-arm-kernel@lists.infradead.org",
        "X-Mailman-Version": "2.1.21",
        "Precedence": "list",
        "List-Unsubscribe": "<http://lists.infradead.org/mailman/options/linux-arm-kernel>,\n\t<mailto:linux-arm-kernel-request@lists.infradead.org?subject=unsubscribe>",
        "List-Archive": "<http://lists.infradead.org/pipermail/linux-arm-kernel/>",
        "List-Post": "<mailto:linux-arm-kernel@lists.infradead.org>",
        "List-Help": "<mailto:linux-arm-kernel-request@lists.infradead.org?subject=help>",
        "List-Subscribe": "<http://lists.infradead.org/mailman/listinfo/linux-arm-kernel>,\n\t<mailto:linux-arm-kernel-request@lists.infradead.org?subject=subscribe>",
        "Cc": "linux-arch@vger.kernel.org, libc-alpha@sourceware.org, Ard Biesheuvel\n\t<ard.biesheuvel@linaro.org>,  Szabolcs Nagy <szabolcs.nagy@arm.com>,\n\tCatalin Marinas\n\t<catalin.marinas@arm.com>, Will Deacon <will.deacon@arm.com>, Richard\n\tSandiford <richard.sandiford@arm.com>, =?utf-8?q?Alex_Benn=C3=A9e?=\n\t<alex.bennee@linaro.org>,  kvmarm@lists.cs.columbia.edu",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "base64",
        "Sender": "\"linux-arm-kernel\" <linux-arm-kernel-bounces@lists.infradead.org>",
        "Errors-To": "linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org",
        "List-Id": "linux-imx-kernel.lists.patchwork.ozlabs.org"
    },
    "content": "This patch adds the core support for switching and managing the SVE\narchitectural state of user tasks.\n\nCalls to the existing FPSIMD low-level save/restore functions are\nfactored out as new functions task_fpsimd_{save,load}(), since SVE\nnow dynamically may or may not need to be handled at these points\ndepending on the kernel configuration, hardware features discovered\nat boot, and the runtime state of the task.  To make these\ndecisions as fast as possible, const cpucaps are used where\nfeasible, via the system_supports_sve() helper.\n\nThe SVE registers are only tracked for threads that have explicitly\nused SVE, indicated by the new thread flag TIF_SVE.  Otherwise, the\nFPSIMD view of the architectural state is stored in\nthread.fpsimd_state as usual.\n\nWhen in use, the SVE registers are not stored directly in\nthread_struct due to their potentially large and variable size.\nBecause the task_struct slab allocator must be configured very\nearly during kernel boot, it is also tricky to configure it\ncorrectly to match the maximum vector length provided by the\nhardware, since this depends on examining secondary CPUs as well as\nthe primary.  Instead, a pointer sve_state in thread_struct points\nto a dynamically allocated buffer containing the SVE register data,\nand code is added to allocate, duplicate and free this buffer at\nappropriate times.\n\nTIF_SVE is set when taking an SVE access trap from userspace, if\nsuitable hardware support has been detected.  This enables SVE for\nthe thread: a subsequent return to userspace will disable the trap\naccordingly.  If such a trap is taken without sufficient hardware\nsupport, SIGILL is sent to the thread instead as if an undefined\ninstruction had been executed: this may happen if userspace tries\nto use SVE in a system where not all CPUs support it for example.\n\nThe kernel may clear TIF_SVE and disable SVE for the thread\nwhenever an explicit syscall is made by userspace, though this is\nconsidered an optimisation opportunity rather than a deterministic\nguarantee: the kernel may not do this on every syscall, but it is\npermitted to do so.  For backwards compatibility reasons and\nconformance with the spirit of the base AArch64 procedure call\nstandard, the subset of the SVE register state that aliases the\nFPSIMD registers is still preserved across a syscall even if this\nhappens.\n\nTIF_SVE is also cleared, and SVE disabled, on exec: this is an\nobvious slow path and a hint that we are running a new binary that\nmay not use SVE.\n\nCode is added to sync data between thread.fpsimd_state and\nthread.sve_state whenever enabling/disabling SVE, in a manner\nconsistent with the SVE architectural programmer's model.\n\nSigned-off-by: Dave Martin <Dave.Martin@arm.com>\nCc: Ard Biesheuvel <ard.biesheuvel@linaro.org>\nCc: Alex Bennée <alex.bennee@linaro.org>\n\n---\n\nChanges since v1\n----------------\n\nRequested by Ard Biesheuvel:\n\n* Fix unbalanced ifelse bracing to match kernel coding style.\n* Improve abstraction of change_cpacr to be a bit less clunky.\n* Rearrange task_fpsimd_{load,save}() and friends to eliminate\nforward declarations.\n\nChanges related to Ard Biesheuvel's comments:\n\n* Undo suprious replacement of assignment by memset in\narch_dup_task_struct().\n\nRequested by Alex Bennée:\n\n* Add missing include of <linux/compat.h>.\n* Make thread_struct.sve_vl an unsigned int: that's the type used\nvirtually everywhere else, and the memory saving is too minor to be\ninteresting.\n\n* Thin out BUG_ON()s:\nRedundant BUG_ON()s and ones that just check invariants are removed.\nImportant sanity-checks are migrated to WARN_ON()s, with some\nminimal best-effort patch-up code.  The fpsimd_dup_sve() case is changed\nto a WARN_ON, for user threads only, and only if actually clearing\nTIF_SVE.\n\nOther:\n\n* [bugfix] Unconditionally drop child task's reference to the parent's\nSVE state on fork.  Otherwise we can end up with it aliased, which is\nbad.\n---\n arch/arm64/include/asm/fpsimd.h      |  19 +++\n arch/arm64/include/asm/processor.h   |   2 +\n arch/arm64/include/asm/thread_info.h |   1 +\n arch/arm64/include/asm/traps.h       |   2 +\n arch/arm64/kernel/entry.S            |  14 ++-\n arch/arm64/kernel/fpsimd.c           | 227 ++++++++++++++++++++++++++++++++++-\n arch/arm64/kernel/process.c          |   4 +\n arch/arm64/kernel/traps.c            |   4 +-\n 8 files changed, 265 insertions(+), 8 deletions(-)",
    "diff": "diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h\nindex 026a7c7..72090a1 100644\n--- a/arch/arm64/include/asm/fpsimd.h\n+++ b/arch/arm64/include/asm/fpsimd.h\n@@ -20,6 +20,8 @@\n \n #ifndef __ASSEMBLY__\n \n+#include <linux/stddef.h>\n+\n /*\n  * FP/SIMD storage area has:\n  *  - FPSR and FPCR\n@@ -72,6 +74,23 @@ extern void sve_load_state(void const *state, u32 const *pfpsr,\n \t\t\t   unsigned long vq_minus_1);\n extern unsigned int sve_get_vl(void);\n \n+#ifdef CONFIG_ARM64_SVE\n+\n+extern size_t sve_state_size(struct task_struct const *task);\n+\n+extern void sve_alloc(struct task_struct *task);\n+extern void fpsimd_release_thread(struct task_struct *task);\n+extern void fpsimd_dup_sve(struct task_struct *dst,\n+\t\t\t   struct task_struct const *src);\n+\n+#else /* ! CONFIG_ARM64_SVE */\n+\n+static void __maybe_unused sve_alloc(struct task_struct *task) { }\n+static void __maybe_unused fpsimd_release_thread(struct task_struct *task) { }\n+static void __maybe_unused fpsimd_dup_sve(struct task_struct *dst,\n+\t\t\t\t\t  struct task_struct const *src) { }\n+#endif /* ! CONFIG_ARM64_SVE */\n+\n /* For use by EFI runtime services calls only */\n extern void __efi_fpsimd_begin(void);\n extern void __efi_fpsimd_end(void);\ndiff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h\nindex 29adab8..4831d28 100644\n--- a/arch/arm64/include/asm/processor.h\n+++ b/arch/arm64/include/asm/processor.h\n@@ -85,6 +85,8 @@ struct thread_struct {\n \tunsigned long\t\ttp2_value;\n #endif\n \tstruct fpsimd_state\tfpsimd_state;\n+\tvoid\t\t\t*sve_state;\t/* SVE registers, if any */\n+\tunsigned int\t\tsve_vl;\t\t/* SVE vector length */\n \tunsigned long\t\tfault_address;\t/* fault info */\n \tunsigned long\t\tfault_code;\t/* ESR_EL1 value */\n \tstruct debug_info\tdebug;\t\t/* debugging */\ndiff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h\nindex 2eca178..f0880fc 100644\n--- a/arch/arm64/include/asm/thread_info.h\n+++ b/arch/arm64/include/asm/thread_info.h\n@@ -91,6 +91,7 @@ void arch_setup_new_exec(void);\n #define TIF_RESTORE_SIGMASK\t20\n #define TIF_SINGLESTEP\t\t21\n #define TIF_32BIT\t\t22\t/* 32bit process */\n+#define TIF_SVE\t\t\t23\t/* Scalable Vector Extension in use */\n \n #define _TIF_SIGPENDING\t\t(1 << TIF_SIGPENDING)\n #define _TIF_NEED_RESCHED\t(1 << TIF_NEED_RESCHED)\ndiff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h\nindex 4136168..282163f 100644\n--- a/arch/arm64/include/asm/traps.h\n+++ b/arch/arm64/include/asm/traps.h\n@@ -34,6 +34,8 @@ struct undef_hook {\n \n void register_undef_hook(struct undef_hook *hook);\n void unregister_undef_hook(struct undef_hook *hook);\n+void force_signal_inject(int signal, int code, struct pt_regs *regs,\n+\t\t\t unsigned long address);\n \n void arm64_notify_segfault(struct pt_regs *regs, unsigned long addr);\n \ndiff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S\nindex e1c59d4..e57020f 100644\n--- a/arch/arm64/kernel/entry.S\n+++ b/arch/arm64/kernel/entry.S\n@@ -607,6 +607,8 @@ el0_sync:\n \tb.eq\tel0_ia\n \tcmp\tx24, #ESR_ELx_EC_FP_ASIMD\t// FP/ASIMD access\n \tb.eq\tel0_fpsimd_acc\n+\tcmp\tx24, #ESR_ELx_EC_SVE\t\t// SVE access\n+\tb.eq\tel0_sve_acc\n \tcmp\tx24, #ESR_ELx_EC_FP_EXC64\t// FP/ASIMD exception\n \tb.eq\tel0_fpsimd_exc\n \tcmp\tx24, #ESR_ELx_EC_SYS64\t\t// configurable trap\n@@ -705,9 +707,19 @@ el0_fpsimd_acc:\n \tmov\tx1, sp\n \tbl\tdo_fpsimd_acc\n \tb\tret_to_user\n+el0_sve_acc:\n+\t/*\n+\t * Scalable Vector Extension access\n+\t */\n+\tenable_dbg\n+\tct_user_exit\n+\tmov\tx0, x25\n+\tmov\tx1, sp\n+\tbl\tdo_sve_acc\n+\tb\tret_to_user\n el0_fpsimd_exc:\n \t/*\n-\t * Floating Point or Advanced SIMD exception\n+\t * Floating Point, Advanced SIMD or SVE exception\n \t */\n \tenable_dbg\n \tct_user_exit\ndiff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c\nindex 9d762dd..9b1ebd7 100644\n--- a/arch/arm64/kernel/fpsimd.c\n+++ b/arch/arm64/kernel/fpsimd.c\n@@ -18,18 +18,25 @@\n  */\n \n #include <linux/bottom_half.h>\n+#include <linux/bug.h>\n+#include <linux/compat.h>\n #include <linux/cpu.h>\n #include <linux/cpu_pm.h>\n #include <linux/kernel.h>\n #include <linux/init.h>\n #include <linux/percpu.h>\n #include <linux/preempt.h>\n+#include <linux/ptrace.h>\n #include <linux/sched/signal.h>\n #include <linux/signal.h>\n+#include <linux/slab.h>\n \n #include <asm/fpsimd.h>\n #include <asm/cputype.h>\n #include <asm/simd.h>\n+#include <asm/sigcontext.h>\n+#include <asm/sysreg.h>\n+#include <asm/traps.h>\n \n #define FPEXC_IOF\t(1 << 0)\n #define FPEXC_DZF\t(1 << 1)\n@@ -99,6 +106,190 @@\n  */\n static DEFINE_PER_CPU(struct fpsimd_state *, fpsimd_last_state);\n \n+static void sve_free(struct task_struct *task)\n+{\n+\tkfree(task->thread.sve_state);\n+\ttask->thread.sve_state = NULL;\n+}\n+\n+/* Offset of FFR in the SVE register dump */\n+static size_t sve_ffr_offset(int vl)\n+{\n+\treturn SVE_SIG_FFR_OFFSET(sve_vq_from_vl(vl)) - SVE_SIG_REGS_OFFSET;\n+}\n+\n+static void *sve_pffr(struct task_struct *task)\n+{\n+\treturn (char *)task->thread.sve_state +\n+\t\tsve_ffr_offset(task->thread.sve_vl);\n+}\n+\n+static void change_cpacr(u64 val, u64 mask)\n+{\n+\tu64 cpacr = read_sysreg(CPACR_EL1);\n+\tu64 new = (cpacr & ~mask) | val;\n+\n+\tif (new != cpacr)\n+\t\twrite_sysreg(new, CPACR_EL1);\n+}\n+\n+static void sve_user_disable(void)\n+{\n+\tchange_cpacr(0, CPACR_EL1_ZEN_EL0EN);\n+}\n+\n+static void sve_user_enable(void)\n+{\n+\tchange_cpacr(CPACR_EL1_ZEN_EL0EN, CPACR_EL1_ZEN_EL0EN);\n+}\n+\n+static void task_fpsimd_load(void)\n+{\n+\tif (system_supports_sve() && test_thread_flag(TIF_SVE))\n+\t\tsve_load_state(sve_pffr(current),\n+\t\t\t       &current->thread.fpsimd_state.fpsr,\n+\t\t\t       sve_vq_from_vl(current->thread.sve_vl) - 1);\n+\telse\n+\t\tfpsimd_load_state(&current->thread.fpsimd_state);\n+\n+\tif (system_supports_sve()) {\n+\t\t/* Toggle SVE trapping for userspace if needed */\n+\t\tif (test_thread_flag(TIF_SVE))\n+\t\t\tsve_user_enable();\n+\t\telse\n+\t\t\tsve_user_disable();\n+\n+\t\t/* Serialised by exception return to user */\n+\t}\n+}\n+\n+static void task_fpsimd_save(void)\n+{\n+\tif (system_supports_sve() &&\n+\t    in_syscall(current_pt_regs()) &&\n+\t    test_thread_flag(TIF_SVE)) {\n+\t\tclear_thread_flag(TIF_SVE);\n+\n+\t\t/* Trap if the task tries to use SVE again: */\n+\t\tsve_user_disable();\n+\t}\n+\n+\tif (!test_thread_flag(TIF_FOREIGN_FPSTATE)) {\n+\t\tif (system_supports_sve() && test_thread_flag(TIF_SVE))\n+\t\t\tsve_save_state(sve_pffr(current),\n+\t\t\t\t       &current->thread.fpsimd_state.fpsr);\n+\t\telse\n+\t\t\tfpsimd_save_state(&current->thread.fpsimd_state);\n+\t}\n+}\n+\n+#define ZREG(sve_state, vq, n) ((char *)(sve_state) +\t\t\\\n+\t(SVE_SIG_ZREG_OFFSET(vq, n) - SVE_SIG_REGS_OFFSET))\n+\n+static void fpsimd_to_sve(struct task_struct *task)\n+{\n+\tunsigned int vq;\n+\tvoid *sst = task->thread.sve_state;\n+\tstruct fpsimd_state const *fst = &task->thread.fpsimd_state;\n+\tunsigned int i;\n+\n+\tif (!system_supports_sve())\n+\t\treturn;\n+\n+\tvq = sve_vq_from_vl(task->thread.sve_vl);\n+\tfor (i = 0; i < 32; ++i)\n+\t\tmemcpy(ZREG(sst, vq, i), &fst->vregs[i],\n+\t\t       sizeof(fst->vregs[i]));\n+}\n+\n+#ifdef CONFIG_ARM64_SVE\n+\n+static void sve_to_fpsimd(struct task_struct *task)\n+{\n+\tunsigned int vq;\n+\tvoid const *sst = task->thread.sve_state;\n+\tstruct fpsimd_state *fst = &task->thread.fpsimd_state;\n+\tunsigned int i;\n+\n+\tif (!system_supports_sve())\n+\t\treturn;\n+\n+\tvq = sve_vq_from_vl(task->thread.sve_vl);\n+\tfor (i = 0; i < 32; ++i)\n+\t\tmemcpy(&fst->vregs[i], ZREG(sst, vq, i),\n+\t\t       sizeof(fst->vregs[i]));\n+}\n+\n+size_t sve_state_size(struct task_struct const *task)\n+{\n+\treturn SVE_SIG_REGS_SIZE(sve_vq_from_vl(task->thread.sve_vl));\n+}\n+\n+void sve_alloc(struct task_struct *task)\n+{\n+\tif (task->thread.sve_state) {\n+\t\tmemset(task->thread.sve_state, 0, sve_state_size(current));\n+\t\treturn;\n+\t}\n+\n+\t/* This is a small allocation (maximum ~8KB) and Should Not Fail. */\n+\ttask->thread.sve_state =\n+\t\tkzalloc(sve_state_size(task), GFP_KERNEL);\n+\n+\t/*\n+\t * If future SVE revisions can have larger vectors though,\n+\t * this may cease to be true:\n+\t */\n+\tBUG_ON(!task->thread.sve_state);\n+}\n+\n+/*\n+ * Handle SVE state across fork():\n+ *\n+ * dst and src must not end up with aliases of the same sve_state.\n+ * Because a task cannot fork except in a syscall, we can discard SVE\n+ * state for dst here, so long as we take care to retain the FPSIMD\n+ * subset of the state if SVE is in use.  Reallocation of the SVE state\n+ * will be deferred until dst tries to use SVE.\n+ */\n+void fpsimd_dup_sve(struct task_struct *dst, struct task_struct const *src)\n+{\n+\tif (test_and_clear_tsk_thread_flag(dst, TIF_SVE)) {\n+\t\tWARN_ON(dst->mm && !in_syscall(task_pt_regs(dst)));\n+\t\tsve_to_fpsimd(dst);\n+\t}\n+\n+\tdst->thread.sve_state = NULL;\n+}\n+\n+void fpsimd_release_thread(struct task_struct *dead_task)\n+{\n+\tsve_free(dead_task);\n+}\n+\n+#endif /* CONFIG_ARM64_SVE */\n+\n+/*\n+ * Trapped SVE access\n+ */\n+void do_sve_acc(unsigned int esr, struct pt_regs *regs)\n+{\n+\t/* Even if we chose not to use SVE, the hardware could still trap: */\n+\tif (unlikely(!system_supports_sve()) || WARN_ON(is_compat_task())) {\n+\t\tforce_signal_inject(SIGILL, ILL_ILLOPC, regs, 0);\n+\t\treturn;\n+\t}\n+\n+\ttask_fpsimd_save();\n+\n+\tsve_alloc(current);\n+\tfpsimd_to_sve(current);\n+\tif (test_and_set_thread_flag(TIF_SVE))\n+\t\tWARN_ON(1); /* SVE access shouldn't have trapped */\n+\n+\ttask_fpsimd_load();\n+}\n+\n /*\n  * Trapped FP/ASIMD access.\n  */\n@@ -144,8 +335,8 @@ void fpsimd_thread_switch(struct task_struct *next)\n \t * the registers is in fact the most recent userland FPSIMD state of\n \t * 'current'.\n \t */\n-\tif (current->mm && !test_thread_flag(TIF_FOREIGN_FPSTATE))\n-\t\tfpsimd_save_state(&current->thread.fpsimd_state);\n+\tif (current->mm)\n+\t\ttask_fpsimd_save();\n \n \tif (next->mm) {\n \t\t/*\n@@ -167,6 +358,8 @@ void fpsimd_thread_switch(struct task_struct *next)\n \n void fpsimd_flush_thread(void)\n {\n+\tint vl;\n+\n \tif (!system_supports_fpsimd())\n \t\treturn;\n \n@@ -174,6 +367,30 @@ void fpsimd_flush_thread(void)\n \n \tmemset(&current->thread.fpsimd_state, 0, sizeof(struct fpsimd_state));\n \tfpsimd_flush_task_state(current);\n+\n+\tif (system_supports_sve()) {\n+\t\tclear_thread_flag(TIF_SVE);\n+\t\tsve_free(current);\n+\n+\t\t/*\n+\t\t * Reset the task vector length as required.\n+\t\t * This is where we ensure that all user tasks have a valid\n+\t\t * vector length configured: no kernel task can become a user\n+\t\t * task without an exec and hence a call to this function.\n+\t\t * If a bug causes this to go wrong, we make some noise and\n+\t\t * try to fudge thread.sve_vl to a safe value here.\n+\t\t */\n+\t\tvl = current->thread.sve_vl;\n+\n+\t\tif (vl == 0)\n+\t\t\tvl = SVE_VL_MIN;\n+\n+\t\tif (WARN_ON(!sve_vl_valid(vl)))\n+\t\t\tvl = SVE_VL_MIN;\n+\n+\t\tcurrent->thread.sve_vl = vl;\n+\t}\n+\n \tset_thread_flag(TIF_FOREIGN_FPSTATE);\n \n \tlocal_bh_enable();\n@@ -211,7 +428,7 @@ void fpsimd_restore_current_state(void)\n \tif (test_and_clear_thread_flag(TIF_FOREIGN_FPSTATE)) {\n \t\tstruct fpsimd_state *st = &current->thread.fpsimd_state;\n \n-\t\tfpsimd_load_state(st);\n+\t\ttask_fpsimd_load();\n \t\t__this_cpu_write(fpsimd_last_state, st);\n \t\tst->cpu = smp_processor_id();\n \t}\n@@ -376,8 +593,8 @@ static int fpsimd_cpu_pm_notifier(struct notifier_block *self,\n {\n \tswitch (cmd) {\n \tcase CPU_PM_ENTER:\n-\t\tif (current->mm && !test_thread_flag(TIF_FOREIGN_FPSTATE))\n-\t\t\tfpsimd_save_state(&current->thread.fpsimd_state);\n+\t\tif (current->mm)\n+\t\t\ttask_fpsimd_save();\n \t\tthis_cpu_write(fpsimd_last_state, NULL);\n \t\tbreak;\n \tcase CPU_PM_EXIT:\ndiff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c\nindex e6bf19c..eb1cae7 100644\n--- a/arch/arm64/kernel/process.c\n+++ b/arch/arm64/kernel/process.c\n@@ -239,6 +239,7 @@ void flush_thread(void)\n \n void release_thread(struct task_struct *dead_task)\n {\n+\tfpsimd_release_thread(dead_task);\n }\n \n int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)\n@@ -246,6 +247,9 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)\n \tif (current->mm)\n \t\tfpsimd_preserve_current_state();\n \t*dst = *src;\n+\n+\tfpsimd_dup_sve(dst, src);\n+\n \treturn 0;\n }\n \ndiff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c\nindex f202932..7f3b5c6 100644\n--- a/arch/arm64/kernel/traps.c\n+++ b/arch/arm64/kernel/traps.c\n@@ -358,8 +358,8 @@ static int call_undef_hook(struct pt_regs *regs)\n \treturn fn ? fn(regs, instr) : 1;\n }\n \n-static void force_signal_inject(int signal, int code, struct pt_regs *regs,\n-\t\t\t\tunsigned long address)\n+void force_signal_inject(int signal, int code, struct pt_regs *regs,\n+\t\t\t unsigned long address)\n {\n \tsiginfo_t info;\n \tvoid __user *pc = (void __user *)instruction_pointer(regs);\n",
    "prefixes": [
        "v2",
        "11/28"
    ]
}