* [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support
@ 2017-03-22 14:50 Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 01/41] arm64: signal: Refactor sigcontext parsing in rt_sigreturn Dave Martin
` (41 more replies)
0 siblings, 42 replies; 66+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
To: linux-arm-kernel
The Scalable Vector Extension (SVE) [1] is an extension to AArch64 which
adds extra SIMD functionality and supports much larger vectors.
This series implements core Linux support for SVE.
Recipents not copied on the whole series can find the rest of the
patches in the linux-arm-kernel archives [2].
Major changes since v1: [3]
* SVE vector length now configurable via prctl() and ptrace()
(based on previously posted work [4]);
* improved CPU feature detection to allow for mismatched CPUs;
* dynamic allocation of per-task storage for the SVE registers.
There are a lot of outstanding issues that reviewers should be aware of,
including some design and implementation issues that I'd appreciate
input on.
Due to the length of the cover note, I've split it up as follows:
* Missing Features and Limitations
* ABI Design Issues
(implementated interfaces that may need improvement)
* Security
(outstanding security-related design considerations)
* Bugs and Implementation Issues
(known and suspected problems with the implementation)
For reviewers, I recommend quickly skimming the remainder of this cover
note and the final (documentation) patch, before deciding what to focus
on in more detail.
Because of the length of the series, be aware that some code added by
earlier patches is substantially rewritten by later patches -- so also
look at the final result of applying the series before commenting
heavily on earlier additions.
Review and comments appreciated.
Cheers
---Dave
[1]
https://community.arm.com/groups/processors/blog/2016/08/22/technology-update-the-scalable-vector-extension-sve-for-the-armv8-a-architecture
[2]
http://lists.infradead.org/pipermail/linux-arm-kernel/2017-March/thread.html
linux-arm-kernel archive
[3]
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/470507.html
[RFC PATCH 00/29] arm64: Scalable Vector Extension core support
[4]
http://lists.infradead.org/pipermail/linux-arm-kernel/2017-January/478941.html
[RFC PATCH 00/10] arm64/sve: Add userspace vector length control API
Missing Features and Limitations
================================
Sparse vector length support
----------------------------
Currently, the code assumes that all possible vector lengths are
supported up to the maximum supported by the CPU. The SVE architecture
doesn't require this, so it will be necessary to probe each possible VL
on every CPU and derive the set of common VLs after the secondaries come
up.
The patches don't currently implement this, which will cause incorrect
context save/restore and userspace malfunctions if a VL is configured
that the CPU implementation does not support.
KVM
---
Use of SVE by KVM guests is not supported yet.
SVE is still detected as present by guests due to the fact that
ID_AA64PFR0_EL1 is still read directly from the hardware, even by the
guest, so right now, a guest kernel configured with CONFIG_ARM64_SVE=y
will go into an illegal-instruction spin during early boot.
Sanitising the the ID registers for guests is a broader problem. It may
be appropriate to implement a stopgap solution for SVE in the meantime,
either:
* Require guests to be configured with CONFIG_ARM64_SVE=n, and kill
affected guests instead of injecting an undef
(not great)
* Add a point hack for trapping the CPU ID regs and hiding (just) SVE
from the guest.
For one or two features this may be acceptable and this may serve as
a stepping stone towards proper ID register sanitisation, but this
approach won't scale well as the number of affected features
increases over time.
* Implement minimal KVM support a guest can at least boot and run,
possibly suboptimally, if it uses SVE. Full userspace ioctl()
extensions for management of the guest VM's SVE support might be
omitted to begin with.
This is the cleanest approach, but involves would involve more work
and might delay merge.
KERNEL_MODE_NEON (non-)support
------------------------------
"arm64/sve: [BROKEN] Basic support for KERNEL_MODE_NEON" is broken.
There are significant design issues here that need discussion -- see the
commit message for details.
Options:
* Make KERNEL_MODE_NEON a runtime choice, and disable it if SVE is
present.
* Fully SVE-ise the KERNEL_MODE_NEON code: this will involve complexity
and effort, and may involve unfavourable (and VL-dependent) tradeoffs
compared with the no-SVE case.
We will nonetheless need something like this if there is a desire to
support "kernel mode SVE" in the future. The fact that with SVE,
KERNEL_MODE_NEON brings the cost of kernel-mode SVE but only the
benefits of kernel-mode NEON argues in favour of this.
* Make KERNEL_MODE_NEON a dynamic choice, and have clients run fallback
C code instead if at runtime on a case-by-case basis, if SVE regs
would otherwise need saving.
This is an interface break, but all NEON-optimised kernel code
necessarily requires a fallback C implementation to exist anyway, and
the number of clients is not huge.
We could go for a stopgap solution that at least works but is suboptimal
for SVE systems (such as the first choice above), and then improve it
later.
ABI Design Issues
=================
Vector length handling in sigcontext
------------------------------------
Currently, the vector length is not saved/restored around signals: it
is not saved in the signal frame, and sigreturn is not allowed to
change it.
It would not be difficult to add this ability now, and retrofitting it
in the future instead would require a kernel upgrade and a mechanism for
new software to know whether it's available.
However, it's unclear whether this feature will ever truly be needed, or
should be encouraged.
During a normal sigreturn, restoration of the VL would only be needed if
the signal handler returned with a different VL configured than the one
it was called with -- something that PCS-compliant functions are
generally not supposed to do.
A non-local return, such as invoking some userspace bottom-half or
scheduler function, or dispatching a userspace exception, could
conceivably legitimately want to change VL.
Choices:
* Implement and support this ability: fairly straightforward, but it
may be abused by userspace (particularly if we can't decide until
later what counts as "abuse").
* Implement it but don't document it and maybe add a pr_info_once() to
warn about future incompatibility if userspace uses it.
* Don't implement it: a caller must use PR_SVE_SET_VL prior to return
if it wants a VL change or to restore VL having previously changed it.
(The caller must sweat the resulting safety issues itself.)
PR_GET_MINSIGSTKSZ (signal frame size discovery)
------------------------------------------------
(Not currently implemented, not 100% trivial to implement, but should be
fairly straightforward.)
It's not obvious whether the maximum possible frame size for the
_current_ thread configuration (e.g., current VL) should be reported, or
the maximum possible frame size irrespective of configuration.
I'd like to be able to hide this call behind sysconf(), which seems a
more natural and cleaner interface for userspace software than issuing
random prctls(), since there is nothing SVE-specific about the problem
of sizing stacks. POSIX doesn't permit sysconf() values to vary over
the lifetime of a process, so this would require the configuration-
independent maximum frame size to be returned, but this may result in
the caller allocating more memory than is really needed.
Taking the system's maximum supported VL into account would mitigate
against this, since it's highly likely to be much smaller than
SVE_VL_MAX.
Reporting of supported vector lengths to userspace
--------------------------------------------------
Currently, the set of supported vector lengths and maximum vector length
are not directly reported to userspace.
Instead, userspace will need to probe by trying to set different vector
lengths and seeing what comes back.
This is unlikely to be a significant burden for now, and it could be
addressed later without backwards-incompatibility.
Maximum vector length
---------------------
For VL-setting interfaces (PR_SVE_SET_VL, ptrace, and possibly
sigreturn):
Is it reasonable to have a way to request "the maximum supported VL" via
these interfaces. Up to now, I've assumed that this is reasonable and
useful, however...
Currently, SVE_VL_MAX is overloaded for this purpose, but this is
intended as an absolute limit encompassing future extensions to SVE --
i.e., this is the limit a remote debug protocol ought to scale up to,
for example. Code compiled for the current SVE architecture is allowed
by the architecture to assume that VL <= 256, so requesting SVE_VL_MAX
may result in an impossibly large VL if executing on some future
hardware that supports vectors > 256 bytes.
This define should probably be forked in two, but confusion and misuse
seem highly likely. Alternatively, the kernel could clamp VL to 256
bytes, and a future flag could be required in order to enable larger VLs
could be set.
PR_SVE_SET_VL interface
-----------------------
Should the arguments to this prctl be merged?
In other interfaces, the vl and flags are separate, but an obvious use
of PR_SVE_SET_VL would be to restore the configuration previously
discovered via PR_SVE_GET_VL, which rather ugly to do today.
Options include:
* merging the PR_SVE_SET_VL arguments
* provide macros to extract the arguments from the PR_SVE_GET_VL return
value
* migrate both prctls to using a struct containing vl and flags.
Vector length setting versus restoration
----------------------------------------
Currently, PTRACE_SETREGSET(NT_ARM_SVE) will fail by default on a
multithreaded target process, even if the vector length is not being
changed. This can be avoided by OR-ing SVE_PT_VL_THREAD into
user_sve_header.flags before calling PTRACE_SETREGSET, to indicate "I
know what I'm doing". But it's weird to have to do this when restoring
the VL to a value it had previously, or when leaving the VL unchanged.
A similar issue applies when calling PR_SVE_SET_VL based on the return
from a previous PR_SVE_GET_VL. If sigreturn is extended to allow VL
changes, it would be affected too.
It's not obvious what the preferred semantics are here, or even if
they're the same in every case.
Options:
* OR the _THREAD flag into the flags or result when reading the VL, as
currently done for PR_SVE_SET_VL, but not for PTRACE_GETREGSET.
* Require the caller to set this flag explicitly, even to restore the
VL to something it was previously successfully set to.
and/or
* Relax the behaviour not to treat VL setting without _THREAD as an
error if the current VL for the thread already matches requested
value.
Different interfaces might take different decisions about these (as at
present).
Coredump padding
----------------
Currently, the regset API and core ELF coredump implementation don't
allow for regsets to have a dynamic size.
NT_ARM_SVE is therefore declared with the theoretical maximum size based
on SVE_MAX_VL, which is ridiculously large.
This is relatively harmless, but it causes about a quarter of a megabyte
of useless padding to be written into the coredump for each thread.
Readers can skip this data, and software consuming coredumps usually
mmaps them rather then streaming them in, so this won't end the world.
I plan to add a regset method to discover the size at runtime, but for
now this is not implemented.
Security
========
Even though it's preferred to work with any vector length, it's
legitimate for code in userspace to prefer certain VLs, or only work
with or be optimised for certain VLs -- or only be tested against
certain VLs.
Thus, controlling the VL that code may execute with, while generally
useful, may have security implications when there is a change of
privilege.
At the moment, it's still unclear how much of this responsibility the
libc startup code should take on. There may be merit in taking a
belt-and-braces approach in the kernel/user ABI, to at least apply some
sanity.
Thus:
* A privilege-escalating execve() (i.e., execing a setuid/setgid binary
or a binary that has filesystem capabilities set on it) could reset
the VL to something "sane" instead of allowing the execve() caller to
control it.
* Currently, the system default VL (configured via
/proc/cpu/sve_default_vl) is my best effort at defining a "sane" VL.
This is writable only by root, but a decision needs to be made about
the interaction of this control with containers.
Either each container needs its own version (cleanest option), or only
the root container should be able to configure it (simplest option).
(It would also be necessary to define how "container" should be defined
for this purpose).
Decisions will be needed on these issues -- neither is currently
addressed.
Bugs and Implementation Issues
==============================
Regarding the patches themselves, comment and review would be
particularly helpful on the following:
procfs
------
It feels wrong to implement /proc/cpu/sve_default_vl by hand (see patch
37), along with all the potential bugs, buffer overflows, and
behavioural inconsistencies this implies, for a rather trivial bit of
functionality.
This may not even belong in procfs at all, though sysfs doesn't seem
right either and there's no natural kobject to tie this control to.
If there's a better framework for this, I'm open to suggestions...
Race conditions
---------------
Because parts of the FPSIMD/SVE-code can preempt other parts on the back
of context switch or IRQ, various races can occur.
The following in particular need close scrutiny:
* Access with preemption enabled, to anything touched by
fpsimd_thread_switch()
* Access with IRQs enabled, to anything touched by
kernel_neon_begin{,_partial}()
SVE register flushing
---------------------
Synchronisation of the Z- (TIF_SVE, thread->sve_state) and V- (!TIF_SVE,
thread->fpsimd_state) views of the registers, and zeroing of the high
bits of the SVE Z-registers is not consistently applied in all cases.
This may lead to noncompliance with the SVE programmer's model whereby,
say,
// syscall
// ...
ldr v0, [x0]
// ...
// context switch
// ...
str z0, [x1]
might not result in the high bits stored from z0 all being zero (which
the SVE programmer's model demands), or there may be other similarly
weird effects -- such behaviour would be a bug, but there may be
outstanding cases I've missed.
Context management
------------------
There are up to 4 views of a task's FPSIMD/SVE state
(thread->fpsimd_state, thread->sve_state, CPU smp_processor_id(), CPU
thread->fpsimd.cpu) and various synchronisations that need to occur at
various times. The desire to minimise preemption/IRQ blackouts when
synchronising complicates matters further by enabling races to occur.
With the addition of SVE on top of KERNEL_MODE_NEON, the code to manage
coherence between these views has grown organically into something
haphazard and hard to reason about and maintain.
I'd like to redesign the way these interactions are abstracted -- any
suggestions are welcome.
Coredump synchronisation
------------------------
In a related, non-SVE-specific issue, the FPSIMD (and SVE) registers are
not necessarily synchronised when generating a coredump, which may
result in stale FPSIMD/SVE register values in the dump compared with the
actual register state at the time the process died.
The series currently makes no attempt to fix this. A fix may be added,
or this may be handled separately.
Bugs
----
An older version of this series exhibited buggy context switch behaviour
under stress. This has not been reproduced on any recent version of the
code, but the test environment is currently not reproducible (involving
experimental KVM support that is not portable to the current branch).
To date, the bug (or bugs) remain undiagnosed. I have reason to belive
that there were multiple contributory bugs in the original code, and it
seems likely that they haven't all been fixed.
The possibility of a bug in the CPU simlation used to run the test has
also never been conclusively ruled out.
The failures:
* were only ever observed in the host;
* were only ever observed when running multiple guests, with all guest
VCPUs busy and all;
* were never observed to affect FPSIMD state, only the extra SVE state;
* were never observed to leak data between tasks, between the kernel
and userspace, or between host and guest;
* did not seem to involve buffer overruns or memory corruption: high
bits of SVE Z-registers, or (more rarely) P-registers or FFR would be
unexpectedly replaced with zeros or stale data belonging to the same
task.
Thus I have seen no evidence that suggests non-SVE systems can be
affected, but it's difficult to say for certain.
I have a strong suspicion that the complexity of the SVE/FPSIMD context
synchronisation code is the source of these issues, but this remains
unproven.
Alan Hayward (1):
arm64/sve: ptrace support
Dave Martin (40):
arm64: signal: Refactor sigcontext parsing in rt_sigreturn
arm64: signal: factor frame layout and population into separate passes
arm64: signal: factor out signal frame record allocation
arm64: signal: Allocate extra sigcontext space as needed
arm64: signal: Parse extra_context during sigreturn
arm64: efi: Add missing Kconfig dependency on KERNEL_MODE_NEON
arm64/sve: Allow kernel-mode NEON to be disabled in Kconfig
arm64/sve: Low-level save/restore code
arm64/sve: Boot-time feature detection and reporting
arm64/sve: Boot-time feature enablement
arm64/sve: Expand task_struct for Scalable Vector Extension state
arm64/sve: Save/restore SVE state on context switch paths
arm64/sve: [BROKEN] Basic support for KERNEL_MODE_NEON
Revert "arm64/sve: Allow kernel-mode NEON to be disabled in Kconfig"
arm64/sve: Restore working FPSIMD save/restore around signals
arm64/sve: signal: Add SVE state record to sigcontext
arm64/sve: signal: Dump Scalable Vector Extension registers to user
stack
arm64/sve: signal: Restore FPSIMD/SVE state in rt_sigreturn
arm64/sve: Avoid corruption when replacing the SVE state
arm64/sve: traps: Add descriptive string for SVE exceptions
arm64/sve: Enable SVE on demand for userspace
arm64/sve: Implement FPSIMD-only context for tasks not using SVE
arm64/sve: Move ZEN handling to the common task_fpsimd_load() path
arm64/sve: Discard SVE state on system call
arm64/sve: Avoid preempt_disable() during sigreturn
arm64/sve: Avoid stale user register state after SVE access exception
arm64: KVM: Treat SVE use by guests as undefined instruction execution
prctl: Add skeleton for PR_SVE_{SET,GET}_VL controls
arm64/sve: Track vector length for each task
arm64/sve: Set CPU vector length to match current task
arm64/sve: Factor out clearing of tasks' SVE regs
arm64/sve: Wire up vector length control prctl() calls
arm64/sve: Disallow VL setting for individual threads by default
arm64/sve: Add vector length inheritance control
arm64/sve: ptrace: Wire up vector length control and reporting
arm64/sve: Enable default vector length control via procfs
arm64/sve: Detect SVE via the cpufeature framework
arm64/sve: Migrate to cpucap based detection for runtime SVE code
arm64/sve: Allocate task SVE context storage dynamically
arm64/sve: Documentation: Add overview of the SVE userspace ABI
Documentation/arm64/sve.txt | 475 ++++++++++++++++++++++++
arch/arm64/Kconfig | 12 +
arch/arm64/include/asm/cpu.h | 3 +
arch/arm64/include/asm/cpucaps.h | 3 +-
arch/arm64/include/asm/cpufeature.h | 13 +
arch/arm64/include/asm/esr.h | 3 +-
arch/arm64/include/asm/fpsimd.h | 72 ++++
arch/arm64/include/asm/fpsimdmacros.h | 150 ++++++++
arch/arm64/include/asm/kvm_arm.h | 1 +
arch/arm64/include/asm/processor.h | 14 +
arch/arm64/include/asm/sysreg.h | 15 +
arch/arm64/include/asm/thread_info.h | 2 +
arch/arm64/include/uapi/asm/hwcap.h | 1 +
arch/arm64/include/uapi/asm/ptrace.h | 130 +++++++
arch/arm64/include/uapi/asm/sigcontext.h | 117 ++++++
arch/arm64/kernel/cpufeature.c | 39 ++
arch/arm64/kernel/cpuinfo.c | 14 +
arch/arm64/kernel/entry-fpsimd.S | 17 +
arch/arm64/kernel/entry.S | 18 +-
arch/arm64/kernel/fpsimd.c | 613 ++++++++++++++++++++++++++++++-
arch/arm64/kernel/head.S | 15 +-
arch/arm64/kernel/process.c | 6 +-
arch/arm64/kernel/ptrace.c | 253 ++++++++++++-
arch/arm64/kernel/setup.c | 1 +
arch/arm64/kernel/signal.c | 500 +++++++++++++++++++++++--
arch/arm64/kernel/signal32.c | 2 +-
arch/arm64/kernel/traps.c | 1 +
arch/arm64/kvm/handle_exit.c | 8 +
arch/arm64/mm/proc.S | 14 +-
include/uapi/linux/elf.h | 1 +
include/uapi/linux/prctl.h | 11 +
kernel/sys.c | 12 +
32 files changed, 2474 insertions(+), 62 deletions(-)
create mode 100644 Documentation/arm64/sve.txt
--
2.1.4
^ permalink raw reply [flat|nested] 66+ messages in thread
* [RFC PATCH v2 01/41] arm64: signal: Refactor sigcontext parsing in rt_sigreturn
2017-03-22 14:50 [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support Dave Martin
@ 2017-03-22 14:50 ` Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 02/41] arm64: signal: factor frame layout and population into separate passes Dave Martin
` (40 subsequent siblings)
41 siblings, 0 replies; 66+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
To: linux-arm-kernel
Currently, rt_sigreturn does very limited checking on the
sigcontext coming from userspace.
Future additions of extra dynamic sigcontext data will increase the
potential for surprises. Also, it is not clear whether the
sigcontext extension records are supposed to occur in a particular
order.
This patch factors out the sigcontext parsing into a separate
function, and adds extra checks to validate the well-formedness of
the sigcontext structure.
To help with this, an abstraction for the signal frame layout is
also added, using offsets to track the location of different
records in the frame. Although trivial, this provides a base to
extend upon in order to track more complex layouts.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/kernel/signal.c | 121 +++++++++++++++++++++++++++++++++++++--------
1 file changed, 101 insertions(+), 20 deletions(-)
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index c7b6de6..f582d1d 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -19,9 +19,11 @@
#include <linux/compat.h>
#include <linux/errno.h>
+#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/personality.h>
#include <linux/freezer.h>
+#include <linux/stddef.h>
#include <linux/uaccess.h>
#include <linux/tracehook.h>
#include <linux/ratelimit.h>
@@ -45,6 +47,10 @@ struct rt_sigframe {
u64 lr;
};
+struct rt_sigframe_user_layout {
+ struct rt_sigframe __user *sigframe;
+};
+
static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
{
struct fpsimd_state *fpsimd = ¤t->thread.fpsimd_state;
@@ -92,12 +98,86 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx)
return err ? -EFAULT : 0;
}
+struct user_ctxs {
+ struct fpsimd_context __user *fpsimd;
+};
+
+static int parse_user_sigframe(struct user_ctxs *user,
+ struct rt_sigframe __user *sf)
+{
+ struct sigcontext __user *sc = &sf->uc.uc_mcontext;
+ struct _aarch64_ctx __user *head =
+ (struct _aarch64_ctx __user *)&sc->__reserved;
+ size_t offset = 0;
+
+ user->fpsimd = NULL;
+
+ while (1) {
+ int err;
+ u32 magic, size;
+
+ head = (struct _aarch64_ctx __user *)&sc->__reserved[offset];
+ if (!IS_ALIGNED((unsigned long)head, 16))
+ goto invalid;
+
+ err = 0;
+ __get_user_error(magic, &head->magic, err);
+ __get_user_error(size, &head->size, err);
+ if (err)
+ return err;
+
+ switch (magic) {
+ case 0:
+ if (size)
+ goto invalid;
+
+ goto done;
+
+ case FPSIMD_MAGIC:
+ if (user->fpsimd)
+ goto invalid;
+
+ if (offset > sizeof(sc->__reserved) -
+ sizeof(*user->fpsimd) ||
+ size < sizeof(*user->fpsimd))
+ goto invalid;
+
+ user->fpsimd = (struct fpsimd_context __user *)head;
+ break;
+
+ case ESR_MAGIC:
+ /* ignore */
+ break;
+
+ default:
+ goto invalid;
+ }
+
+ if (size < sizeof(*head))
+ goto invalid;
+
+ if (size > sizeof(sc->__reserved) - (sizeof(*head) + offset))
+ goto invalid;
+
+ offset += size;
+ }
+
+done:
+ if (!user->fpsimd)
+ goto invalid;
+
+ return 0;
+
+invalid:
+ return -EINVAL;
+}
+
static int restore_sigframe(struct pt_regs *regs,
struct rt_sigframe __user *sf)
{
sigset_t set;
int i, err;
- void *aux = sf->uc.uc_mcontext.__reserved;
+ struct user_ctxs user;
err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
if (err == 0)
@@ -116,12 +196,11 @@ static int restore_sigframe(struct pt_regs *regs,
regs->syscallno = ~0UL;
err |= !valid_user_regs(®s->user_regs, current);
+ if (err == 0)
+ err = parse_user_sigframe(&user, sf);
- if (err == 0) {
- struct fpsimd_context *fpsimd_ctx =
- container_of(aux, struct fpsimd_context, head);
- err |= restore_fpsimd_context(fpsimd_ctx);
- }
+ if (err == 0)
+ err = restore_fpsimd_context(user.fpsimd);
return err;
}
@@ -162,10 +241,11 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
return 0;
}
-static int setup_sigframe(struct rt_sigframe __user *sf,
+static int setup_sigframe(struct rt_sigframe_user_layout *user,
struct pt_regs *regs, sigset_t *set)
{
int i, err = 0;
+ struct rt_sigframe __user *sf = user->sigframe;
void *aux = sf->uc.uc_mcontext.__reserved;
struct _aarch64_ctx *end;
@@ -209,33 +289,32 @@ static int setup_sigframe(struct rt_sigframe __user *sf,
return err;
}
-static struct rt_sigframe __user *get_sigframe(struct ksignal *ksig,
- struct pt_regs *regs)
+static int get_sigframe(struct rt_sigframe_user_layout *user,
+ struct ksignal *ksig, struct pt_regs *regs)
{
unsigned long sp, sp_top;
- struct rt_sigframe __user *frame;
sp = sp_top = sigsp(regs->sp, ksig);
sp = (sp - sizeof(struct rt_sigframe)) & ~15;
- frame = (struct rt_sigframe __user *)sp;
+ user->sigframe = (struct rt_sigframe __user *)sp;
/*
* Check that we can actually write to the signal frame.
*/
- if (!access_ok(VERIFY_WRITE, frame, sp_top - sp))
- frame = NULL;
+ if (!access_ok(VERIFY_WRITE, user->sigframe, sp_top - sp))
+ return -EFAULT;
- return frame;
+ return 0;
}
static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
- void __user *frame, int usig)
+ struct rt_sigframe_user_layout *user, int usig)
{
__sigrestore_t sigtramp;
regs->regs[0] = usig;
- regs->sp = (unsigned long)frame;
+ regs->sp = (unsigned long)user->sigframe;
regs->regs[29] = regs->sp + offsetof(struct rt_sigframe, fp);
regs->pc = (unsigned long)ka->sa.sa_handler;
@@ -250,20 +329,22 @@ static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
struct pt_regs *regs)
{
+ struct rt_sigframe_user_layout user;
struct rt_sigframe __user *frame;
int err = 0;
- frame = get_sigframe(ksig, regs);
- if (!frame)
+ if (get_sigframe(&user, ksig, regs))
return 1;
+ frame = user.sigframe;
+
__put_user_error(0, &frame->uc.uc_flags, err);
__put_user_error(NULL, &frame->uc.uc_link, err);
err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
- err |= setup_sigframe(frame, regs, set);
+ err |= setup_sigframe(&user, regs, set);
if (err == 0) {
- setup_return(regs, &ksig->ka, frame, usig);
+ setup_return(regs, &ksig->ka, &user, usig);
if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
err |= copy_siginfo_to_user(&frame->info, &ksig->info);
regs->regs[1] = (unsigned long)&frame->info;
--
2.1.4
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v2 02/41] arm64: signal: factor frame layout and population into separate passes
2017-03-22 14:50 [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 01/41] arm64: signal: Refactor sigcontext parsing in rt_sigreturn Dave Martin
@ 2017-03-22 14:50 ` Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 03/41] arm64: signal: factor out signal frame record allocation Dave Martin
` (39 subsequent siblings)
41 siblings, 0 replies; 66+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
To: linux-arm-kernel
In preparation for expanding the signal frame, this patch refactors
the signal frame setup code in setup_sigframe() into two separate
passes.
The first pass, setup_sigframe_layout(), determines the size of the
signal frame and its internal layout, including the presence and
location of optional records. The resulting knowledge is used to
allocate and locate the user stack space required for the signal
frame and to determine which optional records to include.
The second pass, setup_sigframe(), is called once the stack frame
is allocated in order to populate it with the necessary context
information.
This change has no effect on the signal ABI, but will make it
easier to expand the signal frame in future patches.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/kernel/signal.c | 112 +++++++++++++++++++++++++++++++++++----------
1 file changed, 88 insertions(+), 24 deletions(-)
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index f582d1d..e2fe34b 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -25,6 +25,7 @@
#include <linux/freezer.h>
#include <linux/stddef.h>
#include <linux/uaccess.h>
+#include <linux/string.h>
#include <linux/tracehook.h>
#include <linux/ratelimit.h>
@@ -49,8 +50,39 @@ struct rt_sigframe {
struct rt_sigframe_user_layout {
struct rt_sigframe __user *sigframe;
+
+ unsigned long size; /* size of allocated sigframe data */
+ unsigned long limit; /* largest allowed size */
+
+ unsigned long fpsimd_offset;
+ unsigned long esr_offset;
+ unsigned long end_offset;
};
+static void init_user_layout(struct rt_sigframe_user_layout *user)
+{
+ memset(user, 0, sizeof(*user));
+ user->size = offsetof(struct rt_sigframe, uc.uc_mcontext.__reserved);
+
+ user->limit = user->size +
+ sizeof(user->sigframe->uc.uc_mcontext.__reserved) -
+ round_up(sizeof(struct _aarch64_ctx), 16);
+ /* ^ reserve space for terminator */
+}
+
+static size_t sigframe_size(struct rt_sigframe_user_layout const *user)
+{
+ return round_up(max(user->size, sizeof(struct rt_sigframe)), 16);
+}
+
+static void __user *apply_user_offset(
+ struct rt_sigframe_user_layout const *user, unsigned long offset)
+{
+ char __user *base = (char __user *)user->sigframe;
+
+ return base + offset;
+}
+
static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
{
struct fpsimd_state *fpsimd = ¤t->thread.fpsimd_state;
@@ -106,26 +138,35 @@ static int parse_user_sigframe(struct user_ctxs *user,
struct rt_sigframe __user *sf)
{
struct sigcontext __user *sc = &sf->uc.uc_mcontext;
- struct _aarch64_ctx __user *head =
- (struct _aarch64_ctx __user *)&sc->__reserved;
+ struct _aarch64_ctx __user *head;
+ char __user *base = (char __user *)&sc->__reserved;
size_t offset = 0;
+ size_t limit = sizeof(sc->__reserved);
user->fpsimd = NULL;
+ if (!IS_ALIGNED((unsigned long)base, 16))
+ goto invalid;
+
while (1) {
- int err;
+ int err = 0;
u32 magic, size;
- head = (struct _aarch64_ctx __user *)&sc->__reserved[offset];
- if (!IS_ALIGNED((unsigned long)head, 16))
+ if (limit - offset < sizeof(*head))
goto invalid;
- err = 0;
+ if (!IS_ALIGNED(offset, 16))
+ goto invalid;
+
+ head = (struct _aarch64_ctx __user *)(base + offset);
__get_user_error(magic, &head->magic, err);
__get_user_error(size, &head->size, err);
if (err)
return err;
+ if (limit - offset < size)
+ goto invalid;
+
switch (magic) {
case 0:
if (size)
@@ -137,9 +178,7 @@ static int parse_user_sigframe(struct user_ctxs *user,
if (user->fpsimd)
goto invalid;
- if (offset > sizeof(sc->__reserved) -
- sizeof(*user->fpsimd) ||
- size < sizeof(*user->fpsimd))
+ if (size < sizeof(*user->fpsimd))
goto invalid;
user->fpsimd = (struct fpsimd_context __user *)head;
@@ -156,7 +195,7 @@ static int parse_user_sigframe(struct user_ctxs *user,
if (size < sizeof(*head))
goto invalid;
- if (size > sizeof(sc->__reserved) - (sizeof(*head) + offset))
+ if (limit - offset < size)
goto invalid;
offset += size;
@@ -241,13 +280,30 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
return 0;
}
+/* Determine the layout of optional records in the signal frame */
+static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)
+{
+ user->fpsimd_offset = user->size;
+ user->size += round_up(sizeof(struct fpsimd_context), 16);
+
+ /* fault information, if valid */
+ if (current->thread.fault_code) {
+ user->esr_offset = user->size;
+ user->size += round_up(sizeof(struct esr_context), 16);
+ }
+
+ /* set the "end" magic */
+ user->end_offset = user->size;
+
+ return 0;
+}
+
+
static int setup_sigframe(struct rt_sigframe_user_layout *user,
struct pt_regs *regs, sigset_t *set)
{
int i, err = 0;
struct rt_sigframe __user *sf = user->sigframe;
- void *aux = sf->uc.uc_mcontext.__reserved;
- struct _aarch64_ctx *end;
/* set up the stack frame for unwinding */
__put_user_error(regs->regs[29], &sf->fp, err);
@@ -265,26 +321,29 @@ static int setup_sigframe(struct rt_sigframe_user_layout *user,
err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
if (err == 0) {
- struct fpsimd_context *fpsimd_ctx =
- container_of(aux, struct fpsimd_context, head);
+ struct fpsimd_context __user *fpsimd_ctx =
+ apply_user_offset(user, user->fpsimd_offset);
err |= preserve_fpsimd_context(fpsimd_ctx);
- aux += sizeof(*fpsimd_ctx);
}
/* fault information, if valid */
- if (current->thread.fault_code) {
- struct esr_context *esr_ctx =
- container_of(aux, struct esr_context, head);
+ if (err == 0 && user->esr_offset) {
+ struct esr_context __user *esr_ctx =
+ apply_user_offset(user, user->esr_offset);
+
__put_user_error(ESR_MAGIC, &esr_ctx->head.magic, err);
__put_user_error(sizeof(*esr_ctx), &esr_ctx->head.size, err);
__put_user_error(current->thread.fault_code, &esr_ctx->esr, err);
- aux += sizeof(*esr_ctx);
}
/* set the "end" magic */
- end = aux;
- __put_user_error(0, &end->magic, err);
- __put_user_error(0, &end->size, err);
+ if (err == 0) {
+ struct _aarch64_ctx __user *end =
+ apply_user_offset(user, user->end_offset);
+
+ __put_user_error(0, &end->magic, err);
+ __put_user_error(0, &end->size, err);
+ }
return err;
}
@@ -293,10 +352,15 @@ static int get_sigframe(struct rt_sigframe_user_layout *user,
struct ksignal *ksig, struct pt_regs *regs)
{
unsigned long sp, sp_top;
+ int err;
- sp = sp_top = sigsp(regs->sp, ksig);
+ init_user_layout(user);
+ err = setup_sigframe_layout(user);
+ if (err)
+ return err;
- sp = (sp - sizeof(struct rt_sigframe)) & ~15;
+ sp = sp_top = sigsp(regs->sp, ksig);
+ sp = (sp & ~15) - sigframe_size(user);
user->sigframe = (struct rt_sigframe __user *)sp;
/*
--
2.1.4
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v2 03/41] arm64: signal: factor out signal frame record allocation
2017-03-22 14:50 [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 01/41] arm64: signal: Refactor sigcontext parsing in rt_sigreturn Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 02/41] arm64: signal: factor frame layout and population into separate passes Dave Martin
@ 2017-03-22 14:50 ` Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 04/41] arm64: signal: Allocate extra sigcontext space as needed Dave Martin
` (38 subsequent siblings)
41 siblings, 0 replies; 66+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
To: linux-arm-kernel
Factor out the allocator for signal frame optional records into a
separate function, to ensure consistency and facilitate later
expansion of the signal frame.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/kernel/signal.c | 43 ++++++++++++++++++++++++++++++++++++-------
1 file changed, 36 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index e2fe34b..411a42d 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -75,6 +75,22 @@ static size_t sigframe_size(struct rt_sigframe_user_layout const *user)
return round_up(max(user->size, sizeof(struct rt_sigframe)), 16);
}
+/*
+ * Allocate space for an optional record of <size> bytes in the user
+ * signal frame. The offset from the signal frame base address to the
+ * allocated block is assigned to *offset.
+ */
+static int sigframe_alloc(struct rt_sigframe_user_layout *user,
+ unsigned long *offset, size_t size)
+{
+ size_t padded_size = round_up(size, 16);
+
+ *offset = user->size;
+ user->size += padded_size;
+
+ return 0;
+}
+
static void __user *apply_user_offset(
struct rt_sigframe_user_layout const *user, unsigned long offset)
{
@@ -283,19 +299,32 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
/* Determine the layout of optional records in the signal frame */
static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)
{
- user->fpsimd_offset = user->size;
- user->size += round_up(sizeof(struct fpsimd_context), 16);
+ int err;
+
+ err = sigframe_alloc(user, &user->fpsimd_offset,
+ sizeof(struct fpsimd_context));
+ if (err)
+ return err;
/* fault information, if valid */
if (current->thread.fault_code) {
- user->esr_offset = user->size;
- user->size += round_up(sizeof(struct esr_context), 16);
+ err = sigframe_alloc(user, &user->esr_offset,
+ sizeof(struct esr_context));
+ if (err)
+ return err;
}
- /* set the "end" magic */
- user->end_offset = user->size;
+ /*
+ * Allocate space for the terminator record.
+ * HACK: here we undo the reservation of space for the end record.
+ * This bodge should be replaced with a cleaner approach later on.
+ */
+ user->limit = offsetof(struct rt_sigframe, uc.uc_mcontext.__reserved) +
+ sizeof(user->sigframe->uc.uc_mcontext.__reserved);
- return 0;
+ err = sigframe_alloc(user, &user->end_offset,
+ sizeof(struct _aarch64_ctx));
+ return err;
}
--
2.1.4
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v2 04/41] arm64: signal: Allocate extra sigcontext space as needed
2017-03-22 14:50 [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support Dave Martin
` (2 preceding siblings ...)
2017-03-22 14:50 ` [RFC PATCH v2 03/41] arm64: signal: factor out signal frame record allocation Dave Martin
@ 2017-03-22 14:50 ` Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 05/41] arm64: signal: Parse extra_context during sigreturn Dave Martin
` (37 subsequent siblings)
41 siblings, 0 replies; 66+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
To: linux-arm-kernel
This patch modifies the context block allocator to create an
extra_context expansion block as necessary, and adds the necessary
code to populate, parse and decode this block.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/include/uapi/asm/sigcontext.h | 27 ++++++++
arch/arm64/kernel/signal.c | 112 +++++++++++++++++++++++++------
2 files changed, 120 insertions(+), 19 deletions(-)
diff --git a/arch/arm64/include/uapi/asm/sigcontext.h b/arch/arm64/include/uapi/asm/sigcontext.h
index ee469be..1af8437 100644
--- a/arch/arm64/include/uapi/asm/sigcontext.h
+++ b/arch/arm64/include/uapi/asm/sigcontext.h
@@ -61,4 +61,31 @@ struct esr_context {
__u64 esr;
};
+/*
+ * Pointer to extra space for additional structures that don't fit in
+ * sigcontext.__reserved[]. Note:
+ *
+ * 1) fpsimd_context, esr_context and extra_context must be placed in
+ * sigcontext.__reserved[] if present. They cannot be placed in the
+ * extra space. Any other record can be placed either in the extra
+ * space or in sigcontext.__reserved[].
+ *
+ * 2) There must not be more than one extra_context.
+ *
+ * 3) If extra_context is present, it must be followed immediately in
+ * sigcontext.__reserved[] by the terminating null _aarch64_ctx (i.e.,
+ * extra_context must be the last record in sigcontext.__reserved[]
+ * except for the terminator).
+ *
+ * 4) The extra space must itself be terminated with a null
+ * _aarch64_ctx.
+ */
+#define EXTRA_MAGIC 0x45585401
+
+struct extra_context {
+ struct _aarch64_ctx head;
+ void *data; /* 16-byte aligned pointer to the extra space */
+ __u32 size; /* size in bytes of the extra space */
+};
+
#endif /* _UAPI__ASM_SIGCONTEXT_H */
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 411a42d..223bd52 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -25,6 +25,7 @@
#include <linux/freezer.h>
#include <linux/stddef.h>
#include <linux/uaccess.h>
+#include <linux/sizes.h>
#include <linux/string.h>
#include <linux/tracehook.h>
#include <linux/ratelimit.h>
@@ -56,18 +57,22 @@ struct rt_sigframe_user_layout {
unsigned long fpsimd_offset;
unsigned long esr_offset;
+ unsigned long extra_offset;
unsigned long end_offset;
};
static void init_user_layout(struct rt_sigframe_user_layout *user)
{
+ const size_t __reserved_size =
+ sizeof(user->sigframe->uc.uc_mcontext.__reserved);
+ const size_t terminator_size =
+ round_up(sizeof(struct _aarch64_ctx), 16);
+
memset(user, 0, sizeof(*user));
user->size = offsetof(struct rt_sigframe, uc.uc_mcontext.__reserved);
-
- user->limit = user->size +
- sizeof(user->sigframe->uc.uc_mcontext.__reserved) -
- round_up(sizeof(struct _aarch64_ctx), 16);
- /* ^ reserve space for terminator */
+ user->limit = user->size + (__reserved_size - terminator_size -
+ sizeof(struct extra_context));
+ /* Reserve space for extension and terminator ^ */
}
static size_t sigframe_size(struct rt_sigframe_user_layout const *user)
@@ -75,6 +80,49 @@ static size_t sigframe_size(struct rt_sigframe_user_layout const *user)
return round_up(max(user->size, sizeof(struct rt_sigframe)), 16);
}
+/* Sanity limit on the maximum size of signal frame we'll try to generate. */
+/* This is NOT ABI. */
+#define SIGFRAME_MAXSZ SZ_64K
+
+static int __sigframe_alloc(struct rt_sigframe_user_layout *user,
+ unsigned long *offset, size_t size, bool extend)
+{
+ size_t padded_size = round_up(size, 16);
+
+ if (padded_size > user->limit - user->size &&
+ !user->extra_offset &&
+ extend) {
+ int ret;
+
+ ret = __sigframe_alloc(user, &user->extra_offset,
+ sizeof(struct extra_context), false);
+ if (ret)
+ return ret;
+
+ /*
+ * Further allocations must go after the fixed-size
+ * part of the signal frame:
+ */
+ user->size = round_up(sizeof(struct rt_sigframe), 16);
+
+ /*
+ * Allow expansion up to SIGFRAME_MAXSZ, ensuring space for
+ * the terminator:
+ */
+ user->limit = SIGFRAME_MAXSZ -
+ round_up(sizeof(struct _aarch64_ctx), 16);
+ }
+
+ /* Still not enough space? Bad luck! */
+ if (padded_size > user->limit - user->size)
+ return -ENOMEM;
+
+ *offset = user->size;
+ user->size += padded_size;
+
+ return 0;
+}
+
/*
* Allocate space for an optional record of <size> bytes in the user
* signal frame. The offset from the signal frame base address to the
@@ -83,11 +131,26 @@ static size_t sigframe_size(struct rt_sigframe_user_layout const *user)
static int sigframe_alloc(struct rt_sigframe_user_layout *user,
unsigned long *offset, size_t size)
{
- size_t padded_size = round_up(size, 16);
+ return __sigframe_alloc(user, offset, size, true);
+}
- *offset = user->size;
- user->size += padded_size;
+/* Allocate the null terminator record and prevent further allocations */
+static int sigframe_alloc_end(struct rt_sigframe_user_layout *user)
+{
+ int ret;
+ const size_t terminator_size =
+ round_up(sizeof(struct _aarch64_ctx), 16);
+
+ /* Un-reserve the space reserved for the terminator: */
+ user->limit += terminator_size;
+
+ ret = sigframe_alloc(user, &user->end_offset,
+ sizeof(struct _aarch64_ctx));
+ if (ret)
+ return ret;
+ /* Prevent further allocation: */
+ user->limit = user->size;
return 0;
}
@@ -314,17 +377,7 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)
return err;
}
- /*
- * Allocate space for the terminator record.
- * HACK: here we undo the reservation of space for the end record.
- * This bodge should be replaced with a cleaner approach later on.
- */
- user->limit = offsetof(struct rt_sigframe, uc.uc_mcontext.__reserved) +
- sizeof(user->sigframe->uc.uc_mcontext.__reserved);
-
- err = sigframe_alloc(user, &user->end_offset,
- sizeof(struct _aarch64_ctx));
- return err;
+ return sigframe_alloc_end(user);
}
@@ -365,6 +418,27 @@ static int setup_sigframe(struct rt_sigframe_user_layout *user,
__put_user_error(current->thread.fault_code, &esr_ctx->esr, err);
}
+ if (err == 0 && user->extra_offset) {
+ struct extra_context __user *extra =
+ apply_user_offset(user, user->extra_offset);
+ struct _aarch64_ctx __user *end =
+ (struct _aarch64_ctx __user *)((char __user *)extra +
+ round_up(sizeof(*extra), 16));
+ void __user *extra_data = apply_user_offset(user,
+ round_up(sizeof(struct rt_sigframe), 16));
+ u32 extra_size = round_up(user->size, 16) -
+ round_up(sizeof(struct rt_sigframe), 16);
+
+ __put_user_error(EXTRA_MAGIC, &extra->head.magic, err);
+ __put_user_error(sizeof(*extra), &extra->head.size, err);
+ __put_user_error(extra_data, &extra->data, err);
+ __put_user_error(extra_size, &extra->size, err);
+
+ /* Add the terminator */
+ __put_user_error(0, &end->magic, err);
+ __put_user_error(0, &end->size, err);
+ }
+
/* set the "end" magic */
if (err == 0) {
struct _aarch64_ctx __user *end =
--
2.1.4
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v2 05/41] arm64: signal: Parse extra_context during sigreturn
2017-03-22 14:50 [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support Dave Martin
` (3 preceding siblings ...)
2017-03-22 14:50 ` [RFC PATCH v2 04/41] arm64: signal: Allocate extra sigcontext space as needed Dave Martin
@ 2017-03-22 14:50 ` Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 06/41] arm64: efi: Add missing Kconfig dependency on KERNEL_MODE_NEON Dave Martin
` (36 subsequent siblings)
41 siblings, 0 replies; 66+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
To: linux-arm-kernel
If extra_context is present, parse it.
To avoid abuse by userspace, this patch attempts to ensure that:
* that no more than one extra_context is accepted;
* that the extra_context is a sensible size;
* that the extra context data is properly aligned.
This patch relies on the user accessors in order to ensure that the
user-supplied extra context data pointer is an honest userspace
address.
Other than that, the kernel doesn't care specially whether the
pointer supplied is sensible (e.g., not garbage, doesn't overlap
sigcontext.__reserved[], etc.) since this cannot harm the kernel.
More checks may be added later in order to aid debugging of
botched sigreturns from userspace.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/kernel/signal.c | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 223bd52..49c30df 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -221,6 +221,7 @@ static int parse_user_sigframe(struct user_ctxs *user,
char __user *base = (char __user *)&sc->__reserved;
size_t offset = 0;
size_t limit = sizeof(sc->__reserved);
+ bool have_extra_context = false;
user->fpsimd = NULL;
@@ -230,6 +231,9 @@ static int parse_user_sigframe(struct user_ctxs *user,
while (1) {
int err = 0;
u32 magic, size;
+ struct extra_context const __user *extra;
+ void __user *extra_data;
+ u32 extra_size;
if (limit - offset < sizeof(*head))
goto invalid;
@@ -267,6 +271,42 @@ static int parse_user_sigframe(struct user_ctxs *user,
/* ignore */
break;
+ case EXTRA_MAGIC:
+ if (have_extra_context)
+ goto invalid;
+
+ if (size < sizeof(*extra))
+ goto invalid;
+
+ extra = (struct extra_context const __user *)head;
+ __get_user_error(extra_data, &extra->data, err);
+ __get_user_error(extra_size, &extra->size, err);
+ if (err)
+ return err;
+
+ /* Prevent looping/repeated parsing of extra_conext */
+ have_extra_context = true;
+
+ /*
+ * Rely on the __user accessors to reject bogus
+ * pointers.
+ */
+ base = extra_data;
+ if (!IS_ALIGNED((unsigned long)base, 16))
+ goto invalid;
+
+ /* Reject "unreasonably large" frames: */
+ limit = extra_size;
+ if (limit > SIGFRAME_MAXSZ - sizeof(sc->__reserved))
+ goto invalid;
+
+ /*
+ * Ignore trailing terminator in __reserved[]
+ * and start parsing extra_data:
+ */
+ offset = 0;
+ continue;
+
default:
goto invalid;
}
--
2.1.4
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v2 06/41] arm64: efi: Add missing Kconfig dependency on KERNEL_MODE_NEON
2017-03-22 14:50 [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support Dave Martin
` (4 preceding siblings ...)
2017-03-22 14:50 ` [RFC PATCH v2 05/41] arm64: signal: Parse extra_context during sigreturn Dave Martin
@ 2017-03-22 14:50 ` Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 07/41] arm64/sve: Allow kernel-mode NEON to be disabled in Kconfig Dave Martin
` (35 subsequent siblings)
41 siblings, 0 replies; 66+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
To: linux-arm-kernel
The EFI runtime services ABI permits calls to EFI to clobber
certain FPSIMD/NEON registers, as per the AArch64 procedure call
standard.
Saving/restoring the clobbered registers around such calls needs
KERNEL_MODE_NEON, but the dependency is missing from Kconfig.
This patch adds the missing dependency.
This will aid bisection of the patches implementing support for the
ARM Scalable Vector Extension (SVE).
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 3741859..6f270a8 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1019,6 +1019,7 @@ config EFI_STUB
config EFI
bool "UEFI runtime support"
depends on OF && !CPU_BIG_ENDIAN
+ depends on KERNEL_MODE_NEON
select LIBFDT
select UCS2_STRING
select EFI_PARAMS_FROM_FDT
--
2.1.4
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v2 07/41] arm64/sve: Allow kernel-mode NEON to be disabled in Kconfig
2017-03-22 14:50 [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support Dave Martin
` (5 preceding siblings ...)
2017-03-22 14:50 ` [RFC PATCH v2 06/41] arm64: efi: Add missing Kconfig dependency on KERNEL_MODE_NEON Dave Martin
@ 2017-03-22 14:50 ` Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 08/41] arm64/sve: Low-level save/restore code Dave Martin
` (34 subsequent siblings)
41 siblings, 0 replies; 66+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
To: linux-arm-kernel
Currently, support for kernel-mode NEON alongside the Scalable
Vector Extension doesn't work, so allow KERNEL_MODE_NEON to be
disabled.
This is only needed for bisectability of the SVE patches and will
be removed later.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/Kconfig | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 6f270a8..cf82776 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -226,9 +226,6 @@ config SWIOTLB
config IOMMU_HELPER
def_bool SWIOTLB
-config KERNEL_MODE_NEON
- def_bool y
-
config FIX_EARLYCON_MEM
def_bool y
@@ -274,6 +271,10 @@ endmenu
menu "Kernel Features"
+config KERNEL_MODE_NEON
+ bool "Support NEON/FPSIMD code in the kernel"
+ default y
+
menu "ARM errata workarounds via the alternatives framework"
config ARM64_ERRATUM_826319
--
2.1.4
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v2 08/41] arm64/sve: Low-level save/restore code
2017-03-22 14:50 [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support Dave Martin
` (6 preceding siblings ...)
2017-03-22 14:50 ` [RFC PATCH v2 07/41] arm64/sve: Allow kernel-mode NEON to be disabled in Kconfig Dave Martin
@ 2017-03-22 14:50 ` Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 09/41] arm64/sve: Boot-time feature detection and reporting Dave Martin
` (33 subsequent siblings)
41 siblings, 0 replies; 66+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
To: linux-arm-kernel
This patch adds low-level save/restore for the Scalable Vector
Extension.
This is helper code only, and is not used for anything yet.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/Kconfig | 12 +++
arch/arm64/include/asm/fpsimd.h | 3 +
arch/arm64/include/asm/fpsimdmacros.h | 145 ++++++++++++++++++++++++++++++++++
arch/arm64/kernel/entry-fpsimd.S | 17 ++++
4 files changed, 177 insertions(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index cf82776..289dcb9 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -932,6 +932,18 @@ config ARM64_UAO
endmenu
+config ARM64_SVE
+ bool "ARM Scalable Vector Extension support"
+ default y
+ depends on !KERNEL_MODE_NEON # until it works with SVE
+ help
+ The Scalable Vector Extension (SVE) is an extension to the AArch64
+ execution state which complements and extends the SIMD functionality
+ of the base architecture to support much larger vectors and to enable
+ additional vectorisation opportunities.
+
+ To enable use of this extension on CPUs that implement it, say Y.
+
config ARM64_MODULE_CMODEL_LARGE
bool
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 50f559f..92f45ee 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -81,6 +81,9 @@ extern void fpsimd_save_partial_state(struct fpsimd_partial_state *state,
u32 num_regs);
extern void fpsimd_load_partial_state(struct fpsimd_partial_state *state);
+extern void sve_save_state(void *state, u32 *pfpsr);
+extern void sve_load_state(void const *state, u32 const *pfpsr);
+
#endif
#endif
diff --git a/arch/arm64/include/asm/fpsimdmacros.h b/arch/arm64/include/asm/fpsimdmacros.h
index a2daf12..e2bb032 100644
--- a/arch/arm64/include/asm/fpsimdmacros.h
+++ b/arch/arm64/include/asm/fpsimdmacros.h
@@ -131,3 +131,148 @@
ldp q0, q1, [\state, #-16 * 0 - 16]
0:
.endm
+
+.macro _check_reg nr
+ .if (\nr) < 0 || (\nr) > 31
+ .error "Bad register number \nr."
+ .endif
+.endm
+
+.macro _check_zreg znr
+ .if (\znr) < 0 || (\znr) > 31
+ .error "Bad Scalable Vector Extension vector register number \znr."
+ .endif
+.endm
+
+.macro _check_preg pnr
+ .if (\pnr) < 0 || (\pnr) > 15
+ .error "Bad Scalable Vector Extension predicate register number \pnr."
+ .endif
+.endm
+
+.macro _check_num n, min, max
+ .if (\n) < (\min) || (\n) > (\max)
+ .error "Number \n out of range [\min,\max]"
+ .endif
+.endm
+
+.macro _zstrv znt, nspb, ioff=0
+ _check_zreg \znt
+ _check_reg \nspb
+ _check_num (\ioff), -0x100, 0xff
+ .inst 0xe5804000 \
+ | (\znt) \
+ | ((\nspb) << 5) \
+ | (((\ioff) & 7) << 10) \
+ | (((\ioff) & 0x1f8) << 13)
+.endm
+
+.macro _zldrv znt, nspb, ioff=0
+ _check_zreg \znt
+ _check_reg \nspb
+ _check_num (\ioff), -0x100, 0xff
+ .inst 0x85804000 \
+ | (\znt) \
+ | ((\nspb) << 5) \
+ | (((\ioff) & 7) << 10) \
+ | (((\ioff) & 0x1f8) << 13)
+.endm
+
+.macro _zstrp pnt, nspb, ioff=0
+ _check_preg \pnt
+ _check_reg \nspb
+ _check_num (\ioff), -0x100, 0xff
+ .inst 0xe5800000 \
+ | (\pnt) \
+ | ((\nspb) << 5) \
+ | (((\ioff) & 7) << 10) \
+ | (((\ioff) & 0x1f8) << 13)
+.endm
+
+.macro _zldrp pnt, nspb, ioff=0
+ _check_preg \pnt
+ _check_reg \nspb
+ _check_num (\ioff), -0x100, 0xff
+ .inst 0x85800000 \
+ | (\pnt) \
+ | ((\nspb) << 5) \
+ | (((\ioff) & 7) << 10) \
+ | (((\ioff) & 0x1f8) << 13)
+.endm
+
+.macro _zrdvl nspd, is1
+ _check_reg \nspd
+ _check_num (\is1), -0x20, 0x1f
+ .inst 0x04bf5000 \
+ | (\nspd) \
+ | (((\is1) & 0x3f) << 5)
+.endm
+
+.macro _zrdffr pnd
+ _check_preg \pnd
+ .inst 0x2519f000 \
+ | (\pnd)
+.endm
+
+.macro _zwrffr pnd
+ _check_preg \pnd
+ .inst 0x25289000 \
+ | ((\pnd) << 5)
+.endm
+
+.macro for from, to, insn
+ .if (\from) >= (\to)
+ \insn (\from)
+ .exitm
+ .endif
+
+ for \from, ((\from) + (\to)) / 2, \insn
+ for ((\from) + (\to)) / 2 + 1, \to, \insn
+.endm
+
+.macro sve_save nb, xpfpsr, ntmp
+ .macro savez n
+ _zstrv \n, \nb, (\n) - 34
+ .endm
+
+ .macro savep n
+ _zstrp \n, \nb, (\n) - 16
+ .endm
+
+ for 0, 31, savez
+ for 0, 15, savep
+ _zrdffr 0
+ _zstrp 0, \nb
+ _zldrp 0, \nb, -16
+
+ mrs x\ntmp, fpsr
+ str w\ntmp, [\xpfpsr]
+ mrs x\ntmp, fpcr
+ str w\ntmp, [\xpfpsr, #4]
+
+ .purgem savez
+ .purgem savep
+.endm
+
+.macro sve_load nb, xpfpsr, ntmp
+ .macro loadz n
+ _zldrv \n, \nb, (\n) - 34
+ .endm
+
+ .macro loadp n
+ _zldrp \n, \nb, (\n) - 16
+ .endm
+
+ for 0, 31, loadz
+ _zldrp 0, \nb
+ _zwrffr 0
+ for 0, 15, loadp
+
+ ldr w\ntmp, [\xpfpsr]
+ msr fpsr, x\ntmp
+ ldr w\ntmp, [\xpfpsr, #4]
+ msr fpcr, x\ntmp
+
+ .purgem loadz
+ .purgem loadp
+.endm
diff --git a/arch/arm64/kernel/entry-fpsimd.S b/arch/arm64/kernel/entry-fpsimd.S
index c44a82f..5dcec55 100644
--- a/arch/arm64/kernel/entry-fpsimd.S
+++ b/arch/arm64/kernel/entry-fpsimd.S
@@ -65,3 +65,20 @@ ENTRY(fpsimd_load_partial_state)
ENDPROC(fpsimd_load_partial_state)
#endif
+
+#ifdef CONFIG_ARM64_SVE
+ENTRY(sve_save_state)
+ sve_save 0, x1, 2
+ ret
+ENDPROC(sve_save_state)
+
+ENTRY(sve_load_state)
+ sve_load 0, x1, 2
+ ret
+ENDPROC(sve_load_state)
+
+ENTRY(sve_get_vl)
+ _zrdvl 0, 1
+ ret
+ENDPROC(sve_get_vl)
+#endif /* CONFIG_ARM64_SVE */
--
2.1.4
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v2 09/41] arm64/sve: Boot-time feature detection and reporting
2017-03-22 14:50 [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support Dave Martin
` (7 preceding siblings ...)
2017-03-22 14:50 ` [RFC PATCH v2 08/41] arm64/sve: Low-level save/restore code Dave Martin
@ 2017-03-22 14:50 ` Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 10/41] arm64/sve: Boot-time feature enablement Dave Martin
` (32 subsequent siblings)
41 siblings, 0 replies; 66+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
To: linux-arm-kernel
This patch adds feature detection for the ARM Scalable Vector
Extension, and adds basic informative feature reporting via
/proc/cpuinfo.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/include/asm/sysreg.h | 1 +
arch/arm64/include/uapi/asm/hwcap.h | 1 +
arch/arm64/kernel/cpufeature.c | 3 +++
arch/arm64/kernel/cpuinfo.c | 1 +
4 files changed, 6 insertions(+)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index ac24b6e..8f1a43e 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -157,6 +157,7 @@
#define ID_AA64ISAR0_AES_SHIFT 4
/* id_aa64pfr0 */
+#define ID_AA64PFR0_SVE_SHIFT 32
#define ID_AA64PFR0_GIC_SHIFT 24
#define ID_AA64PFR0_ASIMD_SHIFT 20
#define ID_AA64PFR0_FP_SHIFT 16
diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h
index 61c263c..7f0f86d 100644
--- a/arch/arm64/include/uapi/asm/hwcap.h
+++ b/arch/arm64/include/uapi/asm/hwcap.h
@@ -32,5 +32,6 @@
#define HWCAP_ASIMDHP (1 << 10)
#define HWCAP_CPUID (1 << 11)
#define HWCAP_ASIMDRDM (1 << 12)
+#define HWCAP_SVE (1 << 13)
#endif /* _UAPI__ASM_HWCAP_H */
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index abda8e8..707dfdb 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -888,6 +888,9 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_FPHP),
HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_ASIMD),
HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_ASIMDHP),
+#ifdef CONFIG_ARM64_SVE
+ HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_SVE_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SVE),
+#endif
{},
};
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
index 5b22c68..8dd410e 100644
--- a/arch/arm64/kernel/cpuinfo.c
+++ b/arch/arm64/kernel/cpuinfo.c
@@ -65,6 +65,7 @@ static const char *const hwcap_str[] = {
"asimdhp",
"cpuid",
"asimdrdm",
+ "sve",
NULL
};
--
2.1.4
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v2 10/41] arm64/sve: Boot-time feature enablement
2017-03-22 14:50 [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support Dave Martin
` (8 preceding siblings ...)
2017-03-22 14:50 ` [RFC PATCH v2 09/41] arm64/sve: Boot-time feature detection and reporting Dave Martin
@ 2017-03-22 14:50 ` Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 11/41] arm64/sve: Expand task_struct for Scalable Vector Extension state Dave Martin
` (31 subsequent siblings)
41 siblings, 0 replies; 66+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
To: linux-arm-kernel
This patch enables Scalable Vector Extension access for the kernel
on boot.
If entered at EL2 without VHE support, ZCR_EL2 is also configured
to allow the maximum available vector length for EL1 initially, so
that the vector length can be correctly probed in advance of KVM
being initialised.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/include/asm/kvm_arm.h | 1 +
arch/arm64/include/asm/sysreg.h | 10 ++++++++++
arch/arm64/kernel/head.S | 15 ++++++++++++++-
arch/arm64/mm/proc.S | 14 ++++++++++++--
4 files changed, 37 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 6e99978..6f536ef 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -185,6 +185,7 @@
#define CPTR_EL2_TCPAC (1 << 31)
#define CPTR_EL2_TTA (1 << 20)
#define CPTR_EL2_TFP (1 << CPTR_EL2_TFP_SHIFT)
+#define CPTR_EL2_TZ (1 << 8)
#define CPTR_EL2_DEFAULT 0x000033ff
/* Hyp Debug Configuration Register bits */
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 8f1a43e..9c4a2cc 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -118,6 +118,9 @@
#define SYS_ID_AA64MMFR1_EL1 sys_reg(3, 0, 0, 7, 1)
#define SYS_ID_AA64MMFR2_EL1 sys_reg(3, 0, 0, 7, 2)
+#define SYS_ZCR_EL1 sys_reg(3, 0, 1, 2, 0)
+#define SYS_ZCR_EL2 sys_reg(3, 4, 1, 2, 0)
+
#define SYS_CNTFRQ_EL0 sys_reg(3, 3, 14, 0, 0)
#define SYS_CTR_EL0 sys_reg(3, 3, 0, 0, 1)
#define SYS_DCZID_EL0 sys_reg(3, 3, 0, 0, 7)
@@ -267,6 +270,13 @@
#endif
+#define ZCR_EL1_LEN_MASK 0x1ff
+
+#define CPACR_EL1_ZEN_EL1EN (1 << 16)
+#define CPACR_EL1_ZEN_EL0EN (1 << 17)
+#define CPACR_EL1_ZEN (CPACR_EL1_ZEN_EL1EN | CPACR_EL1_ZEN_EL0EN)
+
+
/* Safe value for MPIDR_EL1: Bit31:RES1, Bit30:U:0, Bit24:MT:0 */
#define SYS_MPIDR_SAFE_VAL (1UL << 31)
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 4fb6ccd..344a0dd 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -629,9 +629,22 @@ CPU_LE( movk x0, #0x30d0, lsl #16 ) // Clear EE and E0E on LE systems
/* Coprocessor traps. */
mov x0, #0x33ff
+
+ /* SVE register access */
+ mrs x1, id_aa64pfr0_el1
+ ubfx x1, x1, #ID_AA64PFR0_SVE_SHIFT, #4
+ cbz x1, 4f
+
+ bic x0, x0, #CPTR_EL2_TZ // Disable SVE traps to EL2
msr cptr_el2, x0 // Disable copro. traps to EL2
-1:
+ isb
+
+ mov x1, #ZCR_EL1_LEN_MASK // SVE: Enable full vector
+ msr_s SYS_ZCR_EL1, x1 // length for EL1.
+ b 1f
+4: msr cptr_el2, x0 // Disable copro. traps to EL2
+1:
#ifdef CONFIG_COMPAT
msr hstr_el2, xzr // Disable CP15 traps to EL2
#endif
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index 877d42f..dd22ef2 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -27,6 +27,7 @@
#include <asm/pgtable-hwdef.h>
#include <asm/cpufeature.h>
#include <asm/alternative.h>
+#include <asm/sysreg.h>
#ifdef CONFIG_ARM64_64K_PAGES
#define TCR_TG_FLAGS TCR_TG0_64K | TCR_TG1_64K
@@ -186,8 +187,17 @@ ENTRY(__cpu_setup)
tlbi vmalle1 // Invalidate local TLB
dsb nsh
- mov x0, #3 << 20
- msr cpacr_el1, x0 // Enable FP/ASIMD
+ mov x0, #3 << 20 // FEN
+
+ /* SVE */
+ mrs x5, id_aa64pfr0_el1
+ ubfx x5, x5, #ID_AA64PFR0_SVE_SHIFT, #4
+ cbz x5, 1f
+
+ bic x0, x0, #CPACR_EL1_ZEN
+ orr x0, x0, #CPACR_EL1_ZEN_EL1EN // SVE: trap for EL0, not EL1
+1: msr cpacr_el1, x0 // Enable FP/ASIMD
+
mov x0, #1 << 12 // Reset mdscr_el1 and disable
msr mdscr_el1, x0 // access to the DCC from EL0
isb // Unmask debug exceptions now,
--
2.1.4
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v2 11/41] arm64/sve: Expand task_struct for Scalable Vector Extension state
2017-03-22 14:50 [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support Dave Martin
` (9 preceding siblings ...)
2017-03-22 14:50 ` [RFC PATCH v2 10/41] arm64/sve: Boot-time feature enablement Dave Martin
@ 2017-03-22 14:50 ` Dave Martin
2017-03-22 16:20 ` Mark Rutland
2017-03-22 14:50 ` [RFC PATCH v2 12/41] arm64/sve: Save/restore SVE state on context switch paths Dave Martin
` (30 subsequent siblings)
41 siblings, 1 reply; 66+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
To: linux-arm-kernel
This patch expands task_struct to accommodate the Scalable Vector
Extension state.
The extra space is not used for anything yet.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/fpsimd.h | 11 ++++++
arch/arm64/kernel/fpsimd.c | 75 ++++++++++++++++++++++++++++++++++++++++-
arch/arm64/kernel/process.c | 2 +-
arch/arm64/kernel/setup.c | 3 ++
5 files changed, 90 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 289dcb9..820fad1 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -23,6 +23,7 @@ config ARM64
select ARCH_SUPPORTS_NUMA_BALANCING
select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
select ARCH_WANT_FRAME_POINTERS
+ select ARCH_WANTS_DYNAMIC_TASK_STRUCT
select ARCH_HAS_UBSAN_SANITIZE_ALL
select ARM_AMBA
select ARM_ARCH_TIMER
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 92f45ee..757d304 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -51,6 +51,15 @@ struct fpsimd_partial_state {
__uint128_t vregs[32];
};
+/*
+ * Scalable Vector Extension state structure template.
+ * The layout is vector length dependent, with vector length = vl * 16 bytes.
+ */
+#define fpsimd_sve_state(vl) { \
+ __uint128_t zregs[32][vl]; \
+ u16 pregs[16][vl]; \
+ u16 ffr[vl]; \
+}
#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
/* Masks for extracting the FPSR and FPCR from the FPSCR */
@@ -83,6 +92,8 @@ extern void fpsimd_load_partial_state(struct fpsimd_partial_state *state);
extern void sve_save_state(void *state, u32 *pfpsr);
extern void sve_load_state(void const *state, u32 const *pfpsr);
+extern unsigned int sve_get_vl(void);
+extern void __init fpsimd_init_task_struct_size(void);
#endif
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 06da8ea..bc7a2d5 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -27,6 +27,7 @@
#include <asm/fpsimd.h>
#include <asm/cputype.h>
+#include <asm/hwcap.h>
#define FPEXC_IOF (1 << 0)
#define FPEXC_DZF (1 << 1)
@@ -89,6 +90,29 @@
*/
static DEFINE_PER_CPU(struct fpsimd_state *, fpsimd_last_state);
+#ifdef CONFIG_ARM64_SVE
+
+static void *__sve_state(struct task_struct *task)
+{
+ return (char *)task + ALIGN(sizeof(*task), 16);
+}
+
+static void *sve_pffr(struct task_struct *task)
+{
+ unsigned int vl = sve_get_vl();
+
+ BUG_ON(vl % 16);
+ return (char *)__sve_state(task) + 34 * vl;
+}
+
+#else /* ! CONFIG_ARM64_SVE */
+
+/* Dummy declarations for usage protected with I